From c1a79a49f801d57f6a5cfb6b1d8b212fa82554b0 Mon Sep 17 00:00:00 2001 From: Leonardo Gates Date: Thu, 31 Dec 2020 01:16:53 +0000 Subject: [PATCH] settings: implement polling rate --- lib/logitech_receiver/hidpp20.py | 15 +++++++++++++ lib/logitech_receiver/settings_templates.py | 24 +++++++++++++++++++++ lib/solaar/cli/show.py | 6 ++++++ 3 files changed, 45 insertions(+) diff --git a/lib/logitech_receiver/hidpp20.py b/lib/logitech_receiver/hidpp20.py index 3762c6f8..55d8325f 100644 --- a/lib/logitech_receiver/hidpp20.py +++ b/lib/logitech_receiver/hidpp20.py @@ -183,6 +183,8 @@ BATTERY_STATUS = _NamedInts( thermal_error=0x06 ) +ONBOARD_MODES = _NamedInts(MODE_NO_CHANGE=0x00, MODE_ONBOARD=0x01, MODE_HOST=0x02) + CHARGE_STATUS = _NamedInts(charging=0x00, full=0x01, not_charging=0x02, error=0x07) CHARGE_LEVEL = _NamedInts(average=50, full=90, critical=5) @@ -1334,6 +1336,19 @@ def set_host_name(device, name): return response +def get_onboard_mode(device): + state = feature_request(device, FEATURE.ONBOARD_PROFILES, 0x20) + + if state: + mode = _unpack('!B', state[:1])[0] + return mode + + +def set_onboard_mode(device, mode): + state = feature_request(device, FEATURE.ONBOARD_PROFILES, 0x10, mode) + return state + + def get_polling_rate(device): state = feature_request(device, FEATURE.REPORT_RATE, 0x10) if state: diff --git a/lib/logitech_receiver/settings_templates.py b/lib/logitech_receiver/settings_templates.py index 561399fb..c82c4e48 100644 --- a/lib/logitech_receiver/settings_templates.py +++ b/lib/logitech_receiver/settings_templates.py @@ -81,6 +81,7 @@ _HIRES_INV = ('hires-smooth-invert', _('Scroll Wheel Direction'), _('Invert direction for vertical scroll with wheel.')) _HIRES_RES = ('hires-smooth-resolution', _('Scroll Wheel Resolution'), _('High-sensitivity mode for vertical scroll with the wheel.')) +_REPORT_RATE = ('report_rate', _('Polling Rate (ms)'), _('Frequency of device polling, in milliseconds')) _FN_SWAP = ('fn-swap', _('Swap Fx function'), _('When set, the F1..F12 keys will activate their special function,\n' 'and you must hold the FN key to activate their standard function.') + '\n\n' + @@ -527,6 +528,28 @@ def _feature_adjustable_dpi(): return _Setting(_DPI, rw, callback=_feature_adjustable_dpi_callback, device_kind=(_DK.mouse, _DK.trackball)) +# Implemented based on code in libratrag +def _feature_report_rate_callback(device): + # Host mode is required for report rate to be adjustable + if _hidpp20.get_onboard_mode(device) != _hidpp20.ONBOARD_MODES.MODE_HOST: + _hidpp20.set_onboard_mode(device, _hidpp20.ONBOARD_MODES.MODE_HOST) + + reply = device.feature_request(_F.REPORT_RATE, 0x00) + assert reply, 'Oops, report rate choices cannot be retrieved!' + rate_list = [] + rate_flags = _bytes2int(reply[0:1]) + for i in range(0, 8): + if (rate_flags >> i) & 0x01: + rate_list.append(i + 1) + return _ChoicesV(_NamedInts.list(rate_list), byte_count=1) if rate_list else None + + +def _feature_report_rate(): + """Report Rate feature""" + rw = _FeatureRW(_F.REPORT_RATE, read_fnid=0x10, write_fnid=0x20) + return _Setting(_REPORT_RATE, rw, callback=_feature_report_rate_callback, device_kind=(_DK.mouse, )) + + def _feature_pointer_speed(): """Pointer Speed feature""" # min and max values taken from usb traces of Win software @@ -754,6 +777,7 @@ _SETTINGS_TABLE = [ _S(_REPROGRAMMABLE_KEYS, _F.REPROG_CONTROLS_V4, _feature_reprogrammable_keys), _S(_DIVERT_KEYS, _F.REPROG_CONTROLS_V4, _feature_divert_keys), _S(_DISABLE_KEYS, _F.KEYBOARD_DISABLE_KEYS, _feature_disable_keyboard_keys), + _S(_REPORT_RATE, _F.REPORT_RATE, _feature_report_rate), _S(_DIVERT_CROWN, _F.CROWN, _feature_divert_crown), _S(_DIVERT_GKEYS, _F.GKEY, _feature_divert_gkeys), _S(_PLATFORM, _F.MULTIPLATFORM, _feature_multiplatform), diff --git a/lib/solaar/cli/show.py b/lib/solaar/cli/show.py index d8ee1988..7695acd0 100644 --- a/lib/solaar/cli/show.py +++ b/lib/solaar/cli/show.py @@ -216,6 +216,12 @@ def _print_device(dev, num=None): print(' Polling Rate (ms): %d' % _hidpp20.get_polling_rate(dev)) elif feature == _hidpp20.FEATURE.REMAINING_PAIRING: print(' Remaining Pairings: %d' % _hidpp20.get_remaining_pairing(dev)) + elif feature == _hidpp20.FEATURE.ONBOARD_PROFILES: + if _hidpp20.get_onboard_mode(dev) == _hidpp20.ONBOARD_MODES.MODE_HOST: + mode = 'Host' + else: + mode = 'On-Board' + print(' Device Mode: %s' % mode) elif feature == _hidpp20.FEATURE.BATTERY_STATUS or feature == _hidpp20.FEATURE.BATTERY_VOLTAGE: print('', end=' ') _battery_line(dev)