Raw extenmote N64/GC data

Background

For compatiblity, my extenmote adapter has to convert N64 and Gamecube joystick values to match those of a classic controller which has a lower resolution (6 bits instead of 8 bits). This means that the controllers are not working at their full potential. For many games I guess it does not matter, but for N64 and Gamecube [1] emulators, it decreases accuracy and might make the controls feel different or slightly wrong.

To improve the situation, I have implemented new features to make it possible to access the raw data from the adapted controller. This experiment started in version 1.8 and has been improved in version 1.9.

So, how is the raw data made available?

Method 1: The adapter appends raw values to the standard classic controller report. Software unaware of this feature will continue working normally, but the is available and usable by applications were it is useful. See section New structure below for details.

Method 2: The adapter normally appears as a Classic controller. However, if a value of 0x64 is written to register 0x00 after disabling encryption, the extension ID will be different depending on the connected controller. The reported data is only and exactly what was received from the controller. Please see below for details.

What game/software make use of the raw data feature?
At the moment, I am not aware of any users of this feature. If your software use it, please let me know. I would like to list it here.


[1] I'm thinking of Devotion which make it possible to play gamecube titles on Wii and Wii U without gamecube ports using a Classic controller. Not really an emulator, but this is exactly where I think raw data access is useful.


Method 1: Appended data

The first 6 bytes is the standard structure for a wii classic controller (source: http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Classic_Controller).

Bit
Byte76543210
0 RX<4:3> LX<5:0>Standard classic controller data
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') Extenmote specific extension
7 Controller ID byte 0
8 Controller ID byte 1
9-16 Controller specific data bytes 0-7

The controller ID bytes indicate the type of controller connected and therefore how to interpret the controller specific data bytes that follows. Possible values are:
  • 0x36,0x34 ('6','4'): N64 controller
  • 0x47,0x43 ('G','C'): Gamecube controller
  • 0x53,0x46 ('S','F'): SNES controller
  • 0x46,0x43 ('F','C'): NES controller
Rumble/Vibration: Writing at byte 6 will eventually control the vibration function. A non-zero value will turn on the motor, a value of 0 will turn it off. Note that byte 6 will still read 'R' even after being written to.


Method 2: Extension IDs

A value 0x64 must be written to the adapter at address 0x00 before reading the extension ID. Refer to wiiuse/io.c:wiiuse_handshake_expansion() in the example libogc patch.
#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
When the adapter apperas as one of the above extension IDs, the reported data is in the specific controller format starting right at byte 0. It is not appended to a standard classic controller structure.

Rumble/Vibration: Writing at byte 8 will eventually control the vibration function. A non-zero value will turn on the motor, a value of 0 will turn it off.


N64 Controller data

When the controller ID bytes order the extension ID indicates a N64 controller is connected, the controller specific data is as follows:

Bit
Byte76543210
0 ABZSTARTUpDownLeftRight
1 LRC-upC-DownC-LeftC-Right
2 Joystick X value (signed, right positive)
3 Joystick Y value (signed, up positive)


GC Controller data

When the controller ID bytes order the extension ID indicates a Gamecube controller is connected, the controller specific data is as follows:

Bit
Byte76543210
0 STARTYXBA
1 LRZUpDownRightLeft
2 Joystick X value (unsigned. Left low, Mid ~0x7F*, Right high)
3 Joystick Y value (unsigned. Down low, Mid ~0x7F*, Up high)
4 C-stick X value (unsigned. Down low, Mid ~0x7F*, Up high)
5 C-stick Y value (unsigned. Down low, Mid ~0x7F*, Up high)
6 Left shoulder value (unsigned. Released low, pressed high)
7 Right shoulder value (unsigned. Released low, pressed high)


SNES Controller data

When the controller ID bytes order the extension ID indicates an SNES controller is connected, the controller specific data is as follows:

Bit
Byte76543210
0 BYSELECTSTARTUpDownLeftRight
1 AXLR


NES Controller data

When the controller ID bytes order the extension ID indicates a NES controller is connected, the controller specific data is as follows:

Bit
Byte76543210
0 ABSELECTSTARTUpDownLeftRight


New example

Here is patch for libOGC demonstrating the two access methods:
libogc-extenmote1.9-example.diff

And here is a simple application which shows how to access and interpret the raw data:
raphnet_displayer2.tar.gz
Displaying Gamecube raw data, method 1

Displaying Gamecube raw data, method 1




Old structure (v1.8)

This structure was only used in version 1.8. Soon after, I decided to add button data, making available the full raw data.


The first 6 bytes is the standard structure for a wii classic controller (source: http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Classic_Controller).

The extra bytes are the analog N64 or GC values, exactly as received from the controller. Bytes 12-14 are signature bytes used to detect the extenmote adapter, but the two last bytes also serve to indicate the type of controller (N64 or GC). This is important since N64 values are signed while GC values are not, and also because the range is different.

One thing to keep in mind is that the adapter can support more than one type of controller. I.e, the application should continuously check the signature bytes, not only once during init. Also note that due to the dynamic controller handling, when first connected the adapter might look like a normal classic controller, but one or two reads later the signature bytes appear indicating a N64 or GC controller.

One last word about rumble: It is not supported yet, the current hardware is inadequate. It is still documented in the hope that it will be implemented and ready to test once I sort out the hardware.

/*       |                 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.
 */



Old example (v1.8)

This structure was only used in version 1.8. Soon after, I decided to add button data, making available the full raw data.


I modified libOGC and made a simple test program to demonstrate the new feature.
raphnet_displayer.tar.gz
libogc-extenmote-patch.diff


Really, nothing impressive, but it does the job. After all, this was my first time coding on the Wii!