hoc-clk: add live vdd2, live boost clock and basic pwm dimming
This commit is contained in:
@@ -23,20 +23,13 @@
|
||||
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#include "base_gui.h"
|
||||
|
||||
#include "../elements/base_frame.h"
|
||||
#include "logo_rgba_bin.h"
|
||||
|
||||
|
||||
|
||||
|
||||
#define LOGO_X 20
|
||||
#define LOGO_Y 45
|
||||
#define LOGO_LABEL_FONT_SIZE 35
|
||||
|
||||
#define VERSION_X (LOGO_X + 250)
|
||||
#define VERSION_Y LOGO_Y-40
|
||||
#define VERSION_FONT_SIZE 15
|
||||
@@ -52,9 +45,12 @@ std::string getVersionString() {
|
||||
|
||||
void BaseGui::preDraw(tsl::gfx::Renderer* renderer)
|
||||
{
|
||||
// renderer->drawBitmap(LOGO_X, LOGO_Y, LOGO_WIDTH, LOGO_HEIGHT, logo_rgba_bin);
|
||||
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);
|
||||
// Draw "Horizon OC " in default color
|
||||
renderer->drawString("Horizon OC ", false, LOGO_X, LOGO_Y, LOGO_LABEL_FONT_SIZE, renderer->a(TEXT_COLOR));
|
||||
|
||||
// Draw "Gaea" in green
|
||||
tsl::Color greenColor(40, 204, 40, 255); // Light green
|
||||
renderer->drawString("Gaea", false, LOGO_X + 225, LOGO_Y, LOGO_LABEL_FONT_SIZE, greenColor);
|
||||
}
|
||||
|
||||
tsl::elm::Element* BaseGui::createUI()
|
||||
@@ -67,4 +63,4 @@ tsl::elm::Element* BaseGui::createUI()
|
||||
void BaseGui::update()
|
||||
{
|
||||
this->refresh();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,15 @@
|
||||
/*
|
||||
* --------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
|
||||
* wrote this file. As long as you retain this notice you can do whatever you
|
||||
* want with this stuff. If you meet any of us some day, and you think this
|
||||
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (c) Souldbminer and Horizon OC Contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -12,297 +23,322 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "base_menu_gui.h"
|
||||
#include "fatal_gui.h"
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
|
||||
* wrote this file. As long as you retain this notice you can do whatever you
|
||||
* want with this stuff. If you meet any of us some day, and you think this
|
||||
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
// Cache hardware model to avoid repeated syscalls
|
||||
|
||||
BaseMenuGui::BaseMenuGui()
|
||||
{
|
||||
tsl::initializeThemeVars();
|
||||
this->context = nullptr;
|
||||
this->lastContextUpdate = 0;
|
||||
this->listElement = nullptr;
|
||||
|
||||
// Initialize all voltages to zero once
|
||||
memset(&cpuVoltageUv, 0, sizeof(u32) * 5); // Zero all 5 voltage values at once
|
||||
|
||||
// Pre-cache hardware model during initialization
|
||||
IsMariko();
|
||||
|
||||
// Initialize display strings
|
||||
memset(displayStrings, 0, sizeof(displayStrings));
|
||||
}
|
||||
|
||||
BaseMenuGui::~BaseMenuGui() {
|
||||
delete this->context; // delete handles nullptr automatically
|
||||
}
|
||||
|
||||
// Fast preDraw - just renders pre-computed strings
|
||||
void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) {
|
||||
BaseGui::preDraw(renderer);
|
||||
if(!this->context) [[unlikely]] return;
|
||||
|
||||
// All constants pre-calculated and cached
|
||||
static constexpr const char* const labels[] = {
|
||||
"App ID", "Profile", "CPU", "GPU", "MEM", "SoC", "Board", "Skin", "Now", "Avg", "CPU", "GPU", "PLL", "PMIC", "BAT"
|
||||
};
|
||||
|
||||
static constexpr u32 dataPositions[6] = {63-3+3, 200-1, 344-1-3, 200-1, 342-1, 321-1};
|
||||
|
||||
static u32 labelWidths[10];
|
||||
static bool positionsInitialized = false;
|
||||
|
||||
if (!positionsInitialized) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
labelWidths[i] = renderer->getTextDimensions(labels[i], false, SMALL_TEXT_SIZE).first;
|
||||
}
|
||||
positionsInitialized = true;
|
||||
}
|
||||
static u32 positions[10] = {24-1, 310-labelWidths[1], 24-1, 192-labelWidths[3], 332-labelWidths[4], 24-1, 192 - labelWidths[6], 332-labelWidths[7], 192 - labelWidths[8], 332-labelWidths[9]};
|
||||
|
||||
static u32 maxProfileValueWidth = renderer->getTextDimensions("PD Charger", false, SMALL_TEXT_SIZE).first; // longest word
|
||||
|
||||
u32 y = 91;
|
||||
|
||||
// === TOP SECTION ===
|
||||
// renderer->drawRoundedRect(14, 70-1, 420, 30+2, 10.0f, renderer->aWithOpacity(tsl::tableBGColor));
|
||||
|
||||
// App ID - use pre-formatted string
|
||||
renderer->drawString(labels[0], false, positions[0], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
renderer->drawString(displayStrings[0], false, positions[0] + labelWidths[0] + 9, y, SMALL_TEXT_SIZE, tsl::infoTextColor);
|
||||
|
||||
// Profile - use pre-formatted string
|
||||
renderer->drawString(labels[1], false, 423 - maxProfileValueWidth - labelWidths[1] - 9, y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
renderer->drawString(displayStrings[1], false, 423 - maxProfileValueWidth, y, SMALL_TEXT_SIZE, tsl::infoTextColor);
|
||||
|
||||
y = y + 38; // Direct assignment instead of += 38
|
||||
|
||||
// === MAIN DATA SECTION ===
|
||||
// renderer->drawRoundedRect(14, 106, 420, 116, 10.0f, renderer->aWithOpacity(tsl::tableBGColor));
|
||||
|
||||
// === FREQUENCY SECTION ===
|
||||
// Labels first (better cache locality)
|
||||
renderer->drawString(labels[2], false, positions[2], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
renderer->drawString(labels[3], false, positions[3], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
renderer->drawString(labels[4], false, positions[4], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
|
||||
// Current frequencies - use pre-formatted strings
|
||||
renderer->drawString(displayStrings[2], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU
|
||||
renderer->drawString(displayStrings[3], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU
|
||||
renderer->drawString(displayStrings[4], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // MEM
|
||||
|
||||
y = y + 20; // Direct assignment (129 + 20)
|
||||
|
||||
// === REAL FREQUENCIES ===
|
||||
renderer->drawString(displayStrings[5], false, positions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU real
|
||||
renderer->drawString(displayStrings[6], false, positions[3], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU real
|
||||
renderer->drawString(displayStrings[7], false, positions[4], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // MEM real
|
||||
|
||||
y = y + 20; // Direct assignment (149 + 20)
|
||||
|
||||
// === VOLTAGES ===
|
||||
renderer->drawString(displayStrings[8], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU voltage
|
||||
renderer->drawString(displayStrings[9], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU voltage
|
||||
|
||||
// Memory voltage - check if VDD is present
|
||||
if (emcVoltageUv && vddVoltageUv) {
|
||||
renderer->drawStringWithColoredSections(displayStrings[10], false, {""}, dataPositions[5]-16, y, SMALL_TEXT_SIZE, tsl::infoTextColor, tsl::separatorColor);
|
||||
} else if (vddVoltageUv) {
|
||||
renderer->drawString(displayStrings[10], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor);
|
||||
} else if (emcVoltageUv) {
|
||||
renderer->drawString(displayStrings[10], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor);
|
||||
}
|
||||
|
||||
// y = y + 20; // Direct assignment (169 + 22)
|
||||
|
||||
|
||||
// renderer->drawString(displayStrings[17], false, dataPositions[0], y, SMALL_TEXT_SIZE, tempColors[3]); // CPU
|
||||
// renderer->drawString(displayStrings[18], false, dataPositions[1], y, SMALL_TEXT_SIZE, tempColors[4]); // GPU
|
||||
// renderer->drawString(displayStrings[19], false, dataPositions[2], y, SMALL_TEXT_SIZE, tempColors[5]); // PLL
|
||||
|
||||
y = y + 22; // Direct assignment (149 + 20)
|
||||
|
||||
// === TEMPERATURE SECTION ===
|
||||
// Labels
|
||||
renderer->drawString(labels[5], false, positions[5], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
renderer->drawString(labels[6], false, positions[6]-1, y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
renderer->drawString(labels[7], false, positions[7], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
|
||||
// Temperatures with color - use pre-computed colors
|
||||
renderer->drawString(displayStrings[11], false, dataPositions[0], y, SMALL_TEXT_SIZE, tempColors[0]); // SOC
|
||||
renderer->drawString(displayStrings[12], false, dataPositions[1], y, SMALL_TEXT_SIZE, tempColors[1]); // PCB
|
||||
renderer->drawString(displayStrings[13], false, dataPositions[2], y, SMALL_TEXT_SIZE, tempColors[2]); // Skin
|
||||
|
||||
y = y + 20; // Direct assignment (191 + 20)
|
||||
|
||||
// === SOC VOLTAGE & POWER ===
|
||||
// SOC voltage (if available)
|
||||
if (socVoltageUv) [[likely]] {
|
||||
renderer->drawString(displayStrings[14], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor);
|
||||
}
|
||||
|
||||
// Power labels and values
|
||||
renderer->drawString(labels[8], false, positions[8]-1, y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
renderer->drawString(labels[9], false, positions[9], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
|
||||
renderer->drawString(displayStrings[15], false, dataPositions[3], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // Power now
|
||||
renderer->drawString(displayStrings[16], false, dataPositions[4], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // Power avg
|
||||
|
||||
y = y + 20; // Direct assignment (191 + 20)
|
||||
|
||||
renderer->drawString(displayStrings[20], false, dataPositions[0], y, SMALL_TEXT_SIZE, tempColors[4]); // BAT
|
||||
renderer->drawString(displayStrings[21], false, dataPositions[1], y, SMALL_TEXT_SIZE, tempColors[5]); // PMIC
|
||||
|
||||
#include "base_menu_gui.h"
|
||||
#include "fatal_gui.h"
|
||||
y = y + 20; // Direct assignment (191 + 20)
|
||||
|
||||
// Cache hardware model to avoid repeated syscalls
|
||||
|
||||
BaseMenuGui::BaseMenuGui() : tempColors{tsl::Color(0), tsl::Color(0), tsl::Color(0)}
|
||||
{
|
||||
tsl::initializeThemeVars();
|
||||
this->context = nullptr;
|
||||
this->lastContextUpdate = 0;
|
||||
this->listElement = nullptr;
|
||||
|
||||
// Initialize all voltages to zero once
|
||||
memset(&cpuVoltageUv, 0, sizeof(u32) * 5); // Zero all 5 voltage values at once
|
||||
|
||||
// Pre-cache hardware model during initialization
|
||||
IsMariko();
|
||||
|
||||
// Initialize display strings
|
||||
memset(displayStrings, 0, sizeof(displayStrings));
|
||||
}
|
||||
|
||||
BaseMenuGui::~BaseMenuGui() {
|
||||
delete this->context; // delete handles nullptr automatically
|
||||
}
|
||||
|
||||
// Fast preDraw - just renders pre-computed strings
|
||||
void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) {
|
||||
BaseGui::preDraw(renderer);
|
||||
if(!this->context) [[unlikely]] return;
|
||||
|
||||
// All constants pre-calculated and cached
|
||||
static constexpr const char* const labels[10] = {
|
||||
"App ID", "Profile", "CPU", "GPU", "MEM", "SoC", "Board", "Skin", "Now", "Avg"
|
||||
};
|
||||
|
||||
static constexpr u32 dataPositions[6] = {63-3+3, 200-1, 344-1-3, 200-1, 342-1, 321-1};
|
||||
|
||||
static u32 labelWidths[10];
|
||||
static bool positionsInitialized = false;
|
||||
|
||||
if (!positionsInitialized) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
labelWidths[i] = renderer->getTextDimensions(labels[i], false, SMALL_TEXT_SIZE).first;
|
||||
}
|
||||
positionsInitialized = true;
|
||||
}
|
||||
static u32 positions[10] = {24-1, 310-labelWidths[1], 24-1, 192-labelWidths[3], 332-labelWidths[4], 24-1, 192 - labelWidths[6], 332-labelWidths[7], 192 - labelWidths[8], 332-labelWidths[9]};
|
||||
|
||||
static u32 maxProfileValueWidth = renderer->getTextDimensions("PD Charger", false, SMALL_TEXT_SIZE).first; // longest word
|
||||
|
||||
u32 y = 91;
|
||||
|
||||
// === TOP SECTION ===
|
||||
renderer->drawRoundedRect(14, 70-1, 420, 30+2, 10.0f, renderer->aWithOpacity(tsl::tableBGColor));
|
||||
|
||||
// App ID - use pre-formatted string
|
||||
renderer->drawString(labels[0], false, positions[0], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
renderer->drawString(displayStrings[0], false, positions[0] + labelWidths[0] + 9, y, SMALL_TEXT_SIZE, tsl::infoTextColor);
|
||||
|
||||
// Profile - use pre-formatted string
|
||||
renderer->drawString(labels[1], false, 423 - maxProfileValueWidth - labelWidths[1] - 9, y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
renderer->drawString(displayStrings[1], false, 423 - maxProfileValueWidth, y, SMALL_TEXT_SIZE, tsl::infoTextColor);
|
||||
|
||||
y = 129; // Direct assignment instead of += 38
|
||||
|
||||
// === MAIN DATA SECTION ===
|
||||
renderer->drawRoundedRect(14, 106, 420, 116, 10.0f, renderer->aWithOpacity(tsl::tableBGColor));
|
||||
|
||||
// === FREQUENCY SECTION ===
|
||||
// Labels first (better cache locality)
|
||||
renderer->drawString(labels[2], false, positions[2], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
renderer->drawString(labels[3], false, positions[3], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
renderer->drawString(labels[4], false, positions[4], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
|
||||
// Current frequencies - use pre-formatted strings
|
||||
renderer->drawString(displayStrings[2], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU
|
||||
renderer->drawString(displayStrings[3], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU
|
||||
renderer->drawString(displayStrings[4], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // MEM
|
||||
|
||||
y = 149; // Direct assignment (129 + 20)
|
||||
|
||||
// === REAL FREQUENCIES ===
|
||||
renderer->drawString(displayStrings[5], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU real
|
||||
renderer->drawString(displayStrings[6], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU real
|
||||
renderer->drawString(displayStrings[7], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // MEM real
|
||||
|
||||
y = 169; // Direct assignment (149 + 20)
|
||||
|
||||
// === VOLTAGES ===
|
||||
renderer->drawString(displayStrings[8], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU voltage
|
||||
renderer->drawString(displayStrings[9], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU voltage
|
||||
|
||||
// Memory voltage - check if VDD is present
|
||||
if (emcVoltageUv && vddVoltageUv) {
|
||||
renderer->drawStringWithColoredSections(displayStrings[10], false, {""}, dataPositions[5]-16, y, SMALL_TEXT_SIZE, tsl::infoTextColor, tsl::separatorColor);
|
||||
} else if (vddVoltageUv) {
|
||||
renderer->drawString(displayStrings[10], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor);
|
||||
} else if (emcVoltageUv) {
|
||||
renderer->drawString(displayStrings[10], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor);
|
||||
}
|
||||
|
||||
y = 191; // Direct assignment (169 + 22)
|
||||
|
||||
// === TEMPERATURE SECTION ===
|
||||
// Labels
|
||||
renderer->drawString(labels[5], false, positions[5], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
renderer->drawString(labels[6], false, positions[6]-1, y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
renderer->drawString(labels[7], false, positions[7], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
|
||||
// Temperatures with color - use pre-computed colors
|
||||
renderer->drawString(displayStrings[11], false, dataPositions[0], y, SMALL_TEXT_SIZE, tempColors[0]); // SOC
|
||||
renderer->drawString(displayStrings[12], false, dataPositions[1], y, SMALL_TEXT_SIZE, tempColors[1]); // PCB
|
||||
renderer->drawString(displayStrings[13], false, dataPositions[2], y, SMALL_TEXT_SIZE, tempColors[2]); // Skin
|
||||
|
||||
y = 211; // Direct assignment (191 + 20)
|
||||
|
||||
// === SOC VOLTAGE & POWER ===
|
||||
// SOC voltage (if available)
|
||||
if (socVoltageUv) [[likely]] {
|
||||
renderer->drawString(displayStrings[14], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor);
|
||||
}
|
||||
|
||||
// Power labels and values
|
||||
renderer->drawString(labels[8], false, positions[8]-1, y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
renderer->drawString(labels[9], false, positions[9], y, SMALL_TEXT_SIZE, tsl::sectionTextColor);
|
||||
|
||||
renderer->drawString(displayStrings[15], false, dataPositions[3], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // Power now
|
||||
renderer->drawString(displayStrings[16], false, dataPositions[4], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // Power avg
|
||||
}
|
||||
|
||||
// Optimized refresh - now does all the string formatting once per second
|
||||
void BaseMenuGui::refresh()
|
||||
{
|
||||
const u64 ticks = armGetSystemTick();
|
||||
// Use cached comparison - 1 billion nanoseconds
|
||||
if (armTicksToNs(ticks - this->lastContextUpdate) <= 1000000000UL) [[likely]] {
|
||||
return; // Early exit for most calls
|
||||
}
|
||||
|
||||
this->lastContextUpdate = ticks;
|
||||
|
||||
// Lazy context allocation
|
||||
if (!this->context) [[unlikely]] {
|
||||
this->context = new SysClkContext;
|
||||
}
|
||||
|
||||
// === ULTRA-FAST VOLTAGE READING ===
|
||||
// Pre-computed domain configuration based on hardware
|
||||
static const PowerDomainId domains[] = {
|
||||
PcvPowerDomainId_Max77621_Cpu, // [0] CPU
|
||||
PcvPowerDomainId_Max77621_Gpu, // [1] GPU
|
||||
PcvPowerDomainId_Max77812_Dram, // [2] EMC/DRAM - Mariko only
|
||||
PcvPowerDomainId_Max77620_Sd0, // [3] SOC - EOS only
|
||||
PcvPowerDomainId_Max77620_Sd1 // [4] VDD2 - EOS only
|
||||
};
|
||||
|
||||
// Voltage array for direct indexing
|
||||
u32* voltages[] = {&cpuVoltageUv, &gpuVoltageUv, &emcVoltageUv, &socVoltageUv, &vddVoltageUv};
|
||||
|
||||
// Single regulator init/exit cycle
|
||||
if (R_SUCCEEDED(rgltrInitialize())) [[likely]] {
|
||||
if (IsMariko()) {
|
||||
// Mariko with EOS: all 5 domains
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
RgltrSession session;
|
||||
if (R_SUCCEEDED(rgltrOpenSession(&session, domains[i]))) [[likely]] {
|
||||
if (R_FAILED(rgltrGetVoltage(&session, voltages[i]))) {
|
||||
*voltages[i] = 0;
|
||||
}
|
||||
rgltrCloseSession(&session);
|
||||
} else {
|
||||
*voltages[i] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Erista
|
||||
// Erista with EOS: CPU, GPU, SOC, VDD (no DRAM)
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
if (i == 2) continue; // Skip DRAM domain
|
||||
|
||||
RgltrSession session;
|
||||
if (R_SUCCEEDED(rgltrOpenSession(&session, domains[i]))) [[likely]] {
|
||||
if (R_FAILED(rgltrGetVoltage(&session, voltages[i]))) {
|
||||
*voltages[i] = 0;
|
||||
}
|
||||
rgltrCloseSession(&session);
|
||||
} else {
|
||||
*voltages[i] = 0;
|
||||
}
|
||||
emcVoltageUv = 0; // Erista never supports DRAM
|
||||
}
|
||||
}
|
||||
|
||||
rgltrExit();
|
||||
} else {
|
||||
// Zero all voltages on regulator failure
|
||||
memset(&cpuVoltageUv, 0, sizeof(u32) * 5);
|
||||
}
|
||||
|
||||
// === SYSCLK CONTEXT UPDATE ===
|
||||
const Result rc = sysclkIpcGetCurrentContext(this->context);
|
||||
if (R_FAILED(rc)) [[unlikely]] {
|
||||
FatalGui::openWithResultCode("sysclkIpcGetCurrentContext", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
// === FORMAT ALL DISPLAY STRINGS (once per second) ===
|
||||
// App ID (hex conversion)
|
||||
sprintf(displayStrings[0], "%016lX", context->applicationId);
|
||||
|
||||
// Profile
|
||||
strcpy(displayStrings[1], sysclkFormatProfile(context->profile, true));
|
||||
|
||||
// Current frequencies
|
||||
u32 hz = context->freqs[0]; // CPU
|
||||
sprintf(displayStrings[2], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U);
|
||||
|
||||
hz = context->freqs[1]; // GPU
|
||||
sprintf(displayStrings[3], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U);
|
||||
|
||||
hz = context->freqs[2]; // MEM
|
||||
sprintf(displayStrings[4], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U);
|
||||
|
||||
// Real frequencies
|
||||
hz = context->realFreqs[0]; // CPU
|
||||
sprintf(displayStrings[5], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U);
|
||||
|
||||
hz = context->realFreqs[1]; // GPU
|
||||
sprintf(displayStrings[6], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U);
|
||||
|
||||
hz = context->realFreqs[2]; // MEM
|
||||
sprintf(displayStrings[7], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U);
|
||||
|
||||
// Voltages
|
||||
sprintf(displayStrings[8], "%.1f mV", cpuVoltageUv / 1000.0);
|
||||
sprintf(displayStrings[9], "%.1f mV", gpuVoltageUv / 1000.0);
|
||||
|
||||
// Memory voltage (handle VDD case)
|
||||
if (emcVoltageUv && vddVoltageUv) {
|
||||
//sprintf(displayStrings[10], "%u%u mV", vddVoltageUv / 1000U, emcVoltageUv / 1000U);
|
||||
//sprintf(displayStrings[10], "%u%.1f mV", vddVoltageUv / 1000U, emcVoltageUv / 1000.0f);
|
||||
sprintf(displayStrings[10], "%u.%u%u mV", vddVoltageUv / 1000U, (vddVoltageUv % 1000U) / 100U, emcVoltageUv / 1000U);
|
||||
} else if (vddVoltageUv) {
|
||||
//sprintf(displayStrings[10], "%u mV", vddVoltageUv / 1000U);
|
||||
sprintf(displayStrings[10], "%u.%u mV", vddVoltageUv / 1000U, (vddVoltageUv % 1000U) / 100U);
|
||||
} else if (emcVoltageUv) {
|
||||
sprintf(displayStrings[10], "%u mV", emcVoltageUv / 1000U);
|
||||
}
|
||||
|
||||
// Temperatures and pre-compute colors
|
||||
u32 millis = context->temps[0]; // SOC
|
||||
sprintf(displayStrings[11], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U);
|
||||
tempColors[0] = tsl::GradientColor(millis * 0.001f);
|
||||
|
||||
millis = context->temps[1]; // PCB
|
||||
sprintf(displayStrings[12], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U);
|
||||
tempColors[1] = tsl::GradientColor(millis * 0.001f);
|
||||
|
||||
millis = context->temps[2]; // Skin
|
||||
sprintf(displayStrings[13], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U);
|
||||
tempColors[2] = tsl::GradientColor(millis * 0.001f);
|
||||
|
||||
// SOC voltage (if available)
|
||||
if (socVoltageUv) {
|
||||
sprintf(displayStrings[14], "%u mV", socVoltageUv / 1000U);
|
||||
}
|
||||
|
||||
// Power
|
||||
sprintf(displayStrings[15], "%d mW", context->power[0]); // Now
|
||||
sprintf(displayStrings[16], "%d mW", context->power[1]); // Avg
|
||||
}
|
||||
|
||||
tsl::elm::Element* BaseMenuGui::baseUI()
|
||||
{
|
||||
auto* list = new tsl::elm::List();
|
||||
this->listElement = list;
|
||||
this->listUI();
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Optimized refresh - now does all the string formatting once per second
|
||||
void BaseMenuGui::refresh()
|
||||
{
|
||||
|
||||
const u64 ticks = armGetSystemTick();
|
||||
// Use cached comparison - 1 billion nanoseconds
|
||||
if (armTicksToNs(ticks - this->lastContextUpdate) <= 1000000000UL) [[likely]] {
|
||||
return; // Early exit for most calls
|
||||
}
|
||||
|
||||
this->lastContextUpdate = ticks;
|
||||
|
||||
// Lazy context allocation
|
||||
if (!this->context) [[unlikely]] {
|
||||
this->context = new SysClkContext;
|
||||
}
|
||||
|
||||
// === ULTRA-FAST VOLTAGE READING ===
|
||||
// Pre-computed domain configuration based on hardware
|
||||
static const PowerDomainId domains[] = {
|
||||
PcvPowerDomainId_Max77621_Cpu, // [0] CPU
|
||||
PcvPowerDomainId_Max77621_Gpu, // [1] GPU
|
||||
PcvPowerDomainId_Max77812_Dram, // [2] EMC/DRAM - Mariko only
|
||||
PcvPowerDomainId_Max77620_Sd0, // [3] SOC
|
||||
PcvPowerDomainId_Max77620_Sd1 // [4] VDD2
|
||||
};
|
||||
|
||||
// Voltage array for direct indexing
|
||||
u32* voltages[] = {&cpuVoltageUv, &gpuVoltageUv, &emcVoltageUv, &socVoltageUv, &vddVoltageUv};
|
||||
|
||||
// Single regulator init/exit cycle
|
||||
if (R_SUCCEEDED(rgltrInitialize())) [[likely]] {
|
||||
if (IsMariko()) {
|
||||
// Mariko with EOS: all 5 domains
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
RgltrSession session;
|
||||
if (R_SUCCEEDED(rgltrOpenSession(&session, domains[i]))) [[likely]] {
|
||||
if (R_FAILED(rgltrGetVoltage(&session, voltages[i]))) {
|
||||
*voltages[i] = 0;
|
||||
}
|
||||
rgltrCloseSession(&session);
|
||||
} else {
|
||||
*voltages[i] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Erista
|
||||
// Erista with EOS: CPU, GPU, SOC, VDD (no DRAM)
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
if (i == 2) continue; // Skip DRAM domain
|
||||
|
||||
RgltrSession session;
|
||||
if (R_SUCCEEDED(rgltrOpenSession(&session, domains[i]))) [[likely]] {
|
||||
if (R_FAILED(rgltrGetVoltage(&session, voltages[i]))) {
|
||||
*voltages[i] = 0;
|
||||
}
|
||||
rgltrCloseSession(&session);
|
||||
} else {
|
||||
*voltages[i] = 0;
|
||||
}
|
||||
emcVoltageUv = 0; // Erista never supports DRAM
|
||||
}
|
||||
}
|
||||
|
||||
rgltrExit();
|
||||
} else {
|
||||
// Zero all voltages on regulator failure
|
||||
memset(&cpuVoltageUv, 0, sizeof(u32) * 5);
|
||||
}
|
||||
|
||||
// === SYSCLK CONTEXT UPDATE ===
|
||||
const Result rc = sysclkIpcGetCurrentContext(this->context);
|
||||
if (R_FAILED(rc)) [[unlikely]] {
|
||||
FatalGui::openWithResultCode("sysclkIpcGetCurrentContext", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
// === FORMAT ALL DISPLAY STRINGS (once per second) ===
|
||||
// App ID (hex conversion)
|
||||
sprintf(displayStrings[0], "%016lX", context->applicationId);
|
||||
|
||||
// Profile
|
||||
strcpy(displayStrings[1], sysclkFormatProfile(context->profile, true));
|
||||
|
||||
// Current frequencies
|
||||
u32 hz = context->freqs[0]; // CPU
|
||||
|
||||
sprintf(displayStrings[2], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U);
|
||||
|
||||
hz = context->freqs[1]; // GPU
|
||||
sprintf(displayStrings[3], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U);
|
||||
|
||||
hz = context->freqs[2]; // MEM
|
||||
sprintf(displayStrings[4], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U);
|
||||
|
||||
// Real frequencies
|
||||
hz = context->realFreqs[0]; // CPU
|
||||
sprintf(displayStrings[5], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U);
|
||||
|
||||
hz = context->realFreqs[1]; // GPU
|
||||
sprintf(displayStrings[6], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U);
|
||||
|
||||
hz = context->realFreqs[2]; // MEM
|
||||
sprintf(displayStrings[7], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U);
|
||||
|
||||
// Voltages
|
||||
sprintf(displayStrings[8], "%.1f mV", cpuVoltageUv / 1000.0);
|
||||
sprintf(displayStrings[9], "%.1f mV", gpuVoltageUv / 1000.0);
|
||||
|
||||
// Memory voltage (handle VDD case)
|
||||
if (emcVoltageUv && vddVoltageUv) {
|
||||
//sprintf(displayStrings[10], "%u%u mV", vddVoltageUv / 1000U, emcVoltageUv / 1000U);
|
||||
//sprintf(displayStrings[10], "%u%.1f mV", vddVoltageUv / 1000U, emcVoltageUv / 1000.0f);
|
||||
sprintf(displayStrings[10], "%u.%u%u mV", vddVoltageUv / 1000U, (vddVoltageUv % 1000U) / 100U, emcVoltageUv / 1000U);
|
||||
} else if (vddVoltageUv) {
|
||||
//sprintf(displayStrings[10], "%u mV", vddVoltageUv / 1000U);
|
||||
sprintf(displayStrings[10], "%u.%u mV", vddVoltageUv / 1000U, (vddVoltageUv % 1000U) / 100U);
|
||||
} else if (emcVoltageUv) {
|
||||
sprintf(displayStrings[10], "%u mV", emcVoltageUv / 1000U);
|
||||
}
|
||||
|
||||
|
||||
u32 millis = context->temps[SysClkThermalSensor_SOC]; // SOC
|
||||
sprintf(displayStrings[11], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U);
|
||||
tempColors[0] = tsl::GradientColor(millis * 0.001f);
|
||||
|
||||
millis = context->temps[SysClkThermalSensor_PCB]; // PCB
|
||||
sprintf(displayStrings[12], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U);
|
||||
tempColors[1] = tsl::GradientColor(millis * 0.001f);
|
||||
|
||||
millis = context->temps[SysClkThermalSensor_Skin]; // Skin
|
||||
sprintf(displayStrings[13], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U);
|
||||
tempColors[2] = tsl::GradientColor(millis * 0.001f);
|
||||
|
||||
millis = context->temps[HocClkThermalSensor_Battery]; //
|
||||
sprintf(displayStrings[20], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U);
|
||||
tempColors[3] = tsl::GradientColor(millis * 0.001f);
|
||||
|
||||
millis = context->temps[HocClkThermalSensor_PMIC]; //
|
||||
sprintf(displayStrings[21], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U);
|
||||
tempColors[4] = tsl::GradientColor(millis * 0.001f);
|
||||
|
||||
// millis = context->temps[HocClkThermalSensor_GPU]; // Skin
|
||||
// sprintf(displayStrings[18], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U);
|
||||
// tempColors[4] = tsl::GradientColor(millis * 0.001f);
|
||||
|
||||
// millis = context->temps[HocClkThermalSensor_PLL]; // Skin
|
||||
// sprintf(displayStrings[19], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U);
|
||||
// tempColors[5] = tsl::GradientColor(millis * 0.001f);
|
||||
|
||||
// SOC voltage (if available)
|
||||
if (socVoltageUv) {
|
||||
sprintf(displayStrings[14], "%u mV", socVoltageUv / 1000U);
|
||||
}
|
||||
|
||||
// Power
|
||||
sprintf(displayStrings[15], "%d mW", context->power[0]); // Now
|
||||
sprintf(displayStrings[16], "%d mW", context->power[1]); // Avg
|
||||
|
||||
|
||||
}
|
||||
|
||||
tsl::elm::Element* BaseMenuGui::baseUI()
|
||||
{
|
||||
auto* list = new tsl::elm::List();
|
||||
this->listElement = list;
|
||||
this->listUI();
|
||||
|
||||
return list;
|
||||
}
|
||||
@@ -1,4 +1,15 @@
|
||||
/*
|
||||
* --------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
|
||||
* wrote this file. As long as you retain this notice you can do whatever you
|
||||
* want with this stuff. If you meet any of us some day, and you think this
|
||||
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (c) Souldbminer and Horizon OC Contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -12,65 +23,69 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../rgltr_services.h"
|
||||
#include "../../ipc.h"
|
||||
#include "base_gui.h"
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
|
||||
* wrote this file. As long as you retain this notice you can do whatever you
|
||||
* want with this stuff. If you meet any of us some day, and you think this
|
||||
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
class BaseMenuGui : public BaseGui
|
||||
{
|
||||
protected:
|
||||
SysClkContext* context;
|
||||
std::uint64_t lastContextUpdate;
|
||||
std::uint32_t cpuVoltageUv;
|
||||
std::uint32_t gpuVoltageUv;
|
||||
std::uint32_t emcVoltageUv;
|
||||
std::uint32_t socVoltageUv; //add soc voltage
|
||||
std::uint32_t vddVoltageUv;//add vdd2 voltage
|
||||
|
||||
public:
|
||||
uint64_t systemtickfrequency = 19200000;
|
||||
bool g_hardwareModelCached = false;
|
||||
bool g_isMariko = false;
|
||||
bool g_isAula = false;
|
||||
|
||||
bool IsMariko() {
|
||||
if (!g_hardwareModelCached) {
|
||||
SetSysProductModel model = SetSysProductModel_Invalid;
|
||||
setsysGetProductModel(&model);
|
||||
g_isMariko = (model == SetSysProductModel_Iowa ||
|
||||
model == SetSysProductModel_Hoag ||
|
||||
model == SetSysProductModel_Calcio ||
|
||||
model == SetSysProductModel_Aula);
|
||||
g_hardwareModelCached = true;
|
||||
}
|
||||
return g_isMariko;
|
||||
}
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../rgltr_services.h"
|
||||
#include "../../ipc.h"
|
||||
#include "base_gui.h"
|
||||
|
||||
class BaseMenuGui : public BaseGui
|
||||
{
|
||||
protected:
|
||||
SysClkContext* context;
|
||||
std::uint64_t lastContextUpdate;
|
||||
std::uint32_t cpuVoltageUv;
|
||||
std::uint32_t gpuVoltageUv;
|
||||
std::uint32_t emcVoltageUv;
|
||||
std::uint32_t socVoltageUv; //add soc voltage
|
||||
std::uint32_t vddVoltageUv;//add vdd2 voltage
|
||||
|
||||
public:
|
||||
bool g_hardwareModelCached = false;
|
||||
bool g_isMariko = false;
|
||||
|
||||
bool IsMariko() {
|
||||
bool IsAula() {
|
||||
if (!g_hardwareModelCached) {
|
||||
SetSysProductModel model = SetSysProductModel_Invalid;
|
||||
setsysGetProductModel(&model);
|
||||
g_isMariko = (model == SetSysProductModel_Iowa ||
|
||||
model == SetSysProductModel_Hoag ||
|
||||
model == SetSysProductModel_Calcio ||
|
||||
model == SetSysProductModel_Aula);
|
||||
g_hardwareModelCached = true;
|
||||
g_isMariko = (model == SetSysProductModel_Aula);
|
||||
}
|
||||
return g_isMariko;
|
||||
return g_isAula;
|
||||
}
|
||||
|
||||
bool IsErista() {
|
||||
return !IsMariko();
|
||||
}
|
||||
BaseMenuGui();
|
||||
~BaseMenuGui();
|
||||
void preDraw(tsl::gfx::Renderer* renderer) override;
|
||||
tsl::elm::List* listElement;
|
||||
tsl::elm::Element* baseUI() override;
|
||||
void refresh() override;
|
||||
virtual void listUI() = 0;
|
||||
|
||||
private:
|
||||
char displayStrings[17][32]; // Pre-formatted display strings
|
||||
tsl::Color tempColors[3]; // Pre-computed temperature colors
|
||||
};
|
||||
|
||||
bool IsErista() {
|
||||
return !IsMariko();
|
||||
}
|
||||
BaseMenuGui();
|
||||
~BaseMenuGui();
|
||||
void preDraw(tsl::gfx::Renderer* renderer) override;
|
||||
tsl::elm::List* listElement;
|
||||
tsl::elm::Element* baseUI() override;
|
||||
void refresh() override;
|
||||
virtual void listUI() = 0;
|
||||
|
||||
private:
|
||||
char displayStrings[32][32]; // Pre-formatted display strings
|
||||
tsl::Color tempColors[6] = {
|
||||
tsl::Color(0), tsl::Color(0), tsl::Color(0),
|
||||
tsl::Color(0), tsl::Color(0), tsl::Color(0)
|
||||
};
|
||||
};
|
||||
@@ -205,14 +205,18 @@ void MiscGui::listUI()
|
||||
addConfigToggle(HocClkConfigValue_OverwriteBoostMode, nullptr);
|
||||
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Experimental"));
|
||||
addConfigToggle(HocClkConfigValue_EnforceBoardLimit, nullptr);
|
||||
addConfigToggle(HocClkConfigValue_ThermalThrottle, nullptr);
|
||||
addConfigToggle(HocClkConfigValue_HandheldTDP, nullptr);
|
||||
|
||||
addConfigToggle(HocClkConfigValue_EnforceBoardLimit, nullptr);
|
||||
if(IsAula()) {
|
||||
addConfigToggle(HocClkConfigValue_PWMDimming, "PWM Dimming");
|
||||
}
|
||||
ValueThresholds tdpThresholds(8600, 9500);
|
||||
addConfigButton(
|
||||
HocClkConfigValue_HandheldTDPLimit,
|
||||
"TDP Threshold",
|
||||
ValueRange(5000, 10000, 100, "mW", 1),
|
||||
ValueRange(5000, 10000, 200, "mW", 1, 0),
|
||||
"Power",
|
||||
&tdpThresholds
|
||||
);
|
||||
@@ -221,7 +225,7 @@ void MiscGui::listUI()
|
||||
addConfigButton(
|
||||
HocClkConfigValue_LiteTDPLimit,
|
||||
"Lite TDP Threshold",
|
||||
ValueRange(4000, 8000, 100, "mW", 1),
|
||||
ValueRange(4000, 8000, 200, "mW", 1, 0),
|
||||
"Power",
|
||||
&tdpThresholdsLite
|
||||
);
|
||||
@@ -230,11 +234,11 @@ void MiscGui::listUI()
|
||||
addConfigButton(
|
||||
HocClkConfigValue_ThermalThrottleThreshold,
|
||||
"Thermal Throttle Limit",
|
||||
ValueRange(50, 85, 1, "°C", 1),
|
||||
ValueRange(50, 85, 5, "°C", 1, 0),
|
||||
"Temp",
|
||||
&throttleThresholds
|
||||
);
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Max Clocks"));
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Clocks"));
|
||||
if(IsMariko()) {
|
||||
addFreqButton(HocClkConfigValue_MarikoMaxCpuClock, nullptr, SysClkModule_CPU);
|
||||
addFreqButton(HocClkConfigValue_MarikoMaxGpuClock, nullptr, SysClkModule_GPU);
|
||||
@@ -244,6 +248,62 @@ void MiscGui::listUI()
|
||||
addFreqButton(HocClkConfigValue_EristaMaxGpuClock, nullptr, SysClkModule_GPU);
|
||||
addFreqButton(HocClkConfigValue_EristaMaxMemClock, nullptr, SysClkModule_MEM);
|
||||
}
|
||||
|
||||
// addFreqButton(HocClkConfigValue_CustomBoostClock, nullptr, S);
|
||||
if(IsMariko()) {
|
||||
ValueThresholds BoostThresholds(1963, 2397);
|
||||
addConfigButton(
|
||||
HocClkConfigValue_MarikoBoostClock,
|
||||
"CPU Boost Clock",
|
||||
ValueRange(1785, 2805, 102, "MHz", 1, 0),
|
||||
"CPU Boost Clock",
|
||||
&BoostThresholds
|
||||
);
|
||||
} else {
|
||||
ValueThresholds BoostThresholds(1785, 2091);
|
||||
addConfigButton(
|
||||
HocClkConfigValue_EristaBoostClock,
|
||||
"CPU Boost Clock",
|
||||
ValueRange(1785, 2295, 102, "MHz", 1, 0),
|
||||
"CPU Boost Clock",
|
||||
&BoostThresholds
|
||||
);
|
||||
}
|
||||
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("EMC and MTC"));
|
||||
|
||||
addConfigToggle(HocClkConfigValue_EMCEnableUnsafeVoltages, nullptr);
|
||||
|
||||
if(this->configList->values[HocClkConfigValue_EMCEnableUnsafeVoltages]) {
|
||||
ValueThresholds emcUvThresholds(1212500, 1250000);
|
||||
addConfigButton(
|
||||
HocClkConfigValue_EMCVdd2VoltageuV,
|
||||
"EMC VDD2 Voltage",
|
||||
ValueRange(918500, 1350000, 12500, "µV", 1, 1),
|
||||
"EMC VDD2 Voltage",
|
||||
&emcUvThresholds
|
||||
);
|
||||
} else {
|
||||
if(IsMariko()) {
|
||||
ValueThresholds emcUvThresholds(1212500, 1250000);
|
||||
addConfigButton(
|
||||
HocClkConfigValue_EMCVdd2VoltageuV,
|
||||
"EMC VDD2 Voltage",
|
||||
ValueRange(1100000, 1212500, 12500, "µV", 1, 1),
|
||||
"EMC VDD2 Voltage",
|
||||
&emcUvThresholds
|
||||
);
|
||||
} else {
|
||||
ValueThresholds emcUvThresholds(1237500, 1300000);
|
||||
addConfigButton(
|
||||
HocClkConfigValue_EMCVdd2VoltageuV,
|
||||
"EMC VDD2 Voltage",
|
||||
ValueRange(1125000, 1237500, 12500, "mV", 1000, 1),
|
||||
"EMC VDD2 Voltage",
|
||||
&emcUvThresholds
|
||||
);
|
||||
}
|
||||
}
|
||||
tsl::elm::ListItem* applyBtn = new tsl::elm::ListItem("Apply EMC Regs");
|
||||
applyBtn->setClickListener([](u64 keys) {
|
||||
if (keys & HidNpadButton_A) {
|
||||
|
||||
@@ -1,145 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer and Horizon OC Contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
|
||||
* wrote this file. As long as you retain this notice you can do whatever you
|
||||
* want with this stuff. If you meet any of us some day, and you think this
|
||||
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
#include "value_choice_gui.h"
|
||||
#include "../format.h"
|
||||
#include "fatal_gui.h"
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
ValueChoiceGui::ValueChoiceGui(std::uint32_t selectedValue,
|
||||
const ValueRange& range,
|
||||
const std::string& categoryName,
|
||||
ValueChoiceListener listener,
|
||||
const ValueThresholds& thresholds,
|
||||
bool enableThresholds)
|
||||
: selectedValue(selectedValue),
|
||||
range(range),
|
||||
categoryName(categoryName),
|
||||
listener(listener),
|
||||
thresholds(thresholds),
|
||||
enableThresholds(enableThresholds)
|
||||
{
|
||||
}
|
||||
|
||||
#include "value_choice_gui.h"
|
||||
#include "../format.h"
|
||||
#include "fatal_gui.h"
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
ValueChoiceGui::~ValueChoiceGui()
|
||||
{
|
||||
}
|
||||
|
||||
ValueChoiceGui::ValueChoiceGui(std::uint32_t selectedValue,
|
||||
const ValueRange& range,
|
||||
const std::string& categoryName,
|
||||
ValueChoiceListener listener,
|
||||
const ValueThresholds& thresholds,
|
||||
bool enableThresholds)
|
||||
: selectedValue(selectedValue),
|
||||
range(range),
|
||||
categoryName(categoryName),
|
||||
listener(listener),
|
||||
thresholds(thresholds),
|
||||
enableThresholds(enableThresholds)
|
||||
{
|
||||
}
|
||||
std::string ValueChoiceGui::formatValue(std::uint32_t value)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
||||
ValueChoiceGui::~ValueChoiceGui()
|
||||
{
|
||||
}
|
||||
if (value == 0) {
|
||||
return VALUE_DEFAULT_TEXT;
|
||||
}
|
||||
|
||||
std::string ValueChoiceGui::formatValue(std::uint32_t value)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
// Convert to floating point for division
|
||||
double displayValue = static_cast<double>(value) / static_cast<double>(range.divisor);
|
||||
|
||||
if (value == 0) {
|
||||
// Set precision and formatting
|
||||
oss << std::fixed << std::setprecision(range.decimalPlaces) << displayValue;
|
||||
|
||||
if (!range.suffix.empty()) {
|
||||
oss << " " << range.suffix;
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
return VALUE_DEFAULT_TEXT;
|
||||
}
|
||||
int ValueChoiceGui::getSafetyLevel(std::uint32_t value)
|
||||
{
|
||||
if (!enableThresholds) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::uint32_t displayValue = value / range.divisor;
|
||||
std::uint32_t scaledValue = value / range.divisor;
|
||||
|
||||
oss << displayValue;
|
||||
if (!range.suffix.empty()) {
|
||||
oss << " " << range.suffix;
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
if (scaledValue > thresholds.danger) {
|
||||
return 2;
|
||||
}
|
||||
if (scaledValue > thresholds.warning) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ValueChoiceGui::getSafetyLevel(std::uint32_t value)
|
||||
{
|
||||
if (!enableThresholds) {
|
||||
return 0;
|
||||
}
|
||||
tsl::elm::ListItem* ValueChoiceGui::createValueListItem(std::uint32_t value, bool selected, int safety)
|
||||
{
|
||||
std::string text = formatValue(value);
|
||||
if (selected) {
|
||||
text += " \uE14B";
|
||||
}
|
||||
|
||||
std::uint32_t scaledValue = value / range.divisor;
|
||||
tsl::elm::ListItem* listItem = new tsl::elm::ListItem(text, "", false);
|
||||
|
||||
if (scaledValue > thresholds.danger) {
|
||||
return 2;
|
||||
}
|
||||
if (scaledValue > thresholds.warning) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
tsl::elm::ListItem* ValueChoiceGui::createValueListItem(std::uint32_t value, bool selected, int safety)
|
||||
{
|
||||
std::string text = formatValue(value);
|
||||
if (selected) {
|
||||
text += " \uE14B";
|
||||
}
|
||||
listItem->setClickListener([this, value](u64 keys)
|
||||
{
|
||||
if ((keys & HidNpadButton_A) == HidNpadButton_A && this->listener) {
|
||||
if (this->listener(value)) {
|
||||
tsl::goBack();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
tsl::elm::ListItem* listItem = new tsl::elm::ListItem(text, "", false);
|
||||
return listItem;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
void ValueChoiceGui::listUI()
|
||||
{
|
||||
if (!categoryName.empty()) {
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader(categoryName));
|
||||
}
|
||||
|
||||
listItem->setClickListener([this, value](u64 keys)
|
||||
{
|
||||
if ((keys & HidNpadButton_A) == HidNpadButton_A && this->listener) {
|
||||
this->listElement->addItem(this->createValueListItem(0, this->selectedValue == 0, 0));
|
||||
|
||||
if (this->listener(value)) {
|
||||
tsl::goBack();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
for (std::uint32_t value = range.min; value <= range.max; value += range.step)
|
||||
{
|
||||
int safety = getSafetyLevel(value);
|
||||
bool selected = (value == this->selectedValue);
|
||||
this->listElement->addItem(this->createValueListItem(value, selected, safety));
|
||||
}
|
||||
|
||||
return listItem;
|
||||
}
|
||||
|
||||
void ValueChoiceGui::listUI()
|
||||
{
|
||||
|
||||
if (!categoryName.empty()) {
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader(categoryName));
|
||||
}
|
||||
|
||||
this->listElement->addItem(this->createValueListItem(0, this->selectedValue == 0, 0));
|
||||
|
||||
for (std::uint32_t value = range.min; value <= range.max; value += range.step)
|
||||
{
|
||||
int safety = getSafetyLevel(value);
|
||||
bool selected = (value == this->selectedValue);
|
||||
this->listElement->addItem(this->createValueListItem(value, selected, safety));
|
||||
}
|
||||
|
||||
this->listElement->jumpToItem("", "\uE14B");
|
||||
}
|
||||
this->listElement->jumpToItem("", "\uE14B");
|
||||
}
|
||||
@@ -37,20 +37,20 @@
|
||||
#define VALUE_DEFAULT_TEXT "Default"
|
||||
|
||||
struct ValueRange {
|
||||
std::uint32_t min;
|
||||
std::uint32_t max;
|
||||
std::uint32_t step;
|
||||
std::string suffix;
|
||||
std::uint32_t divisor; // Divide input values by this for display
|
||||
|
||||
// Default constructor
|
||||
ValueRange() : min(0), max(0), step(1), suffix(""), divisor(1) {}
|
||||
|
||||
ValueRange(std::uint32_t min, std::uint32_t max, std::uint32_t step,
|
||||
const std::string& suffix = "", std::uint32_t divisor = 1)
|
||||
: min(min), max(max), step(step), suffix(suffix), divisor(divisor) {}
|
||||
};
|
||||
|
||||
std::uint32_t min;
|
||||
std::uint32_t max;
|
||||
std::uint32_t step;
|
||||
std::string suffix;
|
||||
std::uint32_t divisor; // Divide input values by this for display
|
||||
int decimalPlaces; // Number of decimal places to display (0-6)
|
||||
|
||||
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,
|
||||
const std::string& suffix = "", std::uint32_t divisor = 1, int decimalPlaces = 0)
|
||||
: min(min), max(max), step(step), suffix(suffix), divisor(divisor), decimalPlaces(decimalPlaces) {}
|
||||
};
|
||||
|
||||
struct ValueThresholds {
|
||||
std::uint32_t warning; // Values >= this show orange
|
||||
std::uint32_t danger; // Values >= this show red
|
||||
|
||||
Reference in New Issue
Block a user