mirror of
https://github.com/LNH-team/pico-launcher.git
synced 2026-06-02 09:06:54 +02:00
Initial commit
This commit is contained in:
10
arm9/source/services/process/IProcess.h
Normal file
10
arm9/source/services/process/IProcess.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
class IProcess
|
||||
{
|
||||
public:
|
||||
virtual ~IProcess() { }
|
||||
|
||||
virtual void Run() = 0;
|
||||
virtual void Exit() = 0;
|
||||
};
|
||||
11
arm9/source/services/process/ProcessFactory.h
Normal file
11
arm9/source/services/process/ProcessFactory.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "IProcess.h"
|
||||
|
||||
class ProcessFactory
|
||||
{
|
||||
ProcessFactory() { }
|
||||
public:
|
||||
template <class T>
|
||||
static std::unique_ptr<IProcess> Construct();
|
||||
};
|
||||
37
arm9/source/services/process/ProcessFactory.thumb.cpp
Normal file
37
arm9/source/services/process/ProcessFactory.thumb.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "common.h"
|
||||
#include "core/di.h"
|
||||
#include "services/settings/JsonAppSettingsService.h"
|
||||
#include "bgm/AudioStreamPlayer.h"
|
||||
#include "bgm/IBgmService.h"
|
||||
#include "bgm/BgmService.h"
|
||||
#include "App.h"
|
||||
#include "PicoLoaderProcess.h"
|
||||
#include "ProcessFactory.h"
|
||||
|
||||
namespace di = boost::di;
|
||||
|
||||
class injected_and_bound : public di::config
|
||||
{
|
||||
public:
|
||||
static auto policies(...) noexcept
|
||||
{
|
||||
using namespace di::policies;
|
||||
using namespace di::policies::operators;
|
||||
return di::make_policies(
|
||||
constructible(is_bound<di::_>{})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
static auto diConfig = [] { return di::make_injector<injected_and_bound>(
|
||||
di::bind<RandomGenerator>().to((RandomGenerator&)*gRandomGenerator),
|
||||
di::bind<IAudioStreamPlayer>().to<AudioStreamPlayer>(),
|
||||
di::bind<IBgmService>().in(di::singleton).to<BgmService>(),
|
||||
di::bind<>().to((const char*)"/_pico/settings.json"),
|
||||
di::bind<IAppSettingsService>().in(di::singleton).to<JsonAppSettingsService>()
|
||||
); };
|
||||
|
||||
#define REGISTER_PROCESS(name) template <> std::unique_ptr<IProcess> ProcessFactory::Construct<name>() { return diConfig().create<std::unique_ptr<name>>(); }
|
||||
|
||||
REGISTER_PROCESS(App);
|
||||
REGISTER_PROCESS(PicoLoaderProcess);
|
||||
26
arm9/source/services/process/ProcessManager.cpp
Normal file
26
arm9/source/services/process/ProcessManager.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "common.h"
|
||||
#include <libtwl/rtos/rtosIrq.h>
|
||||
#include "ProcessManager.h"
|
||||
|
||||
static void vblankIrq(u32 irqMask)
|
||||
{
|
||||
VBlank::NotifyIrq();
|
||||
}
|
||||
|
||||
void ProcessManager::MainLoop()
|
||||
{
|
||||
SetupDefaultVBlankHandler();
|
||||
while (_nextProcConstructFunc)
|
||||
{
|
||||
_curProcess = _nextProcConstructFunc();
|
||||
_curProcess->Run();
|
||||
SetupDefaultVBlankHandler(); // reset because the currently registered one may use _curProcess
|
||||
_curProcess.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessManager::SetupDefaultVBlankHandler()
|
||||
{
|
||||
rtos_setIrqFunc(RTOS_IRQ_VBLANK, vblankIrq);
|
||||
rtos_enableIrqMask(RTOS_IRQ_VBLANK);
|
||||
}
|
||||
28
arm9/source/services/process/ProcessManager.h
Normal file
28
arm9/source/services/process/ProcessManager.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "IProcess.h"
|
||||
#include "ProcessFactory.h"
|
||||
|
||||
class ProcessManager
|
||||
{
|
||||
std::unique_ptr<IProcess> (*_nextProcConstructFunc)();
|
||||
std::unique_ptr<IProcess> _curProcess;
|
||||
|
||||
public:
|
||||
constexpr ProcessManager()
|
||||
: _nextProcConstructFunc(nullptr) { }
|
||||
|
||||
void MainLoop();
|
||||
void SetupDefaultVBlankHandler();
|
||||
|
||||
template <class T>
|
||||
[[gnu::noinline]]
|
||||
void Goto()
|
||||
{
|
||||
_nextProcConstructFunc = ProcessFactory::Construct<T>;
|
||||
if (_curProcess)
|
||||
_curProcess->Exit();
|
||||
}
|
||||
|
||||
IProcess* GetRunningProcess() { return _curProcess.get(); }
|
||||
};
|
||||
17
arm9/source/services/settings/AppSettings.h
Normal file
17
arm9/source/services/settings/AppSettings.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "core/String.h"
|
||||
#include "RomBrowserDisplaySettings.h"
|
||||
#include "FileAssociation.h"
|
||||
|
||||
class AppSettings
|
||||
{
|
||||
public:
|
||||
String<char, 16> language = "english";
|
||||
String<char, 64> theme = "material";
|
||||
String<char, 256> lastUsedFilePath = "";
|
||||
RomBrowserDisplaySettings romBrowserDisplaySettings;
|
||||
|
||||
std::unique_ptr<FileAssociation[]> fileAssociations;
|
||||
u32 numberOfFileAssociations = 0;
|
||||
};
|
||||
14
arm9/source/services/settings/FileAssociation.h
Normal file
14
arm9/source/services/settings/FileAssociation.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "core/String.h"
|
||||
|
||||
class FileAssociation
|
||||
{
|
||||
public:
|
||||
FileAssociation() { }
|
||||
|
||||
FileAssociation(const char* extension, const char* applicationPath)
|
||||
: extension(extension), applicationPath(applicationPath) { }
|
||||
|
||||
String<char, 8> extension;
|
||||
String<char, 256> applicationPath;
|
||||
};
|
||||
12
arm9/source/services/settings/IAppSettingsService.h
Normal file
12
arm9/source/services/settings/IAppSettingsService.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "AppSettings.h"
|
||||
|
||||
class IAppSettingsService
|
||||
{
|
||||
public:
|
||||
virtual ~IAppSettingsService() { }
|
||||
|
||||
virtual AppSettings& GetAppSettings() = 0;
|
||||
virtual const AppSettings& GetAppSettings() const = 0;
|
||||
virtual void Save() const = 0;
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
class AppSettings;
|
||||
|
||||
class JsonAppSettingsSerializer
|
||||
{
|
||||
public:
|
||||
void Serialize(const AppSettings* appSettings, const char* filePath) const;
|
||||
bool Deserialize(AppSettings* appSettings, const char* filePath) const;
|
||||
};
|
||||
@@ -0,0 +1,211 @@
|
||||
#include "common.h"
|
||||
#include <memory>
|
||||
#include "json/ArduinoJson.h"
|
||||
#include "AppSettings.h"
|
||||
#include "fat/File.h"
|
||||
#include "JsonAppSettingsSerializer.h"
|
||||
|
||||
#pragma GCC optimize("Os")
|
||||
|
||||
#define JSON_RESERVED_SIZE 2048
|
||||
|
||||
#define KEY_LANGUAGE "language"
|
||||
#define KEY_ROM_BROWSER_LAYOUT "romBrowserLayout"
|
||||
#define KEY_ROM_BROWSER_SORT_MODE "romBrowserSortMode"
|
||||
#define KEY_THEME "theme"
|
||||
#define KEY_LAST_USED_FILE_PATH "lastUsedFilePath"
|
||||
#define KEY_FILE_ASSOCIATIONS "fileAssociations"
|
||||
#define KEY_FILE_ASSOCIATIONS_APPLICATION_PATH "appPath"
|
||||
|
||||
static const char* serializeRomBrowserLayout(RomBrowserLayout romBrowserLayout)
|
||||
{
|
||||
switch (romBrowserLayout)
|
||||
{
|
||||
case RomBrowserLayout::HorizontalIconGrid:
|
||||
return "HorizontalIconGrid";
|
||||
case RomBrowserLayout::VerticalIconGrid:
|
||||
return "VerticalIconGrid";
|
||||
case RomBrowserLayout::BannerList:
|
||||
return "BannerList";
|
||||
case RomBrowserLayout::FileList:
|
||||
return "FileList";
|
||||
case RomBrowserLayout::CoverFlow:
|
||||
return "CoverFlow";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
static bool tryParseRomBrowserLayout(
|
||||
const char* romBrowserLayoutString, RomBrowserLayout& romBrowserLayout)
|
||||
{
|
||||
if (!romBrowserLayoutString)
|
||||
return false;
|
||||
|
||||
if (!strcasecmp(romBrowserLayoutString, "HorizontalIconGrid"))
|
||||
romBrowserLayout = RomBrowserLayout::HorizontalIconGrid;
|
||||
else if (!strcasecmp(romBrowserLayoutString, "VerticalIconGrid"))
|
||||
romBrowserLayout = RomBrowserLayout::VerticalIconGrid;
|
||||
else if (!strcasecmp(romBrowserLayoutString, "BannerList"))
|
||||
romBrowserLayout = RomBrowserLayout::BannerList;
|
||||
else if (!strcasecmp(romBrowserLayoutString, "FileList"))
|
||||
romBrowserLayout = RomBrowserLayout::FileList;
|
||||
else if (!strcasecmp(romBrowserLayoutString, "CoverFlow"))
|
||||
romBrowserLayout = RomBrowserLayout::CoverFlow;
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char* serializeRomBrowserSortMode(RomBrowserSortMode romBrowserSortMode)
|
||||
{
|
||||
switch (romBrowserSortMode)
|
||||
{
|
||||
case RomBrowserSortMode::NameAscending:
|
||||
return "NameAscending";
|
||||
case RomBrowserSortMode::NameDescending:
|
||||
return "NameDescending";
|
||||
case RomBrowserSortMode::LastModified:
|
||||
return "LastModified";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
static bool tryParseRomBrowserSortMode(
|
||||
const char* romBrowserDisplayModeString, RomBrowserSortMode& romBrowserSortMode)
|
||||
{
|
||||
if (!romBrowserDisplayModeString)
|
||||
return false;
|
||||
|
||||
if (!strcasecmp(romBrowserDisplayModeString, "NameAscending"))
|
||||
romBrowserSortMode = RomBrowserSortMode::NameAscending;
|
||||
else if (!strcasecmp(romBrowserDisplayModeString, "NameDescending"))
|
||||
romBrowserSortMode = RomBrowserSortMode::NameDescending;
|
||||
else if (!strcasecmp(romBrowserDisplayModeString, "LastModified"))
|
||||
romBrowserSortMode = RomBrowserSortMode::LastModified;
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool tryParseFileAssociations(const JsonObjectConst& json, AppSettings* appSettings)
|
||||
{
|
||||
if (json.isNull())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
appSettings->fileAssociations = std::make_unique_for_overwrite<FileAssociation[]>(json.size());
|
||||
int i = 0;
|
||||
for (auto item : json)
|
||||
{
|
||||
auto extension = item.key().c_str();
|
||||
auto appPath = item.value()[KEY_FILE_ASSOCIATIONS_APPLICATION_PATH].as<const char*>();
|
||||
appSettings->fileAssociations[i++] = FileAssociation(extension, appPath);
|
||||
}
|
||||
appSettings->numberOfFileAssociations = i;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void serializeFileAssociations(DynamicJsonDocument& json, const AppSettings* appSettings)
|
||||
{
|
||||
auto jsonObject = json[KEY_FILE_ASSOCIATIONS].to<JsonObject>();
|
||||
for (u32 i = 0; i < appSettings->numberOfFileAssociations; i++)
|
||||
{
|
||||
const auto& fileAssociation = appSettings->fileAssociations[i];
|
||||
auto jsonAssociation = jsonObject[fileAssociation.extension.GetString()].to<JsonObject>();
|
||||
jsonAssociation[KEY_FILE_ASSOCIATIONS_APPLICATION_PATH] = fileAssociation.applicationPath.GetString();
|
||||
}
|
||||
}
|
||||
|
||||
static std::unique_ptr<u8[]> writeJson(const AppSettings* appSettings, u32& length)
|
||||
{
|
||||
DynamicJsonDocument json(JSON_RESERVED_SIZE);
|
||||
json[KEY_LANGUAGE] = appSettings->language.GetString();
|
||||
json[KEY_ROM_BROWSER_LAYOUT] = serializeRomBrowserLayout(appSettings->romBrowserDisplaySettings.layout);
|
||||
json[KEY_ROM_BROWSER_SORT_MODE] = serializeRomBrowserSortMode(appSettings->romBrowserDisplaySettings.sortMode);
|
||||
json[KEY_THEME] = appSettings->theme.GetString();
|
||||
json[KEY_LAST_USED_FILE_PATH] = appSettings->lastUsedFilePath.GetString();
|
||||
serializeFileAssociations(json, appSettings);
|
||||
|
||||
u32 outputSize = measureJsonPretty(json);
|
||||
std::unique_ptr<u8[]> fileData(new(cache_align) u8[outputSize]);
|
||||
|
||||
serializeJsonPretty(json, fileData.get(), outputSize);
|
||||
|
||||
length = outputSize;
|
||||
return fileData;
|
||||
}
|
||||
|
||||
void JsonAppSettingsSerializer::Serialize(const AppSettings* appSettings, const char* filePath) const
|
||||
{
|
||||
u32 length = 0;
|
||||
std::unique_ptr<u8[]> fileData = writeJson(appSettings, length);
|
||||
|
||||
const auto file = std::make_unique<File>();
|
||||
if (file->Open(filePath, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)
|
||||
{
|
||||
LOG_ERROR("Couldn't open settings file for writing\n");
|
||||
return;
|
||||
}
|
||||
|
||||
u32 bytesWritten;
|
||||
if (file->Write(fileData.get(), length, bytesWritten) != FR_OK || bytesWritten != length)
|
||||
{
|
||||
LOG_ERROR("Error while writing settings file\n");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG("Settings file written\n");
|
||||
}
|
||||
|
||||
static void readJson(AppSettings* appSettings, const JsonDocument& json)
|
||||
{
|
||||
appSettings->language = json[KEY_LANGUAGE] | appSettings->language.GetString();
|
||||
appSettings->theme = json[KEY_THEME] | appSettings->theme.GetString();
|
||||
appSettings->lastUsedFilePath = json[KEY_LAST_USED_FILE_PATH] | appSettings->lastUsedFilePath.GetString();
|
||||
|
||||
RomBrowserLayout romBrowserLayout;
|
||||
if (tryParseRomBrowserLayout(json[KEY_ROM_BROWSER_LAYOUT].as<const char*>(),
|
||||
romBrowserLayout))
|
||||
{
|
||||
appSettings->romBrowserDisplaySettings.layout = romBrowserLayout;
|
||||
}
|
||||
RomBrowserSortMode romBrowserSortMode;
|
||||
if (tryParseRomBrowserSortMode(json[KEY_ROM_BROWSER_SORT_MODE].as<const char*>(),
|
||||
romBrowserSortMode))
|
||||
{
|
||||
appSettings->romBrowserDisplaySettings.sortMode = romBrowserSortMode;
|
||||
}
|
||||
|
||||
tryParseFileAssociations(json[KEY_FILE_ASSOCIATIONS], appSettings);
|
||||
}
|
||||
|
||||
bool JsonAppSettingsSerializer::Deserialize(AppSettings* appSettings, const char* filePath) const
|
||||
{
|
||||
const auto file = std::make_unique<File>();
|
||||
if (file->Open(filePath, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||
return false;
|
||||
|
||||
u32 fileSize = file->GetSize();
|
||||
if (fileSize == 0)
|
||||
return false;
|
||||
|
||||
std::unique_ptr<u8[]> fileData(new(cache_align) u8[fileSize]);
|
||||
u8* fileDataPtr = fileData.get();
|
||||
|
||||
u32 bytesRead = 0;
|
||||
if (file->Read(fileDataPtr, fileSize, bytesRead) != FR_OK)
|
||||
return false;
|
||||
|
||||
DynamicJsonDocument json(JSON_RESERVED_SIZE);
|
||||
if (deserializeJson(json, fileDataPtr, fileSize) != DeserializationError::Ok)
|
||||
return false;
|
||||
|
||||
readJson(appSettings, json);
|
||||
|
||||
return true;
|
||||
}
|
||||
9
arm9/source/services/settings/JsonAppSettingsService.cpp
Normal file
9
arm9/source/services/settings/JsonAppSettingsService.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "common.h"
|
||||
#include "JsonAppSettingsService.h"
|
||||
|
||||
JsonAppSettingsService::JsonAppSettingsService(const char* filePath)
|
||||
: _filePath(filePath)
|
||||
{
|
||||
if (!_serializer.Deserialize(&_appSettings, _filePath))
|
||||
Save();
|
||||
}
|
||||
20
arm9/source/services/settings/JsonAppSettingsService.h
Normal file
20
arm9/source/services/settings/JsonAppSettingsService.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include "IAppSettingsService.h"
|
||||
#include "JsonAppSettingsSerializer.h"
|
||||
|
||||
class JsonAppSettingsService : public IAppSettingsService
|
||||
{
|
||||
JsonAppSettingsSerializer _serializer;
|
||||
AppSettings _appSettings;
|
||||
const char* _filePath;
|
||||
public:
|
||||
explicit JsonAppSettingsService(const char* filePath);
|
||||
|
||||
AppSettings& GetAppSettings() override { return _appSettings; }
|
||||
const AppSettings& GetAppSettings() const override { return _appSettings; }
|
||||
|
||||
void Save() const override
|
||||
{
|
||||
_serializer.Serialize(&_appSettings, _filePath);
|
||||
}
|
||||
};
|
||||
10
arm9/source/services/settings/RomBrowserDisplaySettings.h
Normal file
10
arm9/source/services/settings/RomBrowserDisplaySettings.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include "RomBrowserLayout.h"
|
||||
#include "RomBrowserSortMode.h"
|
||||
|
||||
class RomBrowserDisplaySettings
|
||||
{
|
||||
public:
|
||||
RomBrowserLayout layout = RomBrowserLayout::HorizontalIconGrid;
|
||||
RomBrowserSortMode sortMode = RomBrowserSortMode::NameAscending;
|
||||
};
|
||||
10
arm9/source/services/settings/RomBrowserLayout.h
Normal file
10
arm9/source/services/settings/RomBrowserLayout.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
enum class RomBrowserLayout
|
||||
{
|
||||
HorizontalIconGrid,
|
||||
VerticalIconGrid,
|
||||
BannerList,
|
||||
FileList,
|
||||
CoverFlow
|
||||
};
|
||||
8
arm9/source/services/settings/RomBrowserSortMode.h
Normal file
8
arm9/source/services/settings/RomBrowserSortMode.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
enum class RomBrowserSortMode
|
||||
{
|
||||
NameAscending,
|
||||
NameDescending,
|
||||
LastModified
|
||||
};
|
||||
Reference in New Issue
Block a user