mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-22 18:26:39 +00:00
Implemented background tasks for Borealis.
* core: implemented SCOPED_TRY_LOCK macro. Specific functions are now using it instead of SCOPED_LOCK to avoid potentially locking the Borealis UI. * UI: implemented background tasks for Borealis, which call functions that now use SCOPED_TRY_LOCK.
This commit is contained in:
parent
a16f62fe6d
commit
e48aa2e937
16 changed files with 259 additions and 160 deletions
|
@ -32,7 +32,10 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
/* Scoped lock macro. */
|
||||
#define SCOPED_LOCK(mtx) for(UtilsScopedLock ANONYMOUS_VARIABLE(scoped_lock) __attribute__((__cleanup__(utilsUnlockScope))) = utilsLockScope(mtx); ANONYMOUS_VARIABLE(scoped_lock).cond; ANONYMOUS_VARIABLE(scoped_lock).cond = 0)
|
||||
#define SCOPED_LOCK(mtx) for(UtilsScopedLock ANONYMOUS_VARIABLE(scoped_lock) CLEANUP(utilsUnlockScope) = utilsLockScope(mtx); ANONYMOUS_VARIABLE(scoped_lock).cond; ANONYMOUS_VARIABLE(scoped_lock).cond = 0)
|
||||
|
||||
/* Scoped try lock macro. */
|
||||
#define SCOPED_TRY_LOCK(mtx) for(UtilsScopedLock ANONYMOUS_VARIABLE(scoped_lock) CLEANUP(utilsUnlockScope) = utilsTryLockScope(mtx); ANONYMOUS_VARIABLE(scoped_lock).cond; ANONYMOUS_VARIABLE(scoped_lock).cond = 0)
|
||||
|
||||
/// Used by scoped locks.
|
||||
typedef struct {
|
||||
|
@ -146,6 +149,13 @@ NX_INLINE UtilsScopedLock utilsLockScope(Mutex *mtx)
|
|||
return scoped_lock;
|
||||
}
|
||||
|
||||
NX_INLINE UtilsScopedLock utilsTryLockScope(Mutex *mtx)
|
||||
{
|
||||
UtilsScopedLock scoped_lock = { mtx, !mutexIsLockedByCurrentThread(mtx), 1 };
|
||||
if (scoped_lock.lock) scoped_lock.cond = (int)mutexTryLock(scoped_lock.mtx);
|
||||
return scoped_lock;
|
||||
}
|
||||
|
||||
NX_INLINE void utilsUnlockScope(UtilsScopedLock *scoped_lock)
|
||||
{
|
||||
if (scoped_lock->lock) mutexUnlock(scoped_lock->mtx);
|
||||
|
|
|
@ -43,9 +43,6 @@ void usbExit(void);
|
|||
void *usbAllocatePageAlignedBuffer(size_t size);
|
||||
|
||||
/// Used to check if the console has been connected to a USB host device and if a valid USB session has been established.
|
||||
/// Bear in mind this call will block the calling thread if the console is connected to a USB host device but no USB session has been established.
|
||||
/// If the console is disconnected during this block, the function will return false.
|
||||
/// If the console isn't connected to a USB host device when this function is called, false will be returned right away.
|
||||
bool usbIsReady(void);
|
||||
|
||||
/// Sends file properties to the host device before starting a file data transfer. Must be called before usbSendFileData().
|
||||
|
|
|
@ -50,6 +50,8 @@
|
|||
#define ALWAYS_INLINE inline __attribute__((always_inline))
|
||||
#define ALWAYS_INLINE_LAMBDA __attribute__((always_inline))
|
||||
|
||||
#define CLEANUP(func) __attribute__((__cleanup__(func)))
|
||||
|
||||
#define NXDT_ASSERT(name, size) static_assert(sizeof(name) == (size), "Bad size for " #name "! Expected " #size ".")
|
||||
|
||||
/* Global constants used throughout the application. */
|
||||
|
|
86
include/tasks.hpp
Normal file
86
include/tasks.hpp
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* tasks.hpp
|
||||
*
|
||||
* Copyright (c) 2020-2021, DarkMatterCore <pabloacurielz@gmail.com>.
|
||||
*
|
||||
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
||||
*
|
||||
* nxdumptool is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* nxdumptool is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __TASKS_HPP__
|
||||
#define __TASKS_HPP__
|
||||
|
||||
#include <borealis.hpp>
|
||||
|
||||
#include "core/gamecard.h"
|
||||
#include "core/title.h"
|
||||
#include "core/ums.h"
|
||||
#include "core/usb.h"
|
||||
|
||||
namespace nxdt::tasks
|
||||
{
|
||||
/* Custom event types used by the tasks defined below. */
|
||||
typedef brls::Event<GameCardStatus> GameCardStatusEvent;
|
||||
typedef brls::VoidEvent VoidEvent;
|
||||
typedef brls::Event<bool> BooleanEvent;
|
||||
|
||||
/* Gamecard task. */
|
||||
class GameCardTask: public brls::RepeatingTask
|
||||
{
|
||||
private:
|
||||
GameCardStatus cur_gc_status = GameCardStatus_NotInserted;
|
||||
GameCardStatus prev_gc_status = GameCardStatus_NotInserted;
|
||||
GameCardStatusEvent *gc_status_event = nullptr;
|
||||
public:
|
||||
GameCardTask(GameCardStatusEvent *gc_status_event);
|
||||
void run(retro_time_t current_time) override;
|
||||
};
|
||||
|
||||
/* Gamecard title task. */
|
||||
class GameCardTitleTask: public brls::RepeatingTask
|
||||
{
|
||||
private:
|
||||
VoidEvent *gc_title_event = nullptr;
|
||||
public:
|
||||
GameCardTitleTask(VoidEvent *gc_title_event);
|
||||
void run(retro_time_t current_time) override;
|
||||
};
|
||||
|
||||
/* USB Mass Storage task. */
|
||||
class UmsTask: public brls::RepeatingTask
|
||||
{
|
||||
private:
|
||||
VoidEvent *ums_event = nullptr;
|
||||
public:
|
||||
UmsTask(VoidEvent *ums_event);
|
||||
void run(retro_time_t current_time) override;
|
||||
};
|
||||
|
||||
/* USB host device connection task. */
|
||||
class UsbHostTask: public brls::RepeatingTask
|
||||
{
|
||||
private:
|
||||
bool cur_usb_host_status = false;
|
||||
bool prev_usb_host_status = false;
|
||||
BooleanEvent *usb_host_event = nullptr;
|
||||
public:
|
||||
UsbHostTask(BooleanEvent *usb_host_event);
|
||||
void run(retro_time_t current_time) override;
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* __TASKS_HPP__ */
|
|
@ -1,5 +1,4 @@
|
|||
{
|
||||
"name": "{0}",
|
||||
"tabs": {
|
||||
"first": "First tab",
|
||||
"second": "Second tab",
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"hints": {
|
||||
"ok": "OK",
|
||||
"back": "Retour",
|
||||
"exit": "Quitter"
|
||||
},
|
||||
|
||||
"crash_frame": {
|
||||
"button": "OK"
|
||||
},
|
||||
|
||||
"thumbnail_sidebar": {
|
||||
"save": "Sauvegarder"
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"first_button": "Premier bouton",
|
||||
"second_button": "Deuxième bouton",
|
||||
"third_button": "Troisième bouton"
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"open": "Ouvrir l'installateur de démo",
|
||||
|
||||
"title": "Mon super installateur",
|
||||
|
||||
"stage1": {
|
||||
"text": "Ici vous devriez normalement faire des choses utiles",
|
||||
"button": "Aller à l'étape 2"
|
||||
},
|
||||
|
||||
"stage2": {
|
||||
"text": "Exemple de chargement"
|
||||
},
|
||||
|
||||
"stage3": {
|
||||
"button": "Terminer"
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
{
|
||||
"name": "App de Démo Borealis",
|
||||
"tabs": {
|
||||
"first": "Premier onglet",
|
||||
"second": "Deuxième onglet",
|
||||
"third": "Troisième onglet",
|
||||
"fourth": "Quatrième onglet",
|
||||
"custom_navigation_tab": "Disposition personnalisée"
|
||||
},
|
||||
|
||||
"pozznx": {
|
||||
"open": "Ouvrir une boîte de dialogue",
|
||||
"warning": "Avertissement: PozzNX va effacer toutes les données de votre Switch et la rendre inutilisable, voulez-vous continuer ?",
|
||||
"running": "Exécution de PozzNX...",
|
||||
"continue": "Continuer"
|
||||
},
|
||||
|
||||
"notify": "Afficher une notification aléatoire",
|
||||
|
||||
"tv": {
|
||||
"resolution": "Résolution du téléviseur",
|
||||
"automatic": "Automatique"
|
||||
},
|
||||
|
||||
"i18n": {
|
||||
"title": "Langue : {0} ({1})",
|
||||
"lang": "Français"
|
||||
},
|
||||
|
||||
"jank": {
|
||||
"jank": "Bâclement de l'interface utilisateur",
|
||||
"native": "Natif",
|
||||
"minimal": "Minimal",
|
||||
"regular": "Normal",
|
||||
"maximum": "Maximum",
|
||||
"saxophone": "SX OS",
|
||||
"vista": "Windows Vista",
|
||||
"ios": "iOS 14"
|
||||
},
|
||||
|
||||
"divide": {
|
||||
"title": "Diviser par 0",
|
||||
"description": "Est-ce que la Switch peut le faire ?",
|
||||
"crash": "Le logiciel a été arrêté à cause d'une erreur:\nSIGABRT (signal 6)"
|
||||
},
|
||||
|
||||
"more": "Si vous désirez en savoir plus sur la console Nintendo Switch et ses fonctionnalités, visitez le site d'assistance Nintendo depuis un appareil connecté ou un ordinateur.",
|
||||
|
||||
"actions": {
|
||||
"title": "Actions personnalisées",
|
||||
"notify": "Afficher une notification",
|
||||
"triggered": "Action personnalisée déclenchée"
|
||||
},
|
||||
|
||||
"layers": {
|
||||
"title": "Choisir une couche",
|
||||
"layer1": "Couche 1",
|
||||
"layer2": "Couche 2",
|
||||
|
||||
"item1": "Item 1",
|
||||
"item2": "Item 2",
|
||||
"item3": "Item 3"
|
||||
},
|
||||
|
||||
"keyboard": {
|
||||
"string": {
|
||||
"title": "Ouvrir le clavier",
|
||||
"default": "Texte par défaut",
|
||||
"help": "Message d'aide"
|
||||
},
|
||||
"number": {
|
||||
"title": "Ouvrir le clavier numérique",
|
||||
"help": "Message d'aide"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"open": "Ouvrir une popup",
|
||||
|
||||
"red": "Rouge",
|
||||
"green": "Vert",
|
||||
"blue": "Bleu",
|
||||
|
||||
"title": "Titre de la popup",
|
||||
"subtitle": {
|
||||
"left": "Sous-titre gauche",
|
||||
"right": "Sous-titre right"
|
||||
}
|
||||
}
|
|
@ -307,7 +307,7 @@ u8 gamecardGetStatus(void)
|
|||
{
|
||||
u8 status = GameCardStatus_NotInserted;
|
||||
|
||||
SCOPED_LOCK(&g_gameCardMutex)
|
||||
SCOPED_TRY_LOCK(&g_gameCardMutex)
|
||||
{
|
||||
if (g_gameCardInterfaceInit) status = g_gameCardStatus;
|
||||
}
|
||||
|
|
|
@ -862,7 +862,7 @@ bool titleIsGameCardInfoUpdated(void)
|
|||
{
|
||||
bool ret = false;
|
||||
|
||||
SCOPED_LOCK(&g_titleMutex)
|
||||
SCOPED_TRY_LOCK(&g_titleMutex)
|
||||
{
|
||||
/* Check if the gamecard thread detected a gamecard status change. */
|
||||
ret = (g_titleInterfaceInit && g_titleGameCardInfoUpdated);
|
||||
|
|
|
@ -97,7 +97,7 @@ bool umsIsDeviceInfoUpdated(void)
|
|||
{
|
||||
bool ret = false;
|
||||
|
||||
SCOPED_LOCK(&g_umsMutex)
|
||||
SCOPED_TRY_LOCK(&g_umsMutex)
|
||||
{
|
||||
if (!g_umsInterfaceInit || !g_umsDeviceInfoUpdated) break;
|
||||
ret = true;
|
||||
|
|
|
@ -308,7 +308,7 @@ void *usbAllocatePageAlignedBuffer(size_t size)
|
|||
bool usbIsReady(void)
|
||||
{
|
||||
bool ret = false;
|
||||
SCOPED_LOCK(&g_usbInterfaceMutex) ret = (g_usbHostAvailable && g_usbSessionStarted);
|
||||
SCOPED_TRY_LOCK(&g_usbInterfaceMutex) ret = (g_usbHostAvailable && g_usbSessionStarted);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,11 +20,12 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <nxdt_utils.h>
|
||||
#include <scope_guard.hpp>
|
||||
#include <borealis.hpp>
|
||||
#include <string>
|
||||
|
||||
#include <nxdt_utils.h>
|
||||
#include <tasks.hpp>
|
||||
#include <scope_guard.hpp>
|
||||
|
||||
#include "custom_layout_tab.hpp"
|
||||
#include "sample_installer_page.hpp"
|
||||
#include "sample_loading_page.hpp"
|
||||
|
@ -47,24 +48,54 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
ON_SCOPE_EXIT { utilsCloseResources(); };
|
||||
|
||||
/* Initialize application resources. */
|
||||
if (!utilsInitializeResources(argc, (const char**)argv)) return EXIT_FAILURE;
|
||||
|
||||
// Init the app
|
||||
/* Set Borealis log level. */
|
||||
brls::Logger::setLogLevel(brls::LogLevel::DEBUG);
|
||||
|
||||
|
||||
/* Load Borealis translation files. */
|
||||
i18n::loadTranslations();
|
||||
if (!brls::Application::init("main/name"_i18n))
|
||||
{
|
||||
brls::Logger::error("Unable to init Borealis application");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Initialize Borealis. */
|
||||
if (!brls::Application::init("main/name"_i18n)) return EXIT_FAILURE;
|
||||
|
||||
/* Create root tab frame. */
|
||||
brls::TabFrame *root_frame = new brls::TabFrame();
|
||||
root_frame->setTitle(APP_TITLE);
|
||||
root_frame->setIcon(BOREALIS_ASSET("icon/" APP_TITLE ".jpg"));
|
||||
root_frame->setFooterText("v" APP_VERSION);
|
||||
|
||||
/* Create and start gamecard task. */
|
||||
nxdt::tasks::GameCardStatusEvent gc_status_event;
|
||||
nxdt::tasks::GameCardTask *gc_task = new nxdt::tasks::GameCardTask(&gc_status_event);
|
||||
gc_task->start();
|
||||
|
||||
/* Create and start gamecard title task. */
|
||||
nxdt::tasks::VoidEvent gc_title_event;
|
||||
nxdt::tasks::GameCardTitleTask *gc_title_task = new nxdt::tasks::GameCardTitleTask(&gc_title_event);
|
||||
gc_title_task->start();
|
||||
|
||||
/* Create and start UMS task. */
|
||||
nxdt::tasks::VoidEvent ums_event;
|
||||
nxdt::tasks::UmsTask *ums_task = new nxdt::tasks::UmsTask(&ums_event);
|
||||
ums_task->start();
|
||||
|
||||
/* Create and start USB host task. */
|
||||
nxdt::tasks::BooleanEvent usb_host_event;
|
||||
nxdt::tasks::UsbHostTask *usb_host_task = new nxdt::tasks::UsbHostTask(&usb_host_event);
|
||||
usb_host_task->start();
|
||||
|
||||
// Create a sample view
|
||||
brls::TabFrame* rootFrame = new brls::TabFrame();
|
||||
rootFrame->setTitle(i18n::getStr("main/name", APP_TITLE));
|
||||
rootFrame->setIcon(BOREALIS_ASSET("icon/" APP_TITLE ".jpg" ));
|
||||
|
||||
brls::List* testList = new brls::List();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
brls::List *testList = new brls::List();
|
||||
|
||||
brls::ListItem* dialogItem = new brls::ListItem("main/pozznx/open"_i18n);
|
||||
dialogItem->getClickEvent()->subscribe([](brls::View* view) {
|
||||
|
@ -183,16 +214,16 @@ int main(int argc, char* argv[])
|
|||
|
||||
testList->addView(layerSelectItem);
|
||||
|
||||
rootFrame->addTab("main/tabs/first"_i18n, testList);
|
||||
rootFrame->addTab("main/tabs/second"_i18n, testLayers);
|
||||
rootFrame->addSeparator();
|
||||
rootFrame->addTab("main/tabs/third"_i18n, new brls::Rectangle(nvgRGB(255, 0, 0)));
|
||||
rootFrame->addTab("main/tabs/fourth"_i18n, new brls::Rectangle(nvgRGB(0, 255, 0)));
|
||||
rootFrame->addSeparator();
|
||||
rootFrame->addTab("main/tabs/custom_navigation_tab"_i18n, new CustomLayoutTab());
|
||||
root_frame->addTab("main/tabs/first"_i18n, testList);
|
||||
root_frame->addTab("main/tabs/second"_i18n, testLayers);
|
||||
root_frame->addSeparator();
|
||||
root_frame->addTab("main/tabs/third"_i18n, new brls::Rectangle(nvgRGB(255, 0, 0)));
|
||||
root_frame->addTab("main/tabs/fourth"_i18n, new brls::Rectangle(nvgRGB(0, 255, 0)));
|
||||
root_frame->addSeparator();
|
||||
root_frame->addTab("main/tabs/custom_navigation_tab"_i18n, new CustomLayoutTab());
|
||||
|
||||
// Add the root view to the stack
|
||||
brls::Application::pushView(rootFrame);
|
||||
brls::Application::pushView(root_frame);
|
||||
|
||||
// Run the app
|
||||
while (brls::Application::mainLoop());
|
||||
|
|
102
source/tasks.cpp
Normal file
102
source/tasks.cpp
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* tasks.cpp
|
||||
*
|
||||
* Copyright (c) 2020-2021, DarkMatterCore <pabloacurielz@gmail.com>.
|
||||
*
|
||||
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
||||
*
|
||||
* nxdumptool is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* nxdumptool is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <nxdt_includes.h>
|
||||
#include <tasks.hpp>
|
||||
|
||||
namespace nxdt::tasks
|
||||
{
|
||||
/* Gamecard task. */
|
||||
|
||||
GameCardTask::GameCardTask(GameCardStatusEvent *gc_status_event) : brls::RepeatingTask(100) /* 100 ms intervals. */
|
||||
{
|
||||
this->gc_status_event = gc_status_event;
|
||||
}
|
||||
|
||||
void GameCardTask::run(retro_time_t current_time)
|
||||
{
|
||||
brls::RepeatingTask::run(current_time);
|
||||
|
||||
this->cur_gc_status = (GameCardStatus)gamecardGetStatus();
|
||||
if (this->cur_gc_status != this->prev_gc_status)
|
||||
{
|
||||
this->gc_status_event->fire(this->cur_gc_status);
|
||||
this->prev_gc_status = this->cur_gc_status;
|
||||
brls::Logger::debug("Gamecard status change triggered: {}.", this->cur_gc_status);
|
||||
}
|
||||
}
|
||||
|
||||
/* Gamecard title task. */
|
||||
|
||||
GameCardTitleTask::GameCardTitleTask(VoidEvent *gc_title_event) : brls::RepeatingTask(100) /* 100 ms intervals. */
|
||||
{
|
||||
this->gc_title_event = gc_title_event;
|
||||
}
|
||||
|
||||
void GameCardTitleTask::run(retro_time_t current_time)
|
||||
{
|
||||
brls::RepeatingTask::run(current_time);
|
||||
|
||||
if (titleIsGameCardInfoUpdated())
|
||||
{
|
||||
this->gc_title_event->fire();
|
||||
brls::Logger::debug("Gamecard title info updated.");
|
||||
}
|
||||
}
|
||||
|
||||
/* USB Mass Storage task. */
|
||||
|
||||
UmsTask::UmsTask(VoidEvent *ums_event) : brls::RepeatingTask(100) /* 100 ms intervals. */
|
||||
{
|
||||
this->ums_event = ums_event;
|
||||
}
|
||||
|
||||
void UmsTask::run(retro_time_t current_time)
|
||||
{
|
||||
brls::RepeatingTask::run(current_time);
|
||||
|
||||
if (umsIsDeviceInfoUpdated())
|
||||
{
|
||||
this->ums_event->fire();
|
||||
brls::Logger::debug("UMS device info updated.");
|
||||
}
|
||||
}
|
||||
|
||||
/* USB host device connection task. */
|
||||
|
||||
UsbHostTask::UsbHostTask(BooleanEvent *usb_host_event) : brls::RepeatingTask(100) /* 100 ms intervals. */
|
||||
{
|
||||
this->usb_host_event = usb_host_event;
|
||||
}
|
||||
|
||||
void UsbHostTask::run(retro_time_t current_time)
|
||||
{
|
||||
brls::RepeatingTask::run(current_time);
|
||||
|
||||
this->cur_usb_host_status = usbIsReady();
|
||||
if (this->cur_usb_host_status != this->prev_usb_host_status)
|
||||
{
|
||||
this->usb_host_event->fire(this->cur_usb_host_status);
|
||||
this->prev_usb_host_status = this->cur_usb_host_status;
|
||||
brls::Logger::debug("USB host status change triggered: {}.", this->cur_usb_host_status);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue