cvuchener / hidpp

Collection of HID++ tools
GNU General Public License v3.0
86 stars 23 forks source link

Hidpp list features explanation #1

Open dslul opened 7 years ago

dslul commented 7 years ago

Hi, I was writing a program for configuring my mouse (g402) under linux, then I found your library and I switched to using it. It works really well, good job! I am trying to understand better the inner workings of the protocol used, however I don't understand what these mean (tools/hidpp-list-features):

Logitech Gaming Mouse G402 (046d:c07e) is a HID++ 4.2 device Feature 0x01: [0x0001] Feature 0x02: [0x0003] Feature 0x03: [0x0005] Feature 0x04: [0x00c1] Feature 0x05: [0x1300] Feature 0x06: [0x1801] hidden Feature 0x07: [0x1802] hidden Feature 0x08: [0x1850] hidden Feature 0x09: [0x18a1] hidden Feature 0x0a: [0x1e00] hidden Feature 0x0b: [0x1eb0] hidden Feature 0x0c: [0x2201] Feature 0x0d: [0x2400] Feature 0x0e: [0x8060] Feature 0x0f: [0x8100] Feature 0x10: [0x8110]

Are these "features" all the same for hid++ devices (or instance, I found out that all led configurations are done using a feature id of 0x05)?

Also this:

Memory model: 1 Profile format: 1 Macro format: 1 Profile count: 1 Profile count OOB: 1 Button count: 8 Sector count: 3 Sector size: 1024 Mechanical layout: 0xa (G-shift, DPI shift) Various info: 0x1 (Corded)

What do memory model, profile, macro, count etc stand for?

Thank you

cvuchener commented 7 years ago

Hi,

You should start by reading the HID++2.0 specification.

The output format for hidpp-list-features is "Feature \<feature index>: [\<feature id>] \<flags>". The feature index may change between different devices (except feature 0, which is used to discover other features), the feature id does not change and tell you what feature/interfaces are implemented by your mouse.

Feature names that I know for your list are :

Some come from the document above, others from libratbag or solaar.

AdjustableDPI and OnBoardProfiles are used in libratbag and are mostly understood. ReportRate and MouseButtonSpy and quiet simple and I think I understand most of their functions. If you want more details on these features, I can tell you what I know.

I don't know the name for 0x1300, but I know functions 6 and 7 are used to get and set the mode for dpi leds (only when changing dpi/always on/always off). I am not sure about the rest. On my G502 with RGB leds, most of led manipulation are done with 0x8070 ColorLEDEffects, so I don't know much about 0x1300. I am curious to learn what you found.

The onboard profile description comes from libratbag, I don't understand everything :

You should have a look at libratbag, it is meant for supporting as many mice as possible and writing simpler software like piper. I am writing this library and tools more for experimenting and using advanced features that libratbag may not want to support, being more generic.

cvuchener commented 7 years ago

I must have missed it, 0x1300 is called LEDControl in solaar. I should check that my notes are up to date.

Source

dslul commented 7 years ago

Thank you for your detailed answer,

for now I discovered these things (mostly related to illumination atm): 10 ff 05 6d 00 00 00 gets the status of the dpi leds (0 2 0 is on, 0 4 0 is off, I assume this is the same on your g502); 10 ff 05 7d 00 02 00 turns on the dpi leds; 10 ff 05 7d 00 04 00 turns off the dpi leds. The G logo instead, supports breathing and adjustable brightness, but the process to set these parameters is still a little unclear to me. To "enable" modification, this must be sent: 10 ff 05 3d 01 00 00 then, set the actual values: 11 ff 05 5d 01 00 80 00 XX ZZ ZZ 00 00 00 00 00 00 00 00 00 where XX is the brightness from 0 to 255, and ZZZZ is the breathing rate in two bytes from 533(0x0215) to 20000(0x4e20), or 0x0000 to disable breathing. To "save" these modifications: 10 ff 05 3d 00 00 00

EDIT: I forgot to say, if I try to use just the function in the middle (the long one) I get Error 2 invalid argument. The first one looks like it "blocks" all the lights, and if I don't send the last one I can't turn on the dpi leds by pressing the button under them. I don't know why they did it this way, there should be a reason, but I just can't figure out why.

cvuchener commented 7 years ago

10 ff 05 7d 00 02 00 turns on the dpi leds; 10 ff 05 7d 00 04 00 turns off the dpi leds.

For me, 01 is always off, 02 is always on, 04 is on only when changing dpi. IIRC Logitech software only uses 02 and 04.

The G logo instead, supports breathing and adjustable brightness, but the process to set these parameters is still a little unclear to me. To "enable" modification, this must be sent: 10 ff 05 3d 01 00 00 then, set the actual values: 11 ff 05 5d 01 00 80 00 XX ZZ ZZ 00 00 00 00 00 00 00 00 00 where XX is the brightness from 0 to 255, and ZZZZ is the breathing rate in two bytes from 533(0x0215) to 20000(0x4e20). To "save" these modifications: 10 ff 05 3d 00 00 00

I saw that function 5 required enabling something with function 3 before (and function 2 give you the current state for that) but it did not do anything with my mouse. I guess that's normal since animation are controlled with 0x8070.

Accepted arguments are different for me. I found that function 5 returns "invalid argument" unless the first three bytes are 00 00 01 or 01 00 01 or ff 00 01. There might be other valid values, brute forcing everything is too slow, but your arguments (01 00 80) don't work with me. Valid arguments may depends on the mouse capabilities. I suspect function 0 and 1 are used for discovering them.

Function 0 gives the count of something (LED count: dpi + logo?):

$ ./src/tools/hidpp20-call-function /dev/hidraw1 5 0
02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Function 1 can be called for each object (I am guessing that the argument is the index from 0 to function 0's count - 1, LGS call order hints at that), and returns some data that I don't understand:

$ ./src/tools/hidpp20-call-function /dev/hidraw1 5 1 00
00 02 03 00 03 07 00 00 00 00 00 00 00 00 00 00
$ ./src/tools/hidpp20-call-function /dev/hidraw1 5 1 01
01 03 03 00 03 00 00 00 00 00 00 00 00 00 00 00

Disabling with function 3 returns the mouse in its normal state for me. You say it saves the modifications, do you mean that the animation set with function 5 remains after disabling function 3 and resetting the mouse? On the G502 spectrum (the RGB version), these settings are stored in the profile.

dslul commented 7 years ago

Function 0 returns the same data for me (02), I also think it is the number of configurable leds. Function 1, instead, returns these:

$ tools/hidpp20-call-function /dev/hidraw1 5 1 00
00 02 03 00 03 07 00 00 00 00 00 00 00 00 00 00
$ tools/hidpp20-call-function /dev/hidraw1 5 1 01
01 04 01 00 80 00 00 00 00 00 00 00 00 00 00 00

The first one (DPI led?) is the same as yours, but the second changes. Also notice that 01 00 80 are the parameters used to set the G logo illumination on mine, so it might be related to the parameters to pass to function 5. Function 3 does not actually "save" the configuration (with parameters 0 0 0, the first one with 1 0 0 is still necessary before), because if I disconnect and reconnect the mouse it keeps the modifications, but it is necessary to restore the normal functionality of the other leds without plugging and unplugging.

EDIT: function 7 with parameter 0 1 0 does the same to me, I didn't know about that, I tried only the commands used by LGS. When it's set to 4, the led is on only when changing dpi or pressing the dpi shift button.

bentiss commented 5 years ago

Looking at https://github.com/libratbag/libratbag/issues/471 I realized that there are a few things we can mention here. The 0x1300 support has been implemented in libratbag since this discussion (see https://github.com/libratbag/libratbag/pull/357)

The interesting parts are:

So:

for now I discovered these things (mostly related to illumination atm): 10 ff 05 6d 00 00 00 gets the status of the dpi leds (0 2 0 is on, 0 4 0 is off, I assume this is the same on your g502);

This reads the NV (non volatile memory) state.

10 ff 05 7d 00 02 00 turns on the dpi leds; 10 ff 05 7d 00 04 00 turns off the dpi leds.

function 0x70 is not documented in libratbag but I assume this should be CMD_LED_SW_CONTROL_SET_NV_CONFIG

The G logo instead, supports breathing and adjustable brightness, but the process to set these parameters is still a little unclear to me. To "enable" modification, this must be sent: 10 ff 05 3d 01 00 00

-> SET_SW_CTRL: allow control of the LED from the software

then, set the actual values: 11 ff 05 5d 01 00 80 00 XX ZZ ZZ 00 00 00 00 00 00 00 00 00 where XX is the brightness from 0 to 255, and ZZZZ is the breathing rate in two bytes from 533(0x0215) to 20000(0x4e20), or 0x0000 to disable breathing.

-> SET_LED_STATE , with 0x80 as the mode: breathing.

To "save" these modifications: 10 ff 05 3d 00 00 00

-> go back to HW control of the LEDs, which enables the DPI switches.

I have a G502 without the RGB LEDs, and I see similar issues that you have with the G402. So we should be able to sort this out in libratbag properly. (following the libratbag discussion in the libratbag issue)

cvuchener commented 5 years ago

Thanks for the explanations. I think I already checked most of it when the PR was written. Although I may have missed that caps was simply the available LED mode bits (and I guess the same for nvconfig_caps and the byte passed to function 7).

I still don't understand the "save" part. With my G502 Spectrum (RGB), when I go back to hardware mode, the LED state is forgotten and reverted to whatever the profile wants. Is this because the RGB mice have the LED effects in the profile description unlike the non-RGB ones (profile format 1) ?

bentiss commented 5 years ago

I still don't understand the "save" part. With my G502 Spectrum (RGB), when I go back to hardware mode, the LED state is forgotten and reverted to whatever the profile wants. Is this because the RGB mice have the LED effects in the profile description unlike the non-RGB ones (profile format 1) ?

Seems so. On my non RGB mouse, the DPI/profile LEDs are not stored in NV. They are going back to the black state but then react on the DPI/profile changes. The Logo LED is however different. Reverting to HW mode seems to store the current state in the NV and this allows to configure the LOGO to breathing or off.

So I think the software needs to use the RGB settings when they can, and fall back on the 0x1300 feature when there is no RGB settings.

pedrovanzella commented 5 years ago

I managed to get a pretty comprehensive list of features from the macos drivers. You can see it here:

https://github.com/libratbag/libratbag/wiki/hidpp20-Features

cvuchener commented 5 years ago

Thanks!

It's funny how 0x1e00 (EnableHiddenFeatures) is a hidden feature on the g502 but it is actually usable without hidden features enabled. It looks more like EnableInternalFeatures (or did I confused the two flags?).

I'm still missing 0x1e20 from the g502 that is not an internal/hidden feature.

pedrovanzella commented 5 years ago

Yeah, I have 0x1e20 on the G900 too, but there was no mention of it on the drivers. 0x1e00 is the only hidden but not internal feature, so maybe that tells us something.

I did some digging inside the driver and I got two functions 0x1e00 too: Function ID 0 is GetEnableHiddenFeatures, takes no parameters and returns 0x0 for disabled and 0x1 for enabled, and Function ID 1 is called SetEnableHiddenFeatures takes the same 0x0 and 0x1, returning nothing.

0x1802 is both Hidden and Internal, and is called DeviceReset. Function ID 0 is called ForceDeviceReset, takes no parameters, returns nothing and is a good test for EnableHiddenFeatures.

If you're interested in digging even more, I found that the firmware update installers sometimes have feature names for features exclusive to one model or another. The macos apps are not stripped, so you can just run a demangler on all symbols and you'll see a bunch of Feature1001BatteryVoltage-like class names and methods.

I wasn't able to find the name for any of the other hidden or internal features in all the binaries I disassembled, though.

pedrovanzella commented 5 years ago

I ended up opening up another firmware updater in ghidra and found the names for another 5 or 6 features. I can send a PR with the list in hidpp-list-features.cpp, would you like that?

cvuchener commented 5 years ago

I did some digging inside the driver and I got two functions 0x1e00 too: Function ID 0 is GetEnableHiddenFeatures, takes no parameters and returns 0x0 for disabled and 0x1 for enabled, and Function ID 1 is called SetEnableHiddenFeatures takes the same 0x0 and 0x1, returning nothing.

I guessed that part.

After more testing it is not about the "internal" flag. Features with "internal" flag, will report a "Logitech internal" error when EnableHiddenFeatures is disabled. But feature 0x1e20 will report "Invalid argument" errors instead, and it will start working when hidden features are enabled.

$ sudo ./src/tools/hidpp-list-features /dev/hidraw1
Logitech Gaming Mouse G502 (046d:c332) is a HID++ 4.2 device
Feature 0x01: [0x0001] Feature set
Feature 0x02: [0x8070] Color LED effects
Feature 0x03: [0x0003] Device FW version
Feature 0x04: [0x0005] Device name
Feature 0x05: [0x1300] LED control
Feature 0x06: [0x18a1] ? (hidden, internal)
Feature 0x07: [0x1e00] ? (hidden)
Feature 0x08: [0x1e20] ?
Feature 0x09: [0x1eb0] ? (hidden, internal)
Feature 0x0a: [0x2201] Adjustable dpi
Feature 0x0b: [0x2230] Angle snapping
Feature 0x0c: [0x2240] Surface tuning
Feature 0x0d: [0x8060] Report rate
Feature 0x0e: [0x8100] Onboard profiles
Feature 0x0f: [0x8110] Mouse button spy
Feature 0x10: [0x1850] ? (hidden, internal)
Feature 0x11: [0x00c1] DFUcontrol 2
Feature 0x12: [0x1801] ? (hidden, internal)
Feature 0x13: [0x1802] ? (hidden, internal)
$ sudo ./src/tools/hidpp20-call-function /dev/hidraw1 6 0
Error code 5: Logitech internal
$ sudo ./src/tools/hidpp20-call-function /dev/hidraw1 8 0
Error code 2: Invalid argument
$ sudo ./src/tools/hidpp20-call-function /dev/hidraw1 7 1 01
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
$ sudo ./src/tools/hidpp20-call-function /dev/hidraw1 6 0
04 00 ff 0f 00 00 00 00 00 00 00 00 00 00 00 00
$ sudo ./src/tools/hidpp20-call-function /dev/hidraw1 6 1
00 00 db 06 00 00 00 00 00 00 00 00 00 00 00 00
$ sudo ./src/tools/hidpp20-call-function /dev/hidraw1 6 2
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
$ sudo ./src/tools/hidpp20-call-function /dev/hidraw1 8 0
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
$ sudo ./src/tools/hidpp20-call-function /dev/hidraw1 8 1
ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Feature 0x18a1 (index 6) function 2 turns my LEDs off until I switch profiles, but the profile itself seems unchanged.

pedrovanzella commented 5 years ago

This is interesting. 0x18a1 has the same behaviour on my G900. I also get the same response on 0x1e20. By the way, 04 00 ff looks like some sort of soft error. I'm sure I've seen that response by calling the wrong function or something like that in the past.

$ sudo ./hidpp-list-features -d 1 /dev/hidraw7
G900 (046d:4053) is a HID++ 4.2 device
Feature 0x01: [0x0001] Feature set
Feature 0x02: [0x0003] Device FW version
Feature 0x03: [0x0005] Device name
Feature 0x04: [0x1001] Battery voltage
Feature 0x05: [0x1863] ? (hidden, internal)
Feature 0x06: [0x18a1] ? (hidden, internal)
Feature 0x07: [0x1e00] Enable hidden features (hidden)
Feature 0x08: [0x1e20] ?
Feature 0x09: [0x1eb0] ? (hidden, internal)
Feature 0x0a: [0x2201] Adjustable dpi
Feature 0x0b: [0x2230] Angle snapping
Feature 0x0c: [0x2240] Surface tuning
Feature 0x0d: [0x8060] Report rate
Feature 0x0e: [0x8100] Onboard profiles
Feature 0x0f: [0x8110] Mouse button spy
Feature 0x10: [0x1850] ? (hidden, internal)
Feature 0x11: [0x00c2] DFUcontrol 3
Feature 0x12: [0x1801] ? (hidden, internal)
Feature 0x13: [0x1802] Device reset (hidden, internal)
Feature 0x14: [0x1890] ? (hidden, internal)
Feature 0x15: [0x1811] ? (hidden, internal)
Feature 0x16: [0x8111] Latency monitoring
Feature 0x17: [0x8070] Color LED effects
Feature 0x18: [0x1300] LED control
$ sudo ./hidpp20-call-function -d 1 /dev/hidraw7 6 0
Error code 5: Logitech internal
$ sudo ./hidpp20-call-function -d 1 /dev/hidraw7 7 1 01
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
$ sudo ./hidpp20-call-function -d 1 /dev/hidraw7 6 0
04 00 ff 0f 00 00 00 00 00 00 00 00 00 00 00 00
$ sudo ./hidpp20-call-function -d 1 /dev/hidraw7 6 1
04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
$ sudo ./hidpp20-call-function -d 1 /dev/hidraw7 6 2
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
$ sudo ./hidpp20-call-function -d 1 /dev/hidraw7 8 0
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
$ sudo ./hidpp20-call-function -d 1 /dev/hidraw7 8 1
ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

I combed through all the driver updates and several versions of the apps I had and I found no mention of 0x1e20, though.

There are a few other features we know about that are both public and not in the apps, which is strange.

One thing that becomes apparent while reverse engineering those apps is that there is a shared codebase for the Feature classes, so you take the driver updater for the G900 (which should only really be concerned with 0x00c2 DFUControl and 0x8100 OnBoardProfiles (because it seems to back them up before updating), but the same code you'll find in all apps for, for example, keyboard stuff, is still present there.

What strikes me as even more odd is that a very small number of features show up in one app but not another, even when they are totally unrelated.

Do you know of any other official Logitech Apps that talk to hidpp devices besides their gaming line of apps? Maybe we can figure something out from them.

cvuchener commented 5 years ago

By the way, 04 00 ff looks like some sort of soft error. I'm sure I've seen that response by calling the wrong function or something like that in the past.

I don't think I have ever seen an error not sent as a hidpp error.

Do you know of any other official Logitech Apps that talk to hidpp devices besides their gaming line of apps? Maybe we can figure something out from them.

I've only used LGS and SetPoint, and mostly for looking at USB traffic.


Another thing about EnableHiddenFeatures, I remembered having an "Invalid argument" error with another function when the mouse was not in the right mode. It was setting the report rate (feature 0x8060, function 2): if you are in OnboardMode (from feature 0x8100/OnboardProfiles) you get "Invalid argument", it only works in HostMode. Enabling also allows setting report rate even in OnboardMode. It is effective and you can even set the report rate to any value (reasonable but unsupported values like 3ms or 5ms or even unreasonable value as high as 255ms, if you like unusable mice).

I guess that EnableHiddenFeatures removes more checks than the hidden feature one.

So 0x1e20 may not actually be hidden, but requiring the mouse to be in a certain state for working as I thought before (and it is not OnboardProfiles mode).

pfps commented 1 year ago

Solaar https://github.com/pwr-Solaar/Solaar has a fairly complete list of the non-hidden HID++ 2.0 features.