Skip to content

Commit

Permalink
Implement Rumble Pak support. (#2101)
Browse files Browse the repository at this point in the history
  • Loading branch information
BueniaDev authored Jul 21, 2024
1 parent 5eadd67 commit 9b828c2
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 4 deletions.
43 changes: 42 additions & 1 deletion src/GBACart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,44 @@ void CartRAMExpansion::ROMWrite(u32 addr, u16 val)
}
}

CartRumblePak::CartRumblePak(void* userdata) :
CartCommon(RumblePak),
UserData(userdata)
{
}

CartRumblePak::~CartRumblePak() = default;

void CartRumblePak::Reset()
{
RumbleState = 0;
}

void CartRumblePak::DoSavestate(Savestate* file)
{
CartCommon::DoSavestate(file);
file->Var16(&RumbleState);
}

u16 CartRumblePak::ROMRead(u32 addr) const
{
// A1 is pulled low on a real Rumble Pak, so return the
// necessary detection value here,
// and let the existing open bus implementation take care of the rest
return 0xFFFD;
}

void CartRumblePak::ROMWrite(u32 addr, u16 val)
{
addr &= 0x01FFFFFF;
if (RumbleState != val)
{
Platform::Addon_RumbleStop(UserData);
RumbleState = val;
Platform::Addon_RumbleStart(16, UserData);
}
}

GBACartSlot::GBACartSlot(melonDS::NDS& nds, std::unique_ptr<CartCommon>&& cart) noexcept : NDS(nds), Cart(std::move(cart))
{
}
Expand Down Expand Up @@ -821,13 +859,16 @@ void GBACartSlot::SetSaveMemory(const u8* savedata, u32 savelen) noexcept
}
}

void GBACartSlot::LoadAddon(int type) noexcept
void GBACartSlot::LoadAddon(void* userdata, int type) noexcept
{
switch (type)
{
case GBAAddon_RAMExpansion:
Cart = std::make_unique<CartRAMExpansion>();
break;
case GBAAddon_RumblePak:
Cart = std::make_unique<CartRumblePak>(userdata);
break;

default:
Log(LogLevel::Warn, "GBACart: !! invalid addon type %d\n", type);
Expand Down
22 changes: 21 additions & 1 deletion src/GBACart.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ enum CartType
Game = 0x101,
GameSolarSensor = 0x102,
RAMExpansion = 0x201,
RumblePak = 0x202,
};

// CartCommon -- base code shared by all cart types
Expand Down Expand Up @@ -189,6 +190,25 @@ class CartRAMExpansion : public CartCommon
u16 RAMEnable = 0;
};

// CartRumblePak -- DS Rumble Pak (used in various NDS games)
class CartRumblePak : public CartCommon
{
public:
CartRumblePak(void* userdata);
~CartRumblePak() override;

void Reset() override;

void DoSavestate(Savestate* file) override;

u16 ROMRead(u32 addr) const override;
void ROMWrite(u32 addr, u16 val) override;

private:
void* UserData;
u16 RumbleState = 0;
};

// possible inputs for GBA carts that might accept user input
enum
{
Expand Down Expand Up @@ -219,7 +239,7 @@ class GBACartSlot
[[nodiscard]] CartCommon* GetCart() noexcept { return Cart.get(); }
[[nodiscard]] const CartCommon* GetCart() const noexcept { return Cart.get(); }

void LoadAddon(int type) noexcept;
void LoadAddon(void* userdata, int type) noexcept;

/// @return The cart that was in the cart slot if any,
/// or \c nullptr if the cart slot was empty.
Expand Down
2 changes: 1 addition & 1 deletion src/NDS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,7 @@ void NDS::SetGBASave(const u8* savedata, u32 savelen)

void NDS::LoadGBAAddon(int type)
{
GBACartSlot.LoadAddon(type);
GBACartSlot.LoadAddon(UserData, type);
}

void NDS::LoadBIOS()
Expand Down
1 change: 1 addition & 0 deletions src/NDS.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ enum
enum
{
GBAAddon_RAMExpansion = 1,
GBAAddon_RumblePak = 2,
};

class SPU;
Expand Down
11 changes: 11 additions & 0 deletions src/Platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,17 @@ void Camera_Start(int num, void* userdata);
void Camera_Stop(int num, void* userdata);
void Camera_CaptureFrame(int num, u32* frame, int width, int height, bool yuv, void* userdata);

// interface for addon inputs

// Called by the DS Rumble Pak emulation to start the necessary
// rumble effects on the connected game controller, if available.
// @param len The duration of the controller rumble effect in milliseconds.
void Addon_RumbleStart(u32 len, void* userdata);

// Called by the DS Rumble Pak emulation to stop any necessary
// rumble effects on the connected game controller, if available.
void Addon_RumbleStop(void* userdata);

struct DynamicLibrary;

/**
Expand Down
5 changes: 5 additions & 0 deletions src/frontend/qt_sdl/EmuInstance.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ class EmuInstance
void inputInit();
void inputDeInit();
void inputLoadConfig();
void inputRumbleStart(melonDS::u32 len_ms);
void inputRumbleStop();

void setJoystick(int id);
int getJoystickID() { return joystickID; }
Expand Down Expand Up @@ -291,6 +293,9 @@ class EmuInstance

int joystickID;
SDL_Joystick* joystick;
SDL_GameController* controller;
bool hasRumble = false;
bool isRumbling = false;

melonDS::u32 keyInputMask, joyInputMask;
melonDS::u32 keyHotkeyMask, joyHotkeyMask;
Expand Down
45 changes: 45 additions & 0 deletions src/frontend/qt_sdl/EmuInstanceInput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ void EmuInstance::inputInit()
lastHotkeyMask = 0;

joystick = nullptr;
controller = nullptr;
hasRumble = false;
isRumbling = false;
inputLoadConfig();
}

Expand Down Expand Up @@ -100,6 +103,24 @@ void EmuInstance::inputLoadConfig()
setJoystick(localCfg.GetInt("JoystickID"));
}

void EmuInstance::inputRumbleStart(melonDS::u32 len_ms)
{
if (controller && hasRumble && !isRumbling)
{
SDL_GameControllerRumble(controller, 0xFFFF, 0xFFFF, len_ms);
isRumbling = true;
}
}

void EmuInstance::inputRumbleStop()
{
if (controller && hasRumble && isRumbling)
{
SDL_GameControllerRumble(controller, 0, 0, 0);
isRumbling = false;
}
}


void EmuInstance::setJoystick(int id)
{
Expand All @@ -109,23 +130,47 @@ void EmuInstance::setJoystick(int id)

void EmuInstance::openJoystick()
{
if (controller) SDL_GameControllerClose(controller);

if (joystick) SDL_JoystickClose(joystick);

int num = SDL_NumJoysticks();
if (num < 1)
{
controller = nullptr;
joystick = nullptr;
hasRumble = false;
return;
}

if (joystickID >= num)
joystickID = 0;

joystick = SDL_JoystickOpen(joystickID);

if (SDL_IsGameController(joystickID))
{
controller = SDL_GameControllerOpen(joystickID);
}

if (controller)
{
if (SDL_GameControllerHasRumble(controller))
{
hasRumble = true;
}
}
}

void EmuInstance::closeJoystick()
{
if (controller)
{
SDL_GameControllerClose(controller);
controller = nullptr;
hasRumble = false;
}

if (joystick)
{
SDL_JoystickClose(joystick);
Expand Down
10 changes: 10 additions & 0 deletions src/frontend/qt_sdl/Platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,16 @@ void Camera_CaptureFrame(int num, u32* frame, int width, int height, bool yuv, v
return camManager[num]->captureFrame(frame, width, height, yuv);
}

void Addon_RumbleStart(u32 len, void* userdata)
{
((EmuInstance*)userdata)->inputRumbleStart(len);
}

void Addon_RumbleStop(void* userdata)
{
((EmuInstance*)userdata)->inputRumbleStop();
}

DynamicLibrary* DynamicLibrary_Load(const char* lib)
{
return (DynamicLibrary*) SDL_LoadObject(lib);
Expand Down
4 changes: 4 additions & 0 deletions src/frontend/qt_sdl/Window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,10 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) :
actInsertGBAAddon[0] = submenu->addAction("Memory expansion");
actInsertGBAAddon[0]->setData(QVariant(GBAAddon_RAMExpansion));
connect(actInsertGBAAddon[0], &QAction::triggered, this, &MainWindow::onInsertGBAAddon);

actInsertGBAAddon[1] = submenu->addAction("Rumble Pak");
actInsertGBAAddon[1]->setData(QVariant(GBAAddon_RumblePak));
connect(actInsertGBAAddon[1], &QAction::triggered, this, &MainWindow::onInsertGBAAddon);
}

actEjectGBACart = menu->addAction("Eject cart");
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/qt_sdl/Window.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ private slots:
QAction* actEjectCart;
QAction* actCurrentGBACart;
QAction* actInsertGBACart;
QAction* actInsertGBAAddon[1];
QAction* actInsertGBAAddon[2];
QAction* actEjectGBACart;
QAction* actImportSavefile;
QAction* actSaveState[9];
Expand Down

0 comments on commit 9b828c2

Please sign in to comment.