Adding EditorConfig to normalize code style

This commit is contained in:
Rodrigo Alfonso 2024-08-10 07:21:36 -03:00
parent 6516744b6d
commit 91005296d2
24 changed files with 391 additions and 386 deletions

23
.editorconfig Normal file
View File

@ -0,0 +1,23 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
# Change these settings to your own preference
indent_style = space
indent_size = 2
# We recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab

View File

@ -52,8 +52,8 @@ The Start bit is automatically reset when the transfer completes, ie. when all 8
For 8bit normal mode. Contains 8bit data (only lower 8bit are used). Outgoing data should be written to this register before starting the transfer. During transfer, transmitted bits are shifted-out (MSB first), and received bits are shifted-in simultaneously. Upon transfer completion, the register contains the received 8bit value.
**4000120h - SIODATA32\_L - SIO Normal Communication lower 16bit data (R/W)**
**4000122h - SIODATA32\_H - SIO Normal Communication upper 16bit data (R/W)**
**4000120h - SIODATA32_L - SIO Normal Communication lower 16bit data (R/W)**
**4000122h - SIODATA32_H - SIO Normal Communication upper 16bit data (R/W)**
Same as above SIODATA8, for 32bit normal transfer mode respectively.
SIOCNT/RCNT must be set to 32bit normal mode <before> writing to SIODATA32.
@ -154,7 +154,7 @@ Note: Even though undocumented, many Nintendo games are using Bit 0 to test curr
The ID Bits are undefined until the first transfer has completed.
**400012Ah - SIOMLT\_SEND - Data Send Register (R/W)**
**400012Ah - SIOMLT_SEND - Data Send Register (R/W)**
Outgoing data (16 bit) which is to be sent to the other GBAs.
**4000120h - SIOMULTI0 - SIO Multi-Player Data 0 (Parent) (R/W)**
@ -162,7 +162,7 @@ Outgoing data (16 bit) which is to be sent to the other GBAs.
**4000124h - SIOMULTI2 - SIO Multi-Player Data 2 (2nd child) (R/W)**
**4000126h - SIOMULTI3 - SIO Multi-Player Data 3 (3rd child) (R/W)**
These registers are automatically reset to FFFFh upon transfer start.
After transfer, these registers contain incoming data (16bit each) from all remote GBAs (if any / otherwise still FFFFh), as well as the local outgoing SIOMLT\_SEND data.
After transfer, these registers contain incoming data (16bit each) from all remote GBAs (if any / otherwise still FFFFh), as well as the local outgoing SIOMLT_SEND data.
Ie. after the transfer, all connected GBAs will contain the same values in their SIOMULTI0-3 registers.
**Initialization**
@ -171,7 +171,7 @@ Ie. after the transfer, all connected GBAs will contain the same values in their
\- Read SIOCNT Bit 2 to detect whether this is the Parent/Master unit.
**Recommended Transmission Procedure**
\- Write outgoing data to SIODATA\_SEND.
\- Write outgoing data to SIODATA_SEND.
\- Master must set Start bit.
\- All units must process received data in SIOMULTI0-3 when transfer completed.
\- After the first successful transfer, ID Bits in SIOCNT are valid.
@ -289,6 +289,7 @@ This register is not used in general purpose mode. That is, the separate bits of
# GBA Wireless Adapter
**GBA Wireless Adapter (AGB-015 or OXY-004)**
- GBA Wireless Adapter Games
- GBA Wireless Adapter Login
- GBA Wireless Adapter Commands
@ -497,7 +498,7 @@ Main Chipset
The MC13190 is a Short-Range, Low-Power 2.4 GHz ISM band transceiver.
The processor is Motorola's 32-bit M-Core RISC engine. (?) MCT3000 (?)
See also: [http://www.eetimes.com/document.asp?doc\_id=1271943](http://www.eetimes.com/document.asp?doc_id=1271943)
See also: [http://www.eetimes.com/document.asp?doc_id=1271943](http://www.eetimes.com/document.asp?doc_id=1271943)
Version with GERMAN Postal Code on sticker:

View File

@ -1,17 +1,15 @@
Game Boy Advance Wireless Adapter
-------------------------------------------------
## Game Boy Advance Wireless Adapter
- 🌎 **Original post**: https://blog.kuiper.dev/gba-wireless-adapter 🌎
- ✏️ **Updates**: [@davidgfnet](https://github.com/davidgfnet) and I were discovering new things and we added them here!
> You can learn more details by reading [LinkRawWireless.hpp](../lib/LinkRawWireless.hpp)'s code.
The Wireless Adapter
====================
# The Wireless Adapter
[![The Game Boy Advance Wireless Adapter](img/wirelessadapter.jpg)](img/wirelessadapter.jpg)
*The Game Boy Advance Wireless Adapter*
_The Game Boy Advance Wireless Adapter_
The wireless adapter is a piece of hardware that connects to the link cable port of a GBA that then communicates wirelessly with other adapters. It also contains a multibootable[1](#fn:multiboot) rom for playing games only one player has a copy of (although I am not aware of many games that use it, some NES classic games use this). However, the most notable games to use it is probably the Pokémon games Fire Red, Leaf Green and Emerald (Sapphire and Ruby do _not_ have wireless adapter support)[2](#fn:list_of_games).
@ -19,32 +17,29 @@ The wireless adapter is a piece of hardware that connects to the link cable port
multiboot rom from the wireless adapter showing a game title of AGB.RS and a
username of CORWIN](img/multiboot.jpg)](img/multiboot.jpg)
*You can make this screen display any game*
_You can make this screen display any game_
Communicating with the adapter
==============================
# Communicating with the adapter
When I started, I used the following resources to start being able to talk with the wireless adapter:
* [This Gist contains some details](wireless.txt)
* [GBATEK has a section on the wireless adapter](gbatek.md)
- [This Gist contains some details](wireless.txt)
- [GBATEK has a section on the wireless adapter](gbatek.md)
Pinout
------
## Pinout
The wireless adapter connects using the link cable port to the GBA. It uses
* 3.3V
* Serial In
* Serial out
* SD
* Clock
* Ground
- 3.3V
- Serial In
- Serial out
- SD
- Clock
- Ground
which is all 6 of the pins. If you are going to mess with interfacing with the link cable yourself, make sure you know which pin is which. If you just want to use the wireless adapter as part of the GBA this isnt relevant.
Serial Peripheral Interface
---------------------------
## Serial Peripheral Interface
Broadly speaking the GBA communicates with the wireless adapter using the Serial Peripheral Interface (SPI), however it can be somewhat weird. In the case of the GBA this is a three or four wire protocol depending on how you count. The clock, two data wires, and what is normally chip select but operates more as a reset.
@ -54,22 +49,21 @@ Broadly speaking the GBA communicates with the wireless adapter using the Serial
analyser displaying an SPI trace from the GBA and wireless adapter
communications](img/init.png)](img/init.png)
*A logic analyser can be used to probe the link cable protocol between the GBA and a Wireless Adapter*
_A logic analyser can be used to probe the link cable protocol between the GBA and a Wireless Adapter_
I will break up the ways in which you communicate into three parts:
* Initialisation
* Commands
* Waiting for data
- Initialisation
- Commands
- Waiting for data
One thing to make note of is that when I have screenshots showing the logic analyser traces, these all come from Pokémon Emerald as it is what I had at the time I did a lot of this.
Initialisation
--------------
## Initialisation
[![The initialisation sequence captured using a logic analyser](img/full_initialisation.png)](img/full_initialisation.png)
*The initialisation sequence captured using a logic analyser*
_The initialisation sequence captured using a logic analyser_
Before starting sending and receiving commands, a handshake with the adapter needs to be done. During this, the clocks runs at 256 kHz. Real games start this process by resetting the adapter.
@ -86,22 +80,22 @@ The GBA and the adapter exchange the word “NINTENDO” with each other in quit
[![GBA
sends `0x7FFF494E` and wireless adapter sends `0x00000000`.](img/first_single_u32.png)](img/first_single_u32.png)
*GBA sends `0x7FFF494E` and wireless adapter sends `0x00000000`.*
_GBA sends `0x7FFF494E` and wireless adapter sends `0x00000000`._
The GBA here sends `0x7FFF494E`, of this the relevant part is the `0x494E`. If we look up what the bytes `0x49, 0x4E` are you will find them to be the letters `NI`. As exchanges happen simultaneously, at this point the adapter doesnt know what to respond with and so responds with all zeros.
[![GBA sends `0xFFFF494E` and wireless adapter sends `0x494EB6B1`.](img/first_nintendo_32.png)](img/first_nintendo_32.png)
*GBA sends `0xFFFF494E` and wireless adapter sends `0x494EB6B1`.*
_GBA sends `0xFFFF494E` and wireless adapter sends `0x494EB6B1`._
Next the GBA sends `0xFFFF494E` and now the wireless adapter does respond and responds with `0x494EB6B1`. I can assure you there is a pattern here:
* GBA:
* Two _most_ significant bytes are the inverse of the adapters previous _most_ significant bytes.
* Two _least_ significant bytes are the GBAs own data.
* Adapter:
* Two _least_ significant bytes are the inverse of the GBAs previous _least_ significant bytes.
* Two most significant bytes are the adapters own data.
- GBA:
- Two _most_ significant bytes are the inverse of the adapters previous _most_ significant bytes.
- Two _least_ significant bytes are the GBAs own data.
- Adapter:
- Two _least_ significant bytes are the inverse of the GBAs previous _least_ significant bytes.
- Two most significant bytes are the adapters own data.
The “own” data are the bytes of the string “NINTENDO”, and you advance to the next pair when the most significant bytes equal the inverse of the least significant bytes.
@ -160,39 +154,39 @@ Following these rules the transfer looks like
Although note that due to the rules, the first few transfers may contain some junk data and be different to this in practice. And after this, you can start sending commands.
Commands
--------
## Commands
[![A command being sent by the GBA and acknowledged by the
adapter](img/0x17.png)](img/0x17.png)
*A command being sent by the GBA and acknowledged by the adapter*
_A command being sent by the GBA and acknowledged by the adapter_
Commands are how you tell the adapter to do things. When in command mode the clock operates at 2 mHz. Some examples of commands include connect to adapter, send message, and receive message. All commands follow the same form:
* Command
- Command
The command is a 32 bit value of the form `0x9966LLCC`:
* LL
* The length of the data payload in number of 32 bit values. For example here it is `0x01`, so one value is transmitted after this.
* CC
* The command type, there are a bunch of these! In this case the command type is `0x17`.
* Data
- LL
- The length of the data payload in number of 32 bit values. For example here it is `0x01`, so one value is transmitted after this.
- CC
- The command type, there are a bunch of these! In this case the command type is `0x17`.
- Data
All the data along with the command, must transmit the number given in the command
* Acknowledge
- Acknowledge
The adapter responds with a command, the length is the number of 32 bit values and the command type is always what you send + `0x80`. In this case the length is zero and the command is `0x17` + `0x80` = `0x97`.
* ⚠️ When you send invalid commands or a one you're not supposed to send in the current state (like sending a `0x1d` before a `0x1c`), the adapter responds `0x996601ee`. If you read the next word (as the response size is `01`), it gives you an error code (`2` when using an invalid command, `1` when using a valid command in an invalid state, or `0`).
- ⚠️ When you send invalid commands or a one you're not supposed to send in the current state (like sending a `0x1d` before a `0x1c`), the adapter responds `0x996601ee`. If you read the next word (as the response size is `01`), it gives you an error code (`2` when using an invalid command, `1` when using a valid command in an invalid state, or `0`).
* Response
- Response
The data that the adapter responds with. Equal to the length given in the acknowledgement.
* Ready
- Ready
In the figure, youll see that after exchanging any 32 bit value using SPI, some out of clock communication happens. This is the GBA and the Adapter signalling to each other that they are ready to communicate. This happens over the following stages:
@ -213,21 +207,20 @@ Whenever either side expects something to be sent from the other (as SPI is alwa
[![Image without alt text or caption](img/0x10.png)](img/0x10.png)
* Send length: 0, Response length: 0
* First thing to be called after finishing the initialisation sequence.
- Send length: 0, Response length: 0
- First thing to be called after finishing the initialisation sequence.
#### Setup - `0x17`
[![Image without alt text or caption](img/0x17.png)](img/0x17.png)
* Send length: 1, response length: 0
* Games set this. It seems to setup the adapter's configuration.
- Send length: 1, response length: 0
- Games set this. It seems to setup the adapter's configuration.
Both Pokemon games and the multiboot ROM that the adapter sends when no cartridge is inserted use `0x003C0420`.
🔝 For a game, the most important bits are bits `16-17` (let's call this `maxPlayers`), which specify the maximum number of allowed players:
- `00`: 5 players (1 host and 4 clients)
- `01`: 4 players
- `10`: 3 players
@ -243,9 +236,8 @@ Both Pokemon games and the multiboot ROM that the adapter sends when no cartridg
[![Image without alt text or caption](img/0x16.png)](img/0x16.png)
* Send length: 6, response length: 0
* The data to be broadcast out to all adapters. Examples of use include the union room, broadcasting game name and username in download play, and the username in direct multiplayer in Pokémon.
- Send length: 6, response length: 0
- The data to be broadcast out to all adapters. Examples of use include the union room, broadcasting game name and username in download play, and the username in direct multiplayer in Pokémon.
💻 This is the first command used to start a server. The 6 parameters are the ASCII characters of the game and user name, plus some bytes indicating whether the server should appear in the Download Play list or not. Here's a byte by byte explanation:
@ -259,15 +251,13 @@ Both Pokemon games and the multiboot ROM that the adapter sends when no cartridg
#### StartHost - `0x19`
* Send length: 0, response length: 0
* This uses the broadcast data given by the broadcast command and actually does the broadcasting.
- Send length: 0, response length: 0
- This uses the broadcast data given by the broadcast command and actually does the broadcasting.
#### EndHost - `0x1b`
* Send length: 0, response length: 2+
* This command stops host broadcast. This allows to "close" the session and stop allowing new clients, but also **keeping the existing connections alive**. Sends and Receives still work, but:
- Send length: 0, response length: 2+
- This command stops host broadcast. This allows to "close" the session and stop allowing new clients, but also **keeping the existing connections alive**. Sends and Receives still work, but:
- Clients cannot connect, even if they already know the host ID (`FinishConnection` will fail).
- Calls to `AcceptConnections` on the host side will fail, unless `StartHost` is called again.
@ -275,20 +265,19 @@ Both Pokemon games and the multiboot ROM that the adapter sends when no cartridg
[![Image without alt text or caption](img/0x1d.png)](img/0x1d.png)
* Send length: 0, response length: 7 \* number of broadcasts (maximum: 4)
* All currently broadcasting devices are returned here along with a word of **metadata** (the metadata word first, then 6 words with broadcast data).
* The metadata contains:
* First 2 bytes: Server ID. IDs have 16 bits.
* 3rd byte: Next available slot. This can be used to check whether a player can join a room or not.
* `0b00`: If you join this room, your `clientNumber` will be 0.
* `0b01`: If you join this room, your `clientNumber` will be 1.
* `0b10`: If you join this room, your `clientNumber` will be 2.
* `0b11`: If you join this room, your `clientNumber` will be 3.
* `0xff`: The server is full. You cannot join this room.
* Although `LinkWireless` uses this to know the number of connected players, that only works because -by design- rooms are closed when a player disconnects. The hardware allows disconnecting specific clients, so if the next available slot is e.g. 2, it can mean that there are 3 connected players (1 host + 2 clients) or that there are more players, but the third client (`clientNumber` = 2) has disconnected and the slot is now free.
* The number of available slots depends on `maxPlayers` (see [Setup](#setup---0x17)) and/or [EndHost](#endhost---0x1b).
* 4th byte: Zero.
- Send length: 0, response length: 7 \* number of broadcasts (maximum: 4)
- All currently broadcasting devices are returned here along with a word of **metadata** (the metadata word first, then 6 words with broadcast data).
- The metadata contains:
- First 2 bytes: Server ID. IDs have 16 bits.
- 3rd byte: Next available slot. This can be used to check whether a player can join a room or not.
- `0b00`: If you join this room, your `clientNumber` will be 0.
- `0b01`: If you join this room, your `clientNumber` will be 1.
- `0b10`: If you join this room, your `clientNumber` will be 2.
- `0b11`: If you join this room, your `clientNumber` will be 3.
- `0xff`: The server is full. You cannot join this room.
- Although `LinkWireless` uses this to know the number of connected players, that only works because -by design- rooms are closed when a player disconnects. The hardware allows disconnecting specific clients, so if the next available slot is e.g. 2, it can mean that there are 3 connected players (1 host + 2 clients) or that there are more players, but the third client (`clientNumber` = 2) has disconnected and the slot is now free.
- The number of available slots depends on `maxPlayers` (see [Setup](#setup---0x17)) and/or [EndHost](#endhost---0x1b).
- 4th byte: Zero.
🆔 IDs are randomly generated. Each time you broadcast or connect, the adapter assigns you a new ID.
@ -300,10 +289,9 @@ Both Pokemon games and the multiboot ROM that the adapter sends when no cartridg
#### AcceptConnections - `0x1a`
* Send length: 0, response length: 0+
* Accepts new connections and returns a list with the connected adapters. The length of the response is zero if there are no connected adapters.
* It includes one value per connected client, in which the most significant byte is the `clientNumber` (see [IsFinishedConnect](#isfinishedconnect---0x20)) and the least significant byte is the ID.
- Send length: 0, response length: 0+
- Accepts new connections and returns a list with the connected adapters. The length of the response is zero if there are no connected adapters.
- It includes one value per connected client, in which the most significant byte is the `clientNumber` (see [IsFinishedConnect](#isfinishedconnect---0x20)) and the least significant byte is the ID.
🔗 If this command reports 3 connected consoles, after turning off one of them, it will still report 3 consoles. Servers need to detect timeouts in another way.
@ -311,17 +299,15 @@ Both Pokemon games and the multiboot ROM that the adapter sends when no cartridg
[![Image without alt text or caption](img/0x1f.png)](img/0x1f.png)
* Send length: 1, response length: 0
* Send the ID of the adapter you want to connect to from [BroadcastRead](#broadcastread---0x1c-0x1d-and-0x1e).
- Send length: 1, response length: 0
- Send the ID of the adapter you want to connect to from [BroadcastRead](#broadcastread---0x1c-0x1d-and-0x1e).
#### IsFinishedConnect - `0x20`
[![Image without alt text or caption](img/0x20.png)](img/0x20.png)
* Send length: 0, response length: 1
* Responds with a 16 bit ID as lower 16 bits if finished, otherwise responds with `0x01000000`.
- Send length: 0, response length: 1
- Responds with a 16 bit ID as lower 16 bits if finished, otherwise responds with `0x01000000`.
👆 It also responds in its bits 16 and 17 a number that represents the `clientNumber` (0 to 3). Lets say our ID is `abcd`, it will respond `0x0000abcd` if we are the first client that connects to that server, `0x0001abcd` if we are the second one, `0x0002abcd` third, and `0x0003abcd` fourth. Rooms allow 5 simultaneous adapters at max.
@ -331,52 +317,53 @@ Both Pokemon games and the multiboot ROM that the adapter sends when no cartridg
[![Image without alt text or caption](img/0x21.png)](img/0x21.png)
* Send length: 0, response length: 1
* Called after [IsFinishedConnect](#isfinishedconnect---0x20), responds with the final device ID (which tends to be equal to the ID from the previous command), the `clientNumber` in bits 16 and 17, and if all went well, zeros in its remaining bits.
- Send length: 0, response length: 1
- Called after [IsFinishedConnect](#isfinishedconnect---0x20), responds with the final device ID (which tends to be equal to the ID from the previous command), the `clientNumber` in bits 16 and 17, and if all went well, zeros in its remaining bits.
#### SendData - `0x24`
* Send length: N, response length: 0
* Send N 32 bit values to connected adapter.
- Send length: N, response length: 0
- Send N 32 bit values to connected adapter.
⚠️ The first value **is a header**, and has to be correct. Otherwise, the adapter will ignore the command and won't send any data. The header is as follows:
- For hosts: the number of `bytes` that come next. For example, if we want to send `0xaabbccdd` and `0x12345678` in the same command, we need to send:
* `0x00000008`, `0xaabbccdd`, `0x12345678`.
- `0x00000008`, `0xaabbccdd`, `0x12345678`.
- For clients: `(bytes << (3 + (1+clientNumber) * 5))`. The `clientNumber` is what I described in [IsFinishedConnect](#isfinishedconnect---0x20). For example, if we want to send a single 4-byte value (`0xaabbccdd`):
* The first client should send: `0x400`, `0xaabbccdd`
* The second client should send: `0x8000`, `0xaabbccdd`
* The third client should send: `0x100000`, `0xaabbccdd`
* The fourth client should send: `0x2000000`, `0xaabbccdd`
- The first client should send: `0x400`, `0xaabbccdd`
- The second client should send: `0x8000`, `0xaabbccdd`
- The third client should send: `0x100000`, `0xaabbccdd`
- The fourth client should send: `0x2000000`, `0xaabbccdd`
🔝 Each `SendData` can send up to:
- **Host:** 87 bytes (or 21.75 values)
- **Clients:** 16 bytes (or 4 values)
- *(the header doesn't count)*
- _(the header doesn't count)_
🗂️ Any non-multiple of 4 byte count will send LSB bytes first. For example, a host sending `0x00000003`, `0xaabbccdd` will result in bytes `0xbb`, `0xcc` and `0xdd` being received by clients (the clients will receive `0x00bbccdd`).
🤝 Note that when having more than 2 connected adapters, data is not transferred between different clients. If a client wants to tell something to another client, it has to talk first with the host with `SendData`, and then the host needs to relay that information to the other client.
👑 Internally, data is only sent when **the host** calls `SendData`:
- The send/receive buffer size is 1 packet, so calling `SendData` multiple times on either side (before the other side calls `ReceiveData`) will result in data loss.
- Clients only **schedule** the data transfer, but they don't do it until the host sends something. This is problematic because the command overrides previously scheduled transfers, so calling `SendData` multiple times on the client side before the host calls `SendData` would also result in data loss. I believe this is why most games use `SendDataWait` on the client side.
- Here's an example of this behavior:
- **Client**: `SendData` `{sndHeader}`, `10`
- **Host**: `SendData` `{sndHeader}`, `1` **(\*)**
- *(here, the adapter internally receives the 10 from the client)*
- _(here, the adapter internally receives the 10 from the client)_
- **Host**: `SendData` `{sndHeader}`, `2`
- *(here, the previous packet with 1 is lost since nobody received it yet)*
- _(here, the previous packet with 1 is lost since nobody received it yet)_
- **Client**: `ReceiveData`
- Receives `{rcvHeader}`, `2`
- **Client**: `SendData` `{sndHeader}`, `20`
- **Host**: `ReceiveData`
- Receives `{rcvHeader}`, `10` *(pending from **(\*)**)*
- Receives `{rcvHeader}`, `10` _(pending from **(\*)**)_
- **Host**: `ReceiveData`
- Receives nothing
- **Host**: `SendData` `{sndHeader}`, `3`
- *(here, the adapter internally receives the 20 from the client)*
- _(here, the adapter internally receives the 20 from the client)_
- **Host**: `ReceiveData`
- Receives `{rcvHeader}`, 20
@ -386,19 +373,17 @@ Both Pokemon games and the multiboot ROM that the adapter sends when no cartridg
[![Image without alt text or caption](img/0x25.png)](img/0x25.png)
* Send length: N, response length: 0
* The same as [SendData](#senddata---0x24) but with the additional effect of [Wait](#wait---0x27)
* See [Waiting](#waiting) for more details on this.
- Send length: N, response length: 0
- The same as [SendData](#senddata---0x24) but with the additional effect of [Wait](#wait---0x27)
- See [Waiting](#waiting) for more details on this.
#### ReceiveData - `0x26`
[![Image without alt text or caption](img/0x26.png)](img/0x26.png)
* Send length: 0, response length: N
* Responds with all the data from all adapters. No IDs are included, this is just what was sent concatenated together.
* Once data has been pulled out, it clears the data buffer, so calling this again can only get new data.
- Send length: 0, response length: N
- Responds with all the data from all adapters. No IDs are included, this is just what was sent concatenated together.
- Once data has been pulled out, it clears the data buffer, so calling this again can only get new data.
🧩 The data is only concatenated on the host side, and its order is based on the `clientNumber`. It doesn't matter who called `SendData` first.
@ -412,32 +397,31 @@ Both Pokemon games and the multiboot ROM that the adapter sends when no cartridg
- The rest of the bits are `0`.
🧱 Concatenation is done at **byte** level. So, for example, if client 3 sends 3 bytes (`0xAABBCC`) and client 1 sends 2 bytes (`0xDDEE`), the host would receive 3 words:
- (header) `0b0000_00011_00000_00000_00010_0_0000000`, `0xEEAABBCC`, `0x000000DD`
#### Wait - `0x27`
[![Image without alt text or caption](img/0x27.png)](img/0x27.png)
* Send length: 0, response length: 0
* See [Waiting](#waiting) for more details on this.
- Send length: 0, response length: 0
- See [Waiting](#waiting) for more details on this.
#### DisconnectClient - `0x30`
[![Image without alt text or caption](img/0x30.png)](img/0x30.png)
* Send length 1, reponse length: 0
* This command disconnects clients. The argument is a bitmask of the client ID to disconnect. Sending `0x1` means "disconnect client number 0", sending `0x2` means "disconnect client number 1", and sending `0xF` would disconnect all the clients. After disconnecting a client, its ID won't appear on `AcceptConnection` calls and its `clientNumber` will be liberated, so other peers can connect.
- Send length 1, reponse length: 0
- This command disconnects clients. The argument is a bitmask of the client ID to disconnect. Sending `0x1` means "disconnect client number 0", sending `0x2` means "disconnect client number 1", and sending `0xF` would disconnect all the clients. After disconnecting a client, its ID won't appear on `AcceptConnection` calls and its `clientNumber` will be liberated, so other peers can connect.
⚡ The clients also are able to disconnect themselves using this command, but they can only send its corresponding bit or `0xF`, other bits are ignored (they cannot disconnect other clients). Also, the host won't know if a client disconnects itself, so this feature is not very useful:
* The host still needs to monitor clients to ensure they are still alive (ie. through some PING like mechanism) and disconnect them if they are not, to allow new clients to connect. [4](#pokered)
- The host still needs to monitor clients to ensure they are still alive (ie. through some PING like mechanism) and disconnect them if they are not, to allow new clients to connect. [4](#pokered)
#### Bye - `0x3d`
* Send length: 0, Response length: 0
* This sets the adapter in a low power consumption mode. Games use it when the player exits the multiplayer mode. To use the adapter again after this command, a new reset/initialization is needed.
- Send length: 0, Response length: 0
- This sets the adapter in a low power consumption mode. Games use it when the player exits the multiplayer mode. To use the adapter again after this command, a new reset/initialization is needed.
### Other commands
@ -445,26 +429,26 @@ Both Pokemon games and the multiboot ROM that the adapter sends when no cartridg
[![Image without alt text or caption](img/0x11.png)](img/0x11.png)
* Send length: 0, response length: 1
* This returns the signal level of the other adapters from `0` to `0xFF` (`0` means disconnected).
* The levels are returned in a single value, the first byte being the signal level of client 0, and the last byte being the signal level of client 3.
* When called from a client, it only returns the signal level of that client in its corresponding byte. The rest of the bytes will be `0`.
- Send length: 0, response length: 1
- This returns the signal level of the other adapters from `0` to `0xFF` (`0` means disconnected).
- The levels are returned in a single value, the first byte being the signal level of client 0, and the last byte being the signal level of client 3.
- When called from a client, it only returns the signal level of that client in its corresponding byte. The rest of the bytes will be `0`.
#### VersionStatus - `0x12`
* Send length: 0, Response length: 1
- Send length: 0, Response length: 1
* In my adapter, it always returns `8585495` (decimal). It contains the hardware and firmware version of the adapter.
- In my adapter, it always returns `8585495` (decimal). It contains the hardware and firmware version of the adapter.
#### SystemStatus - `0x13`
* Send length: 0, Response length: 1
- Send length: 0, Response length: 1
* Returns some information about the current connection and device state. The returned word contains:
- Bits `0-15`: The device ID (or zero if the device is not connected nor hosting).
- Bits `16-23`: A 4-bit array with slots. If the console is a client, it'll have a 1 in the position assigned to that slot (e.g. the one with `clientNumber` 3 will have `0100`). The host will always have `0000` here.
- Bits `24-31`: A number indicating the state of the adapter
- Returns some information about the current connection and device state. The returned word contains:
* Bits `0-15`: The device ID (or zero if the device is not connected nor hosting).
* Bits `16-23`: A 4-bit array with slots. If the console is a client, it'll have a 1 in the position assigned to that slot (e.g. the one with `clientNumber` 3 will have `0100`). The host will always have `0000` here.
* Bits `24-31`: A number indicating the state of the adapter
- `0` = idle
- `1`/`2` = serving (host)
- `3` = searching
@ -473,30 +457,31 @@ Both Pokemon games and the multiboot ROM that the adapter sends when no cartridg
#### SlotStatus - `0x14`
* Send length: 0, Response length: 1+
- Send length: 0, Response length: 1+
* It's returns a list of the connected adapters, similar to what `AcceptConnections` responds, but also:
- It's returns a list of the connected adapters, similar to what `AcceptConnections` responds, but also:
- `SlotStatus` has an extra word at the start of the response, indicating the `clientNumber` that the next connection will have (or `0xFF` if the room is not accepting new clients).
- `SlotStatus` can be called after `EndHost`, while `AcceptConnections` fails.
#### ConfigStatus - `0x15`
* Send length: 0, Response length: 7 (as client), or 8 (as host)
* Returns the adapter configuration.
- Send length: 0, Response length: 7 (as client), or 8 (as host)
- Returns the adapter configuration.
🤔 In my tests...
- As client, it returned: `0, 0, 0, 0, 0, 0, 257`.
- As host, it returned: `1, 2, 3, 4, 5, 6, 3933216, 257`.
* `1, 2, 3, 4, 5, 6` would be the broadcast data.
* `3933216` is the value used in the [Setup](#setup---0x17) command (`0x003C0420`).
* No idea what `257` this means.
- `1, 2, 3, 4, 5, 6` would be the broadcast data.
- `3933216` is the value used in the [Setup](#setup---0x17) command (`0x003C0420`).
- No idea what `257` this means.
#### RetransmitAndWait - `0x37`
* Send length: 0, Response length: 0
* Retransmits the last data from a host to all clients, with the additional effect of [Wait](#wait---0x27)
* See [Waiting](#waiting) for more details on this.
- Send length: 0, Response length: 0
- Retransmits the last data from a host to all clients, with the additional effect of [Wait](#wait---0x27)
- See [Waiting](#waiting) for more details on this.
### Unknown commands
@ -510,16 +495,15 @@ If we analyze whether a command ID throws an 'invalid command' error (`0x996601e
- `0x38`
- `0x39`
Waiting
-------
## Waiting
[![Image without alt text or caption](img/wake-up.png)](img/wake-up.png)
* After either [SendDataWait](#senddatawait---0x25) or [Wait](#wait---0x27), clock control switches to the wireless adapter.
* Once the adapter has something to tell the GBA about, the _adapter_ sends a command to the GBA (usually `0x99660028`).
* These transfers are dealt with in much the same way as before but with the roles of the GBA and the adapter reversed, see the figure!
* The GBA then sends the response back (e.g. `0x996600A8` as `0x28` + `0x80` = `0xA8`).
* After this, control of the clock returns to the GBA, and it can start sending commands back again. For example this might be receiving the command sent by the other device using [ReceiveData](#receivedata---0x26).
- After either [SendDataWait](#senddatawait---0x25) or [Wait](#wait---0x27), clock control switches to the wireless adapter.
- Once the adapter has something to tell the GBA about, the _adapter_ sends a command to the GBA (usually `0x99660028`).
- These transfers are dealt with in much the same way as before but with the roles of the GBA and the adapter reversed, see the figure!
- The GBA then sends the response back (e.g. `0x996600A8` as `0x28` + `0x80` = `0xA8`).
- After this, control of the clock returns to the GBA, and it can start sending commands back again. For example this might be receiving the command sent by the other device using [ReceiveData](#receivedata---0x26).
⌚ This timeouts after 500ms of the adapter not having anything to tell the GBA about. In this case, the adapter sends `0x99660027`. **This is only true if the console has used the [Setup](#setup---0x17) command before**. The value that most games use (`0x003C0420`) contains this timeout value, but the default is zero (no timeout).
@ -528,14 +512,16 @@ Waiting
💨 Clients receive the `0x28` when new data from the host is available, but the host receives it immediately (well, after the transfer completes), as it can be used to know which clients received data or are disconnected.
⚠️ If some children didn't receive the data, the adapter sends to the host GBA a `0x99660128`.
- The extra parameter has two bitarrays:
* Bits `0-4`: The clients that _received_ data.
* Bits `8-11`: The clients marked as _inactive_. This depends on the # of maximum transmissions configured with the [Setup](#setup---0x17) command.
- Bits `0-4`: The clients that _received_ data.
- Bits `8-11`: The clients marked as _inactive_. This depends on the # of maximum transmissions configured with the [Setup](#setup---0x17) command.
🔗 When the adapter is disconnected from the host, it sends a `0x99660029`.
- Bit 8 of the response indicates the reason:
* `0` = manual disconnect (aka the host used [DisconnectClient](#disconnectclient---0x30))
* `1` = the connection was lost
- `0` = manual disconnect (aka the host used [DisconnectClient](#disconnectclient---0x30))
- `1` = the connection was lost
◀ **Inverted ACKs**
@ -548,20 +534,19 @@ While the clock is inverted, the acknowledge procedure is 'standard' but with th
5. The adapter goes low when it's ready.
6. The adapter starts a transfer, clock starts pulsing, and both sides exchange the next 32 bit value.
Wireless Multiboot
------------------
## Wireless Multiboot
> You can learn more details by reading [LinkWirelessMultiboot.hpp](../lib/LinkWirelessMultiboot.hpp)'s code.
To host a 'multiboot' room, a host sets the **multiboot flag** (bit 15) in its game ID (inside broadcast data) and starts serving.
- 1) For each new client that connects, it runs a small handshake where the client sends their 'game name' and 'player name'. The bootloader always sends `RFU-MB-DL` as game name and `PLAYER A` (or `B`, `C`, `D`) as player name.
- 1. For each new client that connects, it runs a small handshake where the client sends their 'game name' and 'player name'. The bootloader always sends `RFU-MB-DL` as game name and `PLAYER A` (or `B`, `C`, `D`) as player name.
- 2) When the host player confirms that all players are ready, it sends a 'rom start' command.
- 2. When the host player confirms that all players are ready, it sends a 'rom start' command.
- 3) The host sends the rom bytes in 84-byte chunks.
- 3. The host sends the rom bytes in 84-byte chunks.
- 4) The host sends a 'rom end' command and the games boot.
- 4. The host sends a 'rom end' command and the games boot.
### Valid header
@ -691,22 +676,18 @@ After all ROM chunks are ACK'd, the last transfers are:
- `size=0, n=0, ph=0, ack=0, commState=3` (`3 = ENDING`)
- `size=0, n=1, ph=0, ack=0, commState=0` (`0 = OFF`)
SPI config
----------
## SPI config
Here's how SPI works on the GBA:
[![Image without alt text or caption](img/logic2.png)](img/logic2.png)
I know more!
============
# I know more!
If you know any extra details about the wireless adapter, get in touch!. For specific details Ive left footnotes around if you happen to know that piece of information.
1. Multiboot is what we call a rom that can be booted over link cable. This can be used for something akin to download play software for the DS. [↩︎](#fnref:multiboot)
2. [Games compatible with the wireless adapter](https://en.wikipedia.org/wiki/Game_Boy_Advance_Wireless_Adapter#Compatible_games) [↩︎](#fnref:list_of_games)
3. [Send me an email if you know more about this](https://blog.kuiper.dev/contact)
4. Some interesting data about the RFU adapter can be found in Pokemon Games, see the [FireRed Decompilation](https://github.com/pret/pokefirered/blob/49ea462d7f421e75a76b25d7e85c92494c0a9798/include/librfu.h#L44) for more information.

View File

@ -1,13 +1,13 @@
const { SerialPort, ReadlineParser } = require('serialport') // "^12.0.0"
const { SerialPort, ReadlineParser } = require("serialport"); // "^12.0.0"
var serialPort = new SerialPort({
path: "COM9", // (*nix: /dev/ttyACMX, Windows: COMX)
baudRate: 9600
baudRate: 9600,
});
const parser = serialPort.pipe(new ReadlineParser());
parser.on('data', (it) => console.log(it))
parser.on("data", (it) => console.log(it));
setInterval(() => {
serialPort.write('<< node\n')
serialPort.write("<< node\n");
}, 1000);