hid: Convert definition of HID registers to enum
* Refactor HID Register definitions Use enums for distinct type hints, easy discovery of registers. Make constants uppercase and benefit from enum auto-completion. Related #2273 * Improve type hints: Registers
This commit is contained in:
parent
c23ebcd267
commit
be83dac209
|
@ -26,10 +26,13 @@
|
||||||
|
|
||||||
from solaar.i18n import _
|
from solaar.i18n import _
|
||||||
|
|
||||||
# max_devices is only used for receivers that do not support reading from _R.receiver_info offset 0x03, default to 1
|
# max_devices is only used for receivers that do not support reading from Registers.RECEIVER_INFO offset 0x03, default
|
||||||
# may_unpair is only used for receivers that do not support reading from _R.receiver_info offset 0x03, default to False
|
# to 1.
|
||||||
# unpair is for receivers that do support reading from _R.receiver_info offset 0x03, no default
|
# may_unpair is only used for receivers that do not support reading from Registers.RECEIVER_INFO offset 0x03,
|
||||||
## should this last be changed so that may_unpair is used for all receivers? writing to _R.receiver_pairing doesn't seem right
|
# default to False.
|
||||||
|
# unpair is for receivers that do support reading from Registers.RECEIVER_INFO offset 0x03, no default.
|
||||||
|
## should this last be changed so that may_unpair is used for all receivers? writing to Registers.RECEIVER_PAIRING
|
||||||
|
## doesn't seem right
|
||||||
# re_pairs determines whether a receiver pairs by replacing existing pairings, default to False
|
# re_pairs determines whether a receiver pairs by replacing existing pairings, default to False
|
||||||
## currently only one receiver is so marked - should there be more?
|
## currently only one receiver is so marked - should there be more?
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ An entry should only be added to fix problems, such as
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from .hidpp10_constants import DEVICE_KIND
|
from .hidpp10_constants import DEVICE_KIND
|
||||||
from .hidpp10_constants import REGISTERS as REG
|
from .hidpp10_constants import Registers as Reg
|
||||||
|
|
||||||
|
|
||||||
class _DeviceDescriptor:
|
class _DeviceDescriptor:
|
||||||
|
@ -193,24 +193,24 @@ def get_btid(btid):
|
||||||
|
|
||||||
# Keyboards
|
# Keyboards
|
||||||
|
|
||||||
_D("Wireless Keyboard EX110", codename="EX110", protocol=1.0, wpid="0055", registers=(REG.battery_status,))
|
_D("Wireless Keyboard EX110", codename="EX110", protocol=1.0, wpid="0055", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("Wireless Keyboard S510", codename="S510", protocol=1.0, wpid="0056", registers=(REG.battery_status,))
|
_D("Wireless Keyboard S510", codename="S510", protocol=1.0, wpid="0056", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("Wireless Wave Keyboard K550", codename="K550", protocol=1.0, wpid="0060", registers=(REG.battery_status,))
|
_D("Wireless Wave Keyboard K550", codename="K550", protocol=1.0, wpid="0060", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("Wireless Keyboard EX100", codename="EX100", protocol=1.0, wpid="0065", registers=(REG.battery_status,))
|
_D("Wireless Keyboard EX100", codename="EX100", protocol=1.0, wpid="0065", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("Wireless Keyboard MK300", codename="MK300", protocol=1.0, wpid="0068", registers=(REG.battery_status,))
|
_D("Wireless Keyboard MK300", codename="MK300", protocol=1.0, wpid="0068", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("Number Pad N545", codename="N545", protocol=1.0, wpid="2006", registers=(REG.battery_status,))
|
_D("Number Pad N545", codename="N545", protocol=1.0, wpid="2006", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("Wireless Compact Keyboard K340", codename="K340", protocol=1.0, wpid="2007", registers=(REG.battery_status,))
|
_D("Wireless Compact Keyboard K340", codename="K340", protocol=1.0, wpid="2007", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("Wireless Keyboard MK700", codename="MK700", protocol=1.0, wpid="2008", registers=(REG.battery_status,))
|
_D("Wireless Keyboard MK700", codename="MK700", protocol=1.0, wpid="2008", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("Wireless Wave Keyboard K350", codename="K350", protocol=1.0, wpid="200A", registers=(REG.battery_status,))
|
_D("Wireless Wave Keyboard K350", codename="K350", protocol=1.0, wpid="200A", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("Wireless Keyboard MK320", codename="MK320", protocol=1.0, wpid="200F", registers=(REG.battery_status,))
|
_D("Wireless Keyboard MK320", codename="MK320", protocol=1.0, wpid="200F", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D(
|
_D(
|
||||||
"Wireless Illuminated Keyboard K800",
|
"Wireless Illuminated Keyboard K800",
|
||||||
codename="K800",
|
codename="K800",
|
||||||
protocol=1.0,
|
protocol=1.0,
|
||||||
wpid="2010",
|
wpid="2010",
|
||||||
registers=(REG.battery_status, REG.three_leds),
|
registers=(Reg.BATTERY_STATUS, Reg.THREE_LEDS),
|
||||||
)
|
)
|
||||||
_D("Wireless Keyboard K520", codename="K520", protocol=1.0, wpid="2011", registers=(REG.battery_status,))
|
_D("Wireless Keyboard K520", codename="K520", protocol=1.0, wpid="2011", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("Wireless Solar Keyboard K750", codename="K750", protocol=2.0, wpid="4002")
|
_D("Wireless Solar Keyboard K750", codename="K750", protocol=2.0, wpid="4002")
|
||||||
_D("Wireless Keyboard K270 (unifying)", codename="K270", protocol=2.0, wpid="4003")
|
_D("Wireless Keyboard K270 (unifying)", codename="K270", protocol=2.0, wpid="4003")
|
||||||
_D("Wireless Keyboard K360", codename="K360", protocol=2.0, wpid="4004")
|
_D("Wireless Keyboard K360", codename="K360", protocol=2.0, wpid="4004")
|
||||||
|
@ -235,57 +235,57 @@ _D("K845 Mechanical Keyboard", codename="K845", usbid=0xC341, interface=3)
|
||||||
|
|
||||||
# Mice
|
# Mice
|
||||||
|
|
||||||
_D("LX5 Cordless Mouse", codename="LX5", protocol=1.0, wpid="0036", registers=(REG.battery_status,))
|
_D("LX5 Cordless Mouse", codename="LX5", protocol=1.0, wpid="0036", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("LX7 Cordless Laser Mouse", codename="LX7", protocol=1.0, wpid="0039", registers=(REG.battery_status,))
|
_D("LX7 Cordless Laser Mouse", codename="LX7", protocol=1.0, wpid="0039", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("Wireless Wave Mouse M550", codename="M550", protocol=1.0, wpid="003C", registers=(REG.battery_status,))
|
_D("Wireless Wave Mouse M550", codename="M550", protocol=1.0, wpid="003C", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("Wireless Mouse EX100", codename="EX100m", protocol=1.0, wpid="003F", registers=(REG.battery_status,))
|
_D("Wireless Mouse EX100", codename="EX100m", protocol=1.0, wpid="003F", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("Wireless Mouse M30", codename="M30", protocol=1.0, wpid="0085", registers=(REG.battery_status,))
|
_D("Wireless Mouse M30", codename="M30", protocol=1.0, wpid="0085", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("MX610 Laser Cordless Mouse", codename="MX610", protocol=1.0, wpid="1001", registers=(REG.battery_status,))
|
_D("MX610 Laser Cordless Mouse", codename="MX610", protocol=1.0, wpid="1001", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("G7 Cordless Laser Mouse", codename="G7", protocol=1.0, wpid="1002", registers=(REG.battery_status,))
|
_D("G7 Cordless Laser Mouse", codename="G7", protocol=1.0, wpid="1002", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("V400 Laser Cordless Mouse", codename="V400", protocol=1.0, wpid="1003", registers=(REG.battery_status,))
|
_D("V400 Laser Cordless Mouse", codename="V400", protocol=1.0, wpid="1003", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("MX610 Left-Handled Mouse", codename="MX610L", protocol=1.0, wpid="1004", registers=(REG.battery_status,))
|
_D("MX610 Left-Handled Mouse", codename="MX610L", protocol=1.0, wpid="1004", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("V450 Laser Cordless Mouse", codename="V450", protocol=1.0, wpid="1005", registers=(REG.battery_status,))
|
_D("V450 Laser Cordless Mouse", codename="V450", protocol=1.0, wpid="1005", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D(
|
_D(
|
||||||
"VX Revolution",
|
"VX Revolution",
|
||||||
codename="VX Revolution",
|
codename="VX Revolution",
|
||||||
kind=DEVICE_KIND.mouse,
|
kind=DEVICE_KIND.mouse,
|
||||||
protocol=1.0,
|
protocol=1.0,
|
||||||
wpid=("1006", "100D", "0612"),
|
wpid=("1006", "100D", "0612"),
|
||||||
registers=(REG.battery_charge,),
|
registers=(Reg.BATTERY_CHARGE,),
|
||||||
)
|
)
|
||||||
_D("MX Air", codename="MX Air", protocol=1.0, kind=DEVICE_KIND.mouse, wpid=("1007", "100E"), registers=(REG.battery_charge,))
|
_D("MX Air", codename="MX Air", protocol=1.0, kind=DEVICE_KIND.mouse, wpid=("1007", "100E"), registers=(Reg.BATTERY_CHARGE))
|
||||||
_D(
|
_D(
|
||||||
"MX Revolution",
|
"MX Revolution",
|
||||||
codename="MX Revolution",
|
codename="MX Revolution",
|
||||||
protocol=1.0,
|
protocol=1.0,
|
||||||
kind=DEVICE_KIND.mouse,
|
kind=DEVICE_KIND.mouse,
|
||||||
wpid=("1008", "100C"),
|
wpid=("1008", "100C"),
|
||||||
registers=(REG.battery_charge,),
|
registers=(Reg.BATTERY_CHARGE,),
|
||||||
)
|
)
|
||||||
_D("MX620 Laser Cordless Mouse", codename="MX620", protocol=1.0, wpid=("100A", "1016"), registers=(REG.battery_charge,))
|
_D("MX620 Laser Cordless Mouse", codename="MX620", protocol=1.0, wpid=("100A", "1016"), registers=(Reg.BATTERY_CHARGE,))
|
||||||
_D("VX Nano Cordless Laser Mouse", codename="VX Nano", protocol=1.0, wpid=("100B", "100F"), registers=(REG.battery_charge,))
|
_D("VX Nano Cordless Laser Mouse", codename="VX Nano", protocol=1.0, wpid=("100B", "100F"), registers=(Reg.BATTERY_CHARGE,))
|
||||||
_D("V450 Nano Cordless Laser Mouse", codename="V450 Nano", protocol=1.0, wpid="1011", registers=(REG.battery_charge,))
|
_D("V450 Nano Cordless Laser Mouse", codename="V450 Nano", protocol=1.0, wpid="1011", registers=(Reg.BATTERY_CHARGE,))
|
||||||
_D("V550 Nano Cordless Laser Mouse", codename="V550 Nano", protocol=1.0, wpid="1013", registers=(REG.battery_charge,))
|
_D("V550 Nano Cordless Laser Mouse", codename="V550 Nano", protocol=1.0, wpid="1013", registers=(Reg.BATTERY_CHARGE,))
|
||||||
_D(
|
_D(
|
||||||
"MX 1100 Cordless Laser Mouse",
|
"MX 1100 Cordless Laser Mouse",
|
||||||
codename="MX 1100",
|
codename="MX 1100",
|
||||||
protocol=1.0,
|
protocol=1.0,
|
||||||
kind=DEVICE_KIND.mouse,
|
kind=DEVICE_KIND.mouse,
|
||||||
wpid="1014",
|
wpid="1014",
|
||||||
registers=(REG.battery_charge,),
|
registers=(Reg.BATTERY_CHARGE,),
|
||||||
)
|
)
|
||||||
_D("Anywhere Mouse MX", codename="Anywhere MX", protocol=1.0, wpid="1017", registers=(REG.battery_charge,))
|
_D("Anywhere Mouse MX", codename="Anywhere MX", protocol=1.0, wpid="1017", registers=(Reg.BATTERY_CHARGE,))
|
||||||
_D(
|
_D(
|
||||||
"Performance Mouse MX",
|
"Performance Mouse MX",
|
||||||
codename="Performance MX",
|
codename="Performance MX",
|
||||||
protocol=1.0,
|
protocol=1.0,
|
||||||
wpid="101A",
|
wpid="101A",
|
||||||
registers=(REG.battery_status, REG.three_leds),
|
registers=(Reg.BATTERY_STATUS, Reg.THREE_LEDS),
|
||||||
)
|
)
|
||||||
_D("Marathon Mouse M705 (M-R0009)", codename="M705 (M-R0009)", protocol=1.0, wpid="101B", registers=(REG.battery_charge,))
|
_D("Marathon Mouse M705 (M-R0009)", codename="M705 (M-R0009)", protocol=1.0, wpid="101B", registers=(Reg.BATTERY_CHARGE,))
|
||||||
_D("Wireless Mouse M350", codename="M350", protocol=1.0, wpid="101C", registers=(REG.battery_charge,))
|
_D("Wireless Mouse M350", codename="M350", protocol=1.0, wpid="101C", registers=(Reg.BATTERY_CHARGE,))
|
||||||
_D("Wireless Mouse M505", codename="M505/B605", protocol=1.0, wpid="101D", registers=(REG.battery_charge,))
|
_D("Wireless Mouse M505", codename="M505/B605", protocol=1.0, wpid="101D", registers=(Reg.BATTERY_CHARGE,))
|
||||||
_D("Wireless Mouse M305", codename="M305", protocol=1.0, wpid="101F", registers=(REG.battery_status,))
|
_D("Wireless Mouse M305", codename="M305", protocol=1.0, wpid="101F", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("Wireless Mouse M215", codename="M215", protocol=1.0, wpid="1020")
|
_D("Wireless Mouse M215", codename="M215", protocol=1.0, wpid="1020")
|
||||||
_D(
|
_D(
|
||||||
"G700 Gaming Mouse",
|
"G700 Gaming Mouse",
|
||||||
|
@ -295,12 +295,12 @@ _D(
|
||||||
usbid=0xC06B,
|
usbid=0xC06B,
|
||||||
interface=1,
|
interface=1,
|
||||||
registers=(
|
registers=(
|
||||||
REG.battery_status,
|
Reg.BATTERY_STATUS,
|
||||||
REG.three_leds,
|
Reg.THREE_LEDS,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
_D("Wireless Mouse M310", codename="M310", protocol=1.0, wpid="1024", registers=(REG.battery_status,))
|
_D("Wireless Mouse M310", codename="M310", protocol=1.0, wpid="1024", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("Wireless Mouse M510", codename="M510", protocol=1.0, wpid="1025", registers=(REG.battery_status,))
|
_D("Wireless Mouse M510", codename="M510", protocol=1.0, wpid="1025", registers=(Reg.BATTERY_STATUS,))
|
||||||
_D("Fujitsu Sonic Mouse", codename="Sonic", protocol=1.0, wpid="1029")
|
_D("Fujitsu Sonic Mouse", codename="Sonic", protocol=1.0, wpid="1029")
|
||||||
_D(
|
_D(
|
||||||
"G700s Gaming Mouse",
|
"G700s Gaming Mouse",
|
||||||
|
@ -310,8 +310,8 @@ _D(
|
||||||
usbid=0xC07C,
|
usbid=0xC07C,
|
||||||
interface=1,
|
interface=1,
|
||||||
registers=(
|
registers=(
|
||||||
REG.battery_status,
|
Reg.BATTERY_STATUS,
|
||||||
REG.three_leds,
|
Reg.THREE_LEDS,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
_D("Couch Mouse M515", codename="M515", protocol=2.0, wpid="4007")
|
_D("Couch Mouse M515", codename="M515", protocol=2.0, wpid="4007")
|
||||||
|
|
|
@ -44,8 +44,6 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
_hidpp10 = hidpp10.Hidpp10()
|
_hidpp10 = hidpp10.Hidpp10()
|
||||||
_hidpp20 = hidpp20.Hidpp20()
|
_hidpp20 = hidpp20.Hidpp20()
|
||||||
_R = hidpp10_constants.REGISTERS
|
|
||||||
_IR = hidpp10_constants.INFO_SUBREGISTERS
|
|
||||||
|
|
||||||
|
|
||||||
class LowLevelInterface(Protocol):
|
class LowLevelInterface(Protocol):
|
||||||
|
|
|
@ -25,7 +25,7 @@ from . import common
|
||||||
from .common import Battery
|
from .common import Battery
|
||||||
from .common import BatteryLevelApproximation
|
from .common import BatteryLevelApproximation
|
||||||
from .common import BatteryStatus
|
from .common import BatteryStatus
|
||||||
from .hidpp10_constants import REGISTERS
|
from .hidpp10_constants import Registers
|
||||||
from .hidpp20_constants import FIRMWARE_KIND
|
from .hidpp20_constants import FIRMWARE_KIND
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -52,30 +52,30 @@ class Device(Protocol):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
def read_register(device: Device, register_number, *params):
|
def read_register(device: Device, register: Registers | int, *params) -> Any:
|
||||||
assert device is not None, f"tried to read register {register_number:02X} from invalid device {device}"
|
assert device is not None, f"tried to read register {register:02X} from invalid device {device}"
|
||||||
# support long registers by adding a 2 in front of the register number
|
# support long registers by adding a 2 in front of the register number
|
||||||
request_id = 0x8100 | (int(register_number) & 0x2FF)
|
request_id = 0x8100 | (int(register) & 0x2FF)
|
||||||
return device.request(request_id, *params)
|
return device.request(request_id, *params)
|
||||||
|
|
||||||
|
|
||||||
def write_register(device: Device, register_number, *value):
|
def write_register(device: Device, register: Registers | int, *value) -> Any:
|
||||||
assert device is not None, f"tried to write register {register_number:02X} to invalid device {device}"
|
assert device is not None, f"tried to write register {register:02X} to invalid device {device}"
|
||||||
# support long registers by adding a 2 in front of the register number
|
# support long registers by adding a 2 in front of the register number
|
||||||
request_id = 0x8000 | (int(register_number) & 0x2FF)
|
request_id = 0x8000 | (int(register) & 0x2FF)
|
||||||
return device.request(request_id, *value)
|
return device.request(request_id, *value)
|
||||||
|
|
||||||
|
|
||||||
def get_configuration_pending_flags(receiver):
|
def get_configuration_pending_flags(receiver):
|
||||||
assert not receiver.isDevice
|
assert not receiver.isDevice
|
||||||
result = read_register(receiver, REGISTERS.devices_configuration)
|
result = read_register(receiver, Registers.DEVICES_CONFIGURATION)
|
||||||
if result is not None:
|
if result is not None:
|
||||||
return ord(result[:1])
|
return ord(result[:1])
|
||||||
|
|
||||||
|
|
||||||
def set_configuration_pending_flags(receiver, devices):
|
def set_configuration_pending_flags(receiver, devices):
|
||||||
assert not receiver.isDevice
|
assert not receiver.isDevice
|
||||||
result = write_register(receiver, REGISTERS.devices_configuration, devices)
|
result = write_register(receiver, Registers.DEVICES_CONFIGURATION, devices)
|
||||||
return result is not None
|
return result is not None
|
||||||
|
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ class Hidpp10:
|
||||||
# let's just assume HID++ 2.0 devices do not provide the battery info in a register
|
# let's just assume HID++ 2.0 devices do not provide the battery info in a register
|
||||||
return
|
return
|
||||||
|
|
||||||
for r in (REGISTERS.battery_status, REGISTERS.battery_charge):
|
for r in (Registers.BATTERY_STATUS, Registers.BATTERY_CHARGE):
|
||||||
if r in device.registers:
|
if r in device.registers:
|
||||||
reply = read_register(device, r)
|
reply = read_register(device, r)
|
||||||
if reply:
|
if reply:
|
||||||
|
@ -98,44 +98,44 @@ class Hidpp10:
|
||||||
return
|
return
|
||||||
|
|
||||||
# the descriptor does not tell us which register this device has, try them both
|
# the descriptor does not tell us which register this device has, try them both
|
||||||
reply = read_register(device, REGISTERS.battery_charge)
|
reply = read_register(device, Registers.BATTERY_CHARGE)
|
||||||
if reply:
|
if reply:
|
||||||
# remember this for the next time
|
# remember this for the next time
|
||||||
device.registers.append(REGISTERS.battery_charge)
|
device.registers.append(Registers.BATTERY_CHARGE)
|
||||||
return parse_battery_status(REGISTERS.battery_charge, reply)
|
return parse_battery_status(Registers.BATTERY_CHARGE, reply)
|
||||||
|
|
||||||
reply = read_register(device, REGISTERS.battery_status)
|
reply = read_register(device, Registers.BATTERY_STATUS)
|
||||||
if reply:
|
if reply:
|
||||||
# remember this for the next time
|
# remember this for the next time
|
||||||
device.registers.append(REGISTERS.battery_status)
|
device.registers.append(Registers.BATTERY_STATUS)
|
||||||
return parse_battery_status(REGISTERS.battery_status, reply)
|
return parse_battery_status(Registers.BATTERY_STATUS, reply)
|
||||||
|
|
||||||
def get_firmware(self, device: Device):
|
def get_firmware(self, device: Device):
|
||||||
assert device is not None
|
assert device is not None
|
||||||
|
|
||||||
firmware = [None, None, None]
|
firmware = [None, None, None]
|
||||||
|
|
||||||
reply = read_register(device, REGISTERS.firmware, 0x01)
|
reply = read_register(device, Registers.FIRMWARE, 0x01)
|
||||||
if not reply:
|
if not reply:
|
||||||
# won't be able to read any of it now...
|
# won't be able to read any of it now...
|
||||||
return
|
return
|
||||||
|
|
||||||
fw_version = common.strhex(reply[1:3])
|
fw_version = common.strhex(reply[1:3])
|
||||||
fw_version = f"{fw_version[0:2]}.{fw_version[2:4]}"
|
fw_version = f"{fw_version[0:2]}.{fw_version[2:4]}"
|
||||||
reply = read_register(device, REGISTERS.firmware, 0x02)
|
reply = read_register(device, Registers.FIRMWARE, 0x02)
|
||||||
if reply:
|
if reply:
|
||||||
fw_version += ".B" + common.strhex(reply[1:3])
|
fw_version += ".B" + common.strhex(reply[1:3])
|
||||||
fw = common.FirmwareInfo(FIRMWARE_KIND.Firmware, "", fw_version, None)
|
fw = common.FirmwareInfo(FIRMWARE_KIND.Firmware, "", fw_version, None)
|
||||||
firmware[0] = fw
|
firmware[0] = fw
|
||||||
|
|
||||||
reply = read_register(device, REGISTERS.firmware, 0x04)
|
reply = read_register(device, Registers.FIRMWARE, 0x04)
|
||||||
if reply:
|
if reply:
|
||||||
bl_version = common.strhex(reply[1:3])
|
bl_version = common.strhex(reply[1:3])
|
||||||
bl_version = f"{bl_version[0:2]}.{bl_version[2:4]}"
|
bl_version = f"{bl_version[0:2]}.{bl_version[2:4]}"
|
||||||
bl = common.FirmwareInfo(FIRMWARE_KIND.Bootloader, "", bl_version, None)
|
bl = common.FirmwareInfo(FIRMWARE_KIND.Bootloader, "", bl_version, None)
|
||||||
firmware[1] = bl
|
firmware[1] = bl
|
||||||
|
|
||||||
reply = read_register(device, REGISTERS.firmware, 0x03)
|
reply = read_register(device, Registers.FIRMWARE, 0x03)
|
||||||
if reply:
|
if reply:
|
||||||
o_version = common.strhex(reply[1:3])
|
o_version = common.strhex(reply[1:3])
|
||||||
o_version = f"{o_version[0:2]}.{o_version[2:4]}"
|
o_version = f"{o_version[0:2]}.{o_version[2:4]}"
|
||||||
|
@ -151,7 +151,7 @@ class Hidpp10:
|
||||||
if not device.online:
|
if not device.online:
|
||||||
return
|
return
|
||||||
|
|
||||||
if REGISTERS.three_leds not in device.registers:
|
if Registers.THREE_LEDS not in device.registers:
|
||||||
return
|
return
|
||||||
|
|
||||||
if battery_level is not None:
|
if battery_level is not None:
|
||||||
|
@ -185,10 +185,10 @@ class Hidpp10:
|
||||||
# turn off all leds
|
# turn off all leds
|
||||||
v1, v2 = 0x11, 0x11
|
v1, v2 = 0x11, 0x11
|
||||||
|
|
||||||
write_register(device, REGISTERS.three_leds, v1, v2)
|
write_register(device, Registers.THREE_LEDS, v1, v2)
|
||||||
|
|
||||||
def get_notification_flags(self, device: Device):
|
def get_notification_flags(self, device: Device):
|
||||||
return self._get_register(device, REGISTERS.notifications)
|
return self._get_register(device, Registers.NOTIFICATIONS)
|
||||||
|
|
||||||
def set_notification_flags(self, device: Device, *flag_bits):
|
def set_notification_flags(self, device: Device, *flag_bits):
|
||||||
assert device is not None
|
assert device is not None
|
||||||
|
@ -202,13 +202,13 @@ class Hidpp10:
|
||||||
|
|
||||||
flag_bits = sum(int(b) for b in flag_bits)
|
flag_bits = sum(int(b) for b in flag_bits)
|
||||||
assert flag_bits & 0x00FFFFFF == flag_bits
|
assert flag_bits & 0x00FFFFFF == flag_bits
|
||||||
result = write_register(device, REGISTERS.notifications, common.int2bytes(flag_bits, 3))
|
result = write_register(device, Registers.NOTIFICATIONS, common.int2bytes(flag_bits, 3))
|
||||||
return result is not None
|
return result is not None
|
||||||
|
|
||||||
def get_device_features(self, device: Device):
|
def get_device_features(self, device: Device):
|
||||||
return self._get_register(device, REGISTERS.mouse_button_flags)
|
return self._get_register(device, Registers.MOUSE_BUTTON_FLAGS)
|
||||||
|
|
||||||
def _get_register(self, device: Device, register):
|
def _get_register(self, device: Device, register: Registers | int):
|
||||||
assert device is not None
|
assert device is not None
|
||||||
|
|
||||||
# Avoid a call if the device is not online,
|
# Avoid a call if the device is not online,
|
||||||
|
@ -224,7 +224,7 @@ class Hidpp10:
|
||||||
return common.bytes2int(flags)
|
return common.bytes2int(flags)
|
||||||
|
|
||||||
|
|
||||||
def parse_battery_status(register, reply) -> Battery | None:
|
def parse_battery_status(register: Registers | int, reply) -> Battery | None:
|
||||||
def status_byte_to_charge(status_byte_: int) -> BatteryLevelApproximation:
|
def status_byte_to_charge(status_byte_: int) -> BatteryLevelApproximation:
|
||||||
if status_byte_ == 7:
|
if status_byte_ == 7:
|
||||||
charge_ = BatteryLevelApproximation.FULL
|
charge_ = BatteryLevelApproximation.FULL
|
||||||
|
@ -262,14 +262,14 @@ def parse_battery_status(register, reply) -> Battery | None:
|
||||||
status_text_ = None
|
status_text_ = None
|
||||||
return status_text_
|
return status_text_
|
||||||
|
|
||||||
if register == REGISTERS.battery_charge:
|
if register == Registers.BATTERY_CHARGE:
|
||||||
charge = ord(reply[:1])
|
charge = ord(reply[:1])
|
||||||
status_byte = ord(reply[2:3]) & 0xF0
|
status_byte = ord(reply[2:3]) & 0xF0
|
||||||
|
|
||||||
battery_status = status_byte_to_battery_status(status_byte)
|
battery_status = status_byte_to_battery_status(status_byte)
|
||||||
return Battery(charge, None, battery_status, None)
|
return Battery(charge, None, battery_status, None)
|
||||||
|
|
||||||
if register == REGISTERS.battery_status:
|
if register == Registers.BATTERY_STATUS:
|
||||||
status_byte = ord(reply[:1])
|
status_byte = ord(reply[:1])
|
||||||
charging_byte = ord(reply[1:2])
|
charging_byte = ord(reply[1:2])
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
## You should have received a copy of the GNU General Public License along
|
## You should have received a copy of the GNU General Public License along
|
||||||
## with this program; if not, write to the Free Software Foundation, Inc.,
|
## with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
from enum import IntEnum
|
||||||
|
|
||||||
from .common import NamedInts
|
from .common import NamedInts
|
||||||
|
|
||||||
|
@ -103,38 +104,47 @@ ERROR = NamedInts(
|
||||||
|
|
||||||
PAIRING_ERRORS = NamedInts(device_timeout=0x01, device_not_supported=0x02, too_many_devices=0x03, sequence_timeout=0x06)
|
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)
|
BOLT_PAIRING_ERRORS = NamedInts(device_timeout=0x01, failed=0x02)
|
||||||
"""Known registers.
|
|
||||||
|
|
||||||
|
class Registers(IntEnum):
|
||||||
|
"""Known HID registers.
|
||||||
|
|
||||||
Devices usually have a (small) sub-set of these. Some registers are only
|
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."""
|
applicable to certain device kinds (e.g. smooth_scroll only applies to mice).
|
||||||
REGISTERS = NamedInts(
|
"""
|
||||||
|
|
||||||
|
# Generally applicable
|
||||||
|
NOTIFICATIONS = 0x00
|
||||||
|
FIRMWARE = 0xF1
|
||||||
|
|
||||||
# only apply to receivers
|
# only apply to receivers
|
||||||
receiver_connection=0x02,
|
RECEIVER_CONNECTION = 0x02
|
||||||
receiver_pairing=0xB2,
|
RECEIVER_PAIRING = 0xB2
|
||||||
devices_activity=0x2B3,
|
DEVICES_ACTIVITY = 0x2B3
|
||||||
receiver_info=0x2B5,
|
RECEIVER_INFO = 0x2B5
|
||||||
bolt_device_discovery=0xC0,
|
BOLT_DEVICE_DISCOVERY = 0xC0
|
||||||
bolt_pairing=0x2C1,
|
BOLT_PAIRING = 0x2C1
|
||||||
bolt_uniqueId=0x02FB,
|
BOLT_UNIQUE_ID = 0x02FB
|
||||||
|
|
||||||
# only apply to devices
|
# only apply to devices
|
||||||
mouse_button_flags=0x01,
|
MOUSE_BUTTON_FLAGS = 0x01
|
||||||
keyboard_hand_detection=0x01,
|
KEYBOARD_HAND_DETECTION = 0x01
|
||||||
devices_configuration=0x03,
|
DEVICES_CONFIGURATION = 0x03
|
||||||
battery_status=0x07,
|
BATTERY_STATUS = 0x07
|
||||||
keyboard_fn_swap=0x09,
|
KEYBOARD_FN_SWAP = 0x09
|
||||||
battery_charge=0x0D,
|
BATTERY_CHARGE = 0x0D
|
||||||
keyboard_illumination=0x17,
|
KEYBOARD_ILLUMINATION = 0x17
|
||||||
three_leds=0x51,
|
THREE_LEDS = 0x51
|
||||||
mouse_dpi=0x63,
|
MOUSE_DPI = 0x63
|
||||||
# apply to both
|
|
||||||
notifications=0x00,
|
|
||||||
firmware=0xF1,
|
|
||||||
# notifications
|
# notifications
|
||||||
passkey_request_notification=0x4D,
|
PASSKEY_REQUEST_NOTIFICATION = 0x4D
|
||||||
passkey_pressed_notification=0x4E,
|
PASSKEY_PRESSED_NOTIFICATION = 0x4E
|
||||||
device_discovery_notification=0x4F,
|
DEVICE_DISCOVERY_NOTIFICATION = 0x4F
|
||||||
discovery_status_notification=0x53,
|
DISCOVERY_STATUS_NOTIFICATION = 0x53
|
||||||
pairing_status_notification=0x54,
|
PAIRING_STATUS_NOTIFICATION = 0x54
|
||||||
)
|
|
||||||
|
|
||||||
# Subregisters for receiver_info register
|
# Subregisters for receiver_info register
|
||||||
INFO_SUBREGISTERS = NamedInts(
|
INFO_SUBREGISTERS = NamedInts(
|
||||||
serial_number=0x01, # not found on many receivers
|
serial_number=0x01, # not found on many receivers
|
||||||
|
|
|
@ -33,12 +33,12 @@ from . import hidpp20_constants
|
||||||
from . import settings_templates
|
from . import settings_templates
|
||||||
from .common import Alert
|
from .common import Alert
|
||||||
from .common import BatteryStatus
|
from .common import BatteryStatus
|
||||||
|
from .hidpp10_constants import Registers
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
_hidpp10 = hidpp10.Hidpp10()
|
_hidpp10 = hidpp10.Hidpp10()
|
||||||
_hidpp20 = hidpp20.Hidpp20()
|
_hidpp20 = hidpp20.Hidpp20()
|
||||||
_R = hidpp10_constants.REGISTERS
|
|
||||||
_F = hidpp20_constants.FEATURE
|
_F = hidpp20_constants.FEATURE
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ def _process_receiver_notification(receiver, n):
|
||||||
receiver.changed(reason=reason)
|
receiver.changed(reason=reason)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
elif n.sub_id == _R.discovery_status_notification: # Bolt pairing
|
elif n.sub_id == Registers.DISCOVERY_STATUS_NOTIFICATION: # Bolt pairing
|
||||||
with notification_lock:
|
with notification_lock:
|
||||||
receiver.pairing.discovering = n.address == 0x00
|
receiver.pairing.discovering = n.address == 0x00
|
||||||
reason = _("discovery lock is open") if receiver.pairing.discovering else _("discovery lock is closed")
|
reason = _("discovery lock is open") if receiver.pairing.discovering else _("discovery lock is closed")
|
||||||
|
@ -92,7 +92,7 @@ def _process_receiver_notification(receiver, n):
|
||||||
receiver.changed(reason=reason)
|
receiver.changed(reason=reason)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
elif n.sub_id == _R.device_discovery_notification: # Bolt pairing
|
elif n.sub_id == Registers.DISCOVERY_STATUS_NOTIFICATION: # Bolt pairing
|
||||||
with notification_lock:
|
with notification_lock:
|
||||||
counter = n.address + n.data[0] * 256 # notification counter
|
counter = n.address + n.data[0] * 256 # notification counter
|
||||||
if receiver.pairing.counter is None:
|
if receiver.pairing.counter is None:
|
||||||
|
@ -108,7 +108,7 @@ def _process_receiver_notification(receiver, n):
|
||||||
receiver.pairing.device_name = n.data[3 : 3 + n.data[2]].decode("utf-8")
|
receiver.pairing.device_name = n.data[3 : 3 + n.data[2]].decode("utf-8")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
elif n.sub_id == _R.pairing_status_notification: # Bolt pairing
|
elif n.sub_id == Registers.PAIRING_STATUS_NOTIFICATION: # Bolt pairing
|
||||||
with notification_lock:
|
with notification_lock:
|
||||||
receiver.pairing.device_passkey = None
|
receiver.pairing.device_passkey = None
|
||||||
receiver.pairing.lock_open = n.address == 0x00
|
receiver.pairing.lock_open = n.address == 0x00
|
||||||
|
@ -132,12 +132,12 @@ def _process_receiver_notification(receiver, n):
|
||||||
receiver.changed(reason=reason)
|
receiver.changed(reason=reason)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
elif n.sub_id == _R.passkey_request_notification: # Bolt pairing
|
elif n.sub_id == Registers.PASSKEY_REQUEST_NOTIFICATION: # Bolt pairing
|
||||||
with notification_lock:
|
with notification_lock:
|
||||||
receiver.pairing.device_passkey = n.data[0:6].decode("utf-8")
|
receiver.pairing.device_passkey = n.data[0:6].decode("utf-8")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
elif n.sub_id == _R.passkey_pressed_notification: # Bolt pairing
|
elif n.sub_id == Registers.PASSKEY_PRESSED_NOTIFICATION: # Bolt pairing
|
||||||
return True
|
return True
|
||||||
|
|
||||||
logger.warning("%s: unhandled notification %s", receiver, n)
|
logger.warning("%s: unhandled notification %s", receiver, n)
|
||||||
|
@ -214,7 +214,7 @@ def _process_hidpp10_custom_notification(device, n):
|
||||||
if logger.isEnabledFor(logging.DEBUG):
|
if logger.isEnabledFor(logging.DEBUG):
|
||||||
logger.debug("%s (%s) custom notification %s", device, device.protocol, n)
|
logger.debug("%s (%s) custom notification %s", device, device.protocol, n)
|
||||||
|
|
||||||
if n.sub_id in (_R.battery_status, _R.battery_charge):
|
if n.sub_id in (Registers.BATTERY_STATUS, Registers.BATTERY_CHARGE):
|
||||||
assert n.data[-1:] == b"\x00"
|
assert n.data[-1:] == b"\x00"
|
||||||
data = chr(n.address).encode() + n.data
|
data = chr(n.address).encode() + n.data
|
||||||
device.set_battery_info(hidpp10.parse_battery_status(n.sub_id, data))
|
device.set_battery_info(hidpp10.parse_battery_status(n.sub_id, data))
|
||||||
|
|
|
@ -36,11 +36,11 @@ from . import hidpp10
|
||||||
from . import hidpp10_constants
|
from . import hidpp10_constants
|
||||||
from .common import Alert
|
from .common import Alert
|
||||||
from .device import Device
|
from .device import Device
|
||||||
|
from .hidpp10_constants import Registers
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
_hidpp10 = hidpp10.Hidpp10()
|
_hidpp10 = hidpp10.Hidpp10()
|
||||||
_R = hidpp10_constants.REGISTERS
|
|
||||||
_IR = hidpp10_constants.INFO_SUBREGISTERS
|
_IR = hidpp10_constants.INFO_SUBREGISTERS
|
||||||
|
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ class Receiver:
|
||||||
|
|
||||||
def initialize(self, product_info: dict):
|
def initialize(self, product_info: dict):
|
||||||
# read the receiver information subregister, so we can find out max_devices
|
# read the receiver information subregister, so we can find out max_devices
|
||||||
serial_reply = self.read_register(_R.receiver_info, _IR.receiver_information)
|
serial_reply = self.read_register(Registers.RECEIVER_INFO, _IR.receiver_information)
|
||||||
if serial_reply:
|
if serial_reply:
|
||||||
self.serial = serial_reply[1:5].hex().upper()
|
self.serial = serial_reply[1:5].hex().upper()
|
||||||
self.max_devices = serial_reply[6]
|
self.max_devices = serial_reply[6]
|
||||||
|
@ -146,7 +146,7 @@ class Receiver:
|
||||||
# how many pairings remain (None for unknown, -1 for unlimited)
|
# how many pairings remain (None for unknown, -1 for unlimited)
|
||||||
def remaining_pairings(self, cache=True):
|
def remaining_pairings(self, cache=True):
|
||||||
if self._remaining_pairings is None or not cache:
|
if self._remaining_pairings is None or not cache:
|
||||||
ps = self.read_register(_R.receiver_connection)
|
ps = self.read_register(Registers.RECEIVER_CONNECTION)
|
||||||
if ps is not None:
|
if ps is not None:
|
||||||
ps = ord(ps[2:3])
|
ps = ord(ps[2:3])
|
||||||
self._remaining_pairings = ps - 5 if ps >= 5 else -1
|
self._remaining_pairings = ps - 5 if ps >= 5 else -1
|
||||||
|
@ -174,7 +174,7 @@ class Receiver:
|
||||||
return flag_bits
|
return flag_bits
|
||||||
|
|
||||||
def device_codename(self, n):
|
def device_codename(self, n):
|
||||||
codename = self.read_register(_R.receiver_info, _IR.device_name + n - 1)
|
codename = self.read_register(Registers.RECEIVER_INFO, _IR.device_name + n - 1)
|
||||||
if codename:
|
if codename:
|
||||||
codename = codename[2 : 2 + ord(codename[1:2])]
|
codename = codename[2 : 2 + ord(codename[1:2])]
|
||||||
return codename.decode("ascii")
|
return codename.decode("ascii")
|
||||||
|
@ -182,7 +182,7 @@ class Receiver:
|
||||||
def notify_devices(self):
|
def notify_devices(self):
|
||||||
"""Scan all devices."""
|
"""Scan all devices."""
|
||||||
if self.handle:
|
if self.handle:
|
||||||
if not self.write_register(_R.receiver_connection, 0x02):
|
if not self.write_register(Registers.RECEIVER_CONNECTION, 0x02):
|
||||||
logger.warning("%s: failed to trigger device link notifications", self)
|
logger.warning("%s: failed to trigger device link notifications", self)
|
||||||
|
|
||||||
def notification_information(self, number, notification):
|
def notification_information(self, number, notification):
|
||||||
|
@ -199,13 +199,13 @@ class Receiver:
|
||||||
polling_rate = ""
|
polling_rate = ""
|
||||||
serial = None
|
serial = None
|
||||||
power_switch = "(unknown)"
|
power_switch = "(unknown)"
|
||||||
pair_info = self.read_register(_R.receiver_info, _IR.pairing_information + n - 1)
|
pair_info = self.read_register(Registers.RECEIVER_INFO, _IR.pairing_information + n - 1)
|
||||||
if pair_info: # a receiver that uses Unifying-style pairing registers
|
if pair_info: # a receiver that uses Unifying-style pairing registers
|
||||||
wpid = pair_info[3:5].hex().upper()
|
wpid = pair_info[3:5].hex().upper()
|
||||||
kind = hidpp10_constants.DEVICE_KIND[pair_info[7] & 0x0F]
|
kind = hidpp10_constants.DEVICE_KIND[pair_info[7] & 0x0F]
|
||||||
polling_rate = str(pair_info[2]) + "ms"
|
polling_rate = str(pair_info[2]) + "ms"
|
||||||
elif not self.receiver_kind == "unifying": # may be an old Nano receiver
|
elif not self.receiver_kind == "unifying": # may be an old Nano receiver
|
||||||
device_info = self.read_register(_R.receiver_info, 0x04) # undocumented
|
device_info = self.read_register(Registers.RECEIVER_INFO, 0x04) # undocumented
|
||||||
if device_info:
|
if device_info:
|
||||||
logger.warning("using undocumented register for device wpid")
|
logger.warning("using undocumented register for device wpid")
|
||||||
wpid = device_info[3:5].hex().upper()
|
wpid = device_info[3:5].hex().upper()
|
||||||
|
@ -214,7 +214,7 @@ class Receiver:
|
||||||
raise exceptions.NoSuchDevice(number=n, receiver=self, error="read pairing information - non-unifying")
|
raise exceptions.NoSuchDevice(number=n, receiver=self, error="read pairing information - non-unifying")
|
||||||
else:
|
else:
|
||||||
raise exceptions.NoSuchDevice(number=n, receiver=self, error="read pairing information")
|
raise exceptions.NoSuchDevice(number=n, receiver=self, error="read pairing information")
|
||||||
pair_info = self.read_register(_R.receiver_info, _IR.extended_pairing_information + n - 1)
|
pair_info = self.read_register(Registers.RECEIVER_INFO, _IR.extended_pairing_information + n - 1)
|
||||||
if pair_info:
|
if pair_info:
|
||||||
power_switch = hidpp10_constants.POWER_SWITCH_LOCATION[pair_info[9] & 0x0F]
|
power_switch = hidpp10_constants.POWER_SWITCH_LOCATION[pair_info[9] & 0x0F]
|
||||||
serial = pair_info[1:5].hex().upper()
|
serial = pair_info[1:5].hex().upper()
|
||||||
|
@ -261,13 +261,13 @@ class Receiver:
|
||||||
def set_lock(self, lock_closed=True, device=0, timeout=0):
|
def set_lock(self, lock_closed=True, device=0, timeout=0):
|
||||||
if self.handle:
|
if self.handle:
|
||||||
action = 0x02 if lock_closed else 0x01
|
action = 0x02 if lock_closed else 0x01
|
||||||
reply = self.write_register(_R.receiver_pairing, action, device, timeout)
|
reply = self.write_register(Registers.RECEIVER_PAIRING, action, device, timeout)
|
||||||
if reply:
|
if reply:
|
||||||
return True
|
return True
|
||||||
logger.warning("%s: failed to %s the receiver lock", self, "close" if lock_closed else "open")
|
logger.warning("%s: failed to %s the receiver lock", self, "close" if lock_closed else "open")
|
||||||
|
|
||||||
def count(self):
|
def count(self):
|
||||||
count = self.read_register(_R.receiver_connection)
|
count = self.read_register(Registers.RECEIVER_CONNECTION)
|
||||||
return 0 if count is None else ord(count[1:2])
|
return 0 if count is None else ord(count[1:2])
|
||||||
|
|
||||||
def request(self, request_id, *params):
|
def request(self, request_id, *params):
|
||||||
|
@ -344,7 +344,7 @@ class Receiver:
|
||||||
|
|
||||||
def _unpair_device_per_receiver(self, key):
|
def _unpair_device_per_receiver(self, key):
|
||||||
"""Receiver specific unpairing."""
|
"""Receiver specific unpairing."""
|
||||||
return self.write_register(_R.receiver_pairing, 0x03, key)
|
return self.write_register(Registers.RECEIVER_PAIRING, 0x03, key)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len([d for d in self._devices.values() if d is not None])
|
return len([d for d in self._devices.values() if d is not None])
|
||||||
|
@ -392,18 +392,18 @@ class BoltReceiver(Receiver):
|
||||||
super().__init__(receiver_kind, product_info, handle, path, product_id, setting_callback)
|
super().__init__(receiver_kind, product_info, handle, path, product_id, setting_callback)
|
||||||
|
|
||||||
def initialize(self, product_info: dict):
|
def initialize(self, product_info: dict):
|
||||||
serial_reply = self.read_register(_R.bolt_uniqueId)
|
serial_reply = self.read_register(Registers.BOLT_UNIQUE_ID)
|
||||||
self.serial = serial_reply.hex().upper()
|
self.serial = serial_reply.hex().upper()
|
||||||
self.max_devices = product_info.get("max_devices", 1)
|
self.max_devices = product_info.get("max_devices", 1)
|
||||||
|
|
||||||
def device_codename(self, n):
|
def device_codename(self, n):
|
||||||
codename = self.read_register(_R.receiver_info, _IR.bolt_device_name + n, 0x01)
|
codename = self.read_register(Registers.RECEIVER_INFO, _IR.bolt_device_name + n, 0x01)
|
||||||
if codename:
|
if codename:
|
||||||
codename = codename[3 : 3 + min(14, ord(codename[2:3]))]
|
codename = codename[3 : 3 + min(14, ord(codename[2:3]))]
|
||||||
return codename.decode("ascii")
|
return codename.decode("ascii")
|
||||||
|
|
||||||
def device_pairing_information(self, n: int) -> dict:
|
def device_pairing_information(self, n: int) -> dict:
|
||||||
pair_info = self.read_register(_R.receiver_info, _IR.bolt_pairing_information + n)
|
pair_info = self.read_register(Registers.RECEIVER_INFO, _IR.bolt_pairing_information + n)
|
||||||
if pair_info:
|
if pair_info:
|
||||||
wpid = (pair_info[3:4] + pair_info[2:3]).hex().upper()
|
wpid = (pair_info[3:4] + pair_info[2:3]).hex().upper()
|
||||||
kind = hidpp10_constants.DEVICE_KIND[pair_info[1] & 0x0F]
|
kind = hidpp10_constants.DEVICE_KIND[pair_info[1] & 0x0F]
|
||||||
|
@ -416,7 +416,7 @@ class BoltReceiver(Receiver):
|
||||||
"""Discover Logitech Bolt devices."""
|
"""Discover Logitech Bolt devices."""
|
||||||
if self.handle:
|
if self.handle:
|
||||||
action = 0x02 if cancel else 0x01
|
action = 0x02 if cancel else 0x01
|
||||||
reply = self.write_register(_R.bolt_device_discovery, timeout, action)
|
reply = self.write_register(Registers.BOLT_DEVICE_DISCOVERY, timeout, action)
|
||||||
if reply:
|
if reply:
|
||||||
return True
|
return True
|
||||||
logger.warning("%s: failed to %s device discovery", self, "cancel" if cancel else "start")
|
logger.warning("%s: failed to %s device discovery", self, "cancel" if cancel else "start")
|
||||||
|
@ -425,14 +425,14 @@ class BoltReceiver(Receiver):
|
||||||
"""Pair a Bolt device."""
|
"""Pair a Bolt device."""
|
||||||
if self.handle:
|
if self.handle:
|
||||||
action = 0x01 if pair is True else 0x03 if pair is False else 0x02
|
action = 0x01 if pair is True else 0x03 if pair is False else 0x02
|
||||||
reply = self.write_register(_R.bolt_pairing, action, slot, address, authentication, entropy)
|
reply = self.write_register(Registers.BOLT_PAIRING, action, slot, address, authentication, entropy)
|
||||||
if reply:
|
if reply:
|
||||||
return True
|
return True
|
||||||
logger.warning("%s: failed to %s device %s", self, "pair" if pair else "unpair", address)
|
logger.warning("%s: failed to %s device %s", self, "pair" if pair else "unpair", address)
|
||||||
|
|
||||||
def _unpair_device_per_receiver(self, key):
|
def _unpair_device_per_receiver(self, key):
|
||||||
"""Receiver specific unpairing."""
|
"""Receiver specific unpairing."""
|
||||||
return self.write_register(_R.bolt_pairing, 0x03, key)
|
return self.write_register(Registers.BOLT_PAIRING, 0x03, key)
|
||||||
|
|
||||||
|
|
||||||
class UnifyingReceiver(Receiver):
|
class UnifyingReceiver(Receiver):
|
||||||
|
|
|
@ -610,7 +610,7 @@ class RegisterRW:
|
||||||
|
|
||||||
kind = NamedInt(0x01, _("register"))
|
kind = NamedInt(0x01, _("register"))
|
||||||
|
|
||||||
def __init__(self, register):
|
def __init__(self, register: int):
|
||||||
assert isinstance(register, int)
|
assert isinstance(register, int)
|
||||||
self.register = register
|
self.register = register
|
||||||
|
|
||||||
|
|
|
@ -33,12 +33,12 @@ from . import hidpp20_constants
|
||||||
from . import notify
|
from . import notify
|
||||||
from . import settings
|
from . import settings
|
||||||
from . import special_keys
|
from . import special_keys
|
||||||
|
from .hidpp10_constants import Registers
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
_hidpp20 = hidpp20.Hidpp20()
|
_hidpp20 = hidpp20.Hidpp20()
|
||||||
_DK = hidpp10_constants.DEVICE_KIND
|
_DK = hidpp10_constants.DEVICE_KIND
|
||||||
_R = hidpp10_constants.REGISTERS
|
|
||||||
_F = hidpp20_constants.FEATURE
|
_F = hidpp20_constants.FEATURE
|
||||||
|
|
||||||
_GG = hidpp20_constants.GESTURE
|
_GG = hidpp20_constants.GESTURE
|
||||||
|
@ -137,7 +137,7 @@ class RegisterHandDetection(settings.Setting):
|
||||||
name = "hand-detection"
|
name = "hand-detection"
|
||||||
label = _("Hand Detection")
|
label = _("Hand Detection")
|
||||||
description = _("Turn on illumination when the hands hover over the keyboard.")
|
description = _("Turn on illumination when the hands hover over the keyboard.")
|
||||||
register = _R.keyboard_hand_detection
|
register = Registers.KEYBOARD_HAND_DETECTION
|
||||||
validator_options = {"true_value": b"\x00\x00\x00", "false_value": b"\x00\x00\x30", "mask": b"\x00\x00\xff"}
|
validator_options = {"true_value": b"\x00\x00\x00", "false_value": b"\x00\x00\x30", "mask": b"\x00\x00\xff"}
|
||||||
|
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ class RegisterSmoothScroll(settings.Setting):
|
||||||
name = "smooth-scroll"
|
name = "smooth-scroll"
|
||||||
label = _("Scroll Wheel Smooth Scrolling")
|
label = _("Scroll Wheel Smooth Scrolling")
|
||||||
description = _("High-sensitivity mode for vertical scroll with the wheel.")
|
description = _("High-sensitivity mode for vertical scroll with the wheel.")
|
||||||
register = _R.mouse_button_flags
|
register = Registers.MOUSE_BUTTON_FLAGS
|
||||||
validator_options = {"true_value": 0x40, "mask": 0x40}
|
validator_options = {"true_value": 0x40, "mask": 0x40}
|
||||||
|
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ class RegisterSideScroll(settings.Setting):
|
||||||
"When disabled, pushing the wheel sideways sends custom button events\n"
|
"When disabled, pushing the wheel sideways sends custom button events\n"
|
||||||
"instead of the standard side-scrolling events."
|
"instead of the standard side-scrolling events."
|
||||||
)
|
)
|
||||||
register = _R.mouse_button_flags
|
register = Registers.MOUSE_BUTTON_FLAGS
|
||||||
validator_options = {"true_value": 0x02, "mask": 0x02}
|
validator_options = {"true_value": 0x02, "mask": 0x02}
|
||||||
|
|
||||||
|
|
||||||
|
@ -165,14 +165,14 @@ class RegisterDpi(settings.Setting):
|
||||||
name = "dpi-old"
|
name = "dpi-old"
|
||||||
label = _("Sensitivity (DPI - older mice)")
|
label = _("Sensitivity (DPI - older mice)")
|
||||||
description = _("Mouse movement sensitivity")
|
description = _("Mouse movement sensitivity")
|
||||||
register = _R.mouse_dpi
|
register = Registers.MOUSE_DPI
|
||||||
choices_universe = common.NamedInts.range(0x81, 0x8F, lambda x: str((x - 0x80) * 100))
|
choices_universe = common.NamedInts.range(0x81, 0x8F, lambda x: str((x - 0x80) * 100))
|
||||||
validator_class = settings.ChoicesValidator
|
validator_class = settings.ChoicesValidator
|
||||||
validator_options = {"choices": choices_universe}
|
validator_options = {"choices": choices_universe}
|
||||||
|
|
||||||
|
|
||||||
class RegisterFnSwap(FnSwapVirtual):
|
class RegisterFnSwap(FnSwapVirtual):
|
||||||
register = _R.keyboard_fn_swap
|
register = Registers.KEYBOARD_FN_SWAP
|
||||||
validator_options = {"true_value": b"\x00\x01", "mask": b"\x00\x01"}
|
validator_options = {"true_value": b"\x00\x01", "mask": b"\x00\x01"}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@ from logitech_receiver import hidpp10_constants as _hidpp10_constants
|
||||||
from logitech_receiver import notifications as _notifications
|
from logitech_receiver import notifications as _notifications
|
||||||
|
|
||||||
_hidpp10 = hidpp10.Hidpp10()
|
_hidpp10 = hidpp10.Hidpp10()
|
||||||
_R = _hidpp10_constants.REGISTERS
|
|
||||||
|
|
||||||
|
|
||||||
def run(receivers, args, find_receiver, _ignore):
|
def run(receivers, args, find_receiver, _ignore):
|
||||||
|
|
|
@ -17,12 +17,11 @@
|
||||||
from logitech_receiver import base as _base
|
from logitech_receiver import base as _base
|
||||||
from logitech_receiver import hidpp10_constants as _hidpp10_constants
|
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 logitech_receiver.hidpp10_constants import Registers as Reg
|
||||||
|
|
||||||
from solaar.cli.show import _print_device
|
from solaar.cli.show import _print_device
|
||||||
from solaar.cli.show import _print_receiver
|
from solaar.cli.show import _print_receiver
|
||||||
|
|
||||||
_R = _hidpp10_constants.REGISTERS
|
|
||||||
|
|
||||||
|
|
||||||
def run(receivers, args, find_receiver, _ignore):
|
def run(receivers, args, find_receiver, _ignore):
|
||||||
assert receivers
|
assert receivers
|
||||||
|
@ -45,37 +44,37 @@ def run(receivers, args, find_receiver, _ignore):
|
||||||
|
|
||||||
print("")
|
print("")
|
||||||
print(" Register Dump")
|
print(" Register Dump")
|
||||||
rgst = receiver.read_register(_R.notifications)
|
rgst = receiver.read_register(Reg.NOTIFICATIONS)
|
||||||
print(" Notifications %#04x: %s" % (_R.notifications % 0x100, "0x" + _strhex(rgst) if rgst else "None"))
|
print(" Notifications %#04x: %s" % (Reg.NOTIFICATIONS % 0x100, "0x" + _strhex(rgst) if rgst else "None"))
|
||||||
rgst = receiver.read_register(_R.receiver_connection)
|
rgst = receiver.read_register(Reg.RECEIVER_CONNECTION)
|
||||||
print(" Connection State %#04x: %s" % (_R.receiver_connection % 0x100, "0x" + _strhex(rgst) if rgst else "None"))
|
print(" Connection State %#04x: %s" % (Reg.RECEIVER_CONNECTION % 0x100, "0x" + _strhex(rgst) if rgst else "None"))
|
||||||
rgst = receiver.read_register(_R.devices_activity)
|
rgst = receiver.read_register(Reg.DEVICES_ACTIVITY)
|
||||||
print(" Device Activity %#04x: %s" % (_R.devices_activity % 0x100, "0x" + _strhex(rgst) if rgst else "None"))
|
print(" Device Activity %#04x: %s" % (Reg.DEVICES_ACTIVITY % 0x100, "0x" + _strhex(rgst) if rgst else "None"))
|
||||||
|
|
||||||
for sub_reg in range(0, 16):
|
for sub_reg in range(0, 16):
|
||||||
rgst = receiver.read_register(_R.receiver_info, sub_reg)
|
rgst = receiver.read_register(Reg.RECEIVER_INFO, sub_reg)
|
||||||
print(
|
print(
|
||||||
" Pairing Register %#04x %#04x: %s"
|
" Pairing Register %#04x %#04x: %s"
|
||||||
% (_R.receiver_info % 0x100, sub_reg, "0x" + _strhex(rgst) if rgst else "None")
|
% (Reg.RECEIVER_INFO % 0x100, sub_reg, "0x" + _strhex(rgst) if rgst else "None")
|
||||||
)
|
)
|
||||||
for device in range(0, 7):
|
for device in range(0, 7):
|
||||||
for sub_reg in [0x10, 0x20, 0x30, 0x50]:
|
for sub_reg in [0x10, 0x20, 0x30, 0x50]:
|
||||||
rgst = receiver.read_register(_R.receiver_info, sub_reg + device)
|
rgst = receiver.read_register(Reg.RECEIVER_INFO, sub_reg + device)
|
||||||
print(
|
print(
|
||||||
" Pairing Register %#04x %#04x: %s"
|
" Pairing Register %#04x %#04x: %s"
|
||||||
% (_R.receiver_info % 0x100, sub_reg + device, "0x" + _strhex(rgst) if rgst else "None")
|
% (Reg.RECEIVER_INFO % 0x100, sub_reg + device, "0x" + _strhex(rgst) if rgst else "None")
|
||||||
)
|
)
|
||||||
rgst = receiver.read_register(_R.receiver_info, 0x40 + device)
|
rgst = receiver.read_register(Reg.RECEIVER_INFO, 0x40 + device)
|
||||||
print(
|
print(
|
||||||
" Pairing Name %#04x %#02x: %s"
|
" Pairing Name %#04x %#02x: %s"
|
||||||
% (_R.receiver_info % 0x100, 0x40 + device, rgst[2 : 2 + ord(rgst[1:2])] if rgst else "None")
|
% (Reg.RECEIVER_INFO % 0x100, 0x40 + device, rgst[2 : 2 + ord(rgst[1:2])] if rgst else "None")
|
||||||
)
|
)
|
||||||
for part in range(1, 4):
|
for part in range(1, 4):
|
||||||
rgst = receiver.read_register(_R.receiver_info, 0x60 + device, part)
|
rgst = receiver.read_register(Reg.RECEIVER_INFO, 0x60 + device, part)
|
||||||
print(
|
print(
|
||||||
" Pairing Name %#04x %#02x %#02x: %2d %s"
|
" Pairing Name %#04x %#02x %#02x: %2d %s"
|
||||||
% (
|
% (
|
||||||
_R.receiver_info % 0x100,
|
Reg.RECEIVER_INFO % 0x100,
|
||||||
0x60 + device,
|
0x60 + device,
|
||||||
part,
|
part,
|
||||||
ord(rgst[2:3]) if rgst else 0,
|
ord(rgst[2:3]) if rgst else 0,
|
||||||
|
@ -83,10 +82,10 @@ def run(receivers, args, find_receiver, _ignore):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
for sub_reg in range(0, 5):
|
for sub_reg in range(0, 5):
|
||||||
rgst = receiver.read_register(_R.firmware, sub_reg)
|
rgst = receiver.read_register(Reg.FIRMWARE, sub_reg)
|
||||||
print(
|
print(
|
||||||
" Firmware %#04x %#04x: %s"
|
" Firmware %#04x %#04x: %s"
|
||||||
% (_R.firmware % 0x100, sub_reg, "0x" + _strhex(rgst) if rgst is not None else "None")
|
% (Reg.FIRMWARE % 0x100, sub_reg, "0x" + _strhex(rgst) if rgst is not None else "None")
|
||||||
)
|
)
|
||||||
|
|
||||||
print("")
|
print("")
|
||||||
|
|
|
@ -32,6 +32,7 @@ from logitech_receiver import exceptions
|
||||||
from logitech_receiver import hidpp10_constants as _hidpp10_constants
|
from logitech_receiver import hidpp10_constants as _hidpp10_constants
|
||||||
from logitech_receiver import listener as _listener
|
from logitech_receiver import listener as _listener
|
||||||
from logitech_receiver import notifications as _notifications
|
from logitech_receiver import notifications as _notifications
|
||||||
|
from logitech_receiver.hidpp10_constants import Registers
|
||||||
|
|
||||||
from . import configuration
|
from . import configuration
|
||||||
from . import dbus
|
from . import dbus
|
||||||
|
@ -42,7 +43,6 @@ from gi.repository import GLib # NOQA: E402 # isort:skip
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
_R = _hidpp10_constants.REGISTERS
|
|
||||||
_IR = _hidpp10_constants.INFO_SUBREGISTERS
|
_IR = _hidpp10_constants.INFO_SUBREGISTERS
|
||||||
|
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ class SolaarListener(_listener.EventsListener):
|
||||||
if not already_known:
|
if not already_known:
|
||||||
if n.address == 0x0A and not self.receiver.receiver_kind == "bolt":
|
if n.address == 0x0A and not self.receiver.receiver_kind == "bolt":
|
||||||
# some Nanos send a notification even if no new pairing - check that there really is a device there
|
# some Nanos send a notification even if no new pairing - check that there really is a device there
|
||||||
if self.receiver.read_register(_R.receiver_info, _IR.pairing_information + n.devnumber - 1) is None:
|
if self.receiver.read_register(Registers.RECEIVER_INFO, _IR.pairing_information + n.devnumber - 1) is None:
|
||||||
return
|
return
|
||||||
dev = self.receiver.register_new_device(n.devnumber, n)
|
dev = self.receiver.register_new_device(n.devnumber, n)
|
||||||
elif self.receiver.pairing.lock_open and self.receiver.re_pairs and not ord(n.data[0:1]) & 0x40:
|
elif self.receiver.pairing.lock_open and self.receiver.re_pairs and not ord(n.data[0:1]) & 0x40:
|
||||||
|
|
|
@ -10,6 +10,7 @@ from logitech_receiver import common
|
||||||
from logitech_receiver import hidpp10
|
from logitech_receiver import hidpp10
|
||||||
from logitech_receiver import hidpp10_constants
|
from logitech_receiver import hidpp10_constants
|
||||||
from logitech_receiver import hidpp20_constants
|
from logitech_receiver import hidpp20_constants
|
||||||
|
from logitech_receiver.hidpp10_constants import Registers
|
||||||
|
|
||||||
_hidpp10 = hidpp10.Hidpp10()
|
_hidpp10 = hidpp10.Hidpp10()
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ class Device:
|
||||||
kind: str = "fake"
|
kind: str = "fake"
|
||||||
protocol: float = 1.0
|
protocol: float = 1.0
|
||||||
isDevice: bool = False # incorrect, but useful here
|
isDevice: bool = False # incorrect, but useful here
|
||||||
registers: List[common.NamedInt] = field(default_factory=list)
|
registers: List[Registers] = field(default_factory=list)
|
||||||
responses: List[Response] = field(default_factory=list)
|
responses: List[Response] = field(default_factory=list)
|
||||||
|
|
||||||
def request(self, id, params=None, no_reply=False):
|
def request(self, id, params=None, no_reply=False):
|
||||||
|
@ -42,27 +43,25 @@ class Device:
|
||||||
|
|
||||||
|
|
||||||
device_offline = Device("OFFLINE", False)
|
device_offline = Device("OFFLINE", False)
|
||||||
device_leds = Device(
|
device_leds = Device("LEDS", True, registers=[Registers.THREE_LEDS, Registers.BATTERY_STATUS])
|
||||||
"LEDS", True, registers=[hidpp10_constants.REGISTERS.three_leds, hidpp10_constants.REGISTERS.battery_status]
|
|
||||||
)
|
|
||||||
device_features = Device("FEATURES", True, protocol=4.5)
|
device_features = Device("FEATURES", True, protocol=4.5)
|
||||||
|
|
||||||
registers_standard = [hidpp10_constants.REGISTERS.battery_status, hidpp10_constants.REGISTERS.firmware]
|
registers_standard = [Registers.BATTERY_STATUS, Registers.FIRMWARE]
|
||||||
responses_standard = [
|
responses_standard = [
|
||||||
Response("555555", 0x8100 | hidpp10_constants.REGISTERS.battery_status, 0x00),
|
Response("555555", 0x8100 | Registers.BATTERY_STATUS, 0x00),
|
||||||
Response("666666", 0x8100 | hidpp10_constants.REGISTERS.battery_status, 0x10),
|
Response("666666", 0x8100 | Registers.BATTERY_STATUS, 0x10),
|
||||||
Response("777777", 0x8000 | hidpp10_constants.REGISTERS.battery_status, 0x00),
|
Response("777777", 0x8000 | Registers.BATTERY_STATUS, 0x00),
|
||||||
Response("888888", 0x8000 | hidpp10_constants.REGISTERS.battery_status, 0x10),
|
Response("888888", 0x8000 | Registers.BATTERY_STATUS, 0x10),
|
||||||
Response("052100", 0x8100 | hidpp10_constants.REGISTERS.battery_status, []),
|
Response("052100", 0x8100 | Registers.BATTERY_STATUS, []),
|
||||||
Response("ABCDEF", 0x8100 | hidpp10_constants.REGISTERS.firmware, 0x01),
|
Response("ABCDEF", 0x8100 | Registers.FIRMWARE, 0x01),
|
||||||
Response("ABCDEF", 0x8100 | hidpp10_constants.REGISTERS.firmware, 0x02),
|
Response("ABCDEF", 0x8100 | Registers.FIRMWARE, 0x02),
|
||||||
Response("ABCDEF", 0x8100 | hidpp10_constants.REGISTERS.firmware, 0x03),
|
Response("ABCDEF", 0x8100 | Registers.FIRMWARE, 0x03),
|
||||||
Response("ABCDEF", 0x8100 | hidpp10_constants.REGISTERS.firmware, 0x04),
|
Response("ABCDEF", 0x8100 | Registers.FIRMWARE, 0x04),
|
||||||
Response("000900", 0x8100 | hidpp10_constants.REGISTERS.notifications, []),
|
Response("000900", 0x8100 | Registers.NOTIFICATIONS, []),
|
||||||
Response("101010", 0x8100 | hidpp10_constants.REGISTERS.mouse_button_flags, []),
|
Response("101010", 0x8100 | Registers.MOUSE_BUTTON_FLAGS, []),
|
||||||
Response("010101", 0x8100 | hidpp10_constants.REGISTERS.keyboard_fn_swap, []),
|
Response("010101", 0x8100 | Registers.KEYBOARD_FN_SWAP, []),
|
||||||
Response("020202", 0x8100 | hidpp10_constants.REGISTERS.devices_configuration, []),
|
Response("020202", 0x8100 | Registers.DEVICES_CONFIGURATION, []),
|
||||||
Response("030303", 0x8000 | hidpp10_constants.REGISTERS.devices_configuration, 0x00),
|
Response("030303", 0x8000 | Registers.DEVICES_CONFIGURATION, 0x00),
|
||||||
]
|
]
|
||||||
device_standard = Device("STANDARD", True, registers=registers_standard, responses=responses_standard)
|
device_standard = Device("STANDARD", True, registers=registers_standard, responses=responses_standard)
|
||||||
|
|
||||||
|
@ -70,10 +69,10 @@ device_standard = Device("STANDARD", True, registers=registers_standard, respons
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"device, register, param, expected_result",
|
"device, register, param, expected_result",
|
||||||
[
|
[
|
||||||
(device_offline, hidpp10_constants.REGISTERS.three_leds, 0x00, None),
|
(device_offline, Registers.THREE_LEDS, 0x00, None),
|
||||||
(device_standard, hidpp10_constants.REGISTERS.three_leds, 0x00, None),
|
(device_standard, Registers.THREE_LEDS, 0x00, None),
|
||||||
(device_standard, hidpp10_constants.REGISTERS.battery_status, 0x00, "555555"),
|
(device_standard, Registers.BATTERY_STATUS, 0x00, "555555"),
|
||||||
(device_standard, hidpp10_constants.REGISTERS.battery_status, 0x10, "666666"),
|
(device_standard, Registers.BATTERY_STATUS, 0x10, "666666"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_read_register(device, register, param, expected_result, mocker):
|
def test_read_register(device, register, param, expected_result, mocker):
|
||||||
|
@ -88,10 +87,10 @@ def test_read_register(device, register, param, expected_result, mocker):
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"device, register, param, expected_result",
|
"device, register, param, expected_result",
|
||||||
[
|
[
|
||||||
(device_offline, hidpp10_constants.REGISTERS.three_leds, 0x00, None),
|
(device_offline, Registers.THREE_LEDS, 0x00, None),
|
||||||
(device_standard, hidpp10_constants.REGISTERS.three_leds, 0x00, None),
|
(device_standard, Registers.THREE_LEDS, 0x00, None),
|
||||||
(device_standard, hidpp10_constants.REGISTERS.battery_status, 0x00, "777777"),
|
(device_standard, Registers.BATTERY_STATUS, 0x00, "777777"),
|
||||||
(device_standard, hidpp10_constants.REGISTERS.battery_status, 0x10, "888888"),
|
(device_standard, Registers.BATTERY_STATUS, 0x10, "888888"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_write_register(device, register, param, expected_result, mocker):
|
def test_write_register(device, register, param, expected_result, mocker):
|
||||||
|
@ -104,7 +103,7 @@ def test_write_register(device, register, param, expected_result, mocker):
|
||||||
|
|
||||||
|
|
||||||
def device_charge(name, response):
|
def device_charge(name, response):
|
||||||
responses = [Response(response, 0x8100 | hidpp10_constants.REGISTERS.battery_charge, [])]
|
responses = [Response(response, 0x8100 | Registers.BATTERY_CHARGE, [])]
|
||||||
return Device(name, registers=[], responses=responses)
|
return Device(name, registers=[], responses=responses)
|
||||||
|
|
||||||
|
|
||||||
|
@ -115,7 +114,7 @@ device_charge4 = device_charge("OTHER", "220000")
|
||||||
|
|
||||||
|
|
||||||
def device_status(name, response):
|
def device_status(name, response):
|
||||||
responses = [Response(response, 0x8100 | hidpp10_constants.REGISTERS.battery_status, [])]
|
responses = [Response(response, 0x8100 | Registers.BATTERY_STATUS, [])]
|
||||||
return Device(name, registers=[], responses=responses)
|
return Device(name, registers=[], responses=responses)
|
||||||
|
|
||||||
|
|
||||||
|
@ -136,53 +135,49 @@ device_status6 = device_status("NOSTATUS", "002200")
|
||||||
(
|
(
|
||||||
device_standard,
|
device_standard,
|
||||||
common.Battery(common.BatteryLevelApproximation.GOOD, None, common.BatteryStatus.RECHARGING, None),
|
common.Battery(common.BatteryLevelApproximation.GOOD, None, common.BatteryStatus.RECHARGING, None),
|
||||||
hidpp10_constants.REGISTERS.battery_status,
|
Registers.BATTERY_STATUS,
|
||||||
),
|
|
||||||
(
|
|
||||||
device_charge1,
|
|
||||||
common.Battery(0x55, None, common.BatteryStatus.DISCHARGING, None),
|
|
||||||
hidpp10_constants.REGISTERS.battery_charge,
|
|
||||||
),
|
),
|
||||||
|
(device_charge1, common.Battery(0x55, None, common.BatteryStatus.DISCHARGING, None), Registers.BATTERY_CHARGE),
|
||||||
(
|
(
|
||||||
device_charge2,
|
device_charge2,
|
||||||
common.Battery(0x44, None, common.BatteryStatus.RECHARGING, None),
|
common.Battery(0x44, None, common.BatteryStatus.RECHARGING, None),
|
||||||
hidpp10_constants.REGISTERS.battery_charge,
|
Registers.BATTERY_CHARGE,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
device_charge3,
|
device_charge3,
|
||||||
common.Battery(0x60, None, common.BatteryStatus.FULL, None),
|
common.Battery(0x60, None, common.BatteryStatus.FULL, None),
|
||||||
hidpp10_constants.REGISTERS.battery_charge,
|
Registers.BATTERY_CHARGE,
|
||||||
),
|
),
|
||||||
(device_charge4, common.Battery(0x22, None, None, None), hidpp10_constants.REGISTERS.battery_charge),
|
(device_charge4, common.Battery(0x22, None, None, None), Registers.BATTERY_CHARGE),
|
||||||
(
|
(
|
||||||
device_status1,
|
device_status1,
|
||||||
common.Battery(common.BatteryLevelApproximation.FULL, None, common.BatteryStatus.FULL, None),
|
common.Battery(common.BatteryLevelApproximation.FULL, None, common.BatteryStatus.FULL, None),
|
||||||
hidpp10_constants.REGISTERS.battery_status,
|
Registers.BATTERY_STATUS,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
device_status2,
|
device_status2,
|
||||||
common.Battery(common.BatteryLevelApproximation.GOOD, None, common.BatteryStatus.RECHARGING, None),
|
common.Battery(common.BatteryLevelApproximation.GOOD, None, common.BatteryStatus.RECHARGING, None),
|
||||||
hidpp10_constants.REGISTERS.battery_status,
|
Registers.BATTERY_STATUS,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
device_status3,
|
device_status3,
|
||||||
common.Battery(common.BatteryLevelApproximation.LOW, None, common.BatteryStatus.FULL, None),
|
common.Battery(common.BatteryLevelApproximation.LOW, None, common.BatteryStatus.FULL, None),
|
||||||
hidpp10_constants.REGISTERS.battery_status,
|
Registers.BATTERY_STATUS,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
device_status4,
|
device_status4,
|
||||||
common.Battery(common.BatteryLevelApproximation.CRITICAL, None, None, None),
|
common.Battery(common.BatteryLevelApproximation.CRITICAL, None, None, None),
|
||||||
hidpp10_constants.REGISTERS.battery_status,
|
Registers.BATTERY_STATUS,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
device_status5,
|
device_status5,
|
||||||
common.Battery(common.BatteryLevelApproximation.EMPTY, None, common.BatteryStatus.DISCHARGING, None),
|
common.Battery(common.BatteryLevelApproximation.EMPTY, None, common.BatteryStatus.DISCHARGING, None),
|
||||||
hidpp10_constants.REGISTERS.battery_status,
|
Registers.BATTERY_STATUS,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
device_status6,
|
device_status6,
|
||||||
common.Battery(None, None, common.BatteryStatus.FULL, None),
|
common.Battery(None, None, common.BatteryStatus.FULL, None),
|
||||||
hidpp10_constants.REGISTERS.battery_status,
|
Registers.BATTERY_STATUS,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -227,7 +222,7 @@ def test_set_3leds(device, level, charging, warning, p1, p2, mocker):
|
||||||
|
|
||||||
_hidpp10.set_3leds(device, level, charging, warning)
|
_hidpp10.set_3leds(device, level, charging, warning)
|
||||||
|
|
||||||
spy_request.assert_called_once_with(0x8000 | hidpp10_constants.REGISTERS.three_leds, p1, p2)
|
spy_request.assert_called_once_with(0x8000 | Registers.THREE_LEDS, p1, p2)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("device", [(device_offline), (device_features)])
|
@pytest.mark.parametrize("device", [(device_offline), (device_features)])
|
||||||
|
@ -254,7 +249,7 @@ def test_set_notification_flags(mocker):
|
||||||
device, hidpp10_constants.NOTIFICATION_FLAG.battery_status, hidpp10_constants.NOTIFICATION_FLAG.wireless
|
device, hidpp10_constants.NOTIFICATION_FLAG.battery_status, hidpp10_constants.NOTIFICATION_FLAG.wireless
|
||||||
)
|
)
|
||||||
|
|
||||||
spy_request.assert_called_once_with(0x8000 | hidpp10_constants.REGISTERS.notifications, b"\x10\x01\x00")
|
spy_request.assert_called_once_with(0x8000 | Registers.NOTIFICATIONS, b"\x10\x01\x00")
|
||||||
assert result is not None
|
assert result is not None
|
||||||
|
|
||||||
|
|
||||||
|
@ -279,10 +274,10 @@ def test_get_device_features():
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"device, register, expected_result",
|
"device, register, expected_result",
|
||||||
[
|
[
|
||||||
(device_standard, hidpp10_constants.REGISTERS.battery_status, "052100"),
|
(device_standard, Registers.BATTERY_STATUS, "052100"),
|
||||||
(device_standard, hidpp10_constants.REGISTERS.mouse_button_flags, "101010"),
|
(device_standard, Registers.MOUSE_BUTTON_FLAGS, "101010"),
|
||||||
(device_standard, hidpp10_constants.REGISTERS.keyboard_illumination, None),
|
(device_standard, Registers.KEYBOARD_ILLUMINATION, None),
|
||||||
(device_features, hidpp10_constants.REGISTERS.keyboard_illumination, None),
|
(device_features, Registers.KEYBOARD_ILLUMINATION, None),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_get_register(device, register, expected_result):
|
def test_get_register(device, register, expected_result):
|
||||||
|
|
Loading…
Reference in New Issue