If you have followed melonDS from the beginning, you'd know that wifi was one of the goals. And well, it's getting there.





The first melonDS release, 0.1, already included some wifi code, but it was a very minimalistic stub. The point was merely to allow games to get past wifi initialization successfully. And it even failed at that due to a bug.



Chocolate waffles to you if you can locate the bug, by the way ;)



But well, at that stage, the focus wasn't much on wifi.





It was eventually fixed in 0.2, and some functionality was added, but it still didn't do much at all. Games finally got past wifi initialization, but that was about it.



It wasn't until 0.3 that some serious work was done. With the emulator core getting more robust, I could try going for the wifi quest again. Not that 0.3 went far at all -- it merely allowed players to see eachother, but it wasn't possible to actually connect. But it was something, and infrastructure for sending and receiving packets was in place and working, as well as a good chunk of the wifi hardware functionality.





You may already know how it went back in the DeSmuME days. As far as local multiplayer was concerned, I kept hitting a wall. Couldn't get it working, no matter how hard I tried. WFC is a separate issue.



It didn't help drive motivation knowing that my work was doomed to stay locked behind a permanent EXPERIMENTAL_WIFI wall, requiring a custom wifi-enabled build, and that the DeSmuME team's public attitude is to sweep wifi under the carpet and pretend it doesn't exist, but the main issue was the lack of documentation as far as local multiplayer is concerned.





The DS wifi hardware isn't a simple, standard transceiver. It is a custom, proprietary wifi system made by Nintendo for their purposes. It has special features to assist local multiplay communication at a fast rate.



GBAtek documents the more regular wifi features well enough to get things like WFC working, but the specific multiplay features weren't well known until now. Many packet captures have been made, several multiplay protocols like Pictochat and download play have been reverse-engineered, but details on hardware operation were at a loss. The hardware operates in a very specific way during multiplay, and there's some real clever design there.



As the DS doesn't support ad-hoc communication, multiplay follows a host-client scheme. Clients can't directly communicate between themselves, everything goes through the host. Who is the host depends on the game -- it is generally the person who starts the multiplayer game.



The host sends beacon frames at a regular interval to advertise the game to potential clients, pretty much like how access points send beacons to advertise their presence. The DS wifi hardware allows to automatically send beacons at a set interval, but there's nothing too special there.



When a client connects, the regular 802.11 association procedure is followed. The client sends an auth frame, to which the host replies with an auth frame, then the client sends an association request, and the host replies with an association response which gives the client its ID.



At this point, multiplay communication begins, and this is where the real meat is.



The host sends data frames using a special TX slot (which GBAtek names CMD). It doesn't simply send the data, it actually assists the whole exchange.



The host data frame has a bitmask telling which clients should reply. Each client is given an ID from 1 to 15.



So, after the data frame is sent, the hardware waits for those clients to reply. It uses said bitmask, as well as a register telling how long a client reply should last, to determine how long the wait should last. It can report when clients fail to reply within their window (assuming clients reply in order).



The client doesn't have much control over the process. It has a register that tells where its reply frame is in memory, and a register that holds its client ID, and that's about it. When receiving a data frame, the hardware checks its client bitmask against the client ID register to determine whether it should reply. The data frame also contains the client reply time. With these data, the client can determine when it should send its reply, and do so automatically. This happens even if no reply frame address is set -- in that case, it sends a default empty reply.



When all this is done, the host sends an automatic acknowledgement frame to the connected clients. This frame is different from the standard 802.11 ack in that it is received like a regular frame and processed by the clients. The standard ack isn't exposed to software.



If any replies are missing, the host will attempt to repeat the whole process (maybe altering the client bitmask so the clients that replied successfully aren't polled again, I haven't checked), if there is enough time left -- the CMDCOUNT timer defines a window during which the transfer is possible. When sending packets, it needs to wait until noone else is sending things, crosstalk isn't a good idea. Regular TX slots seem to keep waiting until the channel is free, but the CMD slot can abort if it has waited for too long.



All in all, a neat piece of hardware. You can guess that missing details on all this doesn't help getting multiplay working, especially as there are various status bits that get set here and there during the process, some of which are crucial.





So I set to work. I managed to replicate multiplay communication between two DS's with homebrew, and used it to work out the details. This, coupled with reverse-engineering of the Pictochat code, allowed to finally get it working in melonDS.







It isn't perfect, but this is definitely progress, as neither DeSmuME nor NO$GBA have gotten this far. As far as Pictochat is concerned, it appears that host->client transfers work fine, but client->host transfers sometimes get partially corrupted or lost entirely (and cause the client to get stuck unable to send).



NSMB MvsL also works, and seems rather stable, even though it can disconnect on you. There is some slowdown which appears to be caused by data loss.



There are also issues stemming from the communication medium used, namely, plain old BSD sockets. With UDP, it's easy and cross-platform, but there are issues. Binding to 127.0.0.1 gave the best results for me with Pictochat under Windows, but I got feedback that it doesn't work under Linux. Binding to all possible addresses works under both Window and Linux, but seemed to be worse for Pictochat, while being better for some other games. So we need to work on this too. BSD sockets have the advantage that they allow playing on separate computers over LAN (in theory -- this hasn't been tested), but maybe we will need faster IPC methods. Multiplayer sends packets at an amazing rate (Pictochat sends every ~4ms), so the communication medium has to keep up with this.





Stay tuned for more exciting reports!



melonDS Patreon