An implementation of the Joybus protocol used by N64 and GameCube controllers, for 32-bit microcontrollers.

Features
- C implementation, no external dependencies (besides backend-specific SDKs)
- Provides both host mode and target mode functionality
- Host mode allows communication with N64/GameCube controllers from a microcontroller
- Target mode allows you to build custom N64/GameCube controllers using a microcontroller
- Near-ASIC timing accuracy for reliable communication
- Pre-built targets for N64 controllers and GameCube controllers
Supported Platforms
- Raspberry Pi Pico and Pico 2 (and other RP2xxx-based boards)
- Silicon Labs EFR32 Series 1 and Series 2 MCUs
Examples
The project is used in WavePhoenix, an open source implementation of a GameCube WaveBird receiver.
You can find a number of additonal examples in the examples/ directory, including a full implementation of the GameCube USB adapter for Pi Pico.
Please let me know if you build something with libjoybus! I love seeing my projects used in the wild, and I'll consider adding it to the examples list!
Usage
You can find the full API documentation here, but here are some basic examples to get you started.
Initializing the Joybus
Before using libjoybus, you need to initialize the Joybus interface for your platform. Here's an example for the RP2040:
#include <joybus/joybus.h>
#include <joybus/backend/rp2xxx.h>
int main() {
return 0;
}
int joybus_rp2xxx_init(struct joybus_rp2xxx *rp2xxx_bus, uint8_t gpio, PIO pio)
Initialize a RP2xxx Joybus instance.
Definition joybus.c:427
#define JOYBUS(bus)
Macro to cast a backend-specific Joybus instance to a generic Joybus instance.
Definition bus.h:35
A RP2xxx Joybus instance.
Definition rp2xxx.h:60
A Joybus instance.
Definition bus.h:59
Communicating with Controllers
In host mode, libjoybus allows a microcontroller to communicate with N64 and GameCube controllers. This allows you to use input data from N64 and GameCube controllers in your projects.
#include <joybus/joybus.h>
#include <joybus/host/gamecube.h>
void poll_cb(
struct joybus *bus,
int result,
void *user_data) {
}
}
void main() {
while (1) {
poll_cb, NULL);
sleep_ms(10);
}
}
@ JOYBUS_GCN_MOTOR_STOP
Stop the rumble motor.
Definition gamecube.h:86
@ JOYBUS_GCN_ANALOG_MODE_3
Substick X/Y and triggers full precision, analog A/B omitted.
Definition gamecube.h:75
#define JOYBUS_GCN_BUTTON_A
GameCube controller button bitmask flags.
Definition gamecube.h:11
int joybus_gcn_read(struct joybus *bus, enum joybus_gcn_analog_mode analog_mode, enum joybus_gcn_motor_state motor_state, uint8_t *response, joybus_transfer_cb_t callback, void *user_data)
Read the current input state of a GameCube controller.
Definition gamecube.c:6
int joybus_gcn_unpack_input(struct joybus_gc_controller_input *dest, const uint8_t *src, enum joybus_gcn_analog_mode analog_mode)
Unpack raw input data from a GameCube controller.
Definition gamecube.c:68
static int joybus_enable(struct joybus *bus)
Enable the Joybus instance.
Definition bus.h:71
#define JOYBUS_BLOCK_SIZE
Maximum size of a Joybus transfer, in bytes.
Definition bus.h:24
Emulating a Controller
In target mode, libjoybus allows a microcontroller to act as an N64 or GameCube controller. This allows you to create custom controllers that can interface with N64, GameCube, and Wii consoles.
I've provided built-in targets for N64 controllers and GameCube controllers so you can just populate the input state and let libjoybus handle the rest.
#include <joybus/joybus.h>
#include <joybus/target/gc_controller.h>
void main() {
while (1) {
controller.input.buttons &= ~JOYBUS_GCN_BUTTON_MASK;
controller.input.stick_x = 200;
controller.input.stick_y = 200;
sleep_ms(10);
}
}
#define JOYBUS_GAMECUBE_CONTROLLER
Device type for a standard GameCube controller.
Definition commands.h:116
void joybus_gc_controller_init(struct joybus_gc_controller *controller, uint16_t type)
Initialize a GameCube controller.
Definition gc_controller.c:352
#define JOYBUS_TARGET(target)
Macro to cast a concrete Joybus target instance to a generic Joybus target instance.
Definition target.h:15
static int joybus_target_register(struct joybus *bus, struct joybus_target *target)
Enable Joybus "target" mode, and register a target to handle commands.
Definition bus.h:115
GameCube controller Joybus target.
Definition gc_controller.h:39
Special Thanks
The (insane) accessory detection logic for N64 accessory paks is heavily based on the implementation in the fantastic libdragon, which I consider the gold standard for this.
License
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.