A while ago I started maintaining the mythical GBA emulator gpSP, in particular its libretro fork (see my github repo). I fixed tons of old bugs, rewrote half of its codebase, added new platforms and targets (for instance ARMv8 dynarec support, a new C++ video renderer and big-endian support for devices like Wii/GC).
While this is fun, I haven't really added many new features to it (besides some minor stuff like rumble feedback support). In the past months I played with the possibility of adding multiplayer support by emulating the GBA's serial port. However this is no trivial task: timing is crucial and gpSP sucks at timing. Most emulators that support link cable emulation will run two instances of the emulator in a lock-step fashion, forcing users to run both games on the same device. This is not as much fun as most users might expect in 2024. Also, with the renaissance of all things retro, many new low-end portable consoles have saturated the market providing emulation solutions. Many of these devices feature wifi, which would be great to use for mutliplayer gaming.
At this moment I turned my eye to the GBA Wireless Adapter. This thing uses the serial port to attach an RF link to the GBA, allowing for RF comms in a bunch of supported games. On paper this thing should be more tolerant to timing and errors, since that is the nature of an RF link: there's packet loss, collision, retransmission... The only minor issue is that no other emulator emulates it (I found some stuff in VBA but seems non functional and literally impossible to read). I was almost ready to give up when I found some traces of information, in particular:
The first explains a bit how the device (RFU from now on) works, already a lot of detail is present (at the protocol level) but the commands are not completely understood. Rodrigo took on Corwin's work and reversed further. He managed to create a library that is able to use the RFU to communicate with other devices. His aim is to add support to homebrew games. I reached out to them and we got to work, to understand all the bits that were missing.
I'm not going to explain in detail how this works, since there is a great doc (which we are still completing as we work) that summarizes most of it. The device communicates over SPI, supporting master-slave role switching (so that the device can "interrupt" the GBA when data is available). It is based on some command-response interface, where the GBA will issue commands and the RFU will respond to those. Each command can have some optional data payload.
The RF protocol is not known but we can check the FCC filing and find the device there. According to the documentation it is a 2.4GHz device that uses ASK modulation at around 4mbps in a TDMA fashion. The transmission times described also mention the amount of bits per transmission, which loosely match the maximum known data payloads. One of the interesting things about these devices is that they can act as two roles: host and client. Hosts send broadcast announcements (like WiFi APs) so that clients can find them. These announncements carry a payload that's partially standarized by Nintendo, with a game name and some flags (so that compatible games can recognize each other and ignore non-compatible peers). Clients can connect and exchange data with the host (but not between themselves!) but only when the hosts asks for it. It seems that the host must send data (even if dummy) so that the clients can respond with their own data. There is also a limitation of 4 clients per host (so a maximum of 5 players can be connected toghether).
To better understand the protocol and how it works I captured some traces (with real devices and a DSLogic), checked out the Pokemon reversed sources (which helped inmensely!) for Pokemon Fire Red, and tested in the emulator quite a bit. Once you get the basics working (mostly described in Corwin's blog post) games are able to send commands and you can start making sense out of them.
In order to make the emulator work for multiplayer games, it needs some support from the libretro API (since at the moment, we do not have a native UI). Retroarch supports netplay for multiplayer devices (like SNES or Megadrive) by emulating a single device with multiple gamepads that are controlled by different players over the network. This is a fun piece of software, since it needs to use savestates and replay to accurately emulate the player inputs without inccuring in massive performance penalties (due to network latency). However mutli-device netplay was not supported, that is, a netplay mode where different emulated devices play toghether.
Luckily for me Bernhard Schelling added "true" multiplayer support a few months ago. This new netplay mode is named Netpacket interface and was first implemented for DosBOX, to emulate modems and other network adapters. It should be available from Retroarch version 1.17 onwards. For the GBA RFU this is not too far from what we need, essentially being able to send and receive arbitrary data packets. Some other considerations are also important for this new mode, for instance the ability to play different games and potentially different emulator versions (as long as they are compatible). Regular netplay enforces identical software and games (ROMs), since they must stay in perfect sync, however we want more freedom so that compatible games can be linked (ie. different Pokemon editions).
Right now gpSP supports network play for a bunch of games. Some of them barely work since they do not like high latencies (racing games, for instance, assume they can sync at least once per frame, which might be only true when playing over a LAN connection). Others work fine since they exchange data in a more "asynchronous" way and/or support better packet loss and delay. We emulate some packet loss whenever there is no data in the buffer, that makes many games happy enough to keep on running and re-send/receive data at a later point.
To play, you will need at least Retroarch 1.17, a recent version of the gpsp core, some compatible ROM and of course, some friends! (Retroarch provides a game lobby where you can find people playing a compatible game). It mostly works on PC/Android, but some other platforms might have support for netplay (Vita, 3DS and Switch come to mind).
It would be awesome to be able to add GBA Link support as well, in a way that users can play over the internet. However, looking at the reversed Pokemon sources, it is clear to me that the majority of games will not work. There are already some pretty heavy assumptions for the RFU-compatible games, but these are even tighter for Link cables. Many games assume they can exchange data with peers once per millisecond (given that the serial module can perform four transfers in ~600us). These restrictions make it unfeasible unless the game is pretty relaxed about latencies and bandwidth, which is not usually the case.
However it might be possible to play some games by doing some hacking. I spent some time reading Pokemon sources to realise that they could be patched to support a slower serial port (by increasing serial port timeouts). I will be exploring this approach to see if we can support some of the most played games. At the end of the day, most users wanna play Pokemon 😅️.
In the meantime I hope to help other communities with this Retroarch version, so we can all enjoy wireless multiplayer in GBA. I'd like to add WiFi support to PSP and help adding network support to the PS2 (which is already in the works). More devices will be getting this very soon I suspect, so stay tuned!