diff --git a/src/gba/gba-gpio.c b/src/gba/gba-gpio.c index c8486e296..b11a9b27e 100644 --- a/src/gba/gba-gpio.c +++ b/src/gba/gba-gpio.c @@ -38,9 +38,13 @@ static const int RTC_BYTES[8] = { }; void GBAGPIOInit(struct GBACartridgeGPIO* gpio, uint16_t* base) { + gpio->gpioBase = base; + GBAGPIOClear(gpio); +} + +void GBAGPIOClear(struct GBACartridgeGPIO* gpio) { gpio->gpioDevices = GPIO_NONE; gpio->direction = GPIO_WRITE_ONLY; - gpio->gpioBase = base; gpio->pinState = 0; gpio->direction = 0; } diff --git a/src/gba/gba-gpio.h b/src/gba/gba-gpio.h index 24716320a..458abdf9f 100644 --- a/src/gba/gba-gpio.h +++ b/src/gba/gba-gpio.h @@ -11,6 +11,7 @@ #define IS_GPIO_REGISTER(reg) ((reg) == GPIO_REG_DATA || (reg) == GPIO_REG_DIRECTION || (reg) == GPIO_REG_CONTROL) enum GPIODevice { + GPIO_NO_OVERRIDE = 0x8000, GPIO_NONE = 0, GPIO_RTC = 1, GPIO_RUMBLE = 2, @@ -114,6 +115,7 @@ struct GBACartridgeGPIO { }; void GBAGPIOInit(struct GBACartridgeGPIO* gpio, uint16_t* gpioBase); +void GBAGPIOClear(struct GBACartridgeGPIO* gpio); void GBAGPIOWrite(struct GBACartridgeGPIO* gpio, uint32_t address, uint16_t value); void GBAGPIOInitRTC(struct GBACartridgeGPIO* gpio); diff --git a/src/gba/gba-overrides.c b/src/gba/gba-overrides.c index d82ccda8f..cd314cc34 100644 --- a/src/gba/gba-overrides.c +++ b/src/gba/gba-overrides.c @@ -173,27 +173,35 @@ bool GBAOverrideFind(const struct Configuration* config, struct GBACartridgeOver } void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* override) { - GBASavedataForceType(&gba->memory.savedata, override->savetype); - - if (override->hardware & GPIO_RTC) { - GBAGPIOInitRTC(&gba->memory.gpio); + if (override->savetype != SAVEDATA_AUTODETECT) { + GBASavedataForceType(&gba->memory.savedata, override->savetype); } - if (override->hardware & GPIO_GYRO) { - GBAGPIOInitGyro(&gba->memory.gpio); + if (override->hardware != GPIO_NO_OVERRIDE) { + GBAGPIOClear(&gba->memory.gpio); + + if (override->hardware & GPIO_RTC) { + GBAGPIOInitRTC(&gba->memory.gpio); + } + + if (override->hardware & GPIO_GYRO) { + GBAGPIOInitGyro(&gba->memory.gpio); + } + + if (override->hardware & GPIO_RUMBLE) { + GBAGPIOInitRumble(&gba->memory.gpio); + } + + if (override->hardware & GPIO_LIGHT_SENSOR) { + GBAGPIOInitLightSensor(&gba->memory.gpio); + } + + if (override->hardware & GPIO_TILT) { + GBAGPIOInitTilt(&gba->memory.gpio); + } } - if (override->hardware & GPIO_RUMBLE) { - GBAGPIOInitRumble(&gba->memory.gpio); + if (override->idleLoop != 0xFFFFFFFF) { + gba->busyLoop = override->idleLoop; } - - if (override->hardware & GPIO_LIGHT_SENSOR) { - GBAGPIOInitLightSensor(&gba->memory.gpio); - } - - if (override->hardware & GPIO_TILT) { - GBAGPIOInitTilt(&gba->memory.gpio); - } - - gba->busyLoop = override->idleLoop; } diff --git a/src/gba/gba-savedata.c b/src/gba/gba-savedata.c index 19213f2dd..0a11b794c 100644 --- a/src/gba/gba-savedata.c +++ b/src/gba/gba-savedata.c @@ -113,6 +113,11 @@ bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out) { } void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type) { + if (savedata->type != SAVEDATA_AUTODETECT) { + struct VFile* vf = savedata->vf; + GBASavedataDeinit(savedata); + GBASavedataInit(savedata, vf); + } switch (type) { case SAVEDATA_FLASH512: case SAVEDATA_FLASH1M: diff --git a/src/gba/gba-thread.c b/src/gba/gba-thread.c index 9aa5f1008..7a46cbbdd 100644 --- a/src/gba/gba-thread.c +++ b/src/gba/gba-thread.c @@ -8,7 +8,6 @@ #include "arm.h" #include "gba.h" #include "gba-config.h" -#include "gba-overrides.h" #include "gba-serialize.h" #include "debugger/debugger.h" @@ -146,6 +145,9 @@ static THREAD_ENTRY _GBAThreadRun(void* context) { if (GBAOverrideFind(threadContext->overrides, &override)) { GBAOverrideApply(&gba, &override); } + if (threadContext->hasOverride) { + GBAOverrideApply(&gba, &threadContext->override); + } if (threadContext->bios && GBAIsBIOS(threadContext->bios)) { GBALoadBIOS(&gba, threadContext->bios); diff --git a/src/gba/gba-thread.h b/src/gba/gba-thread.h index 7c1d6e795..fdf084745 100644 --- a/src/gba/gba-thread.h +++ b/src/gba/gba-thread.h @@ -10,6 +10,7 @@ #include "gba.h" #include "gba-input.h" +#include "gba-overrides.h" #include "util/threading.h" @@ -72,6 +73,9 @@ struct GBAThread { struct GBAAVStream* stream; struct Configuration* overrides; + bool hasOverride; + struct GBACartridgeOverride override; + // Run-time options int frameskip; float fpsTarget; diff --git a/src/platform/qt/GameController.cpp b/src/platform/qt/GameController.cpp index c67080526..890ad658a 100644 --- a/src/platform/qt/GameController.cpp +++ b/src/platform/qt/GameController.cpp @@ -140,6 +140,11 @@ GameController::~GameController() { delete[] m_drawContext; } +void GameController::setOverride(const GBACartridgeOverride& override) { + m_threadContext.override = override; + m_threadContext.hasOverride = true; +} + #ifdef USE_GDB_STUB ARMDebugger* GameController::debugger() { return m_threadContext.debugger; diff --git a/src/platform/qt/GameController.h b/src/platform/qt/GameController.h index b570450af..a7c97f7a1 100644 --- a/src/platform/qt/GameController.h +++ b/src/platform/qt/GameController.h @@ -56,6 +56,9 @@ public: void setInputController(InputController* controller) { m_inputController = controller; } void setOverrides(Configuration* overrides) { m_threadContext.overrides = overrides; } + void setOverride(const GBACartridgeOverride& override); + void clearOverride() { m_threadContext.hasOverride = false; } + #ifdef USE_GDB_STUB ARMDebugger* debugger(); void setDebugger(ARMDebugger*); diff --git a/src/platform/qt/GamePakView.cpp b/src/platform/qt/GamePakView.cpp index c069aeb98..261e2bf4c 100644 --- a/src/platform/qt/GamePakView.cpp +++ b/src/platform/qt/GamePakView.cpp @@ -38,46 +38,99 @@ GamePakView::GamePakView(GameController* controller, QWidget* parent) m_ui.time->setDateTime(QDateTime::currentDateTime()); }); + connect(m_ui.hwAutodetect, &QAbstractButton::toggled, [this] (bool enabled) { + m_ui.hwRTC->setEnabled(!enabled); + m_ui.hwGyro->setEnabled(!enabled); + m_ui.hwLight->setEnabled(!enabled); + m_ui.hwTilt->setEnabled(!enabled); + m_ui.hwRumble->setEnabled(!enabled); + }); + + connect(m_ui.savetype, SIGNAL(currentIndexChanged(int)), this, SLOT(updateOverrides())); + connect(m_ui.hwAutodetect, SIGNAL(clicked()), this, SLOT(updateOverrides())); + connect(m_ui.hwRTC, SIGNAL(clicked()), this, SLOT(updateOverrides())); + connect(m_ui.hwGyro, SIGNAL(clicked()), this, SLOT(updateOverrides())); + connect(m_ui.hwLight, SIGNAL(clicked()), this, SLOT(updateOverrides())); + connect(m_ui.hwTilt, SIGNAL(clicked()), this, SLOT(updateOverrides())); + connect(m_ui.hwRumble, SIGNAL(clicked()), this, SLOT(updateOverrides())); + if (controller->isLoaded()) { gameStarted(controller->thread()); } } +void GamePakView::updateOverrides() { + GBACartridgeOverride override = { + "", + static_cast(m_ui.savetype->currentIndex() - 1), + GPIO_NO_OVERRIDE, + 0xFFFFFFFF + }; + + if (!m_ui.hwAutodetect->isChecked()) { + override.hardware = GPIO_NONE; + if (m_ui.hwRTC->isChecked()) { + override.hardware |= GPIO_RTC; + } + if (m_ui.hwGyro->isChecked()) { + override.hardware |= GPIO_GYRO; + } + if (m_ui.hwLight->isChecked()) { + override.hardware |= GPIO_LIGHT_SENSOR; + } + if (m_ui.hwTilt->isChecked()) { + override.hardware |= GPIO_TILT; + } + if (m_ui.hwRumble->isChecked()) { + override.hardware |= GPIO_RUMBLE; + } + } + + if (override.savetype != SAVEDATA_AUTODETECT || override.hardware != GPIO_NO_OVERRIDE) { + m_controller->setOverride(override); + } else { + m_controller->clearOverride(); + } +} + void GamePakView::gameStarted(GBAThread* thread) { if (!thread->gba) { gameStopped(); return; } - SavedataType savetype = thread->gba->memory.savedata.type; - if (m_ui.savetype->currentIndex() > 0) { - if (savetype > SAVEDATA_FORCE_NONE) { - VFile* vf = thread->gba->memory.savedata.vf; - GBASavedataDeinit(&thread->gba->memory.savedata); - GBASavedataInit(&thread->gba->memory.savedata, vf); - } - savetype = static_cast(m_ui.savetype->currentIndex() - 1); - GBASavedataForceType(&thread->gba->memory.savedata, savetype); - } - - if (savetype > SAVEDATA_AUTODETECT) { - m_ui.savetype->setCurrentIndex(savetype + 1); - } + m_ui.savetype->setCurrentIndex(thread->gba->memory.savedata.type + 1); m_ui.savetype->setEnabled(false); - m_ui.sensorRTC->setChecked(thread->gba->memory.gpio.gpioDevices & GPIO_RTC); - m_ui.sensorGyro->setChecked(thread->gba->memory.gpio.gpioDevices & GPIO_GYRO); - m_ui.sensorLight->setChecked(thread->gba->memory.gpio.gpioDevices & GPIO_LIGHT_SENSOR); - m_ui.sensorTilt->setChecked(thread->gba->memory.gpio.gpioDevices & GPIO_TILT); + m_ui.hwAutodetect->setEnabled(false); + m_ui.hwRTC->setEnabled(false); + m_ui.hwGyro->setEnabled(false); + m_ui.hwLight->setEnabled(false); + m_ui.hwTilt->setEnabled(false); + m_ui.hwRumble->setEnabled(false); + + m_ui.hwRTC->setChecked(thread->gba->memory.gpio.gpioDevices & GPIO_RTC); + m_ui.hwGyro->setChecked(thread->gba->memory.gpio.gpioDevices & GPIO_GYRO); + m_ui.hwLight->setChecked(thread->gba->memory.gpio.gpioDevices & GPIO_LIGHT_SENSOR); + m_ui.hwTilt->setChecked(thread->gba->memory.gpio.gpioDevices & GPIO_TILT); + m_ui.hwRumble->setChecked(thread->gba->memory.gpio.gpioDevices & GPIO_RUMBLE); } void GamePakView::gameStopped() { m_ui.savetype->setCurrentIndex(0); m_ui.savetype->setEnabled(true); - m_ui.sensorRTC->setChecked(false); - m_ui.sensorGyro->setChecked(false); - m_ui.sensorLight->setChecked(false); - m_ui.sensorTilt->setChecked(false); + m_ui.hwAutodetect->setEnabled(true); + m_ui.hwRTC->setEnabled(!m_ui.hwAutodetect->isChecked()); + m_ui.hwGyro->setEnabled(!m_ui.hwAutodetect->isChecked()); + m_ui.hwLight->setEnabled(!m_ui.hwAutodetect->isChecked()); + m_ui.hwTilt->setEnabled(!m_ui.hwAutodetect->isChecked()); + m_ui.hwRumble->setEnabled(!m_ui.hwAutodetect->isChecked()); + + m_ui.hwRTC->setChecked(false); + m_ui.hwGyro->setChecked(false); + m_ui.hwLight->setChecked(false); + m_ui.hwTilt->setChecked(false); + m_ui.hwRumble->setChecked(false); } void GamePakView::setLuminanceValue(int value) { diff --git a/src/platform/qt/GamePakView.h b/src/platform/qt/GamePakView.h index ea1e481b3..bcc51e15f 100644 --- a/src/platform/qt/GamePakView.h +++ b/src/platform/qt/GamePakView.h @@ -23,6 +23,7 @@ public: GamePakView(GameController* controller, QWidget* parent = nullptr); private slots: + void updateOverrides(); void gameStarted(GBAThread*); void gameStopped(); void setLuminanceValue(int); diff --git a/src/platform/qt/GamePakView.ui b/src/platform/qt/GamePakView.ui index c7c564a6f..5e4e0aaaf 100644 --- a/src/platform/qt/GamePakView.ui +++ b/src/platform/qt/GamePakView.ui @@ -6,8 +6,8 @@ 0 0 - 259 - 373 + 251 + 391 @@ -39,15 +39,12 @@ - Sensors + Hardware - - - false - + Autodetect @@ -57,7 +54,7 @@ - + false @@ -67,7 +64,7 @@ - + false @@ -77,7 +74,7 @@ - + false @@ -87,7 +84,7 @@ - + false @@ -137,6 +134,16 @@ + + + + false + + + Rumble + + +