My Nintendo DS Broadcasts Radio (kinda)
My Nintendo DS Broadcasts Radio (kinda)
nintendo-ds radio c networking · 2026-06-07 · Loading views...
I've had a hacked Nintendo DS for a while, and I always wanted to write something for it. I tried once before and gave up. This time I had a better excuse.
See, I'm also developing BotWave as one of my many projects, and if you don't know what it is, it's basically a software for Raspberry Pis that lets them broadcast FM radio.
Now you're probably telling yourself: but a DS isn't a Raspberry Pi?
And you're right. But see, BotWave has a remote command feature, that basically exposes a WebSocket acting as a cli interface, making a bridge between the internal commands and external scripts.
This blog post will document how I managed to build a setup managing the DS and the Raspberry Pi to communicate anywhere, anytime, and broadcast some cool songs.
devkitPro
My first goal was to get an "Hello, world!" displayed on my DS screen. To do this, the easiest way seemed to install devkitPro on my system.
As said on their GitHub homepage: devkitPro is an organization dedicated to providing useful tools and libraries targeting a variety of (primarily Nintendo) game consoles.
They provide the required libraries and tools to build .nds files. Those files are ROMs for either emulators to load, or custom firmware running on the hardware console, such as Wood R4 that I use.
As for the hello world, it was fairly easy since the examples provide one:
#include<br>#include
int main(void) {<br>consoleDemoInit();
iprintf("Hello, World!\n");
while (1) {<br>swiWaitForVBlank();
return 0;
To test it, I used the melonDS emulator:
Accessing A Network
The only way for a DS to access a network is using Wifi, but you can probably guess that it isn't this easy using a 2004 console.
First of all, the wifi settings on a Nintendo DS are managed in some obscure on-card way, and accessing them is terrible. Here is how I managed to do it:
I loaded Mariokart DS
I went on the Nintendo WFC (W i-F i C onnection)
Then I accessed the settings
And finally I had access to the WiFi settings
And then, another limitation: the DS accepts either unauthenticated networks or WEP-protected ones, that neither my phone or my router support. So I just went with an unprotected access point. Oh, and no 5GHz, obviously.
Fortunately, programmatically speaking, devkitPro provides a dswifi9 lib that handles all that mess on its own and we just have to Wifi_InitDefault(WFC_CONNECT).
The Side-Quest
After that, I started messing a bit with raw sockets, but sadly the only record I have of that is this image:
Anyways, it rapidly became evident that I would definitely not connect to the BotWave remote connection using WebSocket. It's already a miracle if I can get it to work with a TCP socket.
So I had to build a compatibility bridge, running on the pi, that sits between the BotWave WS and the connecting DS.
As for the code, it was quickly done by Gemini, since it's a small ~200 lines script.
The challenging part was integrating it with BotWave itself. Since I wanted it to be easily reusable for other projects, I had to make it self-contained and easy to plug into any BotWave setup.
First of all, having a python script is nice, but integrating it can rapidly become a mess. That's why I made two small shell scripts, to start and stop the program.
Since it isn't the main thing of this blog post, I won't explain how it works in details, but you can find the full project on GitHub.
To do a rapid summary, the starter script takes the value into REMOTE_CMD_PORT to retrieve the WS port, and then either takes its first argument for the TCP socket port, or defaults to 9940. After parsing the values, it starts the python script as a background process.
The stop script creates a /tmp/killwtt, that the bridge continuously watches, and stops itself if it exists.
All of those scripts are automatically ran using BotWave handlers and custom commands.
As a result, I now can connect to BotWave using a raw TCP socket, which will make it way easier to access it for our DS:
Building the Software
Now that the bridge was running, I had to actually write the DS client.
The first real challenge was the socket. The DS network stack is functional, but the default behavior is blocking, meaning if nothing comes in, the whole program just freezes waiting. On a console where you need to be scanning inputs and redrawing the screen every frame, that's a death sentence.
The fix is FIONBIO, a flag you pass to ioctl to make the socket non-blocking. After that, recv returns immediately whether there's data or not, and you just check errno for EAGAIN to know if it was empty.
int iMode = 1;<br>ioctl(g_sock, FIONBIO, &iMode);
One line. Took some hours to get there though.
As for the software itself, the concept is simple: the DS connects to the bridge, sends commands, and parses the responses to update the UI. And since it's a DS — two...