Skip to content

Commit

Permalink
device: optimize getting profile data
Browse files Browse the repository at this point in the history
  • Loading branch information
pfps committed Feb 12, 2024
1 parent 438ea74 commit faa65b3
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 30 deletions.
11 changes: 11 additions & 0 deletions lib/logitech_receiver/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,17 @@ def profiles(self):
if self._profiles is None:
if self.online and self.protocol >= 2.0:
self._profiles = _hidpp20.get_profiles(self)
return self._profiles
elif hasattr(self._profiles, 'headers_only'):
if self.online:
return self._profiles.complete(self)
return self._profiles

@property
def profile_headers(self):
if self._profiles is None:
if self.online and self.protocol >= 2.0:
self._profiles = _hidpp20.get_profiles(self, headers_only=True)
return self._profiles

@property
Expand Down
65 changes: 40 additions & 25 deletions lib/logitech_receiver/hidpp20.py
Original file line number Diff line number Diff line change
Expand Up @@ -1392,7 +1392,14 @@ def __repr__(self):
_yaml.add_representer(Button, Button.to_yaml)


class OnboardProfile:
class OnboardProfileHeader:

def __init__(self, sector, enabled):
self.sector = sector
self.enabled = enabled


class OnboardProfile(OnboardProfileHeader):
"""A single onboard profile"""

def __init__(self, **kwargs):
Expand Down Expand Up @@ -1433,8 +1440,8 @@ def from_bytes(cls, sector, enabled, buttons, gbuttons, bytes):
)

@classmethod
def from_dev(cls, dev, i, sector, s, enabled, buttons, gbuttons):
bytes = OnboardProfiles.read_sector(dev, sector, s)
def from_device(cls, device, sector, enabled, size, buttons, gbuttons):
bytes = OnboardProfiles.read_sector(device, sector, size)
return cls.from_bytes(sector, enabled, buttons, gbuttons, bytes)

def to_bytes(self, length):
Expand Down Expand Up @@ -1500,22 +1507,29 @@ def to_yaml(cls, dumper, data):

@classmethod
def get_profile_headers(cls, device):
headers = {}
i = 0
headers = []
chunk = device.feature_request(FEATURE.ONBOARD_PROFILES, 0x50, 0, 0, 0, i)
s = 0x00
if chunk[0:4] == b'\x00\x00\x00\x00': # look in ROM instead
chunk = device.feature_request(FEATURE.ONBOARD_PROFILES, 0x50, 0x01, 0, 0, i)
s = 0x01
while chunk[0:2] != b'\xff\xff':
sector, enabled = _unpack('!HB', chunk[0:3])
headers.append((sector, enabled))
headers[i + 1] = OnboardProfileHeader(sector, enabled)
i += 1
chunk = device.feature_request(FEATURE.ONBOARD_PROFILES, 0x50, s, 0, 0, i * 4)
return headers

@classmethod
def from_device(cls, device):
def get_profiles(cls, device, size, buttons, gbuttons, headers):
profiles = {}
for i, h in headers.items():
profiles[i] = OnboardProfile.from_device(device, h.sector, h.enabled, size, buttons, gbuttons)
return profiles

@classmethod
def from_device(cls, device, headers_only=False):
if not device.online: # wake the device up if necessary
device.ping()
response = device.feature_request(FEATURE.ONBOARD_PROFILES, 0x00)
Expand All @@ -1524,22 +1538,20 @@ def from_device(cls, device):
return
count, oob, buttons, sectors, size, shift = _unpack('!BBBBHB', response[3:10])
gbuttons = buttons if (shift & 0x3 == 0x2) else 0
headers = OnboardProfiles.get_profile_headers(device)
profiles = {}
i = 0
for sector, enabled in headers:
profiles[i + 1] = OnboardProfile.from_dev(device, i, sector, size, enabled, buttons, gbuttons)
i += 1
return cls(
version=OnboardProfilesVersion,
name=device.name,
count=count,
buttons=buttons,
gbuttons=gbuttons,
sectors=sectors,
size=size,
profiles=profiles
)
result = cls(name=device.name, count=count, buttons=buttons, gbuttons=gbuttons, sectors=sectors, size=size)
result.version = OnboardProfilesVersion
result.profiles = cls.get_profile_headers(device)
if headers_only:
result.headers_only = True
else:
result.profiles = cls.get_profiles(device, size, buttons, gbuttons, result.profiles)
return result

def complete(self, device):
if hasattr(self, 'headers_only'):
delattr(self, 'headers_only')
self.profiles = self.get_profiles(device, self.size, self.buttons, self.gbuttons, self.profiles)
return self

def to_bytes(self):
bytes = b''
Expand Down Expand Up @@ -1891,11 +1903,14 @@ def get_backlight(device):
return Backlight(device)


def get_profiles(device):
def get_profiles(device, headers_only=False):
if getattr(device, '_profiles', None) is not None:
return device._profiles
if not headers_only and hasattr(device._profiles, 'headers_only') and device.online:
return device._profiles.complete(device)
else:
return device._profiles
if FEATURE.ONBOARD_PROFILES in device.features:
return OnboardProfiles.from_device(device)
return OnboardProfiles.from_device(device, headers_only)


def get_mouse_pointer_info(device):
Expand Down
10 changes: 5 additions & 5 deletions lib/logitech_receiver/settings_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,12 +479,12 @@ class validator_class(_ChoicesV):

@classmethod
def build(cls, setting_class, device):
headers = _hidpp20.OnboardProfiles.get_profile_headers(device)
profiles = device.profile_headers
profiles_list = [setting_class.choices_universe[0]]
if headers:
for (sector, enabled) in headers:
if enabled:
profiles_list.append(setting_class.choices_universe[sector])
if profiles:
for h in profiles.profiles.values():
if h.enabled:
profiles_list.append(setting_class.choices_universe[h.sector])
return cls(choices=_NamedInts.list(profiles_list), byte_count=2) if len(profiles_list) > 1 else None


Expand Down

0 comments on commit faa65b3

Please sign in to comment.