-
-
Save iracigt/50b3a857e4d82c2c11d0dd5f84ecac6b to your computer and use it in GitHub Desktop.
Nintendo Wireless Adapter Specification v1.1 by denopqrihg
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Nintendo Wireless Adapter Specification | |
v1.1 (23th June 2005) | |
by denopqrihg (denopqrihg@centrum.cz) | |
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. | |
Some general info | |
----------------- | |
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. | |
Which mode to use? | |
------------------ | |
32-bit Normal mode, all the time. No exceptions. | |
Mostly 2Mbit internal clock, but there are exceptions which will be pointed out. | |
Initialization | |
-------------- | |
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). | |
Communication | |
------------- | |
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 | |
Ackowledging | |
------------ | |
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. | |
!! Exception !! After commands 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) | |
Commands | |
----------------- | |
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 number | |
-------------- | |
S: how many words to send | |
R: how many words to receive | |
Description of what the command does (if known :-) | |
0x10 | |
---- | |
S: 0 | |
R: 0 | |
Last step of initialization, difference between this and 0x3d is unknown, both are used | |
0x10 seems to be 'safer' | |
0x11 | |
---- | |
S: 0 | |
R: 1 | |
This command always receives 0xff in 2 player link, maybe it has to do with 3+ players ?? | |
0x13 | |
---- | |
S: 0 | |
R: 1 | |
Receives a random value, don't know what it's for | |
0x16 | |
---- | |
S: usually 6 | |
R: 0 | |
Sends 'broadcast' data, which will be received by all adapters in range | |
0x17 | |
---- | |
S: 1 | |
R: 0 | |
Setup?? The value sent should be 003d0620 (Digimon), 003c0420 (Pokemon) or something along this way. | |
0x1a | |
---- | |
S: 0 | |
R: 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 | |
---- | |
S: 0 | |
R: 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 | |
---- | |
S: 1 | |
R: 0 | |
Connect to server. Value sent is the 'ID' of the adapter you want to connect to. | |
0x20 | |
---- | |
S: 0 | |
R: 1 | |
Used after 0x1f, generally resend until highest byte is 0. | |
0x21 | |
---- | |
S: 0 | |
R: 1 | |
Send once after 0x20 successfully finished (returned 0). | |
0x24 | |
---- | |
S: anything | |
R: 0 | |
Send data to connected adapters (I've only seen this command used by servers, but maybe clients can use it as well) | |
0x25 | |
---- | |
S: anything | |
R: 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 | |
---- | |
S: 0 | |
R: anything | |
Receive data. | |
0x27 | |
---- | |
S: 0 | |
R: 0 | |
Similar to 0x25, but without sending data. All strange behavior of 0x25 applies here, too. | |
0x30 | |
---- | |
S: 1? | |
R: 0 | |
Most likely a 'Terminate connection' command. Data value is usually 1. | |
0x3d | |
---- | |
S: 0 | |
R: 0 | |
Same as 0x10 | |
0xa8 | |
---- | |
S: 0 | |
R: 0 | |
Ackowledge of 0x28 sent by adapter. | |
0xee | |
---- | |
S: 1? | |
R: 0 | |
This is very unconfirmed, but is probably used when you want the adapter to resend the last command/whatever ?? | |
Example | |
------------- | |
A complete example of a client/server communication | |
(all numbers are in hex) | |
Server | |
------ | |
value of | |
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 | |
|------------------------------------------------ | |
v | | |
5003 | | |
5083 9966001a 80000000 | | |
500b | | |
5003 | | |
5083 80000000 9966009a | | |
500b | | |
repeat ------------------------------------------ | |
until you get | |
|---------------------------------------------------------------- | |
v | | |
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 | | |
repeat a few times to ensure that it really is a connection ----- | |
5003 | |
5083 99660124 80000000 | |
500b | |
5003 | |
5083 12345678 80000000 | |
500b | |
5003 | |
5083 80000000 99660094 | |
500b | |
|------------------------------------------------ | |
v | | |
5003 | | |
5083 99660026 80000000 | | |
500b | | |
5003 80000000 996600a6 | | |
500b | | |
repeat until you get some data ----------------- | |
send & receive etc. etc. | |
Most games switch to 0x25 for the server as well after a while. | |
when you want to exit | |
5003 | |
5083 99660130 80000000 | |
500b | |
5003 | |
5083 00000001 80000000 | |
500b | |
5003 | |
5083 80000000 996600b0 | |
500b | |
Client | |
------ | |
value of | |
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 | |
|------------------------------------------------------------------------ | |
v | | |
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 | | |
repeat, display available servers and wait until the player picks one --- | |
5003 | |
5083 9966011f 80000000 | |
500b | |
5003 | |
5083 00002154 80000000 pass the ID of the appropriate adapter | |
500b | |
5003 | |
5083 80000000 9966009f | |
500b | |
|------------------------------------------------ | |
v | | |
5003 | | |
5083 99660020 80000000 | | |
500b | | |
5003 | | |
5083 80000000 996601a0 | | |
500b | | |
5003 | | |
5083 80000000 00001567 | | |
500b if highest byte wasn't 0, repeat -------- | |
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 | |
5003 | |
5083 99660130 80000000 | |
500b | |
5003 | |
5083 00000001 80000000 | |
500b | |
5003 | |
5083 80000000 996600b0 | |
500b | |
Thanks to | |
--------- | |
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment