Skip to content

Commit 9d5a44e

Browse files
committed
feat: deep probe 0x807A with 20+ parameter formats
Feature 0x807A getInfo returns 03 05 02 (3 funcs, 5 LEDs, caps=2). This is almost certainly the LED feature. Now tries 20+ parameter combinations on func2 (setter): bitmasks, per-LED, zone+mask, RPM values, brightness, count+states, etc.
1 parent 8801225 commit 9d5a44e

File tree

1 file changed

+152
-15
lines changed

1 file changed

+152
-15
lines changed

Common Files/LogitechLED.cpp

Lines changed: 152 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -421,47 +421,184 @@ bool LogitechLED::TryHIDPPDiscovery(HANDLE h, USHORT outLen, USHORT inLen)
421421
}
422422
}
423423

424-
// --- Try LED commands on each unknown 0x8xxx feature ---
424+
// --- Quick probe on other unknown features ---
425425
Log("");
426-
Log(" === LED attempts on unknown features (WATCH THE WHEEL!) ===");
426+
Log(" === Quick probe on unknown features ===");
427427

428428
for (int pi = 0; pi < numProbe; pi++)
429429
{
430-
Log("");
431-
Log(" --- Feature 0x%04X at index %d ---", probeFid[pi], probeIdx[pi]);
430+
// Skip 0x807A - we'll deep-probe it below
431+
if (probeFid[pi] == 0x807A) continue;
432432

433-
// Try func1-3 with LED bitmask 0x1F (all 5 LEDs)
434-
for (BYTE funcId = 1; funcId <= 3; funcId++)
433+
for (BYTE funcId = 1; funcId <= 2; funcId++)
435434
{
436435
memset(req, 0, sizeof(req));
437436
req[0] = reportId;
438437
req[1] = devIdx;
439438
req[2] = probeIdx[pi];
440439
req[3] = (funcId << 4) | 0x01;
441-
req[4] = 0x1F; // all LEDs on
440+
req[4] = 0x1F;
441+
442+
bool ok = SendReport(h, req, outLen);
443+
BYTE tryResp[64] = {0};
444+
bool gotResp = ok ? ReadReport(h, tryResp, inLen, 300) : false;
445+
446+
if (!ok)
447+
Log(" 0x%04X func%d(0x1F): SEND FAIL", probeFid[pi], funcId);
448+
else if (gotResp && tryResp[2] == 0xFF)
449+
Log(" 0x%04X func%d(0x1F): ERR 0x%02X", probeFid[pi], funcId, tryResp[5]);
450+
else if (gotResp)
451+
Log(" 0x%04X func%d(0x1F): OK resp=%02X %02X %02X %02X",
452+
probeFid[pi], funcId,
453+
tryResp[4], tryResp[5], tryResp[6], tryResp[7]);
454+
else
455+
Log(" 0x%04X func%d(0x1F): OK (no resp)", probeFid[pi], funcId);
456+
457+
Sleep(300);
458+
}
459+
}
460+
461+
// --- Deep probe 0x807A (likely LED feature: func0 returned 03 05 02) ---
462+
// Find 0x807A index
463+
BYTE ledIdx807A = 0;
464+
for (int pi = 0; pi < numProbe; pi++)
465+
{
466+
if (probeFid[pi] == 0x807A) { ledIdx807A = probeIdx[pi]; break; }
467+
}
468+
469+
if (ledIdx807A > 0)
470+
{
471+
Log("");
472+
Log(" === DEEP PROBE 0x807A at index %d (WATCH THE WHEEL!) ===", ledIdx807A);
473+
Log(" func0 said: 03=funcs 05=LEDs 02=caps");
474+
Log("");
475+
476+
// First read current state with func1 (no params)
477+
memset(req, 0, sizeof(req));
478+
req[0] = reportId;
479+
req[1] = devIdx;
480+
req[2] = ledIdx807A;
481+
req[3] = (1 << 4) | 0x01; // func1 = getLedState?
482+
// No params - see what the current state is
483+
484+
if (SendReport(h, req, outLen))
485+
{
486+
memset(resp, 0, sizeof(resp));
487+
if (ReadReport(h, resp, inLen, 500))
488+
Log(" func1() get state: %02X %02X %02X %02X %02X %02X",
489+
resp[4], resp[5], resp[6], resp[7], resp[8], resp[9]);
490+
}
491+
492+
// Try many param formats on func2 (setLedState?)
493+
struct { BYTE p[16]; int plen; const char* desc; } tries[] = {
494+
// Bitmask encodings
495+
{{0x1F}, 1, "mask=0x1F"},
496+
{{0xFF}, 1, "0xFF"},
497+
{{0x01}, 1, "0x01"},
498+
// Per-LED state (5 LEDs, each on)
499+
{{0x01,0x01,0x01,0x01,0x01}, 5, "5x 0x01"},
500+
{{0xFF,0xFF,0xFF,0xFF,0xFF}, 5, "5x 0xFF"},
501+
// Zone + mask
502+
{{0x00,0x1F}, 2, "zone0,mask=0x1F"},
503+
{{0x01,0x1F}, 2, "zone1,mask=0x1F"},
504+
{{0x00,0xFF}, 2, "zone0,0xFF"},
505+
// LED index + state
506+
{{0x00,0x01}, 2, "led0,on"},
507+
{{0x00,0xFF}, 2, "led0,0xFF"},
508+
{{0x04,0x01}, 2, "led4,on"},
509+
// RPM percentage values
510+
{{0x64}, 1, "100(pct)"},
511+
{{0xC8}, 1, "200"},
512+
// With brightness
513+
{{0x1F,0xFF}, 2, "mask=0x1F,bright=0xFF"},
514+
{{0x1F,0x64}, 2, "mask=0x1F,bright=100"},
515+
// Byte-per-LED with brightness
516+
{{0x00,0x01,0xFF}, 3, "led0,on,0xFF"},
517+
{{0x00,0x00,0xFF,0x00,0x00}, 5, "G=0,R=FF"},
518+
// Count + states
519+
{{0x05,0x01,0x01,0x01,0x01,0x01}, 6, "n=5,all on"},
520+
// Enable/mode then mask
521+
{{0x01,0x00,0x1F}, 3, "enable,0,mask"},
522+
{{0x02,0x1F}, 2, "mode2,mask"},
523+
};
524+
int numTries = sizeof(tries) / sizeof(tries[0]);
525+
526+
for (int t = 0; t < numTries; t++)
527+
{
528+
memset(req, 0, sizeof(req));
529+
req[0] = reportId;
530+
req[1] = devIdx;
531+
req[2] = ledIdx807A;
532+
req[3] = (2 << 4) | 0x01; // func2 = setLedState
533+
memcpy(&req[4], tries[t].p, tries[t].plen);
442534

443535
bool ok = SendReport(h, req, outLen);
444536
BYTE tryResp[64] = {0};
445537
bool gotResp = ok ? ReadReport(h, tryResp, inLen, 300) : false;
446538

447539
if (!ok)
448-
Log(" func%d(0x1F): SEND FAIL", funcId);
540+
Log(" [%02d] func2(%-20s): SEND FAIL", t, tries[t].desc);
449541
else if (gotResp && tryResp[2] == 0xFF)
450-
Log(" func%d(0x1F): ERR 0x%02X", funcId, tryResp[5]);
542+
Log(" [%02d] func2(%-20s): ERR 0x%02X", t, tries[t].desc, tryResp[5]);
543+
else if (gotResp)
544+
Log(" [%02d] func2(%-20s): OK r=%02X %02X %02X %02X",
545+
t, tries[t].desc,
546+
tryResp[4], tryResp[5], tryResp[6], tryResp[7]);
547+
else
548+
Log(" [%02d] func2(%-20s): OK (no r)", t, tries[t].desc);
549+
550+
Sleep(500);
551+
}
552+
553+
// Also try func1 as setter with same key formats
554+
Log("");
555+
Log(" --- func1 as setter ---");
556+
BYTE func1Tries[][8] = {
557+
{0x00,0x1F,0,0,0,0,0,0},
558+
{0x01,0x1F,0,0,0,0,0,0},
559+
{0x01,0x01,0x01,0x01,0x01,0,0,0},
560+
{0xFF,0xFF,0xFF,0xFF,0xFF,0,0,0},
561+
{0x05,0x01,0x01,0x01,0x01,0x01,0,0},
562+
};
563+
const char* func1Desc[] = {
564+
"zone0,mask=0x1F", "zone1,mask=0x1F",
565+
"5x 0x01", "5x 0xFF", "n=5,all on"
566+
};
567+
568+
for (int t = 0; t < 5; t++)
569+
{
570+
memset(req, 0, sizeof(req));
571+
req[0] = reportId;
572+
req[1] = devIdx;
573+
req[2] = ledIdx807A;
574+
req[3] = (1 << 4) | 0x01;
575+
memcpy(&req[4], func1Tries[t], 8);
576+
577+
bool ok = SendReport(h, req, outLen);
578+
BYTE tryResp[64] = {0};
579+
bool gotResp = ok ? ReadReport(h, tryResp, inLen, 300) : false;
580+
581+
if (gotResp && tryResp[2] == 0xFF)
582+
Log(" func1(%-20s): ERR 0x%02X", func1Desc[t], tryResp[5]);
451583
else if (gotResp)
452-
Log(" func%d(0x1F): OK resp=%02X %02X %02X %02X",
453-
funcId, tryResp[4], tryResp[5], tryResp[6], tryResp[7]);
584+
Log(" func1(%-20s): OK r=%02X %02X %02X %02X",
585+
func1Desc[t],
586+
tryResp[4], tryResp[5], tryResp[6], tryResp[7]);
454587
else
455-
Log(" func%d(0x1F): OK (no resp)", funcId);
588+
Log(" func1(%-20s): %s", func1Desc[t], ok ? "OK (no r)" : "FAIL");
456589

457-
Sleep(400);
590+
Sleep(500);
458591
}
592+
593+
// Save 0x807A as the LED feature
594+
bestLedIdx = ledIdx807A;
595+
bestLedFid = 0x807A;
459596
}
460597

461-
// Save best guess
598+
// Save config
462599
m_method = METHOD_HIDPP;
463600
m_ledFeatureIdx = bestLedIdx;
464-
m_ledFunctionId = 1;
601+
m_ledFunctionId = 2; // func2 = setter for 0x807A
465602
m_deviceIdx = devIdx;
466603
Log("");
467604
Log(" HID++ saved: feat=0x%04X idx=%d func=%d devIdx=0x%02X",

0 commit comments

Comments
 (0)