WavePhoenix
Was keeping this under wraps until I was pretty confident it was doable, but wanted to share what I've been working on for the past month or so...
WavePhoenix is an open-source implementation of the Nintendo WaveBird protocol using off-the-shelf Silicon Labs Wireless Gecko SoCs. I plan on sharing the firmware source and reference hardware designs as soon as I'm confident the performance is close to, or exceeds, the OEM WaveBird receivers.
History
The WaveBird controller is, in my opinion, the best controller ever made. It is wireless, has a insane battery life, and is very comfortable to hold. Unfortunately, Nintendo stopped production of the WaveBird more than a decade ago, causing an dwindling supply of controllers, and especially the receivers.
Given the decreasing supply of receivers, and the increasing resale prices, I decided to see if I could design my own from scratch.
I was already familiar with the wired GameCube controller protocol, but I had never worked with the wireless side before. In mid 2020 I began researching the WaveBird protocol, and came across Sam Edwards' incredibly well written WaveBird reverse-engineering documentation. Sam's docs aren't quite perfect, but were pretty damn essential in getting this working, thanks Sam!
The most challenging part of this project was finding a wireless SoC that supported the modulation used by the WaveBird. What Sam describes in the line coding and framing section of his document is actually FSK-DSSS (Frequency Shift Keying with Direct Sequence Spread Spectrum), one which uses 15 chips per bit.
DSSS is a modulation technique that spreads the signal over a wide frequency band, making it more robust to interference and noise, here's a great breakdown by GeekyMuch.
While it would certainly be possible to implement 15-chip DSSS demodulation in a software defined radio, I wanted to find a SoC that could do this in hardware. After reading more datasheets than I care to admit, I discovered the SiLabs EFR32FG1 family of SoCs, the datasheet contains the magic incatation:
Chapter One: Receiving a Packet
I spent quite a while theory-crafting on this project, but finding a compatible SoC was the essential unblocking step. I bought a devkit for a Silicon Labs EFR32FG1 SoC, and started playing around with radio settings in the (godawful) Silicon Labs IDE. As I mentioned above, Sam's WaveBird reverse engineering documentation isn't /quite/ right on a few things. Most importantly the DSSS chip length I don't believe is accurate. After setting the DSSS chip length to 15, I got my first packet!
Chapter Two: Decoding a Packet
A bunch of hex isn't that helpful, so we need to turn that into actual controller input data. As a proof of concept, I wrote some C code to decode these packets on my laptop. Decoding these packets requires shuffling bits around, and decoding BCH(31,21) codewords, which are used for forward error correction:
Now we're talking!
Once I had the basic packet decoding, I then had to implement the CRC checking, which was also fairly straightforward. Surprisingly the full packet decoding logic fits in under 100 lines of C.
Chapter Three: Decoding Packets on the SoC
Decoding on my laptop helped me confirm the algorithms were solid, but is useless for an actual WaveBird receiver. Next step was to get the packets decoding in on the actual SoC. The WaveBird sends 480 packets per second, and we need to decode them in real time.
Turns out I was able to use my proof of concept C code almost exactly as-is on the SoC itself. Did I tell you I love C?
Chapter Four: Communicating with a GameCube
Now we have real-time packet decoding, the next step is do send/receive commands on the SI bus. The SI bus is how GameCube/Wii consoles communicate with connected controllers. @jefflongo has an insanely detailed and clear writeup about the GameCube controller protocol which you should definitely check out!
This part of the project was a big learning curve for me, since you have to communicate hella fast as we say here in northern California. Bits are clocked in and out at speeds between 250kHz (OEM controllers) and 200kHz (consoles). It is essential to do this without tying up the CPU, so I had to take full advantage of the peripherals on the EFR32 SoCs.
Receiving commands:
- First we listen for SI commands by configuring a TIMER peripheral in capture/compare mode, and attaching it to the SI GPIO
- Then we connect this to an LDMA peripheral, and fill the DMA buffer with 16 "edges" at a time
- Once we have 16 edges, an interrupt fires, and we measure the time between edges to determine how long each "low" pulse was
- Based on the length of a low pulse, we store either a 0 or a 1 in our incoming byte buffer
- Repeat until we have a complete SI command
- Again, we'll use a TIMER peripheral, but this time in PWM mode
- Based on the byte data we want to send, we'll fill a buffer with pulse widths which correspond to the correct SI pulses
- We then activate another LDMA channel to move to the next pulse width in the buffer, after every clock cycle
Putting this all together, we finally get:
Chapter Five: A new
So the EFR32F1 SoC is great, but it is fairly old, and not the cheapest SoC out there. I really wanted to be able to run this on the Silicon Labs Gecko Series 2 SoCs, since they are cheaper and have really nice modules available which have onboard crystals and chip antennae.
Almost all of my code ported across as-is, but the radio on these devices is slightly different - different enough that I'm still working on tuning it as we speak.
One of the cool things about the Series 2 SoCs is they have a new compact (and reasonably priced) dev board - the EFR32xG22E Explorer Kit. Abusing the onboard qwiic connector gives us something that looks familiar:
The Road to Release
- Tune the radio settings to ensure little-to-no packets get dropped
- Move to using proper BCH(31,21) decoding to get the benefits of actual error correction
- Build a reference hardware design with the MGM210P module (and/or raw SoC+xtal+antenna)
I'd ideally love to have a version of GC+ which can (optionally) work as a WaveBird receiver. Since I've done the work of implementing the SI bus communications already on this SoC, and this module has (just!) enough GPIOs for all the digital and analog inputs, in theory I should be able to make a footprint compatible board which adds WaveBird support to portables.
Here's a photo of the SiliconLabs Gecko SoC module on top of a GC+ for scale.
Epilogue: The Far Future
This SoC not only supports proprietary 2.4GHz protocols, but also has a full Bluetooth stack on it! In theory it should be possible to have this not only act as a WaveBird receiver, but also as a Bluetooth HID receiver too!
I'd also really like to make a USB-HID wavebird dongle, so you can play Dolphin with a real WaveBird without any additional adapters or cables.
I'd love to make both of these a reality down the line.
Thanks for sticking around for the long read! Keep your fingers crossed I can get the radio tuning nailed down.
Attachments
-
14.2 KB Views: 38
Last edited: