Skip to content

Commit 379940e

Browse files
committed
feat: v13 - exhaustive LED SDK scan (all device types + zones)
1 parent 1a88a98 commit 379940e

File tree

1 file changed

+187
-60
lines changed

1 file changed

+187
-60
lines changed

Common Files/LogitechLED.cpp

Lines changed: 187 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ static LogiLedShutdown_t g_LedShutdown = NULL;
104104
static LogiLedGetSdkVersion_t g_LedGetVersion = NULL;
105105
static LogiLedSetZone_t g_LedSetZone = NULL;
106106

107+
// Discovered LED SDK configuration (set during TrySDK scan)
108+
static int g_sdkDevType = 0x8; // Device type for zone API
109+
static int g_sdkMaxZone = 1; // Highest zone that returned OK
110+
static bool g_sdkUseGlobal = false; // Use SetLighting instead of zones
111+
static int g_sdkGlobalTarget = 0x1; // Target for global SetLighting
112+
107113
// --- LogitechLED ---
108114

109115
LogitechLED::LogitechLED()
@@ -612,7 +618,7 @@ bool LogitechLED::TrySteeringSDK()
612618

613619
bool LogitechLED::TrySDK()
614620
{
615-
Log("=== Phase 1: G Hub LED SDK ===");
621+
Log("=== Phase 1: G Hub LED SDK (v13 - exhaustive scan) ===");
616622

617623
#ifdef _WIN64
618624
const char* dllPath = "C:\\Program Files\\LGHUB\\sdks\\sdk_legacy_led_x64.dll";
@@ -628,13 +634,19 @@ bool LogitechLED::TrySDK()
628634
}
629635

630636
Log(" Loaded: %s", dllPath);
631-
DumpExports(m_sdkDll, "LED SDK");
632637

633-
g_LedInit = (LogiLedInit_t)GetProcAddress(m_sdkDll, "LogiLedInit");
634-
g_LedSetTarget = (LogiLedSetTargetDevice_t)GetProcAddress(m_sdkDll, "LogiLedSetTargetDevice");
638+
g_LedInit = (LogiLedInit_t)GetProcAddress(m_sdkDll, "LogiLedInit");
639+
g_LedInitWithName = (LogiLedInitWithName_t)GetProcAddress(m_sdkDll, "LogiLedInitWithName");
640+
g_LedSetTarget = (LogiLedSetTargetDevice_t)GetProcAddress(m_sdkDll, "LogiLedSetTargetDevice");
635641
g_LedSetLighting = (LogiLedSetLighting_t)GetProcAddress(m_sdkDll, "LogiLedSetLighting");
636-
g_LedShutdown = (LogiLedShutdown_t)GetProcAddress(m_sdkDll, "LogiLedShutdown");
637-
g_LedGetVersion = (LogiLedGetSdkVersion_t)GetProcAddress(m_sdkDll, "LogiLedGetSdkVersion");
642+
g_LedShutdown = (LogiLedShutdown_t)GetProcAddress(m_sdkDll, "LogiLedShutdown");
643+
g_LedGetVersion = (LogiLedGetSdkVersion_t)GetProcAddress(m_sdkDll, "LogiLedGetSdkVersion");
644+
g_LedSetZone = (LogiLedSetZone_t)GetProcAddress(m_sdkDll, "LogiLedSetLightingForTargetZone");
645+
646+
Log(" Init=%s InitName=%s Target=%s Lighting=%s Zone=%s Shut=%s",
647+
g_LedInit ? "OK" : "-", g_LedInitWithName ? "OK" : "-",
648+
g_LedSetTarget ? "OK" : "-", g_LedSetLighting ? "OK" : "-",
649+
g_LedSetZone ? "OK" : "-", g_LedShutdown ? "OK" : "-");
638650

639651
if (g_LedGetVersion)
640652
{
@@ -643,63 +655,155 @@ bool LogitechLED::TrySDK()
643655
Log(" SDK version: %d.%d.%d", major, minor, build);
644656
}
645657

646-
if (!g_LedInit)
658+
if (!g_LedInit && !g_LedInitWithName)
647659
{
648660
FreeLibrary(m_sdkDll);
649661
m_sdkDll = NULL;
650662
return false;
651663
}
652664

653-
bool ok = g_LedInit();
654-
Log(" LogiLedInit() -> %s", ok ? "OK" : "FAIL");
655-
if (!ok)
665+
bool initOk = false;
666+
if (g_LedInit)
667+
{
668+
initOk = g_LedInit();
669+
Log(" LogiLedInit() -> %s", initOk ? "OK" : "FAIL");
670+
}
671+
if (!initOk && g_LedInitWithName)
672+
{
673+
initOk = g_LedInitWithName("FFBArcadePlugin");
674+
Log(" LogiLedInitWithName('FFBArcadePlugin') -> %s", initOk ? "OK" : "FAIL");
675+
}
676+
677+
if (!initOk)
656678
{
657679
FreeLibrary(m_sdkDll);
658680
m_sdkDll = NULL;
659681
return false;
660682
}
661683

662-
Sleep(500);
684+
Log(" Init OK, waiting 1s for G Hub registration...");
685+
Sleep(1000);
663686

664-
g_LedSetZone = (LogiLedSetZone_t)GetProcAddress(m_sdkDll, "LogiLedSetLightingForTargetZone");
687+
// ================================================================
688+
// SCAN A: Global LogiLedSetLighting with various target devices
689+
// ================================================================
690+
Log(" --- SCAN A: SetTargetDevice + SetLighting (green) ---");
691+
if (g_LedSetTarget && g_LedSetLighting)
692+
{
693+
// Known device types: 0x1=mono, 0x2=RGB, 0x4=perkey, 0x7=all
694+
// Also try: 0x8=headset, 0x10, 0x20, 0x40, 0x80, 0xFF
695+
int targets[] = { 0x1, 0x2, 0x3, 0x4, 0x7, 0x8, 0xE, 0x10, 0x20, 0x40, 0x80, 0xFF };
696+
int numTargets = sizeof(targets) / sizeof(targets[0]);
665697

666-
if (g_LedSetZone && g_LedSetTarget)
698+
for (int t = 0; t < numTargets; t++)
699+
{
700+
g_LedSetTarget(targets[t]);
701+
bool ok = g_LedSetLighting(0, 100, 0); // Bright green
702+
Log(" target=0x%02X SetLighting(0,100,0) -> %s", targets[t], ok ? "OK" : "FAIL");
703+
if (ok)
704+
{
705+
Log(" >>> VISUAL A: target=0x%02X - CHECK WHEEL LEDs! (500ms)", targets[t]);
706+
Sleep(500);
707+
g_LedSetLighting(0, 0, 0); // Turn off
708+
Sleep(200);
709+
}
710+
}
711+
}
712+
713+
// ================================================================
714+
// SCAN B: LogiLedSetLightingForTargetZone - exhaustive
715+
// ================================================================
716+
if (g_LedSetZone)
667717
{
668-
// Target device type 0x8 (responded OK in previous tests)
669-
g_LedSetTarget(0x8);
718+
Log(" --- SCAN B: SetLightingForTargetZone (exhaustive) ---");
719+
// Device types to test (covers known + potential undocumented)
720+
// 0x0=keyboard, 0x3=mouse, 0x4=mousemat, 0x8=headset, 0xE=speaker
721+
int zoneTypes[] = {
722+
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
723+
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
724+
0x10, 0x11, 0x12, 0x13, 0x14
725+
};
726+
int numZoneTypes = sizeof(zoneTypes) / sizeof(zoneTypes[0]);
670727

671-
// Test: light up zone 0 and 1 with bright green (RPM LED color)
672-
bool z0 = g_LedSetZone(0x8, 0, 0, 100, 0);
673-
bool z1 = g_LedSetZone(0x8, 1, 0, 100, 0);
674-
Log(" devType=0x8 zone0(green) -> %s, zone1(green) -> %s", z0 ? "OK" : "FAIL", z1 ? "OK" : "FAIL");
728+
// Pass 1: silent scan to collect OK results
729+
Log(" Pass 1: collecting OK results...");
730+
struct ZoneResult { int devType; int maxZone; int okCount; };
731+
ZoneResult okResults[21];
732+
int numOkResults = 0;
675733

676-
if (z0 || z1)
734+
for (int dt = 0; dt < numZoneTypes; dt++)
677735
{
678-
Log(" *** Activating LED SDK with devType=0x8 ***");
679-
Log(" Waiting 2s to check if LEDs are visible...");
680-
Sleep(2000);
736+
int okCount = 0;
737+
int maxZone = -1;
681738

682-
// Clear
683-
g_LedSetZone(0x8, 0, 0, 0, 0);
684-
g_LedSetZone(0x8, 1, 0, 0, 0);
739+
for (int zone = 0; zone <= 5; zone++)
740+
{
741+
bool ok = g_LedSetZone(zoneTypes[dt], zone, 0, 100, 0);
742+
if (ok)
743+
{
744+
okCount++;
745+
maxZone = zone;
746+
}
747+
// Immediately turn off
748+
g_LedSetZone(zoneTypes[dt], zone, 0, 0, 0);
749+
}
685750

686-
m_method = METHOD_SDK;
687-
m_available = true;
688-
Log("=== LED CONTROL ACTIVE (LED SDK devType=0x8) ===");
689-
return true;
751+
if (okCount > 0)
752+
{
753+
Log(" devType=0x%02X: %d zones OK (max zone=%d)", zoneTypes[dt], okCount, maxZone);
754+
if (numOkResults < 21)
755+
{
756+
okResults[numOkResults].devType = zoneTypes[dt];
757+
okResults[numOkResults].maxZone = maxZone;
758+
okResults[numOkResults].okCount = okCount;
759+
numOkResults++;
760+
}
761+
}
762+
}
763+
764+
Log(" %d device types returned OK", numOkResults);
765+
766+
// Pass 2: visual test on each OK device type (light ALL zones, 800ms per type)
767+
if (numOkResults > 0)
768+
{
769+
Log(" Pass 2: visual test (%d types, ~%ds)...", numOkResults, numOkResults);
770+
771+
for (int r = 0; r < numOkResults; r++)
772+
{
773+
int dt = okResults[r].devType;
774+
int mz = okResults[r].maxZone;
775+
776+
// Light all zones bright green
777+
for (int z = 0; z <= mz; z++)
778+
g_LedSetZone(dt, z, 0, 100, 0);
779+
780+
Log(" >>> VISUAL B-%d: devType=0x%02X zones 0-%d GREEN - CHECK WHEEL! (800ms)",
781+
r + 1, dt, mz);
782+
Sleep(800);
783+
784+
// Turn off
785+
for (int z = 0; z <= mz; z++)
786+
g_LedSetZone(dt, z, 0, 0, 0);
787+
Sleep(200);
788+
}
789+
}
790+
791+
// Use first OK result as default
792+
if (numOkResults > 0)
793+
{
794+
g_sdkDevType = okResults[0].devType;
795+
g_sdkMaxZone = okResults[0].maxZone;
796+
g_sdkUseGlobal = false;
797+
Log(" Selected: devType=0x%02X maxZone=%d", g_sdkDevType, g_sdkMaxZone);
690798
}
691799
}
692800

693-
// devType=0x8 didn't work, clean up
694-
Log(" LED SDK: no usable zones found");
695-
if (g_LedShutdown) g_LedShutdown();
696-
FreeLibrary(m_sdkDll);
697-
m_sdkDll = NULL;
698-
g_LedInit = NULL;
699-
g_LedSetLighting = NULL;
700-
g_LedShutdown = NULL;
701-
g_LedSetZone = NULL;
702-
return false;
801+
// Accept METHOD_SDK if init was OK (user will check visual tests and log)
802+
m_method = METHOD_SDK;
803+
m_available = true;
804+
Log("=== LED CONTROL ACTIVE (LED SDK v13 scan) ===");
805+
Log("=== Check log above for VISUAL tests that lit the wheel ===");
806+
return true;
703807
}
704808

705809
// --- I/O helpers ---
@@ -899,7 +1003,7 @@ bool LogitechLED::TryLegacy(HANDLE h, USHORT outLen)
8991003

9001004
bool LogitechLED::Init()
9011005
{
902-
Log("=== LogitechLED Init v12b (direct engine + diag) ===");
1006+
Log("=== LogitechLED Init v13 (exhaustive LED SDK scan) ===");
9031007
Log("");
9041008

9051009
if (m_available) return true;
@@ -966,34 +1070,57 @@ bool LogitechLED::SetLEDs(BYTE ledMask)
9661070
return SetLEDsFromPercent(numLeds / 5.0);
9671071
}
9681072

969-
if (m_method == METHOD_SDK && g_LedSetZone)
1073+
if (m_method == METHOD_SDK)
9701074
{
971-
// Map 5-bit LED mask to devType=0x8 zones 0-1
972-
// Zone 0 = lower LEDs (green), Zone 1 = upper LEDs (red)
9731075
int numLeds = 0;
9741076
for (int i = 0; i < 5; i++)
9751077
if (ledMask & (1 << i)) numLeds++;
9761078

977-
// Zone 0: green intensity based on LED count (first 3 LEDs)
978-
// Zone 1: red intensity for high RPM (last 2 LEDs)
979-
int greenPct = 0, redPct = 0;
980-
if (numLeds >= 1) greenPct = 33;
981-
if (numLeds >= 2) greenPct = 66;
982-
if (numLeds >= 3) greenPct = 100;
983-
if (numLeds >= 4) redPct = 50;
984-
if (numLeds >= 5) redPct = 100;
1079+
bool anyOk = false;
9851080

986-
g_LedSetTarget(0x8);
987-
bool z0 = g_LedSetZone(0x8, 0, 0, greenPct, 0);
988-
bool z1 = g_LedSetZone(0x8, 1, redPct, 0, 0);
1081+
if (g_sdkUseGlobal && g_LedSetTarget && g_LedSetLighting)
1082+
{
1083+
// Global mode: single color for all LEDs
1084+
int pct = (numLeds * 100) / 5;
1085+
g_LedSetTarget(g_sdkGlobalTarget);
1086+
anyOk = g_LedSetLighting(0, pct, 0);
1087+
}
1088+
else if (g_LedSetZone)
1089+
{
1090+
// Zone mode: map LED mask to zones
1091+
if (g_sdkMaxZone >= 4)
1092+
{
1093+
// 5+ zones: one zone per LED
1094+
for (int z = 0; z <= g_sdkMaxZone && z < 5; z++)
1095+
{
1096+
int green = (ledMask & (1 << z)) ? 100 : 0;
1097+
bool ok = g_LedSetZone(g_sdkDevType, z, 0, green, 0);
1098+
if (ok) anyOk = true;
1099+
}
1100+
}
1101+
else
1102+
{
1103+
// 2 zones: zone 0 = green intensity, zone 1 = red intensity
1104+
int greenPct = 0, redPct = 0;
1105+
if (numLeds >= 1) greenPct = 33;
1106+
if (numLeds >= 2) greenPct = 66;
1107+
if (numLeds >= 3) greenPct = 100;
1108+
if (numLeds >= 4) redPct = 50;
1109+
if (numLeds >= 5) redPct = 100;
1110+
1111+
bool z0 = g_LedSetZone(g_sdkDevType, 0, 0, greenPct, 0);
1112+
bool z1 = g_LedSetZone(g_sdkDevType, 1, redPct, 0, 0);
1113+
anyOk = z0 || z1;
1114+
}
1115+
}
9891116

9901117
g_setLedsCallCount++;
991-
if (g_setLedsCallCount <= 20 || (!z0 && !z1))
992-
Log("SetLEDs(0x%02X) [SDK 0x8 g=%d r=%d] -> z0=%s z1=%s (#%d)",
993-
ledMask, greenPct, redPct,
994-
z0 ? "OK" : "FAIL", z1 ? "OK" : "FAIL", g_setLedsCallCount);
1118+
if (g_setLedsCallCount <= 20 || !anyOk)
1119+
Log("SetLEDs(0x%02X) [SDK dt=0x%02X mz=%d] -> %s (#%d)",
1120+
ledMask, g_sdkDevType, g_sdkMaxZone,
1121+
anyOk ? "OK" : "FAIL", g_setLedsCallCount);
9951122

996-
return z0 || z1;
1123+
return anyOk;
9971124
}
9981125

9991126
if (m_handle == INVALID_HANDLE_VALUE) return false;

0 commit comments

Comments
 (0)