Skip to content

Commit 27d5318

Browse files
committed
docs: add complete G923 LED research log (v1-v19)
1 parent fc36439 commit 27d5318

File tree

1 file changed

+298
-0
lines changed

1 file changed

+298
-0
lines changed

G923-LED-RESEARCH.md

Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
# G923 Xbox RPM LED Research - FFBArcadePlugin
2+
3+
## Objectif
4+
Faire fonctionner les 5 LEDs RPM du Logitech G923 Xbox/PC (PID 0xC26E) avec FFBArcadePlugin, **avec G Hub qui tourne**.
5+
6+
## Branche : `feature/g923-leds` (basee sur master)
7+
8+
## Fichiers modifies
9+
- `Common Files/LogitechLED.h` - Classe LED controller
10+
- `Common Files/LogitechLED.cpp` - Implementation (actuellement v19)
11+
- `DllMain.cpp` - Ajout `g_bypassDIWrapper` pour bypass du wrapper DirectInput
12+
13+
## Architecture du plugin
14+
- `dinput8.dll` wrapper qui hook DirectInput pour les jeux arcade (TeknoParrot)
15+
- Se charge via DLL_PROCESS_ATTACH, LED init dans `LogitechLED::Init()`
16+
- `SetLEDsFromPercent()` appele depuis la boucle FFB du jeu
17+
- Build : macOS dev -> GitHub Actions -> artifacts x86/x64
18+
19+
## Materiel
20+
- Logitech G923 Xbox/PC, VID=0x046D, PID=0xC26E
21+
- G Hub DOIT rester lance (sinon : pas de FFB, pas de boutons)
22+
- HID collections :
23+
- col02: UP=0xFF43, OUT=20, IN=20 (report 0x11) - **Legacy LED ici**
24+
- col03: UP=0xFF43, OUT=64, IN=64 (report 0x12) - HID++ 2.0
25+
- mi_01: UP=0xFFFD, OUT=64, IN=64
26+
- gamepad: UP=0x0001, IN=11, OUT=0
27+
28+
## Drivers kernel G Hub (la cause du blocage)
29+
- `logi_joy_xlcore.sys` - Translation core
30+
- `logi_joy_bus_enum.sys` - Bus enumerator
31+
- `logi_joy_vir_hid.sys` - Virtual HID
32+
- **Interceptent TOUS les HID output reports** : WriteFile retourne OK mais les donnees ne touchent jamais le bus USB
33+
34+
## Approches testees et resultats
35+
36+
### 1. Direct HID - Legacy [F8 12 mask] (v1-v6)
37+
- Format : `[reportId F8 12 ledMask]` sur col02 (20 bytes, report 0x11)
38+
- WriteFile retourne OK, mais **LEDs ne s'allument pas**
39+
- Confirme par USBlyzer : **zero OUT transfers sur le bus USB** meme pendant le FFB
40+
- Les drivers kernel mangent tout
41+
42+
### 2. HID++ 2.0 Feature Discovery (v3-v4)
43+
- Fonctionne sur col03 (64-byte, report 0x12, device index 0xFF)
44+
- 21 features enumerees dont 0x807A (suspect LED)
45+
- Commandes acceptees mais aucun changement LED
46+
- Meme probleme : drivers kernel interceptent
47+
48+
### 3. LED SDK - sdk_legacy_led_x86.dll (v5-v7)
49+
- Emplacement : `C:\Program Files\LGHUB\sdks\sdk_legacy_led_x86.dll`
50+
- 33 exports, version 75.71.76
51+
- LogiLedInit() -> OK (se connecte a G Hub)
52+
- **Pour clavier/souris UNIQUEMENT, pas pour volant**
53+
- devType=0x8 zones 0-1 retournent OK mais rien ne s'allume
54+
- SetLightingForTargetZone(0x8, 0, ...) = clavier/souris, pas volant
55+
56+
### 4. Steering Wheel SDK - LogitechSteeringWheelEnginesWrapper.dll (v5-v9)
57+
- SDK public v8.75.30 (2018), telecharge depuis Logitech
58+
- 50 exports dont LogiPlayLeds, LogiPlayLedsDInput
59+
- LogiSteeringInitializeWithWindow(false, desktop) -> **OK**
60+
- LogiIsConnected(0) -> **NO** (SDK ne connait pas PID 0xC26E, G923 sorti en 2020)
61+
- Le SDK ne connait que jusqu'au G920 (model 27)
62+
63+
### 5. G Hub Internal Steering SDK (v7)
64+
- Cherche `sdk_legacy_steering_wheel_x86.dll` dans `C:\Program Files\LGHUB\`
65+
- **N'EXISTE PAS** sur la machine de test
66+
- Seuls `sdk_legacy_led_x64.dll` et `sdk_legacy_led_x86.dll` dans le dossier sdks
67+
68+
### 6. Bypass DirectInput Wrapper (v8)
69+
- Notre dinput8.dll wrapper empeche le SDK d'enumerer les devices
70+
- Ajout `g_bypassDIWrapper` flag dans DllMain.cpp
71+
- Quand le SDK appelle DirectInput8Create, on retourne l'interface reelle
72+
- **Resultat : LogiIsConnected(0) toujours NO**
73+
- Le probleme n'est PAS le wrapper, c'est le SDK qui ne connait pas le PID
74+
75+
### 7. LogiPlayLedsDInput Fallback (v9 - PAS ENCORE TESTE)
76+
- Charge le vrai dinput8.dll systeme depuis System32
77+
- Cree un device DirectInput reel pour le G923
78+
- Passe le device a LogiPlayLedsDInput() qui bypass la detection interne
79+
- **Build v9 pret, non teste** (user doit reboot)
80+
81+
### 8. USB Sniffing
82+
- **USBlyzer** : fonctionne avec G Hub, mais capture au niveau HID (au-dessus des drivers)
83+
- Voit uniquement des IN (device -> host), zero OUT
84+
- Confirme : les drivers kernel interceptent TOUS les writes
85+
- PnP Remove Device quand on capture sur le device specifique -> capturer sur le Port/USB composite
86+
- **USBPcap + Wireshark** : pas reussi a configurer (Wireshark ne voit pas USBPcap)
87+
- **Conclusion sniffing** : les drivers kernel redirigent le trafic OUT par un chemin interne invisible aux sniffers HID-level
88+
89+
## Decouverte cle : comment les jeux officiels font
90+
- Les jeux (Forza, F1, etc.) utilisent le meme `LogitechSteeringWheelEnginesWrapper.dll`
91+
- MAIS une **version plus recente** fournie par Logitech aux studios (pas la version publique)
92+
- Cette version connait le G923 PID -> LogiIsConnected retourne YES -> LogiPlayLeds fonctionne
93+
- Le SDK communique avec lghub_agent.exe via IPC, G Hub controle les LEDs via ses drivers kernel
94+
- Un user sur le forum Fanaleds confirme que le SteeringWheelSDKDemo fonctionne avec G923
95+
96+
### 9. Reverse-engineering du Wrapper SDK (v10-v11) - PERCEE MAJEURE
97+
- Analyse binaire de `LogitechSteeringWheelEnginesWrapper.dll` (13 KB, thin wrapper)
98+
- **Aucun PID dans le wrapper** - c'est juste un forwarder
99+
- Imports : `RegOpenKeyExW`, `RegQueryValueExW`, `LoadLibraryW`, `GetProcAddress`
100+
- **Cle registre decouverte** (wide string UTF-16 dans le binaire) :
101+
`SOFTWARE\Classes\CLSID\{63BD165D-1584-4E75-AB56-08330350545F}\ServerBinary`
102+
- Le wrapper lit cette cle pour trouver le VRAI DLL engines installe par G Hub
103+
104+
### 10. Decouverte du vrai moteur SDK v9.1.0 installe par G Hub
105+
- **Cle registre x64** : `HKLM\SOFTWARE\Classes\CLSID\{63BD165D-...}\ServerBinary`
106+
-> `C:\Program Files\Logi\wheel_sdk\9_1_0\logi_steering_wheel_x64.dll` (93 KB)
107+
- **Cle registre x86** (WOW6432Node) :
108+
-> `C:\Program Files\Logi\wheel_sdk\9_1_0\logi_steering_wheel_x86.dll` (78 KB)
109+
- Date : 10/02/2026 - installe/mis a jour par G Hub
110+
- **C'est le vrai moteur** que le wrapper charge via LoadLibrary
111+
- Version 9.1.0 vs SDK public 8.75.30 = bien plus recent, devrait connaitre le G923
112+
- Script `tools/scan_pids.ps1` cree pour scanner les PIDs dans ce DLL
113+
- Copie du DLL dans `tools/logi_steering_wheel_x86.dll` pour analyse locale
114+
115+
### 11. Scan PIDs du moteur v9.1.0 - CONFIRME
116+
- Resultat du scan sur `logi_steering_wheel_x86.dll` (78,488 bytes) :
117+
```
118+
0xC298 (DFP) : PRESENT (2x at 0x00EC3E, 0x0126A0)
119+
0xC299 (G25) : PRESENT (1x at 0x00EC1A)
120+
0xC29A (DFGT) : PRESENT (1x at 0x00EC0E)
121+
0xC29B (G27) : PRESENT (1x at 0x00EC02)
122+
0xC24F (G29) : PRESENT (2x at 0x00EC7A, 0x010DAE)
123+
0xC260 (G920) : ABSENT
124+
0xC262 (G920 alt) : PRESENT (1x at 0x00EC86)
125+
0xC266 (G923 PS) : PRESENT (1x at 0x00EC92)
126+
0xC26E (G923 Xbox) : PRESENT (2x at 0x009D9F, 0x00EC9E) <<<
127+
```
128+
- **G923 Xbox est PRESENT** -> le moteur v9.1.0 connait le G923
129+
- **G920 standard (0xC260) est ABSENT** -> Logitech a change la table de PIDs
130+
- **Conclusion** : le probleme est le wrapper v8.75.30, pas le moteur
131+
132+
### 12. Chargement direct du moteur v9.1.0 (v12-v12b)
133+
- Bypass du wrapper : charge `logi_steering_wheel_x86.dll` directement via LoadLibrary
134+
- Chemin lu depuis registre : `HKLM\SOFTWARE\WOW6432Node\Classes\CLSID\{63BD165D-...}\ServerBinary`
135+
- Exports resolus via GetProcAddress : LogiSteeringInitialize, LogiIsConnected, LogiPlayLeds, etc.
136+
- v12b : ajout CoInitializeEx, polling etendu (5x 500ms), multi-index (0-3)
137+
- **Resultat : LogiSteeringInitialize OK, mais LogiIsConnected(0..3) -> toujours NO**
138+
- Le moteur v9.1.0 utilise DirectInput en interne pour detecter les volants
139+
140+
### 13. Scan exhaustif du LED SDK (v13)
141+
- Test de TOUS les device types (0x0 a 0xE) avec TOUTES les zones (0-5)
142+
- Confirme : LED SDK ne supporte que clavier/souris/headset
143+
- Aucun device type ne correspond au volant
144+
- **LED SDK = impasse definitive pour les volants**
145+
146+
### 14. Integration WebSocket G Hub (v14-v14b)
147+
- G Hub expose un WebSocket IPC sur `ws://127.0.0.1:9010` (protocole JSON)
148+
- API : `{msgId, verb, path, payload}` (GET/SET/SUBSCRIBE)
149+
- Implementation WinHTTP dans le plugin C++ (WinHttpOpen, WinHttpWebSocketSend/Receive)
150+
- `/devices/list` retourne ~22KB de JSON avec tous les devices G Hub
151+
- G923 identifie : `id: "dev00000004"`, PID 49774 (0xC26E), deviceType `STEERING_WHEEL`, model `g923_xbox`
152+
- v14b : corrige le parsing deviceId (recherche backward depuis STEERING_WHEEL), activation ACTION avant WHEEL, timeouts WinHTTP
153+
- **Bug v14b** : JSON G Hub contient des espaces (`"deviceType": "STEERING_WHEEL"`) mais le code cherchait sans espaces
154+
155+
### 15. Fix parsing JSON + activation WHEEL (v15)
156+
- Corrige la recherche : cherche `STEERING_WHEEL` en texte brut + `"dev0` pour le deviceId
157+
- STEERING_WHEEL trouve a offset 790, deviceId `dev00000004` correctement parse
158+
- **WHEEL activation : toujours INVALID_ARG** ("Invalid integration GUID")
159+
- Tous les endpoints HID++ via WebSocket : NO_SUCH_PATH
160+
- Tous les endpoints LED/RPM : NO_SUCH_PATH
161+
162+
### 16. Chargement du vrai dinput8.dll systeme (v16)
163+
- Decouverte : `GetModuleHandleA("dinput8.dll")` retourne NOTRE wrapper (puisque nous SOMMES dinput8.dll)
164+
- Fix : `GetSystemDirectoryA` + `LoadLibraryA("C:\Windows\system32\dinput8.dll")` pour le vrai DLL systeme
165+
- DLL systeme charge a 0x685B0000 (adresse differente = vrai DLL)
166+
- DirectInput8Create reussit
167+
- **ZERO devices enumeres** : ni GAMECTRL ni ALL ne retournent de devices
168+
- **DECOUVERTE CRUCIALE** : le G923 Xbox est un device **XInput/GIP**, pas DirectInput
169+
- Windows 8+ cache les devices XInput de l'enumeration DirectInput
170+
- Le moteur SDK v9.1.0 utilise DirectInput pour detecter -> ne peut PAS voir le G923 Xbox
171+
172+
### 17. Analyse de la reponse d'enregistrement (v17)
173+
- Buffer de log etendu de 300 a 800 chars pour voir la reponse complete
174+
- Reponse d'enregistrement (465 bytes) : **AUCUN champ integrationGuid**
175+
- `"integrationType": "INVALID_TYPE"` - l'enregistrement seul ne cree pas de GUID
176+
- Le GUID n'est cree qu'a l'activation
177+
178+
### 18. Activation WHEEL - percee partielle (v18)
179+
- Strategie : ACTION d'abord pour obtenir un GUID, puis WHEEL avec ce GUID
180+
- **WHEEL avec integrationGuid dans le payload** : `INVALID_MESSAGE_RECEIVED` (champ non accepte)
181+
- **WHEEL sans GUID sur `ffb_arcade`** : `INVALID_ARG` (identifier deja consomme par ACTION)
182+
- **Register `ffb_wheel_sdk` + activate WHEEL : SUCCESS !** -> instanceGuid + integrationGuid
183+
- **Decouverte** : chaque sdkType a besoin de son PROPRE integrationIdentifier
184+
- Mais tous les endpoints LED/RPM : toujours NO_SUCH_PATH
185+
- G Hub ne fournit aucune API WebSocket pour controler les LEDs du volant
186+
187+
### 19. WebSocket keep-alive pendant le polling SDK (v19)
188+
- Hypothese : l'activation WHEEL est session-based, fermer le WebSocket tue la session
189+
- WebSocket garde ouvert (handles statiques : g_wsSession, g_wsConnect, g_wsHandle)
190+
- Enregistrement simplifie : `ffb_wheel` + WHEEL uniquement
191+
- **WHEEL activation : SUCCESS, WebSocket reste ouvert**
192+
- Steering SDK polling : LogiIsConnected(0..3) -> **toujours NO**
193+
- DirectInput : toujours zero devices
194+
- **Conclusion** : garder le WebSocket actif ne aide pas le SDK a detecter le G923
195+
196+
## Diagnostic final
197+
198+
### Cause racine identifiee
199+
Le G923 Xbox/PC (PID 0xC26E) est un device **XInput/GIP** (Gaming Input Protocol), PAS un device DirectInput. Windows 8+ cache systematiquement les devices XInput de l'enumeration DirectInput (`IDirectInput8::EnumDevices` ne les retourne jamais).
200+
201+
Le moteur SDK Logitech v9.1.0 (`logi_steering_wheel_x86.dll`) utilise DirectInput en interne pour detecter les volants connectes. Meme si le PID du G923 est present dans le binaire, le SDK ne peut jamais voir le device car Windows ne le liste pas en DirectInput.
202+
203+
### Chaine de blocage
204+
```
205+
G923 Xbox = device XInput/GIP
206+
-> Invisible pour DirectInput (filtre Windows)
207+
-> SDK v9.1.0 utilise DirectInput pour la detection
208+
-> LogiIsConnected() retourne toujours NO
209+
-> LogiPlayLeds() ne peut pas fonctionner
210+
```
211+
212+
### Comment les jeux officiels font (hypothese mise a jour)
213+
Les jeux (Forza, F1) utilisent probablement :
214+
- Soit une version speciale du SDK qui detecte via **Windows.Gaming.Input (WGI)** au lieu de DirectInput
215+
- Soit un IPC direct avec lghub_agent.exe que le SDK public ne supporte pas
216+
- Le SDK v9.1.0 installe par G Hub est peut-etre utilise UNIQUEMENT par les jeux PS (G29, G923 PS qui sont bien DirectInput)
217+
218+
### Toutes les approches epuisees
219+
| # | Approche | Resultat |
220+
|---|----------|----------|
221+
| 1 | Direct HID Legacy [F8 12] | Drivers kernel interceptent tout |
222+
| 2 | HID++ 2.0 Feature Discovery | Drivers kernel interceptent tout |
223+
| 3 | LED SDK (sdk_legacy_led) | Clavier/souris uniquement |
224+
| 4 | Steering SDK v8.75.30 (wrapper) | Ne connait pas le G923 |
225+
| 5 | G Hub Internal Steering SDK | N'existe pas |
226+
| 6 | Bypass DirectInput wrapper | SDK ne voit toujours pas le G923 |
227+
| 7 | LogiPlayLedsDInput | G923 invisible en DirectInput |
228+
| 8 | USB Sniffing | Confirme : drivers interceptent OUT |
229+
| 9 | Reverse wrapper -> moteur v9.1.0 | PID present mais detection via DI |
230+
| 10 | Chargement direct moteur v9.1.0 | IsConnected toujours NO |
231+
| 11 | Scan exhaustif LED SDK | Impasse definitive |
232+
| 12 | WebSocket G Hub (register/activate) | Pas d'API LED pour volant |
233+
| 13 | System dinput8.dll pour enum | Zero devices (XInput) |
234+
| 14 | WebSocket keep-alive + SDK | SDK toujours aveugle |
235+
236+
## Pistes restantes (non testees)
237+
238+
### A. Windows.Gaming.Input (WGI)
239+
- API moderne Microsoft pour les controllers Xbox/GIP
240+
- Inclut `RacingWheel` class avec support LED potentiel
241+
- Necessite C++/WinRT ou COM, compile comme UWP/desktop bridge
242+
- **Piste la plus prometteuse** car c'est la seule API qui "voit" le G923 Xbox
243+
244+
### B. Kill lghub_agent.exe + HID direct
245+
- Tester si les drivers kernel laissent passer les HID writes quand l'agent est arrete
246+
- Risque : perte du FFB si G Hub est necessaire pour ca aussi
247+
- Test rapide : `taskkill /f /im lghub_agent.exe` puis envoyer [F8 12 mask]
248+
249+
### C. Reverse-engineer l'IPC G Hub
250+
- G Hub WebSocket sur ws://localhost:9010 - explore mais pas d'endpoints LED trouves
251+
- Projet GitHub : LGSTrayBattery_GHUB
252+
- Extraire `app.asar` de G Hub pour trouver des endpoints caches
253+
254+
### D. API Monitor sur lghub_agent.exe
255+
- Hook WriteFile/DeviceIoControl pour voir ce que G Hub envoie reellement
256+
- Fonctionne au user-mode, pas de driver
257+
- http://www.rohitab.com/apimonitor
258+
259+
## Statut : EN PAUSE
260+
Recherche suspendue apres 19 iterations. La cause racine (XInput vs DirectInput) est un blocage fondamental au niveau OS/driver qui ne peut pas etre contourne par du code user-mode classique.
261+
262+
## DLLs sur la machine de test
263+
- `C:\Program Files\LGHUB\sdks\sdk_legacy_led_x86.dll` (3.3 MB)
264+
- `C:\Program Files\LGHUB\sdks\sdk_legacy_led_x64.dll` (4.0 MB)
265+
- `LogitechSteeringWheelEnginesWrapper.dll` (dans le dossier du jeu, SDK v8.75.30)
266+
- `C:\Program Files\Logi\wheel_sdk\9_1_0\logi_steering_wheel_x86.dll` (78 KB) - **VRAI moteur G Hub**
267+
- `C:\Program Files\Logi\wheel_sdk\9_1_0\logi_steering_wheel_x64.dll` (93 KB)
268+
269+
## Commits (du plus ancien au plus recent)
270+
```
271+
9617965 feat: add Steering Wheel SDK support (LogiPlayLeds)
272+
2b6a87d fix: defer steering SDK init, try multiple window handles
273+
bcd2890 feat: enumerate all LED SDK exports, scan wider device types
274+
1feacc3 fix: TrySteeringSDK returns false when wheel not detected
275+
4befd8b feat: try G Hub internal steering wheel SDK (sdk_legacy_steering_wheel)
276+
2e3b63c feat: activate LED SDK devType=0x8 at runtime for G923
277+
a72b6ce fix: bypass dinput8 wrapper for Logitech SDK enumeration
278+
540a7dd feat: fallback to LogiPlayLedsDInput when SDK can't detect G923
279+
43eb3e6 fix: use LPVOID for LogiPlayLedsDInput to fix ANSI/Unicode build
280+
4f1caa4 chore: bump version to v9 for tracking
281+
a2535be fix: use proper __stdcall callback for DirectInput EnumDevices
282+
e7d58dc feat: v11 - add COM init, blind PlayLeds, NULL DInput, HMODULE diagnostics
283+
e47d493 chore: add PID scanner PowerShell script for Windows
284+
4e8975f fix: PowerShell 5.1 compatibility for scan script
285+
5b60d0a feat: v12 - load engine DLL directly via registry, bypass old wrapper
286+
1a88a98 feat: v12b - add COM init, extended polling, multi-index detection diagnostics
287+
379940e feat: v13 - exhaustive LED SDK scan (all device types + zones)
288+
d694505 feat: add G Hub WebSocket explorer script for LED discovery
289+
b86fd65 feat: add HTML WebSocket explorer (no PowerShell needed)
290+
b479fe4 feat: v14 - register with G Hub via WebSocket before engine init
291+
9ff3e4c fix: v14b - fix deviceId parsing, activate ACTION before WHEEL, add timeouts
292+
5daf31f feat: v15 - fix JSON space parsing, WHEEL-first activation, HID++ via WebSocket
293+
17efec5 fix: v16 - load real system dinput8.dll instead of our wrapper for DI enumeration
294+
f902248 feat: v17 - extract integrationGuid from registration, pass in WHEEL activation
295+
c00dcb9 feat: v18 - ACTION-first to get GUID, retry WHEEL with GUID, try integrationType=SDK
296+
638f064 feat: v19 - keep WebSocket alive during steering SDK polling, dedicated WHEEL registration
297+
fc36439 fix: move static WS handles before Close() to fix compilation
298+
```

0 commit comments

Comments
 (0)