diff --git a/CMakeLists.txt b/CMakeLists.txt index 06ddaf7..ff68450 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,15 @@ target_include_directories( src src/libc ) +target_compile_options( + common PUBLIC + -Wall + -Wextra + -Wno-unused-parameter + $<$: + -Wno-pmf-conversions + > +) target_compile_definitions(common PUBLIC VERSION="${PROJECT_VERSION}") link_libraries(common) @@ -127,6 +136,7 @@ addExecutable( target_compile_definitions( main PRIVATE $, + ENABLE_AUTOBOOT=1 ENABLE_DUMMY_DRIVER=1 ENABLE_FULL_IDE_DRIVER=1 ENABLE_I2C_LOGGING=1 @@ -135,6 +145,7 @@ target_compile_definitions( ENABLE_PS1_CONTROLLER=1 #ENABLE_X76F100_DRIVER=1 , + ENABLE_AUTOBOOT=1 #ENABLE_DUMMY_DRIVER=1 ENABLE_FULL_IDE_DRIVER=1 #ENABLE_I2C_LOGGING=1 diff --git a/assets/app.strings.json b/assets/app.strings.json index 4982ae7..a180bc9 100644 --- a/assets/app.strings.json +++ b/assets/app.strings.json @@ -8,7 +8,8 @@ "ideInitWorker": { "initDrives": "Initializing IDE devices...\nDo not turn off the 573 or unplug drives.", "initFileIO": "Detecting and mounting filesystems...\nDo not turn off the 573 or unplug drives.", - "loadResources": "Loading resource pack...\nDo not turn off the 573 or unplug drives." + "loadResources": "Loading resource pack...\nDo not turn off the 573 or unplug drives.", + "autoboot": "Searching for boot executables...\nDo not turn off the 573 or unplug drives." }, "cartDetectWorker": { "readDigitalIO": "Retrieving digital I/O board ID...", @@ -110,6 +111,13 @@ } }, + "AutobootScreen": { + "title": "Note", + "body": "A valid boot executable has been found and will be launched shortly. You may disable automatic booting by turning off DIP switch 1 or creating a file named noboot.txt in the root of the filesystem.\n\nFile: %s", + + "cancel": "{START_BUTTON} Cancel (%ds)" + }, + "ButtonMappingScreen": { "title": "{RIGHT_ARROW} Select button mapping", "prompt": "Use {START_BUTTON} or the Test button to select a mapping preset suitable for your cabinet or JAMMA setup. Other buttons will be enabled once a mapping is selected.", diff --git a/src/common/io.hpp b/src/common/io.hpp index 3751b7d..e091af4 100644 --- a/src/common/io.hpp +++ b/src/common/io.hpp @@ -81,8 +81,8 @@ static inline void clearWatchdog(void) { SYS573_WATCHDOG = 0; } -static inline uint32_t getDIPSwitches(void) { - return SYS573_DIP_CART & 0xf; +static inline bool getDIPSwitch(int bit) { + return !((SYS573_DIP_CART >> bit) & 1); } static inline bool getCartInsertionStatus(void) { diff --git a/src/main/app/app.cpp b/src/main/app/app.cpp index e5cb6f4..8f3069a 100644 --- a/src/main/app/app.cpp +++ b/src/main/app/app.cpp @@ -18,12 +18,13 @@ /* Worker status class */ -void WorkerStatus::reset(void) { +void WorkerStatus::reset(ui::Screen &next, bool goBack) { status = WORKER_IDLE; progress = 0; progressTotal = 1; message = nullptr; - nextScreen = nullptr; + nextScreen = &next; + nextGoBack = goBack; } void WorkerStatus::update(int part, int total, const char *text) { @@ -38,30 +39,27 @@ void WorkerStatus::update(int part, int total, const char *text) { enableInterrupts(); } -void WorkerStatus::setStatus(WorkerStatusType value) { - auto enable = disableInterrupts(); - status = value; +ui::Screen &WorkerStatus::setNextScreen(ui::Screen &next, bool goBack) { + auto enable = disableInterrupts(); + auto oldNext = nextScreen; + nextScreen = &next; + nextGoBack = goBack; if (enable) enableInterrupts(); + + return *oldNext; } -void WorkerStatus::setNextScreen(ui::Screen &next, bool goBack) { - auto enable = disableInterrupts(); - _nextGoBack = goBack; - _nextScreen = &next; +WorkerStatusType WorkerStatus::setStatus(WorkerStatusType value) { + auto enable = disableInterrupts(); + auto oldStatus = status; + status = value; if (enable) enableInterrupts(); -} -void WorkerStatus::finish(void) { - auto enable = disableInterrupts(); - status = _nextGoBack ? WORKER_NEXT_BACK : WORKER_NEXT; - nextScreen = _nextScreen; - - if (enable) - enableInterrupts(); + return oldStatus; } /* Filesystem manager class */ @@ -96,11 +94,8 @@ void FileIOManager::initIDE(void) { continue; } - ide[i] = iso; - bool mapped = vfs.mount("cdrom:", iso, true); - - if (mapped) - LOG("mapped cdrom: -> %s", name); + ide[i] = iso; + vfs.mount("cdrom:", iso, true); } else { auto fat = new file::FATProvider(); @@ -109,11 +104,8 @@ void FileIOManager::initIDE(void) { continue; } - ide[i] = fat; - bool mapped = vfs.mount("hdd:", fat, true); - - if (mapped) - LOG("mapped hdd: -> %s", name); + ide[i] = fat; + vfs.mount("hdd:", fat, true); } vfs.mount(name, ide[i], true); @@ -199,26 +191,6 @@ void App::_unloadCartData(void) { //_selectedEntry = nullptr; } -void App::_setupWorker(bool (App::*func)(void)) { - LOG("restarting worker, func=0x%08x", func); - - auto enable = disableInterrupts(); - - _workerStack.allocate(_WORKER_STACK_SIZE); - _workerStatus.reset(); - - _workerFunction = func; - auto stackBottom = _workerStack.as(); - - initThread( - // This is not how you implement delegates in C++. - &_workerThread, util::forcedCast(&App::_worker), this, - &stackBottom[(_WORKER_STACK_SIZE - 1) & ~7] - ); - if (enable) - enableInterrupts(); -} - void App::_setupInterrupts(void) { setInterruptHandler( util::forcedCast(&App::_interruptHandler), this @@ -282,7 +254,7 @@ bool App::_getNumberedPath(char *output, size_t length, const char *path) { } bool App::_takeScreenshot(void) { - char path[32]; + char path[file::MAX_PATH_LENGTH]; if (!_createDataDirectory()) return false; @@ -299,10 +271,31 @@ bool App::_takeScreenshot(void) { return true; } +void App::_runWorker( + bool (App::*func)(void), ui::Screen &next, bool goBack, bool playSound +) { + auto enable = disableInterrupts(); + + _workerStatus.reset(next, goBack); + _workerStack.allocate(_WORKER_STACK_SIZE); + + _workerFunction = func; + auto stackBottom = _workerStack.as(); + + initThread( + &_workerThread, util::forcedCast(&App::_worker), this, + &stackBottom[(_WORKER_STACK_SIZE - 1) & ~7] + ); + if (enable) + enableInterrupts(); + + _ctx.show(_workerStatusScreen, false, playSound); +} + void App::_worker(void) { if (_workerFunction) { (this->*_workerFunction)(); - _workerStatus.finish(); + _workerStatus.setStatus(WORKER_DONE); } // Do nothing while waiting for vblank once the task is done. @@ -334,15 +327,6 @@ void App::_interruptHandler(void) { _fileIO.resource.init(resourcePtr, resourceLength); _loadResources(); -#ifdef NDEBUG - _workerStatus.setNextScreen(_warningScreen); -#else - // Skip the warning screen in debug builds. - _workerStatus.setNextScreen(_buttonMappingScreen); -#endif - _setupWorker(&App::_ideInitWorker); - _setupInterrupts(); - char dateString[24]; _textOverlay.leftText = dateString; @@ -357,7 +341,9 @@ void App::_interruptHandler(void) { _ctx.overlays[0] = &_logOverlay; #endif _ctx.overlays[1] = &_screenshotOverlay; - _ctx.show(_workerStatusScreen); + + _runWorker(&App::_ideInitWorker, _warningScreen); + _setupInterrupts(); for (;;) { util::Date date; diff --git a/src/main/app/app.hpp b/src/main/app/app.hpp index cd083e2..8b4701a 100644 --- a/src/main/app/app.hpp +++ b/src/main/app/app.hpp @@ -25,17 +25,12 @@ enum WorkerStatusType { WORKER_REBOOT = 1, WORKER_BUSY = 2, WORKER_BUSY_SUSPEND = 3, // Prevent main thread from running - WORKER_NEXT = 4, // Go to next screen (goBack=false) - WORKER_NEXT_BACK = 5 // Go to next screen (goBack=true) + WORKER_DONE = 4 // Go to next screen }; // This class is used by the worker thread to report its current status back to // the main thread and the WorkerStatusScreen. class WorkerStatus { -private: - volatile bool _nextGoBack; - ui::Screen *volatile _nextScreen; - public: volatile WorkerStatusType status; @@ -43,12 +38,12 @@ public: const char *volatile message; ui::Screen *volatile nextScreen; + volatile bool nextGoBack; - void reset(void); + void reset(ui::Screen &next, bool goBack = false); void update(int part, int total, const char *text = nullptr); - void setStatus(WorkerStatusType value); - void setNextScreen(ui::Screen &next, bool goBack = false); - void finish(void); + ui::Screen &setNextScreen(ui::Screen &next, bool goBack = false); + WorkerStatusType setStatus(WorkerStatusType value); }; /* Filesystem manager class */ @@ -86,6 +81,7 @@ class App { friend class ConfirmScreen; friend class FilePickerScreen; friend class FileBrowserScreen; + friend class AutobootScreen; friend class WarningScreen; friend class ButtonMappingScreen; friend class MainMenuScreen; @@ -112,6 +108,7 @@ private: ConfirmScreen _confirmScreen; FilePickerScreen _filePickerScreen; FileBrowserScreen _fileBrowserScreen; + AutobootScreen _autobootScreen; WarningScreen _warningScreen; ButtonMappingScreen _buttonMappingScreen; MainMenuScreen _mainMenuScreen; @@ -159,12 +156,15 @@ private: const cart::CartDBEntry *_identified, *_selectedEntry; void _unloadCartData(void); - void _setupWorker(bool (App::*func)(void)); void _setupInterrupts(void); void _loadResources(void); bool _createDataDirectory(void); bool _getNumberedPath(char *output, size_t length, const char *path); bool _takeScreenshot(void); + void _runWorker( + bool (App::*func)(void), ui::Screen &next, bool goBack = false, + bool playSound = false + ); // cartworkers.cpp bool _cartDetectWorker(void); diff --git a/src/main/app/cartactions.cpp b/src/main/app/cartactions.cpp index 0bc5795..0fee9d4 100644 --- a/src/main/app/cartactions.cpp +++ b/src/main/app/cartactions.cpp @@ -59,17 +59,18 @@ const char *CartActionsScreen::_getItemName(ui::Context &ctx, int index) const { } void CartActionsScreen::qrDump(ui::Context &ctx) { - if (APP->_qrCodeScreen.valid) { + if (APP->_qrCodeScreen.valid) ctx.show(APP->_qrCodeScreen, false, true); - } else { - APP->_setupWorker(&App::_qrCodeWorker); - ctx.show(APP->_workerStatusScreen, false, true); - } + else + APP->_runWorker(&App::_qrCodeWorker, APP->_qrCodeScreen, false, true); } void CartActionsScreen::hddDump(ui::Context &ctx) { - APP->_setupWorker(&App::_cartDumpWorker); - ctx.show(APP->_workerStatusScreen, false, true); + APP->_messageScreen.previousScreens[MESSAGE_SUCCESS] = + &(APP->_cartInfoScreen); + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = this; + + APP->_runWorker(&App::_cartDumpWorker, APP->_messageScreen, false, true); } void CartActionsScreen::hexdump(ui::Context &ctx) { @@ -77,18 +78,23 @@ void CartActionsScreen::hexdump(ui::Context &ctx) { } void CartActionsScreen::hddRestore(ui::Context &ctx) { + APP->_filePickerScreen.previousScreen = this; APP->_filePickerScreen.setMessage( - *this, [](ui::Context &ctx) { ctx.show(APP->_confirmScreen, false, true); }, STR("CartActionsScreen.hddRestore.filePrompt") ); + + APP->_confirmScreen.previousScreen = &(APP->_fileBrowserScreen); APP->_confirmScreen.setMessage( - APP->_fileBrowserScreen, [](ui::Context &ctx) { - APP->_setupWorker(&App::_cartRestoreWorker); - ctx.show(APP->_workerStatusScreen, false, true); + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = + &(APP->_fileBrowserScreen); + + APP->_runWorker( + &App::_cartRestoreWorker, APP->_cartInfoScreen, true, true + ); }, STR("CartActionsScreen.hddRestore.confirm") ); @@ -101,11 +107,15 @@ void CartActionsScreen::reflash(ui::Context &ctx) { } void CartActionsScreen::erase(ui::Context &ctx) { + APP->_confirmScreen.previousScreen = this; APP->_confirmScreen.setMessage( - *this, [](ui::Context &ctx) { - APP->_setupWorker(&App::_cartEraseWorker); - ctx.show(APP->_workerStatusScreen, false, true); + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = + &(APP->_cartActionsScreen); + + APP->_runWorker( + &App::_cartEraseWorker, APP->_cartInfoScreen, true, true + ); }, STR("CartActionsScreen.erase.confirm") ); @@ -115,22 +125,27 @@ void CartActionsScreen::erase(ui::Context &ctx) { void CartActionsScreen::resetSystemID(ui::Context &ctx) { if (!(APP->_cartParser->getIdentifiers()->systemID.isEmpty())) { + APP->_confirmScreen.previousScreen = this; APP->_confirmScreen.setMessage( - *this, [](ui::Context &ctx) { util::clear(APP->_cartParser->getIdentifiers()->systemID); APP->_cartParser->flush(); - APP->_setupWorker(&App::_cartWriteWorker); - ctx.show(APP->_workerStatusScreen, false, true); + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = + &(APP->_cartActionsScreen); + + APP->_runWorker( + &App::_cartWriteWorker, APP->_cartInfoScreen, true, true + ); }, STR("CartActionsScreen.resetSystemID.confirm") ); ctx.show(APP->_confirmScreen, false, true); } else { + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = this; APP->_messageScreen.setMessage( - MESSAGE_ERROR, *this, STR("CartActionsScreen.resetSystemID.error") + MESSAGE_ERROR, STR("CartActionsScreen.resetSystemID.error") ); ctx.show(APP->_messageScreen, false, true); @@ -139,24 +154,29 @@ void CartActionsScreen::resetSystemID(ui::Context &ctx) { void CartActionsScreen::matchSystemID(ui::Context &ctx) { if (APP->_cartDump.flags & cart::DUMP_SYSTEM_ID_OK) { + APP->_confirmScreen.previousScreen = this; APP->_confirmScreen.setMessage( - *this, [](ui::Context &ctx) { APP->_cartParser->getIdentifiers()->systemID.copyFrom( APP->_cartDump.systemID.data ); APP->_cartParser->flush(); - APP->_setupWorker(&App::_cartWriteWorker); - ctx.show(APP->_workerStatusScreen, false, true); + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = + &(APP->_cartActionsScreen); + + APP->_runWorker( + &App::_cartWriteWorker, APP->_cartInfoScreen, true, true + ); }, STR("CartActionsScreen.matchSystemID.confirm") ); ctx.show(APP->_confirmScreen, false, true); } else { + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = this; APP->_messageScreen.setMessage( - MESSAGE_ERROR, *this, STR("CartActionsScreen.matchSystemID.error") + MESSAGE_ERROR, STR("CartActionsScreen.matchSystemID.error") ); ctx.show(APP->_messageScreen, false, true); @@ -164,22 +184,6 @@ void CartActionsScreen::matchSystemID(ui::Context &ctx) { } void CartActionsScreen::editSystemID(ui::Context &ctx) { - APP->_confirmScreen.setMessage( - APP->_systemIDEntryScreen, - [](ui::Context &ctx) { - APP->_systemIDEntryScreen.setSystemID(*(APP->_cartParser)); - - APP->_setupWorker(&App::_cartWriteWorker); - ctx.show(APP->_workerStatusScreen, false, true); - }, - STR("CartActionsScreen.editSystemID.confirm") - ); - - APP->_messageScreen.setMessage( - MESSAGE_ERROR, APP->_systemIDEntryScreen, - STR("CartActionsScreen.editSystemID.error") - ); - APP->_systemIDEntryScreen.getSystemID(*(APP->_cartParser)); ctx.show(APP->_systemIDEntryScreen, false, true); } @@ -284,11 +288,16 @@ void ReflashGameScreen::update(ui::Context &ctx) { if (ctx.buttons.held(ui::BTN_LEFT) || ctx.buttons.held(ui::BTN_RIGHT)) { ctx.show(APP->_cartActionsScreen, true, true); } else { + APP->_confirmScreen.previousScreen = this; APP->_confirmScreen.setMessage( - *this, [](ui::Context &ctx) { - APP->_setupWorker(&App::_cartReflashWorker); - ctx.show(APP->_workerStatusScreen, false, true); + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = + &(APP->_reflashGameScreen); + + APP->_runWorker( + &App::_cartReflashWorker, APP->_cartInfoScreen, true, + true + ); }, STR("CartActionsScreen.reflash.confirm") ); @@ -319,10 +328,35 @@ void SystemIDEntryScreen::update(ui::Context &ctx) { if (_activeButton == _buttonIndexOffset) { ctx.show(APP->_cartActionsScreen, true, true); } else if (_activeButton == (_buttonIndexOffset + 1)) { - if (util::dsCRC8(_buffer, 7) == _buffer[7]) + if (util::dsCRC8(_buffer, 7) == _buffer[7]) { + APP->_confirmScreen.previousScreen = this; + APP->_confirmScreen.setMessage( + [](ui::Context &ctx) { + APP->_systemIDEntryScreen.setSystemID( + *(APP->_cartParser) + ); + + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = + &(APP->_systemIDEntryScreen); + + APP->_runWorker( + &App::_cartWriteWorker, APP->_cartInfoScreen, true, + true + ); + }, + STR("CartActionsScreen.editSystemID.confirm") + ); + ctx.show(APP->_confirmScreen, false, true); - else + } else { + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = this; + APP->_messageScreen.setMessage( + MESSAGE_ERROR, + STR("CartActionsScreen.editSystemID.error") + ); + ctx.show(APP->_messageScreen, false, true); + } } } } diff --git a/src/main/app/cartunlock.cpp b/src/main/app/cartunlock.cpp index f49fe50..833eca5 100644 --- a/src/main/app/cartunlock.cpp +++ b/src/main/app/cartunlock.cpp @@ -308,11 +308,16 @@ void UnlockKeyScreen::update(ui::Context &ctx) { auto &dump = APP->_cartDump; int offset = _getNumSpecialEntries(ctx); + APP->_confirmScreen.previousScreen = this; APP->_confirmScreen.setMessage( - APP->_unlockKeyScreen, [](ui::Context &ctx) { - APP->_setupWorker(&App::_cartUnlockWorker); - ctx.show(APP->_workerStatusScreen, false, true); + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = + &(APP->_unlockKeyScreen); + + APP->_runWorker( + &App::_cartUnlockWorker, APP->_cartInfoScreen, false, + true + ); }, STRH(_UNLOCK_WARNINGS[dump.chipType]) ); @@ -353,11 +358,16 @@ void KeyEntryScreen::update(ui::Context &ctx) { auto &dump = APP->_cartDump; // TODO: deduplicate this code (it is the same as UnlockKeyScreen) + APP->_confirmScreen.previousScreen = this; APP->_confirmScreen.setMessage( - APP->_unlockKeyScreen, [](ui::Context &ctx) { - APP->_setupWorker(&App::_cartUnlockWorker); - ctx.show(APP->_workerStatusScreen, false, true); + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = + &(APP->_keyEntryScreen); + + APP->_runWorker( + &App::_cartUnlockWorker, APP->_cartInfoScreen, false, + true + ); }, STRH(_UNLOCK_WARNINGS[dump.chipType]) ); diff --git a/src/main/app/cartworkers.cpp b/src/main/app/cartworkers.cpp index 228ea45..a2a5879 100644 --- a/src/main/app/cartworkers.cpp +++ b/src/main/app/cartworkers.cpp @@ -141,11 +141,9 @@ bool App::_cartUnlockWorker(void) { if (error) { _messageScreen.setMessage( - MESSAGE_ERROR, _cartInfoScreen, - WSTRH(_UNLOCK_ERRORS[_cartDump.chipType]), + MESSAGE_ERROR, WSTRH(_UNLOCK_ERRORS[_cartDump.chipType]), cart::getErrorString(error) ); - _workerStatus.setNextScreen(_messageScreen); return false; } @@ -189,7 +187,6 @@ bool App::_cartUnlockWorker(void) { bool App::_qrCodeWorker(void) { char qrString[cart::MAX_QR_STRING_LENGTH]; - _workerStatus.setNextScreen(_qrCodeScreen); _workerStatus.update(0, 2, WSTR("App.qrCodeWorker.compress")); _cartDump.toQRString(qrString); @@ -202,7 +199,7 @@ bool App::_qrCodeWorker(void) { bool App::_cartDumpWorker(void) { _workerStatus.update(0, 1, WSTR("App.cartDumpWorker.save")); - char path[32], code[8], region[8]; + char path[file::MAX_PATH_LENGTH], code[8], region[8]; size_t length = _cartDump.getDumpLength(); if (!_createDataDirectory()) @@ -228,17 +225,14 @@ bool App::_cartDumpWorker(void) { goto _error; _messageScreen.setMessage( - MESSAGE_SUCCESS, _cartInfoScreen, WSTR("App.cartDumpWorker.success"), - path + MESSAGE_SUCCESS, WSTR("App.cartDumpWorker.success"), path ); - _workerStatus.setNextScreen(_messageScreen); return true; _error: _messageScreen.setMessage( - MESSAGE_ERROR, _cartInfoScreen, WSTR("App.cartDumpWorker.error"), path + MESSAGE_ERROR, WSTR("App.cartDumpWorker.error"), path ); - _workerStatus.setNextScreen(_messageScreen); return false; } @@ -255,7 +249,7 @@ bool App::_cartWriteWorker(void) { if (error) { _messageScreen.setMessage( - MESSAGE_ERROR, _cartInfoScreen, WSTR("App.cartWriteWorker.error"), + MESSAGE_ERROR, WSTR("App.cartWriteWorker.error"), cart::getErrorString(error) ); _workerStatus.setNextScreen(_messageScreen); @@ -292,8 +286,7 @@ bool App::_cartRestoreWorker(void) { if (_cartDump.chipType != newDump.chipType) { _messageScreen.setMessage( - MESSAGE_ERROR, _fileBrowserScreen, - WSTR("App.cartRestoreWorker.typeError"), path + MESSAGE_ERROR, WSTR("App.cartRestoreWorker.typeError"), path ); _workerStatus.setNextScreen(_messageScreen); return false; @@ -322,8 +315,7 @@ bool App::_cartRestoreWorker(void) { if (error) { _messageScreen.setMessage( - MESSAGE_ERROR, _fileBrowserScreen, - WSTR("App.cartRestoreWorker.writeError"), + MESSAGE_ERROR, WSTR("App.cartRestoreWorker.writeError"), cart::getErrorString(error) ); _workerStatus.setNextScreen(_messageScreen); @@ -338,8 +330,7 @@ _fileError: _fileOpenError: _messageScreen.setMessage( - MESSAGE_ERROR, _fileBrowserScreen, - WSTR("App.cartRestoreWorker.fileError"), path + MESSAGE_ERROR, WSTR("App.cartRestoreWorker.fileError"), path ); _workerStatus.setNextScreen(_messageScreen); return false; @@ -352,8 +343,7 @@ bool App::_cartReflashWorker(void) { !(_cartDump.flags & cart::DUMP_CART_ID_OK) ) { _messageScreen.setMessage( - MESSAGE_ERROR, _cartInfoScreen, - WSTR("App.cartReflashWorker.idError") + MESSAGE_ERROR, WSTR("App.cartReflashWorker.idError") ); _workerStatus.setNextScreen(_messageScreen); return false; @@ -418,8 +408,7 @@ bool App::_cartReflashWorker(void) { if (error) { _messageScreen.setMessage( - MESSAGE_ERROR, _cartInfoScreen, - WSTR("App.cartReflashWorker.writeError"), + MESSAGE_ERROR, WSTR("App.cartReflashWorker.writeError"), cart::getErrorString(error) ); _workerStatus.setNextScreen(_messageScreen); @@ -437,7 +426,7 @@ bool App::_cartEraseWorker(void) { if (error) { _messageScreen.setMessage( - MESSAGE_ERROR, _cartInfoScreen, WSTR("App.cartEraseWorker.error"), + MESSAGE_ERROR, WSTR("App.cartEraseWorker.error"), cart::getErrorString(error) ); _workerStatus.setNextScreen(_messageScreen); diff --git a/src/main/app/main.cpp b/src/main/app/main.cpp index 98a78e1..88b5e26 100644 --- a/src/main/app/main.cpp +++ b/src/main/app/main.cpp @@ -8,6 +8,7 @@ /* Main menu screens */ static constexpr int _WARNING_COOLDOWN = 10; +static constexpr int _AUTOBOOT_DELAY = 5; void WarningScreen::show(ui::Context &ctx, bool goBack) { _title = STR("WarningScreen.title"); @@ -17,18 +18,20 @@ void WarningScreen::show(ui::Context &ctx, bool goBack) { _locked = true; _numButtons = 1; - _cooldownTimer = ctx.time + ctx.gpuCtx.refreshRate * _WARNING_COOLDOWN; +#ifdef NDEBUG + _timer = ctx.time + ctx.gpuCtx.refreshRate * _WARNING_COOLDOWN; +#else + _timer = 0; +#endif + _buttonText[0] = 0; MessageBoxScreen::show(ctx, goBack); - - ctx.buttons.buttonMap = ui::MAP_SINGLE_BUTTON; - ctx.buttons.reset(); } void WarningScreen::update(ui::Context &ctx) { MessageBoxScreen::update(ctx); - int time = _cooldownTimer - ctx.time; + int time = _timer - ctx.time; _locked = (time > 0); if (_locked) { @@ -43,10 +46,53 @@ void WarningScreen::update(ui::Context &ctx) { _buttons[0] = STR("WarningScreen.ok"); - if (ctx.buttons.pressed(ui::BTN_RIGHT) || ctx.buttons.pressed(ui::BTN_START)) + if (ctx.buttons.pressed(ui::BTN_START)) ctx.show(APP->_buttonMappingScreen, false, true); } +void AutobootScreen::show(ui::Context &ctx, bool goBack) { + _title = STR("AutobootScreen.title"); + _body = _bodyText; + _buttons[0] = _buttonText; + + _numButtons = 1; + + _timer = ctx.time + ctx.gpuCtx.refreshRate * _AUTOBOOT_DELAY; + _buttonText[0] = 0; + + snprintf(_bodyText, sizeof(_bodyText), STR("AutobootScreen.body"), path); + + MessageBoxScreen::show(ctx, goBack); +} + +void AutobootScreen::update(ui::Context &ctx) { + MessageBoxScreen::update(ctx); + + int time = _timer - ctx.time; + + if (time < 0) { + __builtin_strncpy( + APP->_fileBrowserScreen.selectedPath, path, + sizeof(APP->_fileBrowserScreen.selectedPath) + ); + + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = + &(APP->_warningScreen); + + APP->_runWorker(&App::_executableWorker, APP->_mainMenuScreen, true); + return; + } + + time = (time / ctx.gpuCtx.refreshRate) + 1; + + snprintf( + _buttonText, sizeof(_buttonText), STR("AutobootScreen.cancel"), time + ); + + if (ctx.buttons.pressed(ui::BTN_START)) + ctx.show(APP->_warningScreen, false, true); +} + static const util::Hash _MAPPING_NAMES[]{ "ButtonMappingScreen.joystick"_h, "ButtonMappingScreen.ddrCab"_h, @@ -55,7 +101,9 @@ static const util::Hash _MAPPING_NAMES[]{ "ButtonMappingScreen.dmxCab"_h }; -const char *ButtonMappingScreen::_getItemName(ui::Context &ctx, int index) const { +const char *ButtonMappingScreen::_getItemName( + ui::Context &ctx, int index +) const { return STRH(_MAPPING_NAMES[index]); } @@ -67,18 +115,14 @@ void ButtonMappingScreen::show(ui::Context &ctx, bool goBack) { _listLength = ui::NUM_BUTTON_MAPS - 1; ListScreen::show(ctx, goBack); - - ctx.buttons.buttonMap = ui::MAP_SINGLE_BUTTON; - ctx.buttons.reset(); + ctx.buttons.setButtonMap(ui::MAP_SINGLE_BUTTON); } void ButtonMappingScreen::update(ui::Context &ctx) { ListScreen::update(ctx); if (ctx.buttons.pressed(ui::BTN_START)) { - ctx.buttons.buttonMap = ui::ButtonMap(_activeItem); - ctx.buttons.reset(); - + ctx.buttons.setButtonMap(ui::ButtonMap(_activeItem)); ctx.show(APP->_mainMenuScreen, false, true); } } @@ -134,12 +178,12 @@ const char *MainMenuScreen::_getItemName(ui::Context &ctx, int index) const { } void MainMenuScreen::cartInfo(ui::Context &ctx) { - if (APP->_cartDriver) { + if (APP->_cartDriver) ctx.show(APP->_cartInfoScreen, false, true); - } else { - APP->_setupWorker(&App::_cartDetectWorker); - ctx.show(APP->_workerStatusScreen, false, true); - } + else + APP->_runWorker( + &App::_cartDetectWorker, APP->_cartInfoScreen, false, true + ); } void MainMenuScreen::storageInfo(ui::Context &ctx) { @@ -151,11 +195,15 @@ void MainMenuScreen::ideInfo(ui::Context &ctx) { } void MainMenuScreen::runExecutable(ui::Context &ctx) { + APP->_filePickerScreen.previousScreen = this; APP->_filePickerScreen.setMessage( - *this, [](ui::Context &ctx) { - APP->_setupWorker(&App::_executableWorker); - ctx.show(APP->_workerStatusScreen, false, true); + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = + &(APP->_fileBrowserScreen); + + APP->_runWorker( + &App::_executableWorker, APP->_mainMenuScreen, true, true + ); }, STR("MainMenuScreen.runExecutable.filePrompt") ); @@ -176,13 +224,14 @@ void MainMenuScreen::about(ui::Context &ctx) { } void MainMenuScreen::ejectCD(ui::Context &ctx) { - APP->_setupWorker(&App::_atapiEjectWorker); - ctx.show(APP->_workerStatusScreen, false, true); + APP->_messageScreen.previousScreens[MESSAGE_SUCCESS] = this; + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = this; + + APP->_runWorker(&App::_atapiEjectWorker, *this, true, true); } void MainMenuScreen::reboot(ui::Context &ctx) { - APP->_setupWorker(&App::_rebootWorker); - ctx.show(APP->_workerStatusScreen, false, true); + APP->_runWorker(&App::_rebootWorker, *this, true, true); } void MainMenuScreen::show(ui::Context &ctx, bool goBack) { diff --git a/src/main/app/main.hpp b/src/main/app/main.hpp index 5bf5fa7..b84fde1 100644 --- a/src/main/app/main.hpp +++ b/src/main/app/main.hpp @@ -9,7 +9,7 @@ class WarningScreen : public ui::MessageBoxScreen { private: - int _cooldownTimer; + int _timer; char _buttonText[16]; public: @@ -17,6 +17,18 @@ public: void update(ui::Context &ctx); }; +class AutobootScreen : public ui::MessageBoxScreen { +private: + int _timer; + char _bodyText[512], _buttonText[16]; + +public: + const char *path; + + void show(ui::Context &ctx, bool goBack = false); + void update(ui::Context &ctx); +}; + class ButtonMappingScreen : public ui::ListScreen { protected: const char *_getItemName(ui::Context &ctx, int index) const; diff --git a/src/main/app/miscworkers.cpp b/src/main/app/miscworkers.cpp index 0bc5278..dbb9124 100644 --- a/src/main/app/miscworkers.cpp +++ b/src/main/app/miscworkers.cpp @@ -4,12 +4,23 @@ #include "common/defs.hpp" #include "common/file.hpp" #include "common/ide.hpp" +#include "common/io.hpp" #include "common/util.hpp" #include "main/app/app.hpp" #include "ps1/system.h" +static const char *const _AUTOBOOT_PATHS[][2]{ + { "hdd:/noboot.txt", "hdd:/psx.exe" }, + { "cdrom:/noboot.txt", "cdrom:/psx.exe" }, + { "cdrom:/noboot.txt", "cdrom:/qsy.dxd" }, + { "cdrom:/noboot.txt", "cdrom:/ssw.bxf" }, + { "cdrom:/noboot.txt", "cdrom:/tsv.axg" }, + { "cdrom:/noboot.txt", "cdrom:/gse.nxx" }, + { "cdrom:/noboot.txt", "cdrom:/nse.gxx" } +}; + bool App::_ideInitWorker(void) { - _workerStatus.update(0, 3, WSTR("App.ideInitWorker.initDrives")); + _workerStatus.update(0, 4, WSTR("App.ideInitWorker.initDrives")); for (size_t i = 0; i < util::countOf(ide::devices); i++) { auto &dev = ide::devices[i]; @@ -21,13 +32,33 @@ bool App::_ideInitWorker(void) { dev.goIdle(); } - _workerStatus.update(1, 3, WSTR("App.ideInitWorker.initFileIO")); + _workerStatus.update(1, 4, WSTR("App.ideInitWorker.initFileIO")); _fileIO.initIDE(); - _workerStatus.update(2, 3, WSTR("App.ideInitWorker.loadResources")); + _workerStatus.update(2, 4, WSTR("App.ideInitWorker.loadResources")); if (_fileIO.loadResourceFile(EXTERNAL_DATA_DIR "/resource.zip")) _loadResources(); +#ifdef ENABLE_AUTOBOOT + // Only try to autoboot if DIP switch 1 is on. + if (io::getDIPSwitch(0)) { + _workerStatus.update(3, 4, WSTR("App.ideInitWorker.autoboot")); + + for (auto path : _AUTOBOOT_PATHS) { + file::FileInfo info; + + if (_fileIO.vfs.getFileInfo(info, path[0])) + continue; + if (!_fileIO.vfs.getFileInfo(info, path[1])) + continue; + + _autobootScreen.path = path[1]; + _workerStatus.setNextScreen(_autobootScreen); + break; + } + } +#endif + _ctx.sounds[ui::SOUND_STARTUP].play(); return true; } @@ -69,8 +100,7 @@ bool App::_executableWorker(void) { if (!header.validateMagic()) { _messageScreen.setMessage( - MESSAGE_ERROR, _fileBrowserScreen, - WSTR("App.executableWorker.fileError"), path + MESSAGE_ERROR, WSTR("App.executableWorker.fileError"), path ); _workerStatus.setNextScreen(_messageScreen); return false; @@ -79,7 +109,7 @@ bool App::_executableWorker(void) { auto executableEnd = header.textOffset + header.textLength; auto stackTop = uintptr_t(header.getStackPtr()); - LOG("ptr=0x%08x, length=0x%x", header.textOffset, header.textLength); + LOG("load=0x%08x, length=0x%x", header.textOffset, header.textLength); // Find a launcher that does not overlap the new executable and can thus be // used to load it. Note that this implicitly assumes that none of the @@ -150,16 +180,14 @@ bool App::_executableWorker(void) { } _messageScreen.setMessage( - MESSAGE_ERROR, _fileBrowserScreen, - WSTR("App.executableWorker.addressError"), path, header.textOffset, - executableEnd - 1, stackTop + MESSAGE_ERROR, WSTR("App.executableWorker.addressError"), path, + header.textOffset, executableEnd - 1, stackTop ); _workerStatus.setNextScreen(_messageScreen); return false; } bool App::_atapiEjectWorker(void) { - _workerStatus.setNextScreen(_mainMenuScreen, true); _workerStatus.update(0, 1, WSTR("App.atapiEjectWorker.eject")); for (auto &dev : ide::devices) { @@ -173,8 +201,7 @@ bool App::_atapiEjectWorker(void) { if (error) { _messageScreen.setMessage( - MESSAGE_ERROR, _mainMenuScreen, - WSTR("App.atapiEjectWorker.ejectError"), + MESSAGE_ERROR, WSTR("App.atapiEjectWorker.ejectError"), ide::getErrorString(error) ); _workerStatus.setNextScreen(_messageScreen); @@ -185,7 +212,7 @@ bool App::_atapiEjectWorker(void) { } _messageScreen.setMessage( - MESSAGE_ERROR, _mainMenuScreen, WSTR("App.atapiEjectWorker.noDrive") + MESSAGE_ERROR, WSTR("App.atapiEjectWorker.noDrive") ); _workerStatus.setNextScreen(_messageScreen); return false; diff --git a/src/main/app/modals.cpp b/src/main/app/modals.cpp index 03e3b26..43e4160 100644 --- a/src/main/app/modals.cpp +++ b/src/main/app/modals.cpp @@ -20,14 +20,11 @@ void WorkerStatusScreen::show(ui::Context &ctx, bool goBack) { } void WorkerStatusScreen::update(ui::Context &ctx) { - auto &worker = APP->_workerStatus; - auto nextScreen = worker.nextScreen; + auto &worker = APP->_workerStatus; - if ((worker.status == WORKER_NEXT) || (worker.status == WORKER_NEXT_BACK)) { - worker.reset(); - ctx.show(*nextScreen, worker.status == WORKER_NEXT_BACK); - - LOG("worker finished, next=0x%08x", nextScreen); + if (worker.status == WORKER_DONE) { + worker.setStatus(WORKER_IDLE); + ctx.show(*worker.nextScreen, worker.nextGoBack); return; } @@ -41,11 +38,8 @@ static const util::Hash _MESSAGE_TITLES[]{ "MessageScreen.title.error"_h }; -void MessageScreen::setMessage( - MessageType type, ui::Screen &prev, const char *format, ... -) { - _type = type; - _prevScreen = &prev; +void MessageScreen::setMessage(MessageType type, const char *format, ...) { + _type = type; va_list ap; @@ -60,7 +54,7 @@ void MessageScreen::show(ui::Context &ctx, bool goBack) { _buttons[0] = STR("MessageScreen.ok"); _numButtons = 1; - _locked = _prevScreen ? false : true; + //_locked = !previousScreen; MessageBoxScreen::show(ctx, goBack); ctx.sounds[ui::SOUND_ALERT].play(); @@ -70,15 +64,13 @@ void MessageScreen::update(ui::Context &ctx) { MessageBoxScreen::update(ctx); if (ctx.buttons.pressed(ui::BTN_START)) - ctx.show(*_prevScreen, true, true); + ctx.show(*previousScreens[_type], true, true); } void ConfirmScreen::setMessage( - ui::Screen &prev, void (*callback)(ui::Context &ctx), const char *format, - ... + void (*callback)(ui::Context &ctx), const char *format, ... ) { - _prevScreen = &prev; - _callback = callback; + _callback = callback; va_list ap; @@ -106,7 +98,7 @@ void ConfirmScreen::update(ui::Context &ctx) { if (_activeButton) _callback(ctx); else - ctx.show(*_prevScreen, true, true); + ctx.show(*previousScreen, true, true); } } @@ -161,11 +153,9 @@ const char *FilePickerScreen::_getItemName(ui::Context &ctx, int index) const { } void FilePickerScreen::setMessage( - ui::Screen &prev, void (*callback)(ui::Context &ctx), const char *format, - ... + void (*callback)(ui::Context &ctx), const char *format, ... ) { - _prevScreen = &prev; - _callback = callback; + _callback = callback; va_list ap; @@ -181,9 +171,9 @@ void FilePickerScreen::reloadAndShow(ui::Context &ctx) { if (!dev.atapiPoll()) continue; - APP->_workerStatus.setNextScreen(*this); - APP->_setupWorker(&App::_ideInitWorker); - ctx.show(APP->_workerStatusScreen, false, true); + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = this; + + APP->_runWorker(&App::_ideInitWorker, *this, false, true); return; } @@ -213,8 +203,9 @@ void FilePickerScreen::update(ui::Context &ctx) { ListScreen::update(ctx); if (!_listLength) { + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = previousScreen; APP->_messageScreen.setMessage( - MESSAGE_ERROR, *_prevScreen, STR("FilePickerScreen.noDeviceError") + MESSAGE_ERROR, STR("FilePickerScreen.noDeviceError") ); ctx.show(APP->_messageScreen, false, true); return; @@ -222,7 +213,7 @@ void FilePickerScreen::update(ui::Context &ctx) { if (ctx.buttons.pressed(ui::BTN_START)) { if (ctx.buttons.held(ui::BTN_LEFT) || ctx.buttons.held(ui::BTN_RIGHT)) { - ctx.show(*_prevScreen, true, true); + ctx.show(*previousScreen, true, true); } else { int index = _activeItem; #ifndef NDEBUG @@ -259,9 +250,8 @@ void FilePickerScreen::update(ui::Context &ctx) { else error = "FilePickerScreen.ideError"_h; - APP->_messageScreen.setMessage( - MESSAGE_ERROR, *this, STRH(error) - ); + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = this; + APP->_messageScreen.setMessage(MESSAGE_ERROR, STRH(error)); ctx.show(APP->_messageScreen, false, true); } } @@ -427,9 +417,10 @@ void FileBrowserScreen::update(ui::Context &ctx) { if (loadDirectory(ctx, selectedPath) < 0) { loadDirectory(ctx, _currentPath, false); + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = this; APP->_messageScreen.setMessage( - MESSAGE_ERROR, *this, - STR("FileBrowserScreen.subdirError"), selectedPath + MESSAGE_ERROR, STR("FileBrowserScreen.subdirError"), + selectedPath ); ctx.show(APP->_messageScreen, false, true); } diff --git a/src/main/app/modals.hpp b/src/main/app/modals.hpp index b9f9281..36fe2c4 100644 --- a/src/main/app/modals.hpp +++ b/src/main/app/modals.hpp @@ -16,6 +16,8 @@ public: void update(ui::Context &ctx); }; +static constexpr size_t NUM_MESSAGE_TYPES = 3; + enum MessageType { MESSAGE_SUCCESS = 0, MESSAGE_WARNING = 1, @@ -26,12 +28,11 @@ class MessageScreen : public ui::MessageBoxScreen { private: MessageType _type; char _bodyText[512]; - ui::Screen *_prevScreen; public: - void setMessage( - MessageType type, ui::Screen &prev, const char *format, ... - ); + ui::Screen *previousScreens[NUM_MESSAGE_TYPES]; + + void setMessage(MessageType type, const char *format, ...); void show(ui::Context &ctx, bool goBack = false); void update(ui::Context &ctx); @@ -39,14 +40,14 @@ public: class ConfirmScreen : public ui::MessageBoxScreen { private: - char _bodyText[512]; - ui::Screen *_prevScreen; - void (*_callback)(ui::Context &ctx); + char _bodyText[512]; + void (*_callback)(ui::Context &ctx); public: + ui::Screen *previousScreen; + void setMessage( - ui::Screen &prev, void (*callback)(ui::Context &ctx), - const char *format, ... + void (*callback)(ui::Context &ctx), const char *format, ... ); void show(ui::Context &ctx, bool goBack = false); @@ -59,9 +60,8 @@ class FilePickerScreen : public ui::ListScreen { friend class FileBrowserScreen; private: - char _promptText[512]; - ui::Screen *_prevScreen; - void (*_callback)(ui::Context &ctx); + char _promptText[512]; + void (*_callback)(ui::Context &ctx); int _drives[util::countOf(ide::devices)]; @@ -69,9 +69,10 @@ protected: const char *_getItemName(ui::Context &ctx, int index) const; public: + ui::Screen *previousScreen; + void setMessage( - ui::Screen &prev, void (*callback)(ui::Context &ctx), - const char *format, ... + void (*callback)(ui::Context &ctx), const char *format, ... ); void reloadAndShow(ui::Context &ctx); diff --git a/src/main/app/romactions.cpp b/src/main/app/romactions.cpp index f61f017..4732be4 100644 --- a/src/main/app/romactions.cpp +++ b/src/main/app/romactions.cpp @@ -205,20 +205,26 @@ const char *StorageActionsScreen::_getItemName( } void StorageActionsScreen::checksum(ui::Context &ctx) { - if (APP->_checksumScreen.valid) { + if (APP->_checksumScreen.valid) ctx.show(APP->_checksumScreen, false, true); - } else { - APP->_setupWorker(&App::_romChecksumWorker); - ctx.show(APP->_workerStatusScreen, false, true); - } + else + APP->_runWorker( + &App::_romChecksumWorker, APP->_checksumScreen, false, true + ); } void StorageActionsScreen::dump(ui::Context &ctx) { + APP->_confirmScreen.previousScreen = this; APP->_confirmScreen.setMessage( - *this, [](ui::Context &ctx) { - APP->_setupWorker(&App::_romDumpWorker); - ctx.show(APP->_workerStatusScreen, false, true); + APP->_messageScreen.previousScreens[MESSAGE_SUCCESS] = + &(APP->_storageInfoScreen); + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = + &(APP->_storageActionsScreen); + + APP->_runWorker( + &App::_romDumpWorker, APP->_messageScreen, false, true + ); }, STR("StorageActionsScreen.dump.confirm") ); @@ -227,18 +233,25 @@ void StorageActionsScreen::dump(ui::Context &ctx) { } void StorageActionsScreen::restore(ui::Context &ctx) { + APP->_filePickerScreen.previousScreen = this; APP->_filePickerScreen.setMessage( - *this, [](ui::Context &ctx) { ctx.show(APP->_confirmScreen, false, true); }, STR("StorageActionsScreen.restore.filePrompt") ); + + APP->_confirmScreen.previousScreen = &(APP->_fileBrowserScreen); APP->_confirmScreen.setMessage( - APP->_fileBrowserScreen, [](ui::Context &ctx) { - APP->_setupWorker(&App::_romRestoreWorker); - ctx.show(APP->_workerStatusScreen, false, true); + APP->_messageScreen.previousScreens[MESSAGE_SUCCESS] = + &(APP->_storageInfoScreen); + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = + &(APP->_fileBrowserScreen); + + APP->_runWorker( + &App::_romRestoreWorker, APP->_messageScreen, false, true + ); }, STR("StorageActionsScreen.restore.confirm") ); @@ -247,11 +260,17 @@ void StorageActionsScreen::restore(ui::Context &ctx) { } void StorageActionsScreen::erase(ui::Context &ctx) { + APP->_confirmScreen.previousScreen = this; APP->_confirmScreen.setMessage( - *this, [](ui::Context &ctx) { - APP->_setupWorker(&App::_romEraseWorker); - ctx.show(APP->_workerStatusScreen, false, true); + APP->_messageScreen.previousScreens[MESSAGE_SUCCESS] = + &(APP->_storageInfoScreen); + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = + &(APP->_storageActionsScreen); + + APP->_runWorker( + &App::_romEraseWorker, APP->_messageScreen, false, true + ); }, STR("StorageActionsScreen.erase.confirm") ); @@ -260,12 +279,18 @@ void StorageActionsScreen::erase(ui::Context &ctx) { } void StorageActionsScreen::resetFlashHeader(ui::Context &ctx) { + APP->_confirmScreen.previousScreen = this; APP->_confirmScreen.setMessage( - *this, [](ui::Context &ctx) { util::clear(APP->_romHeaderDump.data); - APP->_setupWorker(&App::_flashHeaderWriteWorker); - ctx.show(APP->_workerStatusScreen, false, true); + + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = + &(APP->_storageActionsScreen); + + APP->_runWorker( + &App::_flashHeaderWriteWorker, APP->_storageInfoScreen, true, + true + ); }, STR("StorageActionsScreen.resetFlashHeader.confirm") ); @@ -313,8 +338,9 @@ void StorageActionsScreen::update(ui::Context &ctx) { (this->*action.target)(ctx); } } else { + APP->_messageScreen.previousScreens[MESSAGE_ERROR] = this; APP->_messageScreen.setMessage( - MESSAGE_ERROR, *this, STR("StorageActionsScreen.cardError") + MESSAGE_ERROR, STR("StorageActionsScreen.cardError") ); ctx.show(APP->_messageScreen, false, true); diff --git a/src/main/app/romworkers.cpp b/src/main/app/romworkers.cpp index 2b4c8c5..70e5d34 100644 --- a/src/main/app/romworkers.cpp +++ b/src/main/app/romworkers.cpp @@ -57,7 +57,6 @@ static constexpr size_t _DUMP_CHUNKS_PER_CRC = 32; // Save CRC32 every 16 MB // TODO: all these *really* need a cleanup... bool App::_romChecksumWorker(void) { - _workerStatus.setNextScreen(_checksumScreen); _checksumScreen.valid = false; for (auto &entry : _REGION_INFO) { @@ -100,7 +99,7 @@ bool App::_romDumpWorker(void) { // Store all dumps in a subdirectory named "dumpNNNN" within the main data // folder. - char dirPath[32], filePath[32]; + char dirPath[file::MAX_PATH_LENGTH], filePath[file::MAX_PATH_LENGTH]; if (!_createDataDirectory()) goto _initError; @@ -158,26 +157,20 @@ bool App::_romDumpWorker(void) { } _messageScreen.setMessage( - MESSAGE_SUCCESS, _storageInfoScreen, WSTR("App.romDumpWorker.success"), - dirPath + MESSAGE_SUCCESS, WSTR("App.romDumpWorker.success"), dirPath ); - _workerStatus.setNextScreen(_messageScreen); return true; _initError: _messageScreen.setMessage( - MESSAGE_ERROR, _storageInfoScreen, WSTR("App.romDumpWorker.initError"), - dirPath + MESSAGE_ERROR, WSTR("App.romDumpWorker.initError"), dirPath ); - _workerStatus.setNextScreen(_messageScreen); return false; _fileError: _messageScreen.setMessage( - MESSAGE_ERROR, _storageInfoScreen, WSTR("App.romDumpWorker.fileError"), - filePath + MESSAGE_ERROR, WSTR("App.romDumpWorker.fileError"), filePath ); - _workerStatus.setNextScreen(_messageScreen); return false; } @@ -299,18 +292,13 @@ bool App::_romRestoreWorker(void) { delete _file; delete driver; - _messageScreen.setMessage( - MESSAGE_SUCCESS, _storageInfoScreen, WSTRH(message), bytesWritten - ); - _workerStatus.setNextScreen(_messageScreen); + _messageScreen.setMessage(MESSAGE_SUCCESS, WSTRH(message), bytesWritten); return true; _fileError: _messageScreen.setMessage( - MESSAGE_ERROR, _storageInfoScreen, - WSTR("App.romRestoreWorker.fileError"), path + MESSAGE_ERROR, WSTR("App.romRestoreWorker.fileError"), path ); - _workerStatus.setNextScreen(_messageScreen); return false; _flashError: @@ -321,11 +309,9 @@ _flashError: delete driver; _messageScreen.setMessage( - MESSAGE_ERROR, _storageInfoScreen, - WSTR("App.romRestoreWorker.flashError"), rom::getErrorString(error), - bytesWritten + MESSAGE_ERROR, WSTR("App.romRestoreWorker.flashError"), + rom::getErrorString(error), bytesWritten ); - _workerStatus.setNextScreen(_messageScreen); return false; } @@ -366,31 +352,25 @@ bool App::_romEraseWorker(void) { delete driver; _messageScreen.setMessage( - MESSAGE_SUCCESS, _storageInfoScreen, WSTR("App.romEraseWorker.success"), - sectorsErased + MESSAGE_SUCCESS, WSTR("App.romEraseWorker.success"), sectorsErased ); - _workerStatus.setNextScreen(_messageScreen); return true; _flashError: delete driver; _messageScreen.setMessage( - MESSAGE_ERROR, _storageInfoScreen, - WSTR("App.romEraseWorker.flashError"), rom::getErrorString(error), - sectorsErased + MESSAGE_ERROR, WSTR("App.romEraseWorker.flashError"), + rom::getErrorString(error), sectorsErased ); - _workerStatus.setNextScreen(_messageScreen); return false; _unsupported: delete driver; _messageScreen.setMessage( - MESSAGE_ERROR, _storageInfoScreen, - WSTR("App.romEraseWorker.unsupported") + MESSAGE_ERROR, WSTR("App.romEraseWorker.unsupported") ); - _workerStatus.setNextScreen(_messageScreen); return false; } @@ -460,8 +440,6 @@ bool App::_flashHeaderWriteWorker(void) { buffer.destroy(); delete driver; - - _workerStatus.setNextScreen(_storageInfoScreen); return true; _flashError: @@ -469,8 +447,7 @@ _flashError: delete driver; _messageScreen.setMessage( - MESSAGE_ERROR, _storageInfoScreen, - WSTR("App.flashHeaderWriteWorker.flashError"), + MESSAGE_ERROR, WSTR("App.flashHeaderWriteWorker.flashError"), rom::getErrorString(error) ); _workerStatus.setNextScreen(_messageScreen); @@ -480,8 +457,7 @@ _unsupported: delete driver; _messageScreen.setMessage( - MESSAGE_ERROR, _storageInfoScreen, - WSTR("App.flashHeaderWriteWorker.unsupported") + MESSAGE_ERROR, WSTR("App.flashHeaderWriteWorker.unsupported") ); _workerStatus.setNextScreen(_messageScreen); return false; diff --git a/src/main/uibase.cpp b/src/main/uibase.cpp index 8b540b2..337905e 100644 --- a/src/main/uibase.cpp +++ b/src/main/uibase.cpp @@ -52,14 +52,14 @@ static const uint32_t _BUTTON_MAPPINGS[NUM_BUTTON_MAPS][NUM_BUTTONS]{ }; ButtonState::ButtonState(void) -: _held(0), _prevHeld(0), _longHeld(0), _prevLongHeld(0), _pressed(0), -_released(0), _longPressed(0), _longReleased(0), _repeatTimer(0), -buttonMap(MAP_JOYSTICK) {} +: _buttonMap(MAP_JOYSTICK), _held(0), _prevHeld(0), _longHeld(0), +_prevLongHeld(0), _pressed(0), _released(0), _longPressed(0), _longReleased(0), +_repeatTimer(0) {} uint8_t ButtonState::_getHeld(void) const { uint32_t inputs = io::getJAMMAInputs(); uint8_t held = 0; - auto map = _BUTTON_MAPPINGS[buttonMap]; + auto map = _BUTTON_MAPPINGS[_buttonMap]; #ifdef ENABLE_PS1_CONTROLLER if (pad::ports[0].pollPad() || pad::ports[1].pollPad()) { @@ -115,40 +115,43 @@ void ButtonState::update(void) { uint32_t changed = _prevHeld ^ _held; - if (buttonMap == MAP_SINGLE_BUTTON) { + if (_buttonMap == MAP_SINGLE_BUTTON) { _pressed = 0; _released = 0; _longHeld = 0; // In single-button mode, interpret a short button press as the right - // button and a long press as start. - if (_held) { + // button and a long press as start. Note that the repeat timer is not + // started if single button mode is enabled while a button is held down. + if (changed & _held) { + _repeatTimer = 1; + } else if (changed & _prevHeld) { + if (_repeatTimer && (_repeatTimer < REPEAT_DELAY)) + _pressed |= 1 << BTN_RIGHT; + + _repeatTimer = 0; + } else if (_held && _repeatTimer) { if (_repeatTimer == REPEAT_DELAY) _pressed |= 1 << BTN_START; _repeatTimer++; - } else if (_prevHeld) { - if (_repeatTimer >= REPEAT_DELAY) - _released |= 1 << BTN_START; - else - _pressed |= 1 << BTN_RIGHT; - - _repeatTimer = 0; } } else { - if (changed) + if (changed & _held) + _repeatTimer = 1; + else if (changed & _prevHeld) _repeatTimer = 0; - else if (_held) + else if (_held && _repeatTimer) _repeatTimer++; - _pressed = (changed & _held) & ~_pressed; + _pressed = (changed & _held) & ~_pressed; _released = (changed & _prevHeld) & ~_released; _longHeld = (_repeatTimer >= REPEAT_DELAY) ? _held : 0; } changed = _prevLongHeld ^ _longHeld; - _longPressed = (changed & _longHeld) & ~_longPressed; + _longPressed = (changed & _longHeld) & ~_longPressed; _longReleased = (changed & _prevLongHeld) & ~_longReleased; } @@ -162,7 +165,7 @@ Context::Context(gpu::Context &gpuCtx, void *screenData) } void Context::show(Screen &screen, bool goBack, bool playSound) { - auto oldScreen = _screens[_currentScreen]; + auto oldScreen = getCurrentScreen(); if (oldScreen) oldScreen->hide(*this, goBack); @@ -177,8 +180,8 @@ void Context::show(Screen &screen, bool goBack, bool playSound) { } void Context::draw(void) { - auto oldScreen = _screens[_currentScreen ^ 1]; - auto newScreen = _screens[_currentScreen]; + auto oldScreen = getInactiveScreen(); + auto newScreen = getCurrentScreen(); for (auto layer : backgrounds) { if (layer) @@ -204,8 +207,10 @@ void Context::update(void) { layer->update(*this); } - if (_screens[_currentScreen]) - _screens[_currentScreen]->update(*this); + auto screen = getCurrentScreen(); + + if (screen) + screen->update(*this); } /* Layer classes */ diff --git a/src/main/uibase.hpp b/src/main/uibase.hpp index 6474dff..21c8bb8 100644 --- a/src/main/uibase.hpp +++ b/src/main/uibase.hpp @@ -105,7 +105,9 @@ enum ButtonMap { class ButtonState { private: - uint32_t _mappings[NUM_BUTTONS]; + ButtonMap _buttonMap; + uint32_t _mappings[NUM_BUTTONS]; + uint8_t _held, _prevHeld; uint8_t _longHeld, _prevLongHeld; uint8_t _pressed, _released; @@ -116,7 +118,10 @@ private: uint8_t _getHeld(void) const; public: - ButtonMap buttonMap; + inline void setButtonMap(ButtonMap map) { + reset(); + _buttonMap = map; + } inline bool held(Button button) const { return (_held >> button) & 1; @@ -167,6 +172,12 @@ public: int time; void *screenData; // Opaque, can be accessed by screens + inline Screen *getCurrentScreen(void) const { + return _screens[_currentScreen]; + } + inline Screen *getInactiveScreen(void) const { + return _screens[_currentScreen ^ 1]; + } inline void tick(void) { //buttons.update(); time++;