@@ -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