Files
Horizon-OC/Source/Horizon-OC-Monitor/source/main.cpp
2026-05-10 11:22:31 -04:00

1164 lines
38 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#define TESLA_INIT_IMPL
#include <tesla.hpp>
#include "Utils.hpp"
#include <cstdlib>
#include <ctime>
//static tsl::elm::HeaderOverlayFrame* rootFrame = nullptr;
static bool skipMain = false;
static std::string lastSelectedItem;
#include "modes/FPS_Counter.hpp"
#include "modes/FPS_Graph.hpp"
#include "modes/Full.hpp"
#include "modes/Mini.hpp"
#include "modes/Micro.hpp"
#include "modes/Battery.hpp"
#include "modes/Misc.hpp"
#include "modes/Resolutions.hpp"
#include "modes/Configurator.hpp"
//Graphs
//class GraphsMenu : public tsl::Gui {
//public:
// GraphsMenu() {}
//
// virtual tsl::elm::Element* createUI() override {
//
// auto* list = new tsl::elm::List();
//
// list->addItem(new tsl::elm::CategoryHeader("FPS"));
//
// auto* comFPSGraph = new tsl::elm::ListItem("Graph");
// comFPSGraph->setClickListener([](uint64_t keys) {
// if (keys & KEY_A) {
// tsl::swapTo<com_FPSGraph>();
// return true;
// }
// return false;
// });
// list->addItem(comFPSGraph);
//
// auto* comFPSCounter = new tsl::elm::ListItem("Counter");
// comFPSCounter->setClickListener([](uint64_t keys) {
// if (keys & KEY_A) {
// tsl::swapTo<com_FPS>();
// return true;
// }
// return false;
// });
// list->addItem(comFPSCounter);
//
// tsl::elm::HeaderOverlayFrame* rootFrame = new tsl::elm::HeaderOverlayFrame("Horizon OC Monitor", "Modes");
// rootFrame->setContent(list);
//
// return rootFrame;
// }
//
// virtual void update() override {
// if (fixForeground) {
// fixForeground = false;
// tsl::hlp::requestForeground(true);
// }
// }
//
// virtual bool handleInput(u64 keysDown, u64 keysHeld, const HidTouchState &touchPos, HidAnalogStickState joyStickPosLeft, HidAnalogStickState joyStickPosRight) override {
// if (disableJumpTo)
// disableJumpTo = false;
// if (fixHiding) {
// if (isKeyComboPressed2(keysDown, keysHeld)) {
// tsl::Overlay::get()->hide();
// fixHiding = false;
// return true;
// }
// }
//
// if (keysDown & KEY_B) {
// tsl::goBack();
// return true;
// }
// return false;
// }
//};
//Other
class OtherMenu : public tsl::Gui {
public:
OtherMenu() { }
virtual tsl::elm::Element* createUI() override {
auto* list = new tsl::elm::List();
list->addItem(new tsl::elm::CategoryHeader("Other"));
auto* Battery = new tsl::elm::ListItem("Battery/Charger");
Battery->disableClickAnimation();
Battery->setClickListener([](uint64_t keys) {
if (keys & KEY_A) {
tsl::swapTo<BatteryOverlay>();
return true;
}
return false;
});
list->addItem(Battery);
auto* Misc = new tsl::elm::ListItem("Miscellaneous");
Misc->disableClickAnimation();
Misc->setClickListener([](uint64_t keys) {
if (keys & KEY_A) {
tsl::swapTo<MiscOverlay>();
return true;
}
return false;
});
list->addItem(Misc);
//if (SaltySD) {
// auto* Res = new tsl::elm::ListItem("Game Resolutions");
// Res->setClickListener([](uint64_t keys) {
// if (keys & KEY_A) {
// tsl::swapTo<ResolutionsOverlay>();
// return true;
// }
// return false;
// });
// list->addItem(Res);
//}
//tsl::elm::g_disableMenuCacheOnReturn.store(true, std::memory_order_release);
tsl::elm::HeaderOverlayFrame* rootFrame = new tsl::elm::HeaderOverlayFrame("Horizon OC Monitor", "Modes");
if (!lastSelectedItem.empty())
list->jumpToItem(lastSelectedItem);
rootFrame->setContent(list);
return rootFrame;
}
virtual void update() override {
if (fixForeground) {
fixForeground = false;
tsl::hlp::requestForeground(true);
}
}
virtual bool handleInput(u64 keysDown, u64 keysHeld, const HidTouchState &touchPos, HidAnalogStickState joyStickPosLeft, HidAnalogStickState joyStickPosRight) override {
if (disableJumpTo)
disableJumpTo = false;
if (fixHiding) {
if (isKeyComboPressed2(keysDown, keysHeld)) {
tsl::Overlay::get()->hide();
fixHiding = false;
return true;
}
}
if (keysDown & KEY_B) {
lastSelectedItem = "Other";
tsl::swapTo<MainMenu>();
triggerRumbleDoubleClick.store(true, std::memory_order_release);
triggerExitSound.store(true, std::memory_order_release);
return true;
}
return false;
}
};
//Main Menu
class MainMenu : public tsl::Gui {
public:
MainMenu() {
if (lastMode != "returning")
lastMode = "";
}
virtual tsl::elm::Element* createUI() override {
auto* list = new tsl::elm::List();
//list->addItem(new tsl::elm::CategoryHeader("Modes " + ult::DIVIDER_SYMBOL + " \uE0E0 Enter " + ult::DIVIDER_SYMBOL + " \uE0E3 Configure"));
list->addItem(new tsl::elm::CategoryHeader("Modes " + ult::DIVIDER_SYMBOL + " \uE0E3 Configure"));
auto* Full = new tsl::elm::ListItem("Full");
Full->disableClickAnimation();
Full->setClickListener([](uint64_t keys) {
if (keys & KEY_A) {
lastMode = "full";
tsl::swapTo<FullOverlay>();
return true;
}
if (keys & KEY_Y) {
triggerRumbleClick.store(true, std::memory_order_release);
triggerSettingsSound.store(true, std::memory_order_release);
// Launch configurator for Mini mode
tsl::swapTo<ConfiguratorOverlay>("Full");
return true;
}
return false;
});
list->addItem(Full);
//auto* Mini = new tsl::elm::ListItem("Mini");
//Mini->setClickListener([](uint64_t keys) {
// if (keys & KEY_A) {
// tsl::swapTo<MiniOverlay>();
// return true;
// }
// return false;
//});
//list->addItem(Mini);
bool fileExist = false;
FILE* test = fopen(std::string(folderpath + filename).c_str(), "rb");
if (test) {
fclose(test);
fileExist = true;
filepath = folderpath + filename;
}
else {
test = fopen(std::string(folderpath + "Status-Monitor-Overlay.ovl").c_str(), "rb");
if (test) {
fclose(test);
fileExist = true;
filepath = folderpath + "Status-Monitor-Overlay.ovl";
}
}
if (fileExist) {
auto* Mini = new tsl::elm::ListItem("Mini");
Mini->disableClickAnimation();
Mini->setClickListener([](uint64_t keys) {
if (keys & KEY_A) {
tsl::setNextOverlay(filepath, "-mini_");
tsl::Overlay::get()->close();
return true;
}
if (keys & KEY_Y) {
triggerRumbleClick.store(true, std::memory_order_release);
triggerSettingsSound.store(true, std::memory_order_release);
// Launch configurator for Mini mode
tsl::swapTo<ConfiguratorOverlay>("Mini");
return true;
}
return false;
});
list->addItem(Mini);
auto* Micro = new tsl::elm::ListItem("Micro");
Micro->disableClickAnimation();
Micro->setClickListener([](uint64_t keys) {
if (keys & KEY_A) {
tsl::setNextOverlay(filepath, "-micro_");
tsl::Overlay::get()->close();
return true;
}
if (keys & KEY_Y) {
triggerRumbleClick.store(true, std::memory_order_release);
triggerSettingsSound.store(true, std::memory_order_release);
// Launch configurator for Micro mode
tsl::swapTo<ConfiguratorOverlay>("Micro");
return true;
}
return false;
});
list->addItem(Micro);
}
if (SaltySD) {
//auto* Graphs = new tsl::elm::ListItem("FPS");
//Graphs->setValue(ult::DROPDOWN_SYMBOL);
//Graphs->setClickListener([](uint64_t keys) {
// if (keys & KEY_A) {
// tsl::swapTo<GraphsMenu>();
// return true;
// }
// return false;
//});
//list->addItem(Graphs);
auto* comFPSGraph = new tsl::elm::ListItem("FPS Graph");
comFPSGraph->disableClickAnimation();
comFPSGraph->setClickListener([](uint64_t keys) {
//if (keys & KEY_A) {
// tsl::elm::g_disableMenuCacheOnReturn.store(true, std::memory_order_release);
// lastMode = "fps_graph";
// tsl::swapTo<com_FPSGraph>();
// return true;
//}
if (keys & KEY_A) {
tsl::setNextOverlay(filepath, "-fps_graph_");
tsl::Overlay::get()->close();
return true;
}
if (keys & KEY_Y) {
triggerRumbleClick.store(true, std::memory_order_release);
triggerSettingsSound.store(true, std::memory_order_release);
// Launch configurator for Micro mode
tsl::swapTo<ConfiguratorOverlay>("FPS Graph");
return true;
}
return false;
});
list->addItem(comFPSGraph);
auto* comFPSCounter = new tsl::elm::ListItem("FPS Counter");
comFPSCounter->disableClickAnimation();
comFPSCounter->setClickListener([](uint64_t keys) {
//if (keys & KEY_A) {
// tsl::elm::g_disableMenuCacheOnReturn.store(true, std::memory_order_release);
// lastMode = "fps_counter";
// tsl::swapTo<com_FPS>();
// return true;
//}
if (keys & KEY_A) {
tsl::setNextOverlay(filepath, "-fps_counter_");
tsl::Overlay::get()->close();
return true;
}
if (keys & KEY_Y) {
triggerRumbleClick.store(true, std::memory_order_release);
triggerSettingsSound.store(true, std::memory_order_release);
// Launch configurator for Micro mode
tsl::swapTo<ConfiguratorOverlay>("FPS Counter");
return true;
}
return false;
});
list->addItem(comFPSCounter);
auto* Res = new tsl::elm::ListItem("Game Resolutions");
Res->disableClickAnimation();
Res->setClickListener([](uint64_t keys) {
//if (keys & KEY_A) {
// tsl::elm::g_disableMenuCacheOnReturn.store(true, std::memory_order_release);
// lastMode = "game_resolutions";
// tsl::swapTo<ResolutionsOverlay>();
// return true;
//}
if (keys & KEY_A) {
tsl::setNextOverlay(filepath, "-game_resolutions_");
tsl::Overlay::get()->close();
return true;
}
if (keys & KEY_Y) {
triggerRumbleClick.store(true, std::memory_order_release);
triggerSettingsSound.store(true, std::memory_order_release);
// Launch configurator for Micro mode
tsl::swapTo<ConfiguratorOverlay>("Game Resolutions");
return true;
}
return false;
});
list->addItem(Res);
}
auto* Other = new tsl::elm::ListItem("Other");
Other->disableClickAnimation();
Other->setValue(ult::DROPDOWN_SYMBOL);
Other->setClickListener([](uint64_t keys) {
if (keys & KEY_A) {
triggerRumbleClick.store(true, std::memory_order_release);
triggerEnterSound.store(true, std::memory_order_release);
tsl::swapTo<OtherMenu>();
return true;
}
return false;
});
list->addItem(Other);
if (!lastSelectedItem.empty())
list->jumpToItem(lastSelectedItem);
//list->disableCaching();
tsl::elm::HeaderOverlayFrame* rootFrame = new tsl::elm::HeaderOverlayFrame("Horizon OC Monitor", APP_VERSION);
rootFrame->setContent(list);
return rootFrame;
}
virtual void update() override {
if (!ult::useRightAlignment) {
//if ((tsl::cfg::LayerPosX || tsl::cfg::LayerPosY)) {
tsl::gfx::Renderer::get().setLayerPos(0, 0);
//}
} else {
const auto [horizontalUnderscanPixels, verticalUnderscanPixels] = tsl::gfx::getUnderscanPixels();
tsl::gfx::Renderer::get().setLayerPos(1280-32 - horizontalUnderscanPixels, 0);
}
if (fixForeground) {
fixForeground = false;
tsl::hlp::requestForeground(true);
}
}
virtual bool handleInput(u64 keysDown, u64 keysHeld, const HidTouchState &touchPos, HidAnalogStickState joyStickPosLeft, HidAnalogStickState joyStickPosRight) override {
if (disableJumpTo)
disableJumpTo = false;
if (fixHiding) {
if (isKeyComboPressed2(keysDown, keysHeld)) {
tsl::Overlay::get()->hide();
fixHiding = false;
return true;
}
}
if (keysDown & KEY_B) {
tsl::goBack();
return true;
}
return false;
}
};
class MonitorOverlay : public tsl::Overlay {
public:
virtual void initServices() override {
//Initialize services
tsl::hlp::doWithSmSession([this]{
apmInitialize();
if (hosversionAtLeast(5,0,0)) tcCheck = tcInitialize();
if (hosversionAtLeast(6,0,0) && R_SUCCEEDED(pwmInitialize())) {
pwmCheck = pwmOpenSession2(&g_ICon, 0x3D000001);
}
if (R_SUCCEEDED(nvInitialize())) nvCheck = nvOpen(&fd, "/dev/nvhost-ctrl-gpu");
psmCheck = psmInitialize();
if (R_SUCCEEDED(psmCheck)) {
psmService = psmGetServiceSession();
}
i2cCheck = i2cInitialize();
SaltySD = CheckPort();
if (SaltySD) {
LoadSharedMemoryAndRefreshRate();
}
if (hocclkIpcRunning() && R_SUCCEEDED(hocclkIpcInitialize())) {
uint32_t hocClkApiVer = 0;
hocclkIpcGetAPIVersion(&hocClkApiVer);
if (hocClkApiVer != HOCCLK_IPC_API_VERSION) {
hocclkIpcExit();
}
else hocclkCheck = 0;
}
if (R_SUCCEEDED(splInitialize())) {
u64 sku = 0;
splGetConfig(SplConfigItem_HardwareType, &sku);
switch(sku) {
case 2 ... 5:
isMariko = true;
break;
default:
isMariko = false;
}
}
splExit();
});
Hinted = envIsSyscallHinted(0x6F);
}
virtual void exitServices() override {
CloseThreads();
if (R_SUCCEEDED(hocclkCheck)) {
hocclkIpcExit();
}
shmemClose(&_sharedmemory);
//Exit services
tsExit();
tcExit();
pwmChannelSessionClose(&g_ICon);
pwmExit();
nvClose(fd);
nvExit();
psmExit();
i2cExit();
apmExit();
}
virtual void onShow() override {} // Called before overlay wants to change from invisible to visible state
virtual void onHide() override {} // Called before overlay wants to change from visible to invisible state
virtual std::unique_ptr<tsl::Gui> loadInitialGui() override {
return initially<MainMenu>(); // Initial Gui to load. It's possible to pass arguments to it's constructor like this
}
};
class MicroMode : public tsl::Overlay {
public:
virtual void initServices() override {
//tsl::hlp::requestForeground(false);
//Initialize services
tsl::hlp::doWithSmSession([this]{
apmInitialize();
if (R_SUCCEEDED(nvInitialize())) nvCheck = nvOpen(&fd, "/dev/nvhost-ctrl-gpu");
if (hosversionAtLeast(5,0,0)) tcCheck = tcInitialize();
if (hosversionAtLeast(6,0,0) && R_SUCCEEDED(pwmInitialize())) {
pwmCheck = pwmOpenSession2(&g_ICon, 0x3D000001);
}
i2cCheck = i2cInitialize();
psmCheck = psmInitialize();
if (R_SUCCEEDED(psmCheck)) {
psmService = psmGetServiceSession();
}
SaltySD = CheckPort();
if (SaltySD) {
LoadSharedMemory();
}
if (hocclkIpcRunning() && R_SUCCEEDED(hocclkIpcInitialize())) {
uint32_t hocClkApiVer = 0;
hocclkIpcGetAPIVersion(&hocClkApiVer);
if (hocClkApiVer != HOCCLK_IPC_API_VERSION) {
hocclkIpcExit();
}
else hocclkCheck = 0;
}
if (R_SUCCEEDED(splInitialize())) {
u64 sku = 0;
splGetConfig(SplConfigItem_HardwareType, &sku);
switch(sku) {
case 2 ... 5:
isMariko = true;
break;
default:
isMariko = false;
}
}
splExit();
});
Hinted = envIsSyscallHinted(0x6F);
}
virtual void exitServices() override {
CloseThreads();
shmemClose(&_sharedmemory);
if (R_SUCCEEDED(hocclkCheck)) {
hocclkIpcExit();
}
//Exit services
tsExit();
tcExit();
pwmChannelSessionClose(&g_ICon);
pwmExit();
i2cExit();
psmExit();
nvClose(fd);
nvExit();
apmExit();
}
virtual void onShow() override { // Called before overlay wants to change from invisible to visible state
tsl::hlp::requestForeground(false);
}
virtual void onHide() override {} // Called before overlay wants to change from visible to invisible state
virtual std::unique_ptr<tsl::Gui> loadInitialGui() override {
return initially<MicroOverlay>(); // Initial Gui to load. It's possible to pass arguments to it's constructor like this
}
};
class MiniEntryOverlay : public tsl::Overlay {
public:
MiniEntryOverlay() {}
virtual void initServices() override {
//tsl::hlp::requestForeground(false);
// Same serviceinit as before
tsl::hlp::doWithSmSession([this]{
apmInitialize();
if (R_SUCCEEDED(nvInitialize())) nvCheck = nvOpen(&fd, "/dev/nvhost-ctrl-gpu");
if (hosversionAtLeast(5,0,0)) tcCheck = tcInitialize();
if (hosversionAtLeast(6,0,0) && R_SUCCEEDED(pwmInitialize())) {
pwmCheck = pwmOpenSession2(&g_ICon, 0x3D000001);
}
i2cCheck = i2cInitialize();
psmCheck = psmInitialize();
if (R_SUCCEEDED(psmCheck)) {
psmService = psmGetServiceSession();
}
SaltySD = CheckPort();
if (SaltySD) {
LoadSharedMemory();
}
if (hocclkIpcRunning() && R_SUCCEEDED(hocclkIpcInitialize())) {
uint32_t hocClkApiVer = 0;
hocclkIpcGetAPIVersion(&hocClkApiVer);
if (hocClkApiVer != HOCCLK_IPC_API_VERSION) {
hocclkIpcExit();
}
else hocclkCheck = 0;
}
if (R_SUCCEEDED(splInitialize())) {
u64 sku = 0;
splGetConfig(SplConfigItem_HardwareType, &sku);
switch(sku) {
case 2 ... 5:
isMariko = true;
break;
default:
isMariko = false;
}
}
splExit();
});
Hinted = envIsSyscallHinted(0x6F);
}
virtual void exitServices() override {
CloseThreads();
shmemClose(&_sharedmemory);
if (R_SUCCEEDED(hocclkCheck)) {
hocclkIpcExit();
}
// Exit services
tsExit();
tcExit();
pwmChannelSessionClose(&g_ICon);
pwmExit();
i2cExit();
psmExit();
nvClose(fd);
nvExit();
apmExit();
}
// **Override onShow** so that as soon as this Overlay appears, we let input pass through.
virtual void onShow() override {
// Request that Tesla stop grabbing all buttons/touches
tsl::hlp::requestForeground(false);
// (Optional) hide Teslas footer if you dont want it
//deactivateOriginalFooter = true;
}
virtual std::unique_ptr<tsl::Gui> loadInitialGui() override {
// Immediately show your MiniOverlay page
return initially<MiniOverlay>();
}
};
class FPSGraphEntryOverlay : public tsl::Overlay {
public:
FPSGraphEntryOverlay() {}
virtual void initServices() override {
tsl::hlp::doWithSmSession([this]{
apmInitialize();
if (R_SUCCEEDED(nvInitialize())) nvCheck = nvOpen(&fd, "/dev/nvhost-ctrl-gpu");
if (hosversionAtLeast(5,0,0)) tcCheck = tcInitialize();
if (hosversionAtLeast(6,0,0) && R_SUCCEEDED(pwmInitialize())) {
pwmCheck = pwmOpenSession2(&g_ICon, 0x3D000001);
}
i2cCheck = i2cInitialize();
psmCheck = psmInitialize();
if (R_SUCCEEDED(psmCheck)) {
psmService = psmGetServiceSession();
}
SaltySD = CheckPort();
if (SaltySD) {
LoadSharedMemoryAndRefreshRate();
}
if (hocclkIpcRunning() && R_SUCCEEDED(hocclkIpcInitialize())) {
uint32_t hocClkApiVer = 0;
hocclkIpcGetAPIVersion(&hocClkApiVer);
if (hocClkApiVer != HOCCLK_IPC_API_VERSION) {
hocclkIpcExit();
}
else hocclkCheck = 0;
}
if (R_SUCCEEDED(splInitialize())) {
u64 sku = 0;
splGetConfig(SplConfigItem_HardwareType, &sku);
switch(sku) {
case 2 ... 5:
isMariko = true;
break;
default:
isMariko = false;
}
}
splExit();
});
Hinted = envIsSyscallHinted(0x6F);
}
virtual void exitServices() override {
CloseThreads();
shmemClose(&_sharedmemory);
if (R_SUCCEEDED(hocclkCheck)) {
hocclkIpcExit();
}
tsExit();
tcExit();
pwmChannelSessionClose(&g_ICon);
pwmExit();
i2cExit();
psmExit();
nvClose(fd);
nvExit();
apmExit();
}
virtual void onShow() override {
tsl::hlp::requestForeground(false);
//deactivateOriginalFooter = true;
}
virtual std::unique_ptr<tsl::Gui> loadInitialGui() override {
return initially<com_FPSGraph>();
}
};
class FPSCounterEntryOverlay : public tsl::Overlay {
public:
FPSCounterEntryOverlay() {}
virtual void initServices() override {
tsl::hlp::doWithSmSession([this]{
apmInitialize();
if (R_SUCCEEDED(nvInitialize())) nvCheck = nvOpen(&fd, "/dev/nvhost-ctrl-gpu");
if (hosversionAtLeast(5,0,0)) tcCheck = tcInitialize();
if (hosversionAtLeast(6,0,0) && R_SUCCEEDED(pwmInitialize())) {
pwmCheck = pwmOpenSession2(&g_ICon, 0x3D000001);
}
i2cCheck = i2cInitialize();
psmCheck = psmInitialize();
if (R_SUCCEEDED(psmCheck)) {
psmService = psmGetServiceSession();
}
SaltySD = CheckPort();
if (SaltySD) {
LoadSharedMemoryAndRefreshRate();
}
if (hocclkIpcRunning() && R_SUCCEEDED(hocclkIpcInitialize())) {
uint32_t hocClkApiVer = 0;
hocclkIpcGetAPIVersion(&hocClkApiVer);
if (hocClkApiVer != HOCCLK_IPC_API_VERSION) {
hocclkIpcExit();
}
else hocclkCheck = 0;
}
if (R_SUCCEEDED(splInitialize())) {
u64 sku = 0;
splGetConfig(SplConfigItem_HardwareType, &sku);
switch(sku) {
case 2 ... 5:
isMariko = true;
break;
default:
isMariko = false;
}
}
splExit();
});
Hinted = envIsSyscallHinted(0x6F);
}
virtual void exitServices() override {
CloseThreads();
shmemClose(&_sharedmemory);
if (R_SUCCEEDED(hocclkCheck)) {
hocclkIpcExit();
}
tsExit();
tcExit();
pwmChannelSessionClose(&g_ICon);
pwmExit();
i2cExit();
psmExit();
nvClose(fd);
nvExit();
apmExit();
}
virtual void onShow() override {
tsl::hlp::requestForeground(false);
//deactivateOriginalFooter = true;
}
virtual std::unique_ptr<tsl::Gui> loadInitialGui() override {
return initially<com_FPS>();
}
};
class GameResolutionsEntryOverlay : public tsl::Overlay {
public:
GameResolutionsEntryOverlay() {}
virtual void initServices() override {
tsl::hlp::doWithSmSession([this]{
apmInitialize();
if (R_SUCCEEDED(nvInitialize())) nvCheck = nvOpen(&fd, "/dev/nvhost-ctrl-gpu");
if (hosversionAtLeast(5,0,0)) tcCheck = tcInitialize();
if (hosversionAtLeast(6,0,0) && R_SUCCEEDED(pwmInitialize())) {
pwmCheck = pwmOpenSession2(&g_ICon, 0x3D000001);
}
i2cCheck = i2cInitialize();
psmCheck = psmInitialize();
if (R_SUCCEEDED(psmCheck)) {
psmService = psmGetServiceSession();
}
SaltySD = CheckPort();
if (SaltySD) {
LoadSharedMemoryAndRefreshRate();
}
if (hocclkIpcRunning() && R_SUCCEEDED(hocclkIpcInitialize())) {
uint32_t hocClkApiVer = 0;
hocclkIpcGetAPIVersion(&hocClkApiVer);
if (hocClkApiVer != HOCCLK_IPC_API_VERSION) {
hocclkIpcExit();
}
else hocclkCheck = 0;
}
if (R_SUCCEEDED(splInitialize())) {
u64 sku = 0;
splGetConfig(SplConfigItem_HardwareType, &sku);
switch(sku) {
case 2 ... 5:
isMariko = true;
break;
default:
isMariko = false;
}
}
splExit();
});
Hinted = envIsSyscallHinted(0x6F);
}
virtual void exitServices() override {
CloseThreads();
shmemClose(&_sharedmemory);
if (R_SUCCEEDED(hocclkCheck)) {
hocclkIpcExit();
}
tsExit();
tcExit();
pwmChannelSessionClose(&g_ICon);
pwmExit();
i2cExit();
psmExit();
nvClose(fd);
nvExit();
apmExit();
}
virtual void onShow() override {
tsl::hlp::requestForeground(false);
//deactivateOriginalFooter = true;
}
virtual std::unique_ptr<tsl::Gui> loadInitialGui() override {
return initially<ResolutionsOverlay>();
}
};
// Helper function to check if overlay file exists
bool checkOverlayFile(const std::string& filename) {
struct stat buffer;
return stat(filename.c_str(), &buffer) == 0;
}
// Helper function to setup micro mode paths
inline void setupMode(const std::string& modeType = "") {
if (modeType == "micro") {
if (!ult::limitedMemory) {
ult::DefaultFramebufferWidth = 1280;
ult::DefaultFramebufferHeight = 720;
} else {
ult::DefaultFramebufferWidth = 1280;
ult::DefaultFramebufferHeight = 28;
}
} else {
if (!ult::limitedMemory) {
ult::DefaultFramebufferWidth = 1280;
ult::DefaultFramebufferHeight = 720;
}
}
// Try user-specified filename first, then fallback to default
const std::string primaryPath = folderpath + filename;
if (checkOverlayFile(primaryPath)) {
filepath = primaryPath;
} else {
const std::string fallbackPath = folderpath + "Status-Monitor-Overlay.ovl";
if (checkOverlayFile(fallbackPath)) {
filepath = fallbackPath;
}
}
}
//void setupMicroMode() {
// ult::DefaultFramebufferWidth = 1280;
// //ult::DefaultFramebufferHeight = 28;
// ult::DefaultFramebufferHeight = 720;
//
// // Try user-specified filename first, then fallback to default
// const std::string primaryPath = folderpath + filename;
//
// if (checkOverlayFile(primaryPath)) {
// filepath = primaryPath;
// } else {
// const std::string fallbackPath = folderpath + "Status-Monitor-Overlay.ovl";
// if (checkOverlayFile(fallbackPath)) {
// filepath = fallbackPath;
// }
// }
//}
// This function gets called on startup to create a new Overlay object
int main(int argc, char **argv) {
// load heap settings outside of loop (only Status Monitor directive)
ult::currentHeapSize = ult::getCurrentHeapSize();
ult::expandedMemory = ult::currentHeapSize >= ult::OverlayHeapSize::Size_8MB;
ult::limitedMemory = ult::currentHeapSize == ult::OverlayHeapSize::Size_4MB;
// Initialize buffer sizes based on expanded memory setting
if (ult::expandedMemory) {
ult::furtherExpandedMemory = ult::currentHeapSize > ult::OverlayHeapSize::Size_8MB;
if (!ult::furtherExpandedMemory) {
ult::loaderTitle += "+";
ult::COPY_BUFFER_SIZE = 262144;
ult::HEX_BUFFER_SIZE = 8192;
ult::UNZIP_READ_BUFFER = 262144;
ult::UNZIP_WRITE_BUFFER = 131072;
ult::DOWNLOAD_READ_BUFFER = 131072;
ult::DOWNLOAD_WRITE_BUFFER = 131072;
} else {
ult::loaderTitle += "×";
ult::COPY_BUFFER_SIZE = 262144*2;
ult::HEX_BUFFER_SIZE = 8192;
ult::UNZIP_READ_BUFFER = 262144*2;
ult::UNZIP_WRITE_BUFFER = 131072*4;
ult::DOWNLOAD_READ_BUFFER = 131072*4;
ult::DOWNLOAD_WRITE_BUFFER = 131072*4;
}
} else if (ult::limitedMemory) {
ult::loaderTitle += "-";
ult::DOWNLOAD_READ_BUFFER = 16*1024;
ult::UNZIP_READ_BUFFER = 16*1024;
}
systemtickfrequency = armGetSystemTickFreq();
ParseIniFile(); // parse INI from file
if (argc > 0) {
filename = argv[0]; // set global
{
// Read the entire INI file once
auto iniData = ult::getParsedDataFromIniFile(ult::OVERLAYS_INI_FILEPATH);
auto sectionIt = iniData.find(filename);
if (sectionIt != iniData.end()) {
auto& section = sectionIt->second;
// Compare and update if values differ
const std::string expectedArgs = "(-mini, -micro, -fps_graph, -fps_counter, -game_resolutions)";
if (section["mode_args"] != expectedArgs) {
section["mode_args"] = expectedArgs;
section["mode_labels"] = "(Mini, Micro, FPS Graph, FPS Counter, Game Resolutions)";
ult::saveIniFileData(ult::OVERLAYS_INI_FILEPATH, iniData);
}
} else {
// If section doesn't exist, create it with expected values
iniData[filename]["mode_args"] = "(-mini, -micro, -fps_graph, -fps_counter, -game_resolutions)";
iniData[filename]["mode_labels"] = "(Mini, Micro, FPS Graph, FPS Counter, Game Resolutions)";
ult::saveIniFileData(ult::OVERLAYS_INI_FILEPATH, iniData);
}
}
// Process command line arguments
for (u8 arg = 0; arg < argc; arg++) {
const char* argStr = argv[arg];
if (argStr[0] != '-') continue;
// Check if ends with underscore and create comparison string without it
const size_t len = strlen(argStr);
const bool hasUnderscore = (len > 1 && argStr[len-1] == '_');
// For underscore variants, compare without the trailing underscore
char modeStr[32];
const char* compareStr;
if (hasUnderscore) {
strncpy(modeStr, argStr, len - 1);
modeStr[len - 1] = '\0';
compareStr = modeStr;
} else {
compareStr = argStr;
}
// Micro mode
if (strcasecmp(compareStr, "-micro") == 0) {
FullMode = false;
lastMode = "micro";
if (hasUnderscore) {
setupMode(lastMode);
} else {
skipMain = true;
if (!ult::limitedMemory) {
ult::DefaultFramebufferWidth = 1280;
ult::DefaultFramebufferHeight = 720;
} else {
ult::DefaultFramebufferWidth = 1280;
ult::DefaultFramebufferHeight = 28;
}
}
return tsl::loop<MicroMode>(argc, argv);
}
// Mini mode
else if (strcasecmp(compareStr, "-mini") == 0) {
FullMode = false;
lastMode = "mini";
if (hasUnderscore) {
setupMode();
} else {
skipMain = true;
if (!ult::limitedMemory) {
ult::DefaultFramebufferWidth = 1280;
ult::DefaultFramebufferHeight = 720;
}
}
return tsl::loop<MiniEntryOverlay>(argc, argv);
}
// FPS Graph mode
else if (strcasecmp(compareStr, "-fps_graph") == 0) {
FullMode = false;
lastMode = "fps_graph";
if (hasUnderscore) {
setupMode();
} else {
skipMain = true;
if (!ult::limitedMemory) {
ult::DefaultFramebufferWidth = 1280;
ult::DefaultFramebufferHeight = 720;
}
}
return tsl::loop<FPSGraphEntryOverlay>(argc, argv);
}
// FPS Counter mode
else if (strcasecmp(compareStr, "-fps_counter") == 0) {
FullMode = false;
lastMode = "fps_counter";
if (hasUnderscore) {
setupMode();
} else {
skipMain = true;
if (!ult::limitedMemory) {
ult::DefaultFramebufferWidth = 1280;
ult::DefaultFramebufferHeight = 720;
}
}
return tsl::loop<FPSCounterEntryOverlay>(argc, argv);
}
// Game Resolutions mode
else if (strcasecmp(compareStr, "-game_resolutions") == 0) {
FullMode = false;
lastMode = "game_resolutions";
if (hasUnderscore) {
setupMode();
} else {
skipMain = true;
if (!ult::limitedMemory) {
ult::DefaultFramebufferWidth = 1280;
ult::DefaultFramebufferHeight = 720;
}
}
return tsl::loop<GameResolutionsEntryOverlay>(argc, argv);
}
// Handle --lastSelectedItem (multi-token argument)
else if (strcmp(argStr, "--lastSelectedItem") == 0 && arg + 1 < argc) {
lastSelectedItem.clear();
for (++arg; arg < argc; ++arg) {
const char* token = argv[arg];
// Stop if we hit another flag
if (token[0] == '-' && !lastSelectedItem.empty())
break;
// Add space separator
if (!lastSelectedItem.empty())
lastSelectedItem += ' ';
lastSelectedItem += token;
// Stop if token ends with quote
const char lastChar = token[strlen(token) - 1];
if (lastChar == '"' || lastChar == '\'') {
++arg;
break;
}
}
// Clean up quotes and whitespace
ult::removeQuotes(lastSelectedItem);
// Trim whitespace
const size_t start = lastSelectedItem.find_first_not_of(" \t");
if (start != std::string::npos) {
const size_t end = lastSelectedItem.find_last_not_of(" \t");
lastSelectedItem = lastSelectedItem.substr(start, end - start + 1);
} else {
lastSelectedItem.clear();
}
}
}
}
// Default case
return tsl::loop<MonitorOverlay>(argc, argv);
}