hoc-sys: add extra features to overlay

This commit is contained in:
souldbminersmwc
2025-11-22 15:53:21 -05:00
parent 39ae532108
commit 3bca6ba97d
26 changed files with 650 additions and 332 deletions

View File

@@ -23,6 +23,7 @@
#define ENABLED 1 #define ENABLED 1
#define DISABLED 0 #define DISABLED 0
#define CPU_MAX_MAX_VOLT 1375000 #define CPU_MAX_MAX_VOLT 1375000
namespace ams::ldr::oc { namespace ams::ldr::oc {
//volatile EristaMtcTable EristaMtcTablePlaceholder = { .rev = ERISTA_MTC_MAGIC, }; //volatile EristaMtcTable EristaMtcTablePlaceholder = { .rev = ERISTA_MTC_MAGIC, };
@@ -199,8 +200,8 @@ volatile CustomizeTable C = {
.marikoCpuDvfsTableSLT = { .marikoCpuDvfsTableSLT = {
// { 204000, { 732856, -17335, 113 }, { } }, // { 204000, { 732856, -17335, 113 }, { } },
// { 306000, { 760024, -18195, 113 }, { } }, // { 306000, { 760024, -18195, 113 }, { } },
{ 408000, { 789258, -19055, 113 }, { } }, // { 408000, { 789258, -19055, 113 }, { } },
{ 510000, { 789258, -19915, 113 }, { } }, // { 510000, { 789258, -19915, 113 }, { } },
{ 612000, { 789258, -19055, 113 }, { } }, { 612000, { 789258, -19055, 113 }, { } },
{ 714000, { 820558, -19915, 113 }, { } }, { 714000, { 820558, -19915, 113 }, { } },
{ 816000, { 853926, -20775, 113 }, { } }, { 816000, { 853926, -20775, 113 }, { } },
@@ -223,8 +224,8 @@ volatile CustomizeTable C = {
{ 2601000, { 1702903, -36675, 113 }, { CPU_MAX_MAX_VOLT } }, { 2601000, { 1702903, -36675, 113 }, { CPU_MAX_MAX_VOLT } },
{ 2703000, { 1748360, -37535, 113 }, { CPU_MAX_MAX_VOLT } }, { 2703000, { 1748360, -37535, 113 }, { CPU_MAX_MAX_VOLT } },
{ 2805000, { 1793817, -38395, 113 }, { CPU_MAX_MAX_VOLT } }, { 2805000, { 1793817, -38395, 113 }, { CPU_MAX_MAX_VOLT } },
// { 2907000, { 1839274, -39255, 113 }, { CPU_MAX_MAX_VOLT } }, { 2907000, { 1839274, -39255, 113 }, { CPU_MAX_MAX_VOLT } },
// { 3009000, { 1884731, -40115, 113 }, { CPU_MAX_MAX_VOLT } }, { 3009000, { 1884731, -40115, 113 }, { CPU_MAX_MAX_VOLT } },
}, },
/* - Erista GPU DVFS Table: /* - Erista GPU DVFS Table:

Binary file not shown.

Binary file not shown.

View File

@@ -1 +1 @@
python3 src/main.py python src/main.py

View File

@@ -44,10 +44,10 @@ import misc
true = True true = True
false = False false = False
# if getattr(sys, 'frozen', False): if getattr(sys, 'frozen', False):
assets_path = os.path.join(sys._MEIPASS, 'assets/') assets_path = os.path.join(sys._MEIPASS, 'assets/')
# else: else:
# assets_path = os.path.join(os.path.dirname(__file__), '../assets/') assets_path = os.path.join(os.path.dirname(__file__), '../assets/')
cooler_image_path = assets_path + "coolerhd.png" # coolerHD Emoji from OC server cooler_image_path = assets_path + "coolerhd.png" # coolerHD Emoji from OC server
cooler_image = Image.open(cooler_image_path).convert("RGBA") cooler_image = Image.open(cooler_image_path).convert("RGBA")

View File

@@ -60,6 +60,7 @@ freqs_mhz_cpu = [
variables = [ variables = [
("custRev", "u32"), ("custRev", "u32"),
("mtcConf", "u32"), ("mtcConf", "u32"),
("hpMode", "u32"),
("commonCpuBoostClock", "u32"), ("commonCpuBoostClock", "u32"),
("commonEmcMemVolt", "u32"), ("commonEmcMemVolt", "u32"),
("eristaCpuMaxVolt", "u32"), ("eristaCpuMaxVolt", "u32"),

View File

@@ -74,10 +74,11 @@ typedef enum
typedef enum typedef enum
{ {
SysClkRamLoad_All = 0, SysClkPartLoad_EMC = 0,
SysClkRamLoad_Cpu, SysClkPartLoad_EMCCpu,
SysClkRamLoad_EnumMax HocClkPartLoad_GPU,
} SysClkRamLoad; SysClkPartLoad_EnumMax
} SysClkPartLoad;
typedef enum typedef enum
{ {

View File

@@ -40,7 +40,7 @@ typedef struct
uint32_t overrideFreqs[SysClkModule_EnumMax]; uint32_t overrideFreqs[SysClkModule_EnumMax];
uint32_t temps[SysClkThermalSensor_EnumMax]; uint32_t temps[SysClkThermalSensor_EnumMax];
int32_t power[SysClkPowerSensor_EnumMax]; int32_t power[SysClkPowerSensor_EnumMax];
uint32_t ramLoad[SysClkRamLoad_EnumMax]; uint32_t partLoad[SysClkPartLoad_EnumMax];
// uint32_t perfConfId; // uint32_t perfConfId;
} SysClkContext; } SysClkContext;

View File

@@ -32,7 +32,7 @@
#include "clock_manager.h" #include "clock_manager.h"
#define SYSCLK_IPC_API_VERSION 4 #define SYSCLK_IPC_API_VERSION 4
#define SYSCLK_IPC_SERVICE_NAME "sys:clk" #define SYSCLK_IPC_SERVICE_NAME "horizon:oc"
enum SysClkIpcCmd enum SysClkIpcCmd
{ {

View File

@@ -37,7 +37,7 @@ include ${TOPDIR}/lib/libultrahand/ultrahand.mk
# version control constants # version control constants
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
#TARGET_VERSION := $(shell git describe --dirty --always --tags) #TARGET_VERSION := $(shell git describe --dirty --always --tags)
APP_VERSION := 1.0.1 APP_VERSION := 0.0.4
TARGET_VERSION := $(APP_VERSION) TARGET_VERSION := $(APP_VERSION)
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------

View File

@@ -57,7 +57,7 @@ class AppOverlay : public tsl::Overlay
if(!sysclkIpcRunning()) if(!sysclkIpcRunning())
{ {
return initially<FatalGui>( return initially<FatalGui>(
"sys-clk is not running.\n\n" "Horizon OC is not running.\n\n"
"\n" "\n"
"Please make sure it is correctly\n\n" "Please make sure it is correctly\n\n"
"installed and enabled.", "installed and enabled.",
@@ -68,7 +68,7 @@ class AppOverlay : public tsl::Overlay
if(R_FAILED(sysclkIpcInitialize()) || R_FAILED(sysclkIpcGetAPIVersion(&apiVersion))) if(R_FAILED(sysclkIpcInitialize()) || R_FAILED(sysclkIpcGetAPIVersion(&apiVersion)))
{ {
return initially<FatalGui>( return initially<FatalGui>(
"Could not connect to sys-clk.\n\n" "Could not connect to Horizon OC.\n\n"
"\n" "\n"
"Please make sure it is correctly\n\n" "Please make sure it is correctly\n\n"
"installed and enabled.", "installed and enabled.",
@@ -80,7 +80,7 @@ class AppOverlay : public tsl::Overlay
{ {
return initially<FatalGui>( return initially<FatalGui>(
"Overlay not compatible with\n\n" "Overlay not compatible with\n\n"
"the running sys-clk version.\n\n" "the running Horizon OC version.\n\n"
"\n" "\n"
"Please make sure everything is\n\n" "Please make sure everything is\n\n"
"installed and up to date.", "installed and up to date.",

View File

@@ -7,14 +7,14 @@
* *
* This program is distributed in the hope it will be useful, but WITHOUT * This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* more details. * for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42): * "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net> * <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
@@ -24,37 +24,124 @@
* -------------------------------------------------------------------------- * --------------------------------------------------------------------------
*/ */
#include "base_gui.h" #include "base_gui.h"
#include "../elements/base_frame.h" #include "../elements/base_frame.h"
#include "logo_rgba_bin.h" #include "logo_rgba_bin.h"
#include <tesla.hpp>
#include <math.h>
// -------------------------------------------------------------
// Layout constants
// -------------------------------------------------------------
#define LOGO_X 20 #define LOGO_X 20
#define LOGO_Y 45 #define LOGO_Y 50
#define LOGO_LABEL_FONT_SIZE 35 #define LOGO_LABEL_FONT_SIZE 45
#define VERSION_X (LOGO_X + 250) #define VERSION_X (LOGO_X + 250)
#define VERSION_Y LOGO_Y-40 #define VERSION_Y (LOGO_Y - 40)
#define VERSION_FONT_SIZE 15 #define VERSION_FONT_SIZE 15
// -------------------------------------------------------------
// Version string getter
// -------------------------------------------------------------
std::string getVersionString() { std::string getVersionString() {
char buf[0x100] = ""; // 256 bytes — safe for any expected version string char buf[0x100] = "";
Result rc = sysclkIpcGetVersionString(buf, sizeof(buf)); Result rc = sysclkIpcGetVersionString(buf, sizeof(buf));
if (R_FAILED(rc) || buf[0] == '\0') { if (R_FAILED(rc) || buf[0] == '\0') {
return "unknown"; return "HorizonOC-Misc";
} }
return std::string(buf); return std::string(buf);
} }
// -------------------------------------------------------------
// Animated Ultra Text
// -------------------------------------------------------------
// Your animated wave colors (example placeholders)
static constexpr tsl::Color dynamicLogoRGB1 = tsl::Color(40, 255, 80, 255);
static constexpr tsl::Color dynamicLogoRGB2 = tsl::Color(120, 255, 160, 255);
// Your project name rendered letter-by-letter
static constexpr const char* PROJECT_NAME = "Horizon OC Gaea";
// Fully corrected function signature
static s32 drawDynamicUltraText(
tsl::gfx::Renderer* renderer,
s32 startX,
s32 y,
u32 fontSize,
const tsl::Color& staticColor,
bool useNotificationMethod = false)
{
static constexpr double cycleDuration = 1.6;
const std::string name = "Horizon OC Gaea";
s32 currentX = startX;
const u64 currentTime_ns = armTicksToNs(armGetSystemTick());
const double timeNow = static_cast<double>(currentTime_ns) / 1e9;
const double timeBase = fmod(timeNow, cycleDuration);
// Controls wave spacing
const double waveScale = 2.0 * M_PI / cycleDuration;
// Every character has its own index offset
for (size_t i = 0; i < name.size(); i++)
{
char letter = name[i];
if (letter == '\0') break;
// phase shift per character → THIS CREATES THE WAVE
double phase = waveScale * (timeBase + i * 0.12);
double raw = cos(phase);
double n = (raw + 1.0) * 0.5;
// Smoothstep ×2 (ultra smooth)
double s1 = n * n * (3.0 - 2.0 * n);
double s2 = s1 * s1 * (3.0 - 2.0 * s1);
double blend = std::clamp(s2, 0.0, 1.0);
tsl::Color color = {
static_cast<u8>(staticColor.r + (dynamicLogoRGB2.r - staticColor.r) * blend),
static_cast<u8>(staticColor.g + (dynamicLogoRGB2.g - staticColor.g) * blend),
static_cast<u8>(staticColor.b + (dynamicLogoRGB2.b - staticColor.b) * blend),
255
};
std::string ls(1, letter);
if (useNotificationMethod)
currentX += renderer->drawNotificationString(ls, false, currentX, y, fontSize, color).first;
else
currentX += renderer->drawString(ls, false, currentX, y, fontSize, color).first;
}
return currentX;
}
// -------------------------------------------------------------
// Rendering functions
// -------------------------------------------------------------
void BaseGui::preDraw(tsl::gfx::Renderer* renderer) void BaseGui::preDraw(tsl::gfx::Renderer* renderer)
{ {
// renderer->drawBitmap(LOGO_X, LOGO_Y, LOGO_WIDTH, LOGO_HEIGHT, logo_rgba_bin); static constexpr tsl::Color STATIC_GREEN = tsl::Color(80, 255, 120, 255);
renderer->drawString("Horizon OC overlay", false, LOGO_X, LOGO_Y, LOGO_LABEL_FONT_SIZE, renderer->a(TEXT_COLOR));
// renderer->drawString(TARGET_VERSION, false, VERSION_X, VERSION_Y, VERSION_FONT_SIZE, tsl::bannerVersionTextColor); drawDynamicUltraText(
renderer,
LOGO_X,
LOGO_Y,
LOGO_LABEL_FONT_SIZE,
STATIC_GREEN,
false
);
} }
tsl::elm::Element* BaseGui::createUI() tsl::elm::Element* BaseGui::createUI()

View File

@@ -25,154 +25,184 @@
*/ */
#include "freq_choice_gui.h" #include "freq_choice_gui.h"
#include "../format.h"
#include "fatal_gui.h"
FreqChoiceGui::FreqChoiceGui(std::uint32_t selectedHz,
std::uint32_t* hzList,
std::uint32_t hzCount,
SysClkModule module,
FreqChoiceListener listener,
bool checkMax,
std::map<uint32_t, std::string> labels)
{
this->selectedHz = selectedHz;
this->hzList = hzList;
this->hzCount = hzCount;
this->module = module;
this->listener = listener;
this->checkMax = checkMax;
this->labels = labels; // NEW
this->configList = new SysClkConfigValueList {};
}
#include "../format.h"
#include "fatal_gui.h"
FreqChoiceGui::FreqChoiceGui(std::uint32_t selectedHz, std::uint32_t *hzList, std::uint32_t hzCount, SysClkModule module, FreqChoiceListener listener, bool checkMax)
{
this->selectedHz = selectedHz;
this->hzList = hzList;
this->hzCount = hzCount;
this->module = module;
this->listener = listener;
this->checkMax = checkMax;
this->configList = new SysClkConfigValueList {};
}
FreqChoiceGui::~FreqChoiceGui() FreqChoiceGui::~FreqChoiceGui()
{ {
delete this->configList; delete this->configList;
} }
tsl::elm::ListItem* FreqChoiceGui::createFreqListItem(std::uint32_t hz, bool selected, int safety) tsl::elm::ListItem* FreqChoiceGui::createFreqListItem(std::uint32_t hz, bool selected, int safety)
{ {
std::string text = formatListFreqHz(hz); std::string text = formatListFreqHz(hz);
if (selected) text += " \uE14B"; if (selected)
text += " \uE14B";
tsl::elm::ListItem* listItem = new tsl::elm::ListItem(text, "", false);
switch (safety)
{
case 0:
listItem->setTextColor(tsl::Color(255, 255, 255, 255));
listItem->setValueColor(tsl::Color(255, 255, 255, 255));
break;
case 1:
listItem->setTextColor(tsl::Color(255, 165, 0, 255));
listItem->setValueColor(tsl::Color(255, 165, 0, 255));
break;
case 2:
listItem->setTextColor(tsl::Color(255, 0, 0, 255));
listItem->setValueColor(tsl::Color(255, 0, 0, 255));
break;
}
listItem->setClickListener([this, hz](u64 keys)
{
if ((keys & HidNpadButton_A) == HidNpadButton_A && this->listener) {
if (this->listener(hz)) {
tsl::goBack();
}
return true;
}
return false;
});
return listItem;
}
void FreqChoiceGui::listUI()
{
sysclkIpcGetConfigValues(this->configList);
// Add CategoryHeader based on module
std::string moduleName = sysclkFormatModule(this->module, false);
this->listElement->addItem(new tsl::elm::CategoryHeader(moduleName));
this->listElement->addItem(this->createFreqListItem(0, this->selectedHz == 0, false));
std::uint32_t hz;
for (std::uint32_t i = 0; i < this->hzCount; i++)
{
hz = this->hzList[i];
uint32_t mhz = hz / 1000000;
// Skip 204 MHz exactly
if(checkMax && IsMariko()) {
if (this->configList->values[HocClkConfigValue_MarikoMaxCpuClock] < mhz && moduleName == "cpu") {
continue;
}
if (this->configList->values[HocClkConfigValue_MarikoMaxGpuClock] < mhz && moduleName == "gpu") {
continue;
}
if (this->configList->values[HocClkConfigValue_MarikoMaxMemClock] < mhz && moduleName == "mem") {
continue;
}
} else if (checkMax && IsErista()) {
if (this->configList->values[HocClkConfigValue_EristaMaxCpuClock] < mhz && moduleName == "cpu") {
continue;
}
if (this->configList->values[HocClkConfigValue_EristaMaxGpuClock] < mhz && moduleName == "gpu") {
continue;
}
if (this->configList->values[HocClkConfigValue_EristaMaxMemClock] < mhz && moduleName == "mem") {
continue;
}
}
if (moduleName == "mem" && mhz <= 600)
{
continue;
}
uint32_t unsafe_cpu;
uint32_t unsafe_gpu;
uint32_t danger_cpu;
uint32_t danger_gpu;
if (IsMariko())
{
unsafe_cpu = 1964;
unsafe_gpu = 1076;
danger_cpu = 2398;
danger_gpu = 1306;
}
else
{
unsafe_cpu = 1786;
unsafe_gpu = 922;
danger_cpu = 2092;
danger_gpu = 999;
}
if (moduleName == "cpu") { // NEW: Right-side label
if (mhz >= danger_cpu) { std::string rightText = "";
this->listElement->addItem(this->createFreqListItem(hz, mhz == this->selectedHz / 1000000, 2)); auto it = labels.find(hz);
continue; if (it != labels.end())
} rightText = it->second;
if (mhz >= unsafe_cpu) {
this->listElement->addItem(this->createFreqListItem(hz, mhz == this->selectedHz / 1000000, 1)); tsl::elm::ListItem* listItem =
continue; new tsl::elm::ListItem(text, rightText, false);
}
if (mhz <= unsafe_cpu) { switch (safety)
this->listElement->addItem(this->createFreqListItem(hz, mhz == this->selectedHz / 1000000, 0)); {
case 0:
listItem->setTextColor(tsl::Color(255, 255, 255, 255));
listItem->setValueColor(tsl::Color(255, 255, 255, 255));
break;
case 1:
listItem->setTextColor(tsl::Color(255, 165, 0, 255));
listItem->setValueColor(tsl::Color(255, 165, 0, 255));
break;
case 2:
listItem->setTextColor(tsl::Color(255, 0, 0, 255));
listItem->setValueColor(tsl::Color(255, 0, 0, 255));
break;
}
// Make annotation grey
if (!rightText.empty())
listItem->setValueColor(tsl::Color(180, 180, 180, 255));
listItem->setClickListener([this, hz](u64 keys)
{
if ((keys & HidNpadButton_A) == HidNpadButton_A && this->listener) {
if (this->listener(hz)) {
tsl::goBack();
}
return true;
}
return false;
});
return listItem;
}
void FreqChoiceGui::listUI()
{
sysclkIpcGetConfigValues(this->configList);
// Header based on CPU/GPU/MEM module
std::string moduleName = sysclkFormatModule(this->module, false);
this->listElement->addItem(new tsl::elm::CategoryHeader(moduleName));
// Default option
this->listElement->addItem(
this->createFreqListItem(0, this->selectedHz == 0, 0));
for (std::uint32_t i = 0; i < this->hzCount; i++)
{
std::uint32_t hz = this->hzList[i];
uint32_t mhz = hz / 1000000;
if (checkMax && IsMariko()) {
if (moduleName == "cpu" &&
this->configList->values[HocClkConfigValue_MarikoMaxCpuClock] < mhz)
continue; continue;
}
} else if (moduleName == "gpu") { if (moduleName == "gpu" &&
if (mhz >= danger_gpu) { this->configList->values[HocClkConfigValue_MarikoMaxGpuClock] < mhz)
this->listElement->addItem(this->createFreqListItem(hz, mhz == this->selectedHz / 1000000, 2));
continue;
}
if (mhz >= unsafe_gpu) {
this->listElement->addItem(this->createFreqListItem(hz, mhz == this->selectedHz / 1000000, 1));
continue;
}
if (mhz <= unsafe_gpu) {
this->listElement->addItem(this->createFreqListItem(hz, mhz == this->selectedHz / 1000000, 0));
continue; continue;
}
} else if (moduleName == "mem") { if (moduleName == "mem" &&
this->listElement->addItem(this->createFreqListItem(hz, mhz == this->selectedHz / 1000000, 0)); this->configList->values[HocClkConfigValue_MarikoMaxMemClock] < mhz)
continue;
} else if (checkMax && IsErista()) {
if (moduleName == "cpu" &&
this->configList->values[HocClkConfigValue_EristaMaxCpuClock] < mhz)
continue;
if (moduleName == "gpu" &&
this->configList->values[HocClkConfigValue_EristaMaxGpuClock] < mhz)
continue;
if (moduleName == "mem" &&
this->configList->values[HocClkConfigValue_EristaMaxMemClock] < mhz)
continue;
}
if (moduleName == "mem" && mhz <= 600)
continue; continue;
}
uint32_t unsafe_cpu;
} uint32_t unsafe_gpu;
this->listElement->jumpToItem("", ""); uint32_t danger_cpu;
} uint32_t danger_gpu;
if (IsMariko())
{
unsafe_cpu = 1964;
unsafe_gpu = 1076;
danger_cpu = 2398;
danger_gpu = 1306;
}
else
{
unsafe_cpu = 1786;
unsafe_gpu = 922;
danger_cpu = 2092;
danger_gpu = 999;
}
int safety = 0;
if (moduleName == "cpu") {
if (mhz >= danger_cpu)
safety = 2;
else if (mhz >= unsafe_cpu)
safety = 1;
else
safety = 0;
} else if (moduleName == "gpu") {
if (mhz >= danger_gpu)
safety = 2;
else if (mhz >= unsafe_gpu)
safety = 1;
else
safety = 0;
} else if (moduleName == "mem") {
safety = 0;
}
this->listElement->addItem(
this->createFreqListItem(
hz,
(mhz == this->selectedHz / 1000000),
safety
)
);
}
this->listElement->jumpToItem("", "");
}

View File

@@ -29,6 +29,7 @@
#include <list> #include <list>
#include <functional> #include <functional>
#include <map>
#include "base_menu_gui.h" #include "base_menu_gui.h"
using FreqChoiceListener = std::function<bool(std::uint32_t hz)>; using FreqChoiceListener = std::function<bool(std::uint32_t hz)>;
@@ -42,19 +43,24 @@ protected:
std::uint32_t selectedHz; std::uint32_t selectedHz;
std::uint32_t* hzList; std::uint32_t* hzList;
std::uint32_t hzCount; std::uint32_t hzCount;
SysClkModule module; // added module SysClkModule module;
FreqChoiceListener listener; FreqChoiceListener listener;
bool checkMax; // new member bool checkMax;
// NEW: Optional annotation labels
std::map<uint32_t, std::string> labels;
tsl::elm::ListItem* createFreqListItem(std::uint32_t hz, bool selected, int safety); tsl::elm::ListItem* createFreqListItem(std::uint32_t hz, bool selected, int safety);
public: public:
// Updated constructor with checkMaxValue
FreqChoiceGui(std::uint32_t selectedHz, FreqChoiceGui(std::uint32_t selectedHz,
std::uint32_t* hzList, std::uint32_t* hzList,
std::uint32_t hzCount, std::uint32_t hzCount,
SysClkModule module, SysClkModule module,
FreqChoiceListener listener, FreqChoiceListener listener,
bool checkMax = true); bool checkMax = true,
std::map<uint32_t, std::string> labels = {}); // NEW ARG
~FreqChoiceGui(); ~FreqChoiceGui();
void listUI() override; void listUI() override;

View File

@@ -59,7 +59,8 @@ void MiscGui::addConfigButton(SysClkConfigValue configVal,
const char* altName, const char* altName,
const ValueRange& range, const ValueRange& range,
const std::string& categoryName, const std::string& categoryName,
const ValueThresholds* thresholds) const ValueThresholds* thresholds,
const std::map<uint32_t, std::string>& labels)
{ {
const char* configName = altName ? altName : sysclkFormatConfigValue(configVal, true); const char* configName = altName ? altName : sysclkFormatConfigValue(configVal, true);
@@ -82,7 +83,7 @@ void MiscGui::addConfigButton(SysClkConfigValue configVal,
ValueThresholds thresholdsCopy = (thresholds ? *thresholds : ValueThresholds{}); ValueThresholds thresholdsCopy = (thresholds ? *thresholds : ValueThresholds{});
listItem->setClickListener( listItem->setClickListener(
[this, configVal, range, categoryName, thresholdsCopy](u64 keys) [this, configVal, range, categoryName, thresholdsCopy, labels](u64 keys)
{ {
if ((keys & HidNpadButton_A) == 0) if ((keys & HidNpadButton_A) == 0)
return false; return false;
@@ -106,7 +107,8 @@ void MiscGui::addConfigButton(SysClkConfigValue configVal,
return true; return true;
}, },
thresholdsCopy, thresholdsCopy,
true true,
labels // <── NEW
); );
} else { } else {
@@ -123,7 +125,10 @@ void MiscGui::addConfigButton(SysClkConfigValue configVal,
} }
this->lastContextUpdate = armGetSystemTick(); this->lastContextUpdate = armGetSystemTick();
return true; return true;
} },
ValueThresholds(),
false,
labels // <── NEW
); );
} }
@@ -135,7 +140,11 @@ void MiscGui::addConfigButton(SysClkConfigValue configVal,
this->configRanges[configVal] = range; this->configRanges[configVal] = range;
} }
void MiscGui::addFreqButton(SysClkConfigValue configVal, const char* altName, SysClkModule module) { void MiscGui::addFreqButton(SysClkConfigValue configVal,
const char* altName,
SysClkModule module,
const std::map<uint32_t, std::string>& labels)
{
const char* configName = altName ? altName : sysclkFormatConfigValue(configVal, true); const char* configName = altName ? altName : sysclkFormatConfigValue(configVal, true);
tsl::elm::ListItem* listItem = new tsl::elm::ListItem(configName); tsl::elm::ListItem* listItem = new tsl::elm::ListItem(configName);
@@ -145,45 +154,48 @@ void MiscGui::addFreqButton(SysClkConfigValue configVal, const char* altName, Sy
snprintf(valueText, sizeof(valueText), "%lu MHz", currentMHz); snprintf(valueText, sizeof(valueText), "%lu MHz", currentMHz);
listItem->setValue(valueText); listItem->setValue(valueText);
listItem->setClickListener([this, configVal, module](u64 keys) { listItem->setClickListener(
if ((keys & HidNpadButton_A) == 0) [this, configVal, module, labels](u64 keys)
return false; {
if ((keys & HidNpadButton_A) == 0)
return false;
std::uint32_t hzList[SYSCLK_FREQ_LIST_MAX]; std::uint32_t hzList[SYSCLK_FREQ_LIST_MAX];
std::uint32_t hzCount; std::uint32_t hzCount;
Result rc = sysclkIpcGetFreqList(module, hzList, SYSCLK_FREQ_LIST_MAX, &hzCount); Result rc = sysclkIpcGetFreqList(module, hzList, SYSCLK_FREQ_LIST_MAX, &hzCount);
if (R_FAILED(rc)) { if (R_FAILED(rc)) {
FatalGui::openWithResultCode("sysclkIpcGetFreqList", rc); FatalGui::openWithResultCode("sysclkIpcGetFreqList", rc);
return false; return false;
} }
std::uint32_t currentHz = this->configList->values[configVal] * 1'000'000; std::uint32_t currentHz = this->configList->values[configVal] * 1'000'000;
tsl::changeTo<FreqChoiceGui>( tsl::changeTo<FreqChoiceGui>(
currentHz, currentHz,
hzList, hzList,
hzCount, hzCount,
module, module,
[this, configVal](std::uint32_t hz) { [this, configVal](std::uint32_t hz)
{
uint64_t mhz = hz / 1'000'000;
this->configList->values[configVal] = mhz;
uint64_t mhz = hz / 1'000'000; Result rc = sysclkIpcSetConfigValues(this->configList);
this->configList->values[configVal] = mhz; if (R_FAILED(rc)) {
FatalGui::openWithResultCode("sysclkIpcSetConfigValues", rc);
return false;
}
Result rc = sysclkIpcSetConfigValues(this->configList); this->lastContextUpdate = armGetSystemTick();
if (R_FAILED(rc)) { return true;
FatalGui::openWithResultCode("sysclkIpcSetConfigValues", rc); },
return false; false,
} labels
);
this->lastContextUpdate = armGetSystemTick(); return true;
return true; });
},
false
);
return true;
});
this->listElement->addItem(listItem); this->listElement->addItem(listItem);
this->configButtons[configVal] = listItem; this->configButtons[configVal] = listItem;
@@ -204,18 +216,24 @@ void MiscGui::listUI()
addConfigToggle(HocClkConfigValue_UncappedClocks, nullptr); addConfigToggle(HocClkConfigValue_UncappedClocks, nullptr);
addConfigToggle(HocClkConfigValue_OverwriteBoostMode, nullptr); addConfigToggle(HocClkConfigValue_OverwriteBoostMode, nullptr);
this->listElement->addItem(new tsl::elm::CategoryHeader("Experimental")); // this->listElement->addItem(new tsl::elm::CategoryHeader("Experimental"));
addConfigToggle(HocClkConfigValue_ThermalThrottle, nullptr); addConfigToggle(HocClkConfigValue_ThermalThrottle, nullptr);
addConfigToggle(HocClkConfigValue_HandheldTDP, nullptr); addConfigToggle(HocClkConfigValue_HandheldTDP, nullptr);
addConfigToggle(HocClkConfigValue_EnforceBoardLimit, nullptr); addConfigToggle(HocClkConfigValue_EnforceBoardLimit, nullptr);
std::map<uint32_t, std::string> labels_pwr_r = {
{8600, "Official Rating"}
};
std::map<uint32_t, std::string> labels_pwr_l = {
{6400, "Official Rating"}
};
ValueThresholds tdpThresholds(8600, 9500); ValueThresholds tdpThresholds(8600, 9500);
addConfigButton( addConfigButton(
HocClkConfigValue_HandheldTDPLimit, HocClkConfigValue_HandheldTDPLimit,
"TDP Threshold", "TDP Threshold",
ValueRange(5000, 10000, 200, "mW", 1), ValueRange(5000, 10000, 200, "mW", 1),
"Power", "Power",
&tdpThresholds &tdpThresholds,
labels_pwr_r
); );
ValueThresholds tdpThresholdsLite(6400, 7500); ValueThresholds tdpThresholdsLite(6400, 7500);
@@ -224,7 +242,8 @@ void MiscGui::listUI()
"Lite TDP Threshold", "Lite TDP Threshold",
ValueRange(4000, 8000, 200, "mW", 1), ValueRange(4000, 8000, 200, "mW", 1),
"Power", "Power",
&tdpThresholdsLite &tdpThresholdsLite,
labels_pwr_l
); );
ValueThresholds throttleThresholds(70, 80); ValueThresholds throttleThresholds(70, 80);
@@ -235,45 +254,130 @@ void MiscGui::listUI()
"Temp", "Temp",
&throttleThresholds &throttleThresholds
); );
this->listElement->addItem(new tsl::elm::CategoryHeader("Max Clocks")); std::map<uint32_t, std::string> cpu_freq_label_m = {
{612000000, "Sleep Mode"},
{1020000000, "Stock"},
{1224000000, "Dev OC"},
{1785000000, "Boost Mode"},
{1963000000, "Safe Max"},
{2397000000, "Unsafe Max"},
{2805000000, "Aboslute Max"},
};
std::map<uint32_t, std::string> cpu_freq_label_e = {
{612000000, "Sleep Mode"},
{1020000000, "Stock"},
{1224000000, "Dev OC"},
{1785000000, "Boost Mode & Safe Max"},
{2091000000, "Unsafe Max"},
{2295000000, "Aboslute Max"},
};
std::map<uint32_t, std::string> gpu_freq_label_e = {
{76800000, "Boost Mode"},
{307200000, "Handheld"},
{384000000, "Handheld"},
{460800000, "Handheld Safe Max"},
{768000000, "Docked"},
{844000000, "Safe Max"},
{998400000, "Unsafe Max"},
{1075200000, "Aboslute Max"},
};
std::map<uint32_t, std::string> gpu_freq_label_m = {
{76800000, "Boost Mode"},
{307200000, "Handheld"},
{384000000, "Handheld"},
{460800000, "Handheld"},
{614400000, "Handheld Safe Max"},
{768000000, "Docked"},
{1152200000, "Safe Max"},
{1305600000, "Unsafe Max"},
{1536000000, "Aboslute Max"},
};
std::map<uint32_t, std::string> emc_freq_label_e = {
{133120000, "Handheld"},
{160000000, "Docked & Safe Max"},
{213100000, "JEDEC Max"},
{236000000, "Absolute Max"},
};
std::map<uint32_t, std::string> emc_freq_label_m = {
{133120000, "Handheld"},
{160000000, "Docked"},
{186600000, "Safe Max (3733MT/s)"},
{213300000, "Safe Max (4266MT/s)"},
{320000000, "Absolute Max"},
};
this->listElement->addItem(new tsl::elm::CategoryHeader("Clocks"));
if(IsMariko()) { if(IsMariko()) {
addFreqButton(HocClkConfigValue_MarikoMaxCpuClock, nullptr, SysClkModule_CPU); addFreqButton(HocClkConfigValue_MarikoMaxCpuClock, nullptr, SysClkModule_CPU, cpu_freq_label_m);
addFreqButton(HocClkConfigValue_MarikoMaxGpuClock, nullptr, SysClkModule_GPU); addFreqButton(HocClkConfigValue_MarikoMaxGpuClock, nullptr, SysClkModule_GPU, gpu_freq_label_m);
addFreqButton(HocClkConfigValue_MarikoMaxMemClock, nullptr, SysClkModule_MEM); addFreqButton(HocClkConfigValue_MarikoMaxMemClock, nullptr, SysClkModule_MEM, emc_freq_label_m);
} else { } else {
addFreqButton(HocClkConfigValue_EristaMaxCpuClock, nullptr, SysClkModule_CPU); addFreqButton(HocClkConfigValue_EristaMaxCpuClock, nullptr, SysClkModule_CPU, cpu_freq_label_e);
addFreqButton(HocClkConfigValue_EristaMaxGpuClock, nullptr, SysClkModule_GPU); addFreqButton(HocClkConfigValue_EristaMaxGpuClock, nullptr, SysClkModule_GPU, gpu_freq_label_e);
addFreqButton(HocClkConfigValue_EristaMaxMemClock, nullptr, SysClkModule_MEM); addFreqButton(HocClkConfigValue_EristaMaxMemClock, nullptr, SysClkModule_MEM, emc_freq_label_e);
} }
this->listElement->addItem(new tsl::elm::CategoryHeader("EMC"));
addConfigToggle(HocClkConfigValue_EMCDVFS, nullptr); addConfigToggle(HocClkConfigValue_EMCDVFS, nullptr);
ValueThresholds emcUvThresholds(1212500, 1250000); std::map<uint32_t, std::string> emc_voltage_label_m = {
addConfigButton( {1100000, "Default"},
HocClkConfigValue_EMCVdd2VoltageUV, {1175000, "Rating"},
"EMC VDD2 Voltage", {1212500, "Safe Max"},
ValueRange(1100000, 1237500, 12500, "mV", 1000, 1), };
"EMC VDD2 Voltage",
&emcUvThresholds
);
// if(IsMariko()) { std::map<uint32_t, std::string> emc_voltage_label_e = {
// addConfigButton( {1125000, "Default"},
// HocClkConfigValue_EMCVdd2VoltageUVStockMariko, {1175000, "Rating"},
// "EMC Stock VDD2 Voltage", {1237500, "Safe Max"},
// ValueRange(912500, 1175000, 12500, "mV", 1000, 1), };
// "EMC Stock VDD2 Voltage",
// &emcUvThresholds
// ); if(IsMariko()) {
// } else { ValueThresholds emcUvThresholds(1212500, 1250000);
addConfigButton(
HocClkConfigValue_EMCVdd2VoltageUV,
"EMC VDD2 Voltage",
ValueRange(1100000, 1237500, 12500, "mV", 1000, 1),
"EMC VDD2 Voltage",
&emcUvThresholds,
emc_voltage_label_m
);
addConfigButton(
HocClkConfigValue_EMCVdd2VoltageUVStockMariko,
"EMC Stock VDD2 Voltage",
ValueRange(912500, 1175000, 12500, "mV", 1000, 1),
"EMC Stock VDD2 Voltage",
&emcUvThresholds,
emc_voltage_label_m
);
} else {
ValueThresholds emcUvThresholds(1237500, 1300000);
addConfigButton(
HocClkConfigValue_EMCVdd2VoltageUV,
"EMC VDD2 Voltage",
ValueRange(1100000, 1237500, 12500, "mV", 1000, 1),
"EMC VDD2 Voltage",
&emcUvThresholds,
emc_voltage_label_e
);
addConfigButton( addConfigButton(
HocClkConfigValue_EMCVdd2VoltageUVStockErista, HocClkConfigValue_EMCVdd2VoltageUVStockErista,
"EMC Stock VDD2 Voltage", "EMC Stock VDD2 Voltage",
ValueRange(1000000, 1175000, 12500, "mV", 1000, 1), ValueRange(1000000, 1175000, 12500, "mV", 1000, 1),
"EMC Stock VDD2 Voltage", "EMC Stock VDD2 Voltage",
&emcUvThresholds &emcUvThresholds,
emc_voltage_label_e
); );
// } }
tsl::elm::ListItem* applyBtn = new tsl::elm::ListItem("Apply EMC Regs"); tsl::elm::ListItem* applyBtn = new tsl::elm::ListItem("Apply EMC Regs");
applyBtn->setClickListener([](u64 keys) { applyBtn->setClickListener([](u64 keys) {

View File

@@ -27,8 +27,12 @@ protected:
const char* altName, const char* altName,
const ValueRange& range, const ValueRange& range,
const std::string& categoryName, const std::string& categoryName,
const ValueThresholds* thresholds = nullptr); const ValueThresholds* thresholds,
void addFreqButton(SysClkConfigValue configVal, const char* altName, SysClkModule module); const std::map<uint32_t, std::string>& labels = {});
void addFreqButton(SysClkConfigValue configVal,
const char* altName,
SysClkModule module,
const std::map<uint32_t, std::string>& labels = {});
void updateConfigToggles(); void updateConfigToggles();
tsl::elm::ToggleListItem* enabledToggle; tsl::elm::ToggleListItem* enabledToggle;

View File

@@ -9,13 +9,15 @@ ValueChoiceGui::ValueChoiceGui(std::uint32_t selectedValue,
const std::string& categoryName, const std::string& categoryName,
ValueChoiceListener listener, ValueChoiceListener listener,
const ValueThresholds& thresholds, const ValueThresholds& thresholds,
bool enableThresholds) bool enableThresholds,
std::map<std::uint32_t, std::string> labels)
: selectedValue(selectedValue), : selectedValue(selectedValue),
range(range), range(range),
categoryName(categoryName), categoryName(categoryName),
listener(listener), listener(listener),
thresholds(thresholds), thresholds(thresholds),
enableThresholds(enableThresholds) enableThresholds(enableThresholds),
labels(labels)
{ {
} }
@@ -31,12 +33,10 @@ std::string ValueChoiceGui::formatValue(std::uint32_t value)
return VALUE_DEFAULT_TEXT; return VALUE_DEFAULT_TEXT;
} }
// Convert to floating point for division
double displayValue = static_cast<double>(value) / static_cast<double>(range.divisor); double displayValue = static_cast<double>(value) / static_cast<double>(range.divisor);
// Set precision and formatting
oss << std::fixed << std::setprecision(range.decimalPlaces) << displayValue; oss << std::fixed << std::setprecision(range.decimalPlaces) << displayValue;
if (!range.suffix.empty()) { if (!range.suffix.empty()) {
oss << " " << range.suffix; oss << " " << range.suffix;
} }
@@ -45,12 +45,6 @@ std::string ValueChoiceGui::formatValue(std::uint32_t value)
int ValueChoiceGui::getSafetyLevel(std::uint32_t value) int ValueChoiceGui::getSafetyLevel(std::uint32_t value)
{ {
// if (!enableThresholds) {
// return 0;
// }
std::uint32_t scaledValue = value / range.divisor;
if (value > thresholds.danger) { if (value > thresholds.danger) {
return 2; return 2;
} }
@@ -67,7 +61,13 @@ tsl::elm::ListItem* ValueChoiceGui::createValueListItem(std::uint32_t value, boo
text += " \uE14B"; text += " \uE14B";
} }
tsl::elm::ListItem* listItem = new tsl::elm::ListItem(text, "", false); std::string rightText = "";
auto it = labels.find(value);
if (it != labels.end()) {
rightText = it->second;
}
tsl::elm::ListItem* listItem = new tsl::elm::ListItem(text, rightText, false);
switch (safety) switch (safety)
{ {
@@ -85,6 +85,9 @@ tsl::elm::ListItem* ValueChoiceGui::createValueListItem(std::uint32_t value, boo
break; break;
} }
if (!rightText.empty())
listItem->setValueColor(tsl::Color(180, 180, 180, 255));
listItem->setClickListener([this, value](u64 keys) listItem->setClickListener([this, value](u64 keys)
{ {
if ((keys & HidNpadButton_A) == HidNpadButton_A && this->listener) { if ((keys & HidNpadButton_A) == HidNpadButton_A && this->listener) {
@@ -115,4 +118,4 @@ void ValueChoiceGui::listUI()
} }
this->listElement->jumpToItem("", "\uE14B"); this->listElement->jumpToItem("", "\uE14B");
} }

View File

@@ -25,62 +25,69 @@
*/ */
#pragma once #pragma once
#include <list> #include <list>
#include <functional> #include <functional>
#include <string> #include <string>
#include "base_menu_gui.h" #include <map>
#include "base_menu_gui.h"
using ValueChoiceListener = std::function<bool(std::uint32_t value)>;
using ValueChoiceListener = std::function<bool(std::uint32_t value)>;
#define VALUE_DEFAULT_TEXT "Default"
#define VALUE_DEFAULT_TEXT "Default"
struct ValueRange {
struct ValueRange {
std::uint32_t min; std::uint32_t min;
std::uint32_t max; std::uint32_t max;
std::uint32_t step; std::uint32_t step;
std::string suffix; std::string suffix;
std::uint32_t divisor; // Divide input values by this for display std::uint32_t divisor;
int decimalPlaces; // Number of decimal places to display (0-6) int decimalPlaces;
ValueRange() : min(0), max(0), step(1), suffix(""), divisor(1), decimalPlaces(0) {} ValueRange()
: min(0), max(0), step(1), suffix(""), divisor(1), decimalPlaces(0) {}
ValueRange(std::uint32_t min, std::uint32_t max, std::uint32_t step,
ValueRange(std::uint32_t min, std::uint32_t max, std::uint32_t step,
const std::string& suffix = "", std::uint32_t divisor = 1, int decimalPlaces = 0) const std::string& suffix = "", std::uint32_t divisor = 1, int decimalPlaces = 0)
: min(min), max(max), step(step), suffix(suffix), divisor(divisor), decimalPlaces(decimalPlaces) {} : min(min), max(max), step(step), suffix(suffix),
divisor(divisor), decimalPlaces(decimalPlaces) {}
}; };
struct ValueThresholds { struct ValueThresholds {
std::uint32_t warning; // Values >= this show orange std::uint32_t warning;
std::uint32_t danger; // Values >= this show red std::uint32_t danger;
ValueThresholds(std::uint32_t warning = 0, std::uint32_t danger = 0) ValueThresholds(std::uint32_t warning = 0, std::uint32_t danger = 0)
: warning(warning), danger(danger) {} : warning(warning), danger(danger) {}
}; };
class ValueChoiceGui : public BaseMenuGui class ValueChoiceGui : public BaseMenuGui
{ {
protected: protected:
std::uint32_t selectedValue; std::uint32_t selectedValue;
ValueRange range; ValueRange range;
std::string categoryName; std::string categoryName;
ValueChoiceListener listener; ValueChoiceListener listener;
ValueThresholds thresholds; ValueThresholds thresholds;
bool enableThresholds; bool enableThresholds;
tsl::elm::ListItem* createValueListItem(std::uint32_t value, bool selected, int safety); // NEW — map of value → right-side text (like version numbers)
std::string formatValue(std::uint32_t value); std::map<std::uint32_t, std::string> labels;
int getSafetyLevel(std::uint32_t value);
tsl::elm::ListItem* createValueListItem(std::uint32_t value, bool selected, int safety);
public: std::string formatValue(std::uint32_t value);
ValueChoiceGui(std::uint32_t selectedValue, int getSafetyLevel(std::uint32_t value);
const ValueRange& range,
const std::string& categoryName, public:
ValueChoiceListener listener, ValueChoiceGui(std::uint32_t selectedValue,
const ValueThresholds& thresholds = ValueThresholds(), const ValueRange& range,
bool enableThresholds = false); const std::string& categoryName,
~ValueChoiceGui(); ValueChoiceListener listener,
const ValueThresholds& thresholds = ValueThresholds(),
void listUI() override; bool enableThresholds = false,
}; std::map<std::uint32_t, std::string> labels = {});
~ValueChoiceGui();
void listUI() override;
};

View File

@@ -39,7 +39,7 @@ DEFINES := -DDISABLE_IPC -DTARGET="\"$(TARGET)\"" -DTARGET_VERSION="\"$(TARGET_V
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
CFLAGS := -g -Wall -O2 -ffunction-sections \ CFLAGS := -g -Wall -Os -ffunction-sections \
$(ARCH) $(DEFINES) $(ARCH) $(DEFINES)
CFLAGS += $(INCLUDE) -D__SWITCH__ CFLAGS += $(INCLUDE) -D__SWITCH__

View File

@@ -1,5 +1,5 @@
{ {
"name": "sys:clk", "name": "horizon:oc",
"title_id": "0x00FF0000636C6BFF", "title_id": "0x00FF0000636C6BFF",
"title_id_range_min": "0x00FF0000636C6BFF", "title_id_range_min": "0x00FF0000636C6BFF",
"title_id_range_max": "0x00FF0000636C6BFF", "title_id_range_max": "0x00FF0000636C6BFF",
@@ -18,7 +18,7 @@
"*" "*"
], ],
"service_host": [ "service_host": [
"sys:clk" "horizon:oc"
], ],
"kernel_capabilities": [ "kernel_capabilities": [
{ {

View File

@@ -31,6 +31,10 @@
#define HOSSVC_HAS_CLKRST (hosversionAtLeast(8,0,0)) #define HOSSVC_HAS_CLKRST (hosversionAtLeast(8,0,0))
#define HOSSVC_HAS_TC (hosversionAtLeast(5,0,0)) #define HOSSVC_HAS_TC (hosversionAtLeast(5,0,0))
#define NVGPU_GPU_IOCTL_PMU_GET_GPU_LOAD 0x80044715
Result nvCheck = 1;
u32 fd = 0;
static SysClkSocType g_socType = SysClkSocType_Erista; static SysClkSocType g_socType = SysClkSocType_Erista;
@@ -117,6 +121,11 @@ void Board::Initialize()
rc = tmp451Initialize(); rc = tmp451Initialize();
ASSERT_RESULT_OK(rc, "tmp451Initialize"); ASSERT_RESULT_OK(rc, "tmp451Initialize");
// u32 fd = 0;
// if (R_SUCCEEDED(nvInitialize())) nvCheck = nvOpen(&fd, "/dev/nvhost-ctrl-gpu");
FetchHardwareInfos(); FetchHardwareInfos();
} }
@@ -141,6 +150,7 @@ void Board::Exit()
max17050Exit(); max17050Exit();
tmp451Exit(); tmp451Exit();
nvExit();
} }
SysClkProfile Board::GetProfile() SysClkProfile Board::GetProfile()
@@ -463,16 +473,23 @@ std::int32_t Board::GetPowerMw(SysClkPowerSensor sensor)
return 0; return 0;
} }
std::uint32_t Board::GetRamLoad(SysClkRamLoad loadSource) std::uint32_t Board::GetPartLoad(SysClkPartLoad loadSource)
{ {
// u32 temp, GPU_Load_u = 0;
switch(loadSource) switch(loadSource)
{ {
case SysClkRamLoad_All: case SysClkPartLoad_EMC:
return t210EmcLoadAll(); return t210EmcLoadAll();
case SysClkRamLoad_Cpu: case SysClkPartLoad_EMCCpu:
return t210EmcLoadCpu(); return t210EmcLoadCpu();
// case HocClkPartLoad_GPU:
// #define gpu_samples_average 10
// // nvIoctl(fd, NVGPU_GPU_IOCTL_PMU_GET_GPU_LOAD, &temp);
// GPU_Load_u = ((GPU_Load_u * (gpu_samples_average-1)) + temp) / gpu_samples_average;
// return GPU_Load_u / 10;
default: default:
ASSERT_ENUM_VALID(SysClkRamLoad, loadSource); ASSERT_ENUM_VALID(SysClkPartLoad, loadSource);
} }
return 0; return 0;
@@ -502,4 +519,4 @@ void Board::FetchHardwareInfos()
default: default:
g_socType = SysClkSocType_Erista; g_socType = SysClkSocType_Erista;
} }
} }

View File

@@ -51,7 +51,7 @@ class Board
static void GetFreqList(SysClkModule module, std::uint32_t* outList, std::uint32_t maxCount, std::uint32_t* outCount); static void GetFreqList(SysClkModule module, std::uint32_t* outList, std::uint32_t maxCount, std::uint32_t* outCount);
static std::uint32_t GetTemperatureMilli(SysClkThermalSensor sensor); static std::uint32_t GetTemperatureMilli(SysClkThermalSensor sensor);
static std::int32_t GetPowerMw(SysClkPowerSensor sensor); static std::int32_t GetPowerMw(SysClkPowerSensor sensor);
static std::uint32_t GetRamLoad(SysClkRamLoad load); static std::uint32_t GetPartLoad(SysClkPartLoad load);
static SysClkSocType GetSocType(); static SysClkSocType GetSocType();
protected: protected:

View File

@@ -24,6 +24,7 @@
* -------------------------------------------------------------------------- * --------------------------------------------------------------------------
*/ */
#include "notification.h"
#include "clock_manager.h" #include "clock_manager.h"
#include <cstring> #include <cstring>
@@ -35,6 +36,10 @@
#define HOSPPC_HAS_BOOST (hosversionAtLeast(7,0,0)) #define HOSPPC_HAS_BOOST (hosversionAtLeast(7,0,0))
bool HAS_TDP_BEEN_FIRED = false;
bool HAS_EBL_BEEN_FIRED = false;
bool HAS_TT_BEEN_FIRED = false;
ClockManager *ClockManager::instance = NULL; ClockManager *ClockManager::instance = NULL;
ClockManager *ClockManager::GetInstance() ClockManager *ClockManager::GetInstance()
@@ -228,6 +233,7 @@ void ClockManager::RefreshFreqTableRow(SysClkModule module)
void ClockManager::Tick() void ClockManager::Tick()
{ {
std::uint32_t mode = 0; std::uint32_t mode = 0;
AppletOperationMode opMode = appletGetOperationMode(); AppletOperationMode opMode = appletGetOperationMode();
Result rc = apmExtGetCurrentPerformanceConfiguration(&mode); Result rc = apmExtGetCurrentPerformanceConfiguration(&mode);
@@ -257,25 +263,47 @@ void ClockManager::Tick()
if(this->config->GetConfigValue(HocClkConfigValue_HandheldTDP) && opMode == AppletOperationMode_Handheld) { if(this->config->GetConfigValue(HocClkConfigValue_HandheldTDP) && opMode == AppletOperationMode_Handheld) {
if(Board::GetSocType() == SysClkSocType_MarikoLite) { if(Board::GetSocType() == SysClkSocType_MarikoLite) {
if(Board::GetPowerMw(SysClkPowerSensor_Avg) < -(int)this->config->GetConfigValue(HocClkConfigValue_LiteTDPLimit)) { if(Board::GetPowerMw(SysClkPowerSensor_Avg) < -(int)this->config->GetConfigValue(HocClkConfigValue_LiteTDPLimit)) {
if(!HAS_TDP_BEEN_FIRED)
writeNotification("Horizon OC\nTDP has been activated");
HAS_TDP_BEEN_FIRED = true;
ResetToStockClocks(); ResetToStockClocks();
return; return;
} else {
HAS_TDP_BEEN_FIRED = false;
} }
} else { } else {
if(Board::GetPowerMw(SysClkPowerSensor_Avg) < -(int)this->config->GetConfigValue(HocClkConfigValue_HandheldTDPLimit)) { if(Board::GetPowerMw(SysClkPowerSensor_Avg) < -(int)this->config->GetConfigValue(HocClkConfigValue_HandheldTDPLimit)) {
if(!HAS_TDP_BEEN_FIRED)
writeNotification("Horizon OC\nTDP has been activated");
HAS_TDP_BEEN_FIRED = true;
ResetToStockClocks(); ResetToStockClocks();
return; return;
} else {
HAS_TDP_BEEN_FIRED = false;
} }
} }
} else if(opMode == AppletOperationMode_Console && this->config->GetConfigValue(HocClkConfigValue_EnforceBoardLimit)) { } else if(opMode == AppletOperationMode_Console && this->config->GetConfigValue(HocClkConfigValue_EnforceBoardLimit)) {
if(Board::GetPowerMw(SysClkPowerSensor_Avg) < 0) { if(Board::GetPowerMw(SysClkPowerSensor_Avg) < 0) {
if(!HAS_EBL_BEEN_FIRED)
writeNotification("Horizon OC\nBoard Limit has been exeeded");
HAS_EBL_BEEN_FIRED = true;
ResetToStockClocks(); ResetToStockClocks();
return; return;
} else {
HAS_EBL_BEEN_FIRED = false;
} }
} }
if(((tmp451TempSoc() / 1000) > (int)this->config->GetConfigValue(HocClkConfigValue_ThermalThrottleThreshold)) && this->config->GetConfigValue(HocClkConfigValue_ThermalThrottle)) { if(this->config->GetConfigValue(HocClkConfigValue_ThermalThrottle)) {
ResetToStockClocks(); if(tmp451TempSoc() / 1000 > (int)this->config->GetConfigValue(HocClkConfigValue_ThermalThrottleThreshold)) {
return; if(!HAS_TT_BEEN_FIRED)
writeNotification("Horizon OC\nThermal Throttle has started");
HAS_TT_BEEN_FIRED = true;
ResetToStockClocks();
return;
} else {
HAS_TT_BEEN_FIRED = false;
}
} }
std::scoped_lock lock{this->contextMutex}; std::scoped_lock lock{this->contextMutex};
@@ -454,9 +482,9 @@ bool ClockManager::RefreshContext()
} }
// ram load do not and should not force a refresh, hasChanged untouched // ram load do not and should not force a refresh, hasChanged untouched
for (unsigned int loadSource = 0; loadSource < SysClkRamLoad_EnumMax; loadSource++) for (unsigned int loadSource = 0; loadSource < SysClkPartLoad_EnumMax; loadSource++)
{ {
this->context->ramLoad[loadSource] = Board::GetRamLoad((SysClkRamLoad)loadSource); this->context->partLoad[loadSource] = Board::GetPartLoad((SysClkPartLoad)loadSource);
} }
if (this->ConfigIntervalTimeout(SysClkConfigValue_CsvWriteIntervalMs, ns, &this->lastCsvWriteNs)) if (this->ConfigIntervalTimeout(SysClkConfigValue_CsvWriteIntervalMs, ns, &this->lastCsvWriteNs))
@@ -481,31 +509,29 @@ void ClockManager::set_sd1_voltage(uint32_t voltage_uv)
const u8 volt_addr = 0x17; // MAX77620_REG_SD1 const u8 volt_addr = 0x17; // MAX77620_REG_SD1
const u8 volt_mask = 0x7F; // MAX77620_SD1_VOLT_MASK const u8 volt_mask = 0x7F; // MAX77620_SD1_VOLT_MASK
// Validate input voltage
if (voltage_uv < uv_min || voltage_uv > uv_max) if (voltage_uv < uv_min || voltage_uv > uv_max)
return; return;
// Calculate voltage multiplier
u32 mult = (voltage_uv + uv_step - 1 - uv_min) / uv_step; u32 mult = (voltage_uv + uv_step - 1 - uv_min) / uv_step;
mult = mult & volt_mask; mult = mult & volt_mask;
// Open I2C session to MAX77620 PMIC
I2cSession session; I2cSession session;
Result res = i2cOpenSession(&session, I2cDevice_Max77620Pmic); Result res = i2cOpenSession(&session, I2cDevice_Max77620Pmic);
if (R_FAILED(res)) { if (R_FAILED(res)) {
return; return;
} }
// Read current register value
u8 current_val = 0; u8 current_val = 0;
res = i2csessionSendAuto(&session, &volt_addr, 1, I2cTransactionOption_Start); res = i2csessionSendAuto(&session, &volt_addr, 1, I2cTransactionOption_Start);
if (R_FAILED(res)) { if (R_FAILED(res)) {
writeNotification("I2C write failed. This may be a hardware issue");
i2csessionClose(&session); i2csessionClose(&session);
return; return;
} }
res = i2csessionReceiveAuto(&session, &current_val, 1, I2cTransactionOption_Stop); res = i2csessionReceiveAuto(&session, &current_val, 1, I2cTransactionOption_Stop);
if (R_FAILED(res)) { if (R_FAILED(res)) {
writeNotification("I2C write failed. This may be a hardware issue");
i2csessionClose(&session); i2csessionClose(&session);
return; return;
} }

View File

@@ -40,7 +40,7 @@
#include "fancontrol.h" #include "fancontrol.h"
#include "emc_patcher.h" #include "emc_patcher.h"
#define INNER_HEAP_SIZE 0xFFFFF #define INNER_HEAP_SIZE 0x50000
extern "C" extern "C"
{ {
@@ -92,7 +92,7 @@ extern "C"
hosversionSet(MAKEHOSVERSION(fw.major, fw.minor, fw.micro)); hosversionSet(MAKEHOSVERSION(fw.major, fw.minor, fw.micro));
setsysExit(); setsysExit();
} }
} }
void __appExit(void) void __appExit(void)
@@ -124,7 +124,7 @@ int main(int argc, char** argv)
ClockManager* clockMgr = new ClockManager(); ClockManager* clockMgr = new ClockManager();
IpcService* ipcSrv = new IpcService(clockMgr); IpcService* ipcSrv = new IpcService(clockMgr);
FileUtils::LogLine("Starting Horizon OC Sysmodule"); FileUtils::LogLine("Starting Horizon OC Sysmodule");
clockMgr->SetRunning(true); clockMgr->SetRunning(true);

View File

@@ -0,0 +1,31 @@
#pragma once
#include <string>
#include <ctime>
#include <cstdio>
static void writeNotification(const std::string& message) {
const char* flagPath = "sdmc:/config/ultrahand/flags/NOTIFICATIONS.flag";
// Check if flag file exists
FILE* flagFile = fopen(flagPath, "r");
if (!flagFile) {
// Flag file does not exist, do nothing
return;
}
fclose(flagFile);
// Generate filename with timestamp
std::string filename = "Horzon OC -" + std::to_string(std::time(nullptr)) + ".notify";
std::string fullPath = "sdmc:/config/ultrahand/notifications/" + filename;
// Write JSON manually
FILE* file = fopen(fullPath.c_str(), "w");
if (file) {
fprintf(file, "{\n");
fprintf(file, " \"text\": \"%s\",\n", message.c_str());
fprintf(file, " \"fontSize\": 28\n");
fprintf(file, "}\n");
fclose(file);
}
}

View File

@@ -1,5 +1,5 @@
{ {
"name" : "hoc-clk", "name" : "Horizon OC",
"tid" : "00FF0000636C6BFF", "tid" : "00FF0000636C6BFF",
"requires_reboot": false "requires_reboot": false
} }