Données N64/GC brutes avec extenmote

Sommaire

Afin d'assurer sa compatibilité avec les logiciels déjà existants, mon adaptateur extenmote doit convertir les valeurs d'axes au format utilisé par la manette classique. Malheureusement, cela occasionne une diminution de précision. Par exemple, la position du stick gauche passe de 8 bits (N64/GC) à 6 bits (manette classique). Bref, les manettes N64 et Gamecube utilisés via l'adaptateur ne fonctionnent pas au maximum de leur potentiel. Pour bien des jeux, cela n'a peut-être pas d'importance, mais pour les émulateurs N64 et Gamecube[1], cela diminue la précision et peut donner l'impression que les manettes ne fonctionnent pas comme sur la console d'origine.

Afin de remédier à la situation, j'ai ajouté des fonctionnalités pour donner accès aux données brutes reçues de la manette. Cette expérience a commencé dans la version 1.8 et a été améliorée dans la version 1.9.

Alors comment accède-t-on à ces données?

Méthode 1: L'adaptateur concatène les données brutes à la structure de donées manette classique standard. Les logiciels déjà existants continuent donc de fonctionner comme d'habitude, mais les nouveaux logiciels peuvent bénéficier des données brutes au besoin.

Méthode 2: L'adaptateur se déclare habituellement comme étant une manette Classique. Toutefois, si une valeur de 0x64 est écrite dans le registre 0x00 après avoir déactivé l'encryption, l'ID de l'extension variera selon le type de manette reliée à l'adaptateur. La structure de données rapportée ne contiendra uniquement les données brutes spécifiques à la manette utilisée.

Quels jeux/logiciels utilisent les données brutes?
À ma connaissance, pour l'instant, malheureusement aucuns. Si vous utilisez les données brutes dans votre projet, veuillez m'en faire part que je puisse le lister ici.


[1] Je pense ici à Devotion, un logiciel permettant de faire fonctionner des jeux originaux pour Gamecube sur Wii et Wii U supportant la wiimote et les accessoires comme la manette classique. Ce n'est pas vraiment un émulateur, mais c'est exactement le genre de logiciel pouvant bénéficier d'un accès brute aux données provenant de la manette.


Méthode 1: Données concaténées

Les premiers 6 octets sont ceux d'une manette classique (source: http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Classic_Controller).

Bit
Octet76543210
0 RX<4:3> LX<5:0>Données manette classique standard
1 RX<2:1> LY<5:0>
2 RX<0> LT<4:3> RY<4:0>
3 LT<2:0> RT<4:0>
4 BDRBDDBLTB-BHB+BRT1
5 BZLBBBYBABXBZRBDLBDU
6 0x52 ('R') Extension spécifique à Extenmote
7 Octet 0 de l'ID de la manette
8 Octet 1 de l'ID de la manette
9-16 Données spéficiques à la manette (8 octets)

L'ID de la manette connectée à l'adaptateur est indiqué par deux octets. Cela permet d'interpréter les données qui suivent correctement:
  • 0x36,0x34 ('6','4'): Manette N64
  • 0x47,0x43 ('G','C'): Manette Gamecube
  • 0x53,0x46 ('S','F'): Manette SNES
  • 0x46,0x43 ('F','C'): Manette NES
Rumble/Vibration: La vibration sera eventuellement supportée et sera contrôlé par des écritures faites à l'octet 6. Non-zéro: Moteur activé, Zéro: Moteur déactivé. Notez qu'en lecture, l'octet 6 restera à 'R' malgré les écritures.


Méthode 2: ID d'Extension

Une valeur de 0x64 doit être écrite à l'adresse 0x00 avant de lire l'ID de l'extension. Vous pouvez vous référer à l'exemple de patch libOGC fourni, spécifiquement à la fonction wiiuse/io.c:wiiuse_handshake_expansion();

Les ID d'extension sont les suivants:
#define EXP_ID_CODE_EXTENMOTE_N64                   0xa4205264
#define EXP_ID_CODE_EXTENMOTE_GC                    0xa4205247
#define EXP_ID_CODE_EXTENMOTE_SNES                  0xa4205210
#define EXP_ID_CODE_EXTENMOTE_NES                   0xa4205208
Lorsque l'adaptateur s'affiche sous l'une des identités listées ci-dessus, la structure de données retournée est dans le format de la manette correspondante, et ce dès le premier octet. Aucune autre information ou structure de compatiblité n'est présente.

Rumble/Vibration: La vibration sera eventuellement supportée et sera contrôlé par des écritures faites à l'octet 8. Non-zéro: Moteur activé, Zéro: Moteur déactivé.


Données N64

Lorsque l'ID de l'extension ou l'ID de la manette indique qu'une manette N64 est connectée, les données spécifiques sont tel qu'exposé ci-dessous:

Bit
Octet76543210
0 ABZSTARTUpDownLeftRight
1 LRC-upC-DownC-LeftC-Right
2 Joystick, axe des X (signé, droite positive)
3 Joystick, axe des Y (signé, haut positif)




Données GC

Lorsque l'ID de l'extension ou l'ID de la manette indique qu'une manette Gamecube est connectée, les données spécifiques sont tel qu'exposé ci-dessous:

Bit
Octet76543210
0 STARTYXBA
1 LRZUpDownRightLeft
2 Joystick, axe des X (non-signé. Left low, Mid ~0x7F[*], Right high)
3 Joystick, axe des Y (non-signé. Down low, Mid ~0x7F[*], Up high)
4 C-stick, axe des X (non-signé. Down low, Mid ~0x7F[*], Up high)
5 C-stick, axe des Y (non-signé. Down low, Mid ~0x7F[*], Up high)
6 Levier gauche (unsigned. Released low, pressed high)
7 Levier droit (unsigned. Released low, pressed high)

[*] Attention, les valeurs données ici sont à titre d'exemple seulement. Il faut tenir compte que la position au repos n'est pas toujours exactement la même d'une manette à l'autre, mais aussi sur la même manette (jeu mécanique, usure).


Données SNES

Lorsque l'ID de l'extension ou l'ID de la manette indique qu'une manette SNES est connectée, les données spécifiques sont tel qu'exposé ci-dessous:

Bit
Octet76543210
0 BYSELECTSTARTUpDownLeftRight
1 AXLR




Données NES

Lorsque l'ID de l'extension ou l'ID de la manette indique qu'une manette NES est connectée, les données spécifiques sont tel qu'exposé ci-dessous:

Bit
Octet76543210
0 ABSELECTSTARTUpDownLeftRight




Exemple

Voici un patch pour libOGC démontrant les deux méthodes d'accès:
libogc-extenmote1.9-example.diff

Et voici un petit logiciel démontrant comment accéder et utiliser les données brutes:
raphnet_displayer2.tar.gz
Affichage des données Gamecube, méthode 1

Affichage des données Gamecube, méthode 1





Ancienne structure (v1.8)

Cette structure n'a existé que dans la version 1.8. Peu après, j'ai décidé de changer pour inclure les boutons, couvrant ainsi la totalité des donnés reçues.


Les 6 premiers octets se conforment à la structure de donnés normale pour une manettes classique. (source: http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Classic_Controller).

Les octets supplémentaires contiennent les valeurs analogiques N64 ou GC, dans le format tel que reçu de la manette. Les octets 12 à 14 sont une signature permettant de détecter qu'il s'agit d'un adaptateur extemote, mais aussi d'indiquer le type de manette. Ceci est très important car les valeurs d'axe N64 signés et celles de la GC ne le sont pas. La plage de valeur que peuvent prendre les axes de chaque manette diffère également.

Un point important à ne pas perdre de vue est qu'un adaptateur peut être bâti pour supporter plusieurs types de manettes. L'application aura donc intérêt à continuellement surveiller les octets de signature, pas seulement lors de l'initialisation. D'ailleurs, en raison de la gestion dynamique du type de manette branchée, lors du branchement intial il se peut que l'adaptateur s'affiche comme une manette classique standard mais que quelques lectures plus tard les octets de signature changent pour indiquer une manette N64 or GC.

Un dernier mot au sujet de la fonction vibration: Elle n'est pas supportée pour le moment car l'électronique de l'adaptateur n'est pas adéquate. Mais le protocole est quand même documenté dans l'espoir que cela puisse être implémenté à l'avance et soit prêt pour un futur adaptateur.

/*       |                 Bit                                |
 * Byte  |   7   |   6   |   5   |  4  |  3 |  2 |  1  |  0   |
 * ------+---------------+-------+----------------------------+
 *  0    |    RX<4:3>    |            LX<5:0>                 |
 *  1    |    RX<2:1>    |           LY<5:0>                  |
 *  2    | RX<0> |    LT<4:3>    |      RY<4:0>               |
 *  3    |        LT<2:0>        |      RT<4:0>               |
 *  4    | BDR   |  BDD  |  BLT  |  B- | BH | B+  | BRT | 1   |
 *  5    | BZL   |   BB  |  BY   | BA  | BX | BZR | BDL | BDU |
 *
 *  6    | GC Left stick/N64 stick raw X value                |
 *  7    | GC Left stick/N64 stick raw Y value                |
 *  8    | GC C-stick raw X value                             |
 *  9    | GC C-stick raw Y value                             |
 *  10   | GC Left shoulder raw X value                       |
 *  11   | GC Right shoulder raw Y value                      |
 *  12   | 0x52 ('R')                                         |
 *  13   | Controller ID byte 0                               |
 *  14   | Controller ID byte 1                               |
 *  15   | Rumble status (RW) for future use                  |
 *
 *  Controller ID:
 *
 *   0   |  1     
 *  -----+-----
 *   '6' | '4'    N64 controller
 *   'G' | 'C'    Gamecube controller
 *
 * When neither a N64 nor GC controller is connected, all values from
 * byte 6 up to byte 14 are 0x00.
 *
 * Writing at byte 15 controls the rumble motor. Rumbles on when non-zero.
 */




Ancien exemple (v1.8)

Cette structure n'a existé que dans la version 1.8. Peu après, j'ai décidé de changer pour inclure les boutons, couvrant ainsi la totalité des donnés reçues.


J'ai modifié ligOGC et réalisé un petit programme de test pour démontrer cette nouvelle fonctionnalité et son utilisation.

raphnet_displayer.tar.gz
libogc-extenmote-patch.diff


Rien d'impressionnant, mais cela fait le travail. Après tout, c'est là mon premier logiciel pour Wii!