1.1 (23th June 2005) by denopqrihg ([email protected])
This document describes how a GBA program can communicate with a plugged-in Nintendo wireless adapter. This info is not 100% accurate, nor am I responsible for any damage it may do. I am only sharing my partial knowledge.
The Nintendo Wireless Adapter is a device that presents more multiplayer features than the link cable. It uses a kind of server/client approach (broadcasting, connections etc.). It allows to send quite large amounts of data at once (most I've seen was 80 bytes), has built-in synchronisation and much more.
This document is only about two player link. At the moment, I have no info about how it works with mre players.
If you don't understand something in this document or think something is unclear, contact me and I'll try to clarify.
32-bit Normal mode, all the time. No exceptions.
Mostly 2Mbit internal clock, but there are exceptions which will be pointed out.
Use: 32-bit Normal mode, 256Khz internal clock.
Send the text "NINTENDO/0x01/0x80" in the following manner:
Store two bytes of the text in the lower 16 bits of the send data. The upper 16 bits should be 1's complement of the previously received lower 16 bits. Send it. Received data should look like the one you sent, except that the upper and lower halfword are swapped. Repeat this process until you have sent the whole string (the last two bytes are 0x8001
).
Example:
Send | Receive |
---|---|
0xgggg494e | 0x494egggg |
0xb6b1494e | 0x494eb6b1 |
0xb6b1544e | 0x544eb6b1 |
0xabb1544e | 0x544eabb1 |
0xabb14e45 | 0x4e45abb1 |
0xb1ba4e45 | 0x4e45b1ba |
0xb1ba4f44 | 0x4f44b1ba |
0xb0bb4f44 | 0x4f44b0bb |
0xb0bb8001 | 0x8001b0bb |
(gggg = garbage)
Then send command 0x3d
or 0x10
, difference is unknown (what is a command and how to use it is in the next section).
The adapter uses a form of communication that I call 'commands'.
It waits until you send a command to it, and then it does something according to what command you sent.
The format is:
0x9966wwcc
cc
is the 1-byte command
ww
is a number indicating how many 4-byte units of data will follow the command (I don't know what happens when you send data with a command that shouldn't send any).
When you send this, you always receive 0x80000000
(also when sending the additional data).
Then, you must send 0x80000000
. You then receive a similar structure, 0x9966wwaa
.
ww
is again a number of words (4 byte) following this command
aa
is the command you sent ORed
with 0x80
(with some exceptions)
If there was a nonzero word count in the response, send 0x80000000
the apropriate number of times and store the data you receive (you requested it, so you should store it).
Remember to keep some delays between transfers.
Example:
Send | Receive |
---|---|
0x99660117 | 0x80000000 |
0x003c0720 | 0x80000000 |
0x80000000 | 0x99660097 |
Another example:
Send | Receive |
---|---|
0x9966001a | 0x80000000 |
0x80000000 | 0x9966019a |
0x80000000 | 0x00001547 |
After each transfer (except initialization), a kind of 'acknowledge procedure' must be done (maybe it isn't necessary, but the games do it):
Right after the transfer ends, output SO=low, wait until SI becomes high, then output SO=high and wait until SI=low.
0xa5
and 0xa7
, the polarity is 'swapped': output SO=low, wait until SI=low, then send SO=high and wait until SI=high
Also, just before each transfer, set SO=low
(This part is a bit unclear to me, maybe it doesn't work like this at all)
Many commands have completely unknown function, some of them must be sent but nobody knows why and what they mean. This is not a complete list of commands, I only listed the commands that either are important or I know something about them.
I will use the following notation:
Command: Command number
Send: how many words to send
Receive: how many words to receive
Description: what the command does (if known :-)
Command | Send | Receive | Description |
---|---|---|---|
0x10 | 0 | 0 | Last step of initialization, difference between this and 0x3d is unknown, both are used 0x10 seems to be 'safer' |
0x11 | 0 | 1 | This command always receives 0xff in 2 player link, maybe it has to do with 3+ players ?? |
0x13 | 0 | 1 | Receives a random value, don't know what it's for |
0x16 | usually 6 | 0 | Sends 'broadcast' data, which will be received by all adapters in range |
0x17 | 1 | 0 | Setup?? The value sent should be 003d0620 (Digimon), 003c0420 (Pokemon) or something along this way. |
0x1a | 0 | 0 or 1 | This command is used by the 'server' to check if someone wants to connect. If not, no data is received. If yes, you'll get a value (random? or ID?) |
0x1d | |||
0x1e | 0 | multiples of 7 (usually) | Read 'broadcast' data. Data from each adapter is prefixed by one word containing an 'ID' of the adapter , which is used when you want to connect. |
0x1f | 1 | 0 | Connect to server. Value sent is the 'ID' of the adapter you want to connect to. |
0x20 | 0 | 1 | Used after 0x1f, generally resend until highest byte is 0. |
0x21 | 0 | 1 | Send once after 0x20 successfully finished (returned 0). |
0x24 | anything | 0 | Send data to connected adapters (I've only seen this command used by servers, but maybe clients can use it as well) |
0x25 | anything | 0 | Same as 0x24 , with the exception that this command 'waits' until incoming data is available. This keeps the games synchronized without any further in-game programming. How to use: After you send all the data and get 0x996600a5 from the adapter, store 0x80000000 in the send data register and start a transfer with _EXTERNAL_ clock. Once the data arrives, you'll receive a 0x99660028 command (which you have to ackowledge just like the adapter - send back 0x996600a8 ). Also note that after you receive the 0x996600a5 until you use the next command (usually 0x26 ), the polarity of the SI and SO conmfirmation procedure is swapped. |
0x26 | 0 | anything | Receive data. |
0x27 | 0 | 0 | Similar to 0x25, but without sending data. All strange behavior of 0x25 applies here, too. |
0x30 | 1? | 0 | Most likely a 'Terminate connection' command. Data value is usually 1. |
0x3d | 0 | 0 | Same as 0x10 |
0xa8 | 0 | 0 | Ackowledge of 0x28 sent by adapter. |
0xee | 1? | 0 | This is very unconfirmed, but is probably used when you want the adapter to resend the last command/whatever ?? |
A complete example of a client/server communication
(all numbers are in hex)
0x128 reg means the value of 0x128 reg
0x128 reg | Send | Receive |
---|---|---|
5084 | 00000000 | garbage |
5085 | ffff494e | 494egggg |
5085 | b6b1494e | 494eb6b1 |
5085 | b6b1544e | 544eb6b1 |
5085 | abb1544e | abb1544e |
5085 | abb14e45 | 4e45abb1 |
5085 | b1ba4e45 | 4e45b1ba |
5085 | b1ba4f44 | 4f44b1ba |
5085 | b0bb4f44 | 4f44b0bb |
5085 | b0bb8001 | 8001b0bb |
5003 | ||
5083 | 99660010 | 80000000 |
500b | ||
5003 | ||
5083 | 80000000 | 99660090 |
500b | ||
5003 | ||
5083 | 99660117 | 80000000 |
500b | ||
5003 | ||
5083 | 003c0420 | 80000000 |
500b | ||
5003 | ||
5083 | 80000000 | 99660097 |
500b | ||
5003 | ||
5003 | ||
5083 | 99660616 | 80000000 |
500b | ||
5003 | ||
5083 | 0c020002 | 80000000 |
500b | ||
5003 | ||
5083 | 00005ce1 | 80000000 |
500b | ||
5003 | ||
5083 | 00000000 | 80000000 |
500b | ||
5003 | ||
5083 | 09000040 | 80000000 |
500b | ||
5003 | ||
5083 | c1cfc8cd | 80000000 |
500b | ||
5003 | ||
5083 | 00ffccbb | 80000000 |
500b | ||
5003 | ||
5083 | 80000000 | 99660096 |
500b | ||
5003 | ||
5083 | 99660013 | 80000000 |
500b | ||
5003 | ||
5083 | 80000000 | 99660193 |
500b | ||
5003 | ||
5083 | 80000000 | 02001234 (example) |
500b | ||
5003 | ||
5083 | 99660019 | 80000000 |
500b | ||
5003 | ||
5083 | 80000000 | 99660099 |
500b |
repeat
0x128 reg | Send | Receive |
---|---|---|
5003 | ||
5083 | 9966001a | 80000000 |
500b | ||
5003 | ||
5083 | 80000000 | 9966009a |
500b |
until you get:
repeat a few times to ensure that it really is a connection
0x128 reg | Send | Receive |
---|---|---|
5003 | ||
5083 | 9966001a | 80000000 |
500b | ||
5003 | ||
5083 | 80000000 | 9966019a |
5003 | ||
5083 | 80000000 | 00004875 (example) |
500b | ||
5003 | ||
5083 | 99660011 | 80000000 |
500b | ||
5003 | ||
5083 | 80000000 | 99660191 |
500b | ||
5003 | ||
5083 | 80000000 | 000000ff |
500b |
0x128 reg | Send | Receive |
---|---|---|
5003 | ||
5083 | 99660124 | 80000000 |
500b | ||
5003 | ||
5083 | 12345678 | 80000000 |
500b | ||
5003 | ||
5083 | 80000000 | 99660094 |
500b |
repeat until you get some data
value of 0x128 reg | Send | Receive |
---|---|---|
5003 | ||
5083 | 99660026 | 80000000 |
500b | ||
5003 | 80000000 | 996600a6 |
500b |
send & receive etc. etc. Most games switch to 0x25 for the server as well after a while.
when you want to exit
0x128 reg | Send | Receive |
---|---|---|
5003 | ||
5083 | 99660130 | 80000000 |
500b | ||
5003 | ||
5083 | 00000001 | 80000000 |
500b | ||
5003 | ||
5083 | 80000000 | 996600b0 |
500b |
0x128 reg means the value of 0x128 reg
0x128 reg | Send | Receive |
---|---|---|
5084 | 00000000 | garbage |
5085 | ffff494e | 494egggg |
5085 | b6b1494e | 494eb6b1 |
5085 | b6b1544e | 544eb6b1 |
5085 | abb1544e | abb1544e |
5085 | abb14e45 | 4e45abb1 |
5085 | b1ba4e45 | 4e45b1ba |
5085 | b1ba4f44 | 4f44b1ba |
5085 | b0bb4f44 | 4f44b0bb |
5085 | b0bb8001 | 8001b0bb |
5003 | ||
5083 | 99660010 | 80000000 |
500b | ||
5003 | ||
5083 | 80000000 | 99660090 |
500b | ||
5003 | ||
5083 | 99660117 | 80000000 |
500b | ||
5003 | ||
5083 | 003c0420 | 80000000 |
500b | ||
5003 | ||
5083 | 80000000 | 99660097 |
500b | ||
5003 | ||
5003 | ||
5083 | 99660616 | 80000000 |
500b | ||
5003 | ||
5083 | 0c020002 | 80000000 |
500b | ||
5003 | ||
5083 | 00005ce1 | 80000000 |
500b | ||
5003 | ||
5083 | 00000000 | 80000000 |
500b | ||
5003 | ||
5083 | 09000040 | 80000000 |
500b | ||
5003 | ||
5083 | c1cfc8cd | 80000000 |
500b | ||
5003 | ||
5083 | 00ffccbb | 80000000 |
500b | ||
5003 | ||
5083 | 80000000 | 99660096 |
500b |
repeat, display available servers and wait until the player picks one
0x128 reg | Send | Receive | Comment |
---|---|---|---|
5003 | |||
5083 | 99660017 | 80000000 | |
500b | |||
5003 | |||
5083 | 80000000 | 99660797 | |
500b | |||
5003 | |||
5083 | 80000000 | 00002154 | adapter's ID |
500b | |||
5003 | |||
5083 | 80000000 | 0c020002 | |
500b | |||
5003 | |||
5083 | 80000000 | 00005ce1 | |
500b | |||
5003 | |||
5083 | 80000000 | 00000000 | |
500b | |||
5003 | |||
5083 | 80000000 | 09000040 | |
500b | |||
5003 | |||
5083 | 80000000 | c1cfc8cd | |
500b | |||
5003 | |||
5083 | 80000000 | 00ffccbb | |
500b |
0x128 reg | Send | Receive | Comment |
---|---|---|---|
5003 | |||
5083 | 9966011f | 80000000 | |
500b | |||
5003 | |||
5083 | 00002154 | 80000000 | pass the ID of the appropriate adapter |
500b | |||
5003 | |||
5083 | 80000000 | 9966009f | |
500b |
0x128 reg | Send | Receive | Comment |
---|---|---|---|
5003 | |||
5083 | 99660020 | 80000000 | |
500b | |||
5003 | |||
5083 | 80000000 | 996601a0 | |
500b | |||
5003 | |||
5083 | 80000000 | 00001567 | |
500b | if highest byte wasn't 0, repeat |
0x128 reg | Send | Receive | Comment |
---|---|---|---|
5003 | |||
5083 | 99660021 | 80000000 | |
500b | |||
5003 | |||
5083 | 80000000 | 996600a1 | |
500b | |||
5003 | |||
5083 | 99660027 | 80000000 | |
500b | |||
5003 | |||
5083 | 80000000 | 996600a7 | now you wait until SI = SO, not the other way around |
500b | |||
5002 | |||
5082 | 80000000 | 99660028 | !! EXTERNAL clock |
500a | |||
5002 | |||
5082 | 996600a8 | 80000000 | |
500a | |||
5003 | |||
5083 | 99660026 | 80000000 | up till now |
500b | |||
5003 | |||
5083 | 80000000 | 996601a6 | |
500b | |||
5003 | |||
5083 | 80000000 | 12345678 | |
500b | |||
5003 | |||
5083 | 996602a5 | 80000000 | |
500b | |||
5003 | |||
5083 | 87654321 | 80000000 | |
500b | |||
5003 | |||
5083 | 45678123 | 80000000 | |
500b | |||
5003 | |||
5083 | 80000000 | 996600a5 | here again, SI = SO |
500b | |||
5002 | |||
5082 | 80000000 | 99660028 | !! EXTERNAL clock |
500a | |||
5002 | |||
5082 | 996600a8 | 80000000 | |
500a | |||
5003 | |||
5083 | 99660026 | 80000000 | from here it's normal |
etc. etc. |
when you want to exit
0x128 reg | Send | Receive |
---|---|---|
5003 | ||
5083 | 99660130 | 80000000 |
500b | ||
5003 | ||
5083 | 00000001 | 80000000 |
500b | ||
5003 | ||
5083 | 80000000 | 996600b0 |
500b |
Lizardon for trying out my 'pimped' ROMS on his adapter
Nintendo for not giving away ANY info on this thing :-( (at least it was nice practice to figure it out)
You for reading the whole example
This version of the file was edited with markdown to make it more readable. There were also some typos fixed, while most of the original text was untouched.