- [Sys-clk-OC overlay] Report info on battery current flow, battery cycle (might be useless, reset after each reboot)

- Remove InfoNX as voltage is not reported accurate
This commit is contained in:
KazushiM
2022-01-01 01:01:50 +08:00
parent 4b0bd74e80
commit 82fccb99e1
13 changed files with 109 additions and 731 deletions

View File

@@ -1,10 +1,10 @@
# Switch OC Suite
[![Join the chat at https://gitter.im/Switch-OC-Suite/community](https://badges.gitter.im/Switch-OC-Suite/community.svg)](https://gitter.im/Switch-OC-Suite/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![License: GPL v2](https://img.shields.io/badge/License-GPL_v2-blue.svg)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) [![Join the chat at https://gitter.im/Switch-OC-Suite/community](https://badges.gitter.im/Switch-OC-Suite/community.svg)](https://gitter.im/Switch-OC-Suite/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Overclocking suite for Switch **(Mariko Only)** running on Atmosphere CFW. Support Horizon OS 13.0.0-13.2.0.
This project will not be actively maintained by me and I'm looking for collaborators. Open an issue if you are interested and would like to be added into the maintainer list.
This project will not be actively maintained in 2022 and I'm looking for collaborators. Open an issue if you are interested and would like to be added into the maintainer list.
@@ -39,6 +39,8 @@ This project will not be actively maintained by me and I'm looking for collabora
- **Official X1+ CPU/GPU Max clock: 1963.5/1267.2 MHz**.
- Anything above that are not in the table of official module. ([issue #4](https://github.com/KazushiMe/Switch-OC-Suite/issues/4))
- All maxed out OC is not recommended, and is strongly discouraged without charger.
- See `Battery Current Flow` in sys-clk-OC overlay `Miscellaneous`.
- **Recommended RAM clock: 1862.4/1996.8 MHz**.
- Only 1600 and MAX MHz could be selected in sys-clk.
@@ -55,18 +57,9 @@ This project will not be actively maintained by me and I'm looking for collabora
- CPU overvolting: 1220 mV, up from default 1120 mV. Frequencies ≥ 2193 MHz will enable overvolting.
- GPU overvolting: 1170 mV, default 1050 mV. Frequencies ≥ 1420 Mhz trigger overvolting. ([issue #4](https://github.com/KazushiMe/Switch-OC-Suite/issues/4))
- GPU overvolting: 1170 mV, default 1050 mV. Frequencies ≥ 1420 MHz trigger overvolting.
- You cannot set > 1267 MHz without official chargers.
- RAM [NOT RECOMMENDED]
- Only diff patch for hekate bootloader is provided.
- Edit `oc.ini` to change Vddq voltage value:
```ini
[emc]
volt=600000
```
- Overvolting beyond 650mV is not safe and proved to be not much helpful.
- **Fan Control Optimization** at high load
- Higher tolerable temperature and smoother fan curve. Set `holdable_tskin` to 56˚C. Previously it's set to 48˚C, so by default the fan would go crazy (80~100%) easily with a slight degree of OC.
- Replace crappy factory thermal paste is preferred.
@@ -75,10 +68,9 @@ This project will not be actively maintained by me and I'm looking for collabora
- **Modded sys-clk and ReverseNX**(-Tools and -RT)
- **No need to change clocks manually** after toggling modes in ReverseNX
- Add `/config/sys-clk/downclock_dock.flag` to use handheld clocks in Docked mode when Handheld mode is set in ReverseNX.
- To **disable this feature**, use original version of ReverseNX-RT and delete `/config/sys-clk/ReverseNX_sync.flag`.
- **Auto-Boost CPU for faster game loading**
- Enable CPU Boost (1963.5 MHz) if CPU Core#3 (System Core) is stressed, especially when the game is loading assets from eMMC/SD card.
- Enable CPU Boost (1785 MHz) when CPU Core#3 (System Core) is stressed, especially when the game is loading assets from eMMC/SD card.
- Auto-Boost will be enabled only when charger is connected. (>90% w/ PD charger or >95% w/ unsupported charger)
- To **disable this feature**, simply remove `boost.flag` in `/config/sys-clk/`.
@@ -128,7 +120,7 @@ Grab necessary patches from the repo, then compile sys-clk, ReverseNX-RT, hekate
- CTCaer for [Hekate-ipl](https://github.com/CTCaer/hekate) bootloader, RE and hardware research
- [devkitPro](https://devkitpro.org/) for All-In-One homebrew toolchains
- masagrator for [ReverseNX-RT](https://github.com/masagrator/ReverseNX-RT) and [BatteryChargeInfoNX](https://github.com/masagrator/BatteryChargeInfoNX)
- masagrator for [ReverseNX-RT](https://github.com/masagrator/ReverseNX-RT) and info on BatteryChargeInfoFields in psm module
- Nvidia for [Tegra X1 Technical Reference Manual](https://developer.nvidia.com/embedded/dlc/tegra-x1-technical-reference-manual)
- RetroNX team for [sys-clk](https://github.com/retronx-team/sys-clk)
- SciresM and Reswitched Team for the state-of-the-art [Atmosphere](https://github.com/Atmosphere-NX/Atmosphere) CFW of Switch

View File

@@ -1,2 +0,0 @@
[emc]
volt=600000

View File

@@ -1,11 +0,0 @@
build/
*.ovl
*.elf
*.nacp
*.nro
*.DS_Store

View File

@@ -1,208 +0,0 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif
TOPDIR ?= $(CURDIR)
include $(DEVKITPRO)/libnx/switch_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
#
# NO_ICON: if set to anything, do not use icon.
# NO_NACP: if set to anything, no .nacp file is generated.
# APP_TITLE is the name of the app stored in the .nacp file (Optional)
# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
# APP_VERSION is the version of the app stored in the .nacp file (Optional)
# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
# ICON is the filename of the icon (.jpg), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - <Project name>.jpg
# - icon.jpg
# - <libnx folder>/default_icon.jpg
#
# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - <Project name>.json
# - config.json
# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead
# of a homebrew executable (.nro). This is intended to be used for sysmodules.
# NACP building is skipped as well.
#---------------------------------------------------------------------------------
APP_TITLE := InfoNX
APP_VERSION := 1.0.1
TARGET := InfoNX-ovl
BUILD := build
SOURCES := source
DATA := data
INCLUDES := libs/libtesla/include
NO_ICON := 1
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
CFLAGS := -g -Wall -Os -ffunction-sections \
$(ARCH) $(DEFINES)
CFLAGS += $(INCLUDE) -D__SWITCH__ -DAPP_VERSION="\"$(APP_VERSION)\""
CXXFLAGS := $(CFLAGS) -fno-exceptions -std=c++20
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := -lnx
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(LIBNX)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
ifeq ($(strip $(CONFIG_JSON)),)
jsons := $(wildcard *.json)
ifneq (,$(findstring $(TARGET).json,$(jsons)))
export APP_JSON := $(TOPDIR)/$(TARGET).json
else
ifneq (,$(findstring config.json,$(jsons)))
export APP_JSON := $(TOPDIR)/config.json
endif
endif
else
export APP_JSON := $(TOPDIR)/$(CONFIG_JSON)
endif
ifeq ($(strip $(ICON)),)
icons := $(wildcard *.jpg)
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
else
ifneq (,$(findstring icon.jpg,$(icons)))
export APP_ICON := $(TOPDIR)/icon.jpg
endif
endif
else
export APP_ICON := $(TOPDIR)/$(ICON)
endif
ifeq ($(strip $(NO_ICON)),)
export NROFLAGS += --icon=$(APP_ICON)
endif
ifeq ($(strip $(NO_NACP)),)
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
endif
ifneq ($(APP_TITLEID),)
export NACPFLAGS += --titleid=$(APP_TITLEID)
endif
ifneq ($(ROMFS),)
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
endif
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@rm -fr $(BUILD) $(TARGET).ovl $(TARGET).nro $(TARGET).nacp $(TARGET).elf
#---------------------------------------------------------------------------------
else
.PHONY: all
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
all : $(OUTPUT).ovl
$(OUTPUT).ovl : $(OUTPUT).elf $(OUTPUT).nacp
@elf2nro $< $@ $(NROFLAGS)
@echo "built ... $(notdir $(OUTPUT).ovl)"
$(OUTPUT).elf : $(OFILES)
$(OFILES_SRC) : $(HFILES_BIN)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View File

@@ -1,411 +0,0 @@
#define TESLA_INIT_IMPL // If you have more than one file using the tesla header, only define this in the main one
#include <tesla.hpp> // The Tesla Header
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <switch.h>
#include "rgltr.h"
#define IS_BAT_CHARGE_ON ((_batteryChargeInfoFields->unk_x14 >> 8) & 1)
#define IS_SLOW_CHARGE_ON (_batteryChargeInfoFields->ChargeCurrentLimit < 1024)
static Service g_rgltrSrv;
Result rgltrInitialize(void) {
if(hosversionBefore(8,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return smGetService(&g_rgltrSrv, "rgltr");
}
void rgltrExit(void) {
serviceClose(&g_rgltrSrv);
}
Service* rgltrGetServiceSession(void) {
return &g_rgltrSrv;
}
Result rgltrOpenSession(RgltrSession* session_out, PowerDomainId module_id) {
const u32 in = module_id;
return serviceDispatchIn(&g_rgltrSrv, 0, in,
.out_num_objects = 1,
.out_objects = &session_out->s,
);
}
Result rgltrGetPowerModuleNumLimit(u32 *out) {
return serviceDispatchOut(&g_rgltrSrv, 3, *out);
}
void rgltrCloseSession(RgltrSession* session) {
serviceClose(&session->s);
}
Result rgltrGetVoltageEnabled(RgltrSession* session, u32 *out) {
return serviceDispatchOut(&session->s, 2, *out);
}
Result rgltrGetVoltage(RgltrSession* session, u32 *out_volt) {
return serviceDispatchOut(&session->s, 4, *out_volt);
}
///* Notes VoltageAvg
//
// Vavg time = 175.8ms x 2^(6+VOLT), default: VOLT = 2 (Vavg time = 45s)
//
///End of Notes
extern "C" bool is_mariko();
extern "C" void clk_check();
typedef struct {
u32 cpu_out_hz;
u32 gpu_out_hz;
u32 emc_out_hz;
u32 cpu_out_volt;
u32 gpu_out_volt;
u32 emc_out_volt;
} ClkFields;
bool is_mariko() {
u64 hardware_type = 0;
splInitialize();
splGetConfig(SplConfigItem_HardwareType, &hardware_type);
splExit();
switch(hardware_type) {
case 0: //Icosa
case 1: //Copper
return false;
case 2: //Hoag
case 3: //Iowa
case 4: //Calcio
case 5: //Aula
return true;
default:
return false;
}
}
void clk_check(ClkFields *out, bool mariko) {
int res = 0;
ClkrstSession clkrstSession;
RgltrSession rgltrSession;
res = clkrstInitialize();
if(R_FAILED(res)) {
fatalThrow(res);
}
res = rgltrInitialize();
if(R_FAILED(res)) {
fatalThrow(res);
}
rgltrOpenSession(&rgltrSession, mariko ? PcvPowerDomainId_Max77812_Cpu : PcvPowerDomainId_Max77621_Cpu);
clkrstOpenSession(&clkrstSession, PcvModuleId_CpuBus, 3);
rgltrGetVoltage(&rgltrSession, &out->cpu_out_volt);
clkrstGetClockRate(&clkrstSession, &out->cpu_out_hz);
clkrstCloseSession(&clkrstSession);
rgltrCloseSession(&rgltrSession);
rgltrOpenSession(&rgltrSession, mariko ? PcvPowerDomainId_Max77812_Gpu : PcvPowerDomainId_Max77621_Gpu);
clkrstOpenSession(&clkrstSession, PcvModuleId_GPU, 3);
rgltrGetVoltage(&rgltrSession, &out->gpu_out_volt);
clkrstGetClockRate(&clkrstSession, &out->gpu_out_hz);
clkrstCloseSession(&clkrstSession);
rgltrCloseSession(&rgltrSession);
rgltrOpenSession(&rgltrSession, mariko ? PcvPowerDomainId_Max77812_Dram : PcvPowerDomainId_Max77620_Sd1);
clkrstOpenSession(&clkrstSession, PcvModuleId_EMC, 3);
rgltrGetVoltage(&rgltrSession, &out->emc_out_volt);
clkrstGetClockRate(&clkrstSession, &out->emc_out_hz);
clkrstCloseSession(&clkrstSession);
rgltrCloseSession(&rgltrSession);
clkrstExit();
rgltrExit();
}
typedef enum {
NoHub = BIT(0), //If hub is disconnected
Rail = BIT(8), //At least one Joy-con is charging from rail
SPDSRC = BIT(12), //OTG
ACC = BIT(16) //Accessory
} BatteryChargeInfoFieldsFlags;
typedef enum {
NewPDO = 1, //Received new Power Data Object
NoPD = 2, //No Power Delivery source is detected
AcceptedRDO = 3 //Received and accepted Request Data Object
} BatteryChargeInfoFieldsPDControllerState; //BM92T series
const char* strPDControllerState[] = {
"Received new PDO",
"No PD Source",
"Received/Accpted RDO"
};
typedef enum {
None = 0,
PD = 1,
TypeC_1500mA = 2,
TypeC_3000mA = 3,
DCP = 4,
CDP = 5,
SDP = 6,
Apple_500mA = 7,
Apple_1000mA = 8,
Apple_2000mA = 9
} BatteryChargeInfoFieldsChargerType;
const char* strChargerType[] = {
"None",
"PD",
"USB-C@1.5A",
"USB-C@3.0A",
"USB-DCP",
"USB-CDP",
"USB-SDP",
"Apple@0.5A",
"Apple@1.0A",
"Apple@2.0A",
};
typedef enum {
Sink = 1,
Source = 2
} BatteryChargeInfoFieldsPowerRole;
const char* strPowerRole[] = {
"Sink",
"Source",
};
typedef struct {
int32_t InputCurrentLimit; //Input (Sink) current limit in mA
int32_t VBUSCurrentLimit; //Output (Source/VBUS/OTG) current limit in mA
int32_t ChargeCurrentLimit; //Battery charging current limit in mA (512mA when Docked, 768mA when BatteryTemperature < 17.0 C)
int32_t ChargeVoltageLimit; //Battery charging voltage limit in mV (3952mV when BatteryTemperature >= 51.0 C)
int32_t unk_x10; //Possibly an emum, getting the same value as PowerRole in all tested cases
int32_t unk_x14; //Possibly flags
BatteryChargeInfoFieldsPDControllerState PDControllerState; //Power Delivery Controller State
int32_t BatteryTemperature; //Battery temperature in milli C
int32_t RawBatteryCharge; //Raw battery charged capacity per cent-mille (i.e. 100% = 100000 pcm)
int32_t VoltageAvg; //Voltage avg in mV (more in Notes)
int32_t BatteryAge; //Battery age (capacity full / capacity design) per cent-mille (i.e. 100% = 100000 pcm)
BatteryChargeInfoFieldsPowerRole PowerRole;
BatteryChargeInfoFieldsChargerType ChargerType;
int32_t ChargerVoltageLimit; //Charger and external device voltage limit in mV
int32_t ChargerCurrentLimit; //Charger and external device current limit in mA
BatteryChargeInfoFieldsFlags Flags; //Unknown flags
} BatteryChargeInfoFields;
Result psmGetBatteryChargeInfoFields(Service* psmService, BatteryChargeInfoFields *out) {
return serviceDispatchOut(psmService, 17, *out);
}
static Result psmEnableBatteryCharging(Service* psmService) {
return serviceDispatch(psmService, 2);
}
static Result psmDisableBatteryCharging(Service* psmService) {
return serviceDispatch(psmService, 3);
}
static Result psmDisableSlowCharging(Service* psmService) {
return serviceDispatch(psmService, 10);
}
static Result psmEnableSlowCharging(Service* psmService) {
return serviceDispatch(psmService, 11);
}
FanController g_ICon;
float rotationSpeedLevel = 0;
unsigned int changeSlowChargingState = 0;
unsigned int changeDisableChargingState = 0;
bool threadexit = false;
int32_t socTempMili = 0;
char Print_x[800];
Thread t0;
bool IsEnoughPowerSupplied;
void Loop(void*) {
static Service* psmService = psmGetServiceSession();
static BatteryChargeInfoFields* _batteryChargeInfoFields = new BatteryChargeInfoFields;
static ClkFields* _clkFields = new ClkFields;
while (threadexit == false) {
if(changeSlowChargingState)
{
changeSlowChargingState = 0;
if(IS_SLOW_CHARGE_ON)
psmDisableSlowCharging(psmService);
else
psmEnableSlowCharging(psmService);
}
if(changeDisableChargingState)
{
changeDisableChargingState = 0;
if(IS_BAT_CHARGE_ON)
psmDisableBatteryCharging(psmService);
else
psmEnableBatteryCharging(psmService);
}
psmGetBatteryChargeInfoFields(psmService, _batteryChargeInfoFields);
clk_check(_clkFields, is_mariko());
tsGetTemperatureMilliC(TsLocation_External, &socTempMili);
psmIsEnoughPowerSupplied(&IsEnoughPowerSupplied);
fanControllerGetRotationSpeedLevel(&g_ICon, &rotationSpeedLevel);
snprintf(Print_x, sizeof(Print_x),
"Current Limit: %u mA IN, %u mA OUT"
"\nBattery Charg. Limit: %u mA, %u mV"
"\nunk_x10: 0x%08" PRIx32
"\nunk_x14: 0x%08" PRIx32
"\nPD Contr. State: %s (%u)"
"\nBattery Temp.: %.2f\u00B0C"
"\nRaw Battery Charge: %.2f%%"
"\nVoltage Avg: %u mV"
"\nBattery Age: %.2f%%"
"\nPower Role: %s (%u)"
"\nCharger Type: %s (%u)"
"\nCharger Limit: %u mV, %u mA"
"\nunk_x3c: 0x%08" PRIx32
"\nEnough Power Supplied: %s"
"\n"
"\nCPU Clock: %6.1f MHz"
"\nCPU Volt : %6.1f mV\n"
"\nGPU Clock: %6.1f MHz"
"\nGPU Volt : %6.1f mV\n"
"\nEMC Clock: %6.1f MHz"
"\nEMC Volt : %6.1f mV\n"
"\nSoC Temp : %2.2f \u00B0C"
"\nFan Speed: %2.2f %%\n"
"\nL-Stick: Slow Charging(0.5A) (%s)"
"\nR-Stick: Disable Charging (%s)"
,
_batteryChargeInfoFields->InputCurrentLimit,
_batteryChargeInfoFields->VBUSCurrentLimit,
_batteryChargeInfoFields->ChargeCurrentLimit,
_batteryChargeInfoFields->ChargeVoltageLimit,
_batteryChargeInfoFields->unk_x10,
_batteryChargeInfoFields->unk_x14,
strPDControllerState[_batteryChargeInfoFields->PDControllerState], _batteryChargeInfoFields->PDControllerState,
(float)_batteryChargeInfoFields->BatteryTemperature / 1000,
(float)_batteryChargeInfoFields->RawBatteryCharge / 1000,
_batteryChargeInfoFields->VoltageAvg,
(float)_batteryChargeInfoFields->BatteryAge / 1000,
strPowerRole[_batteryChargeInfoFields->PowerRole], _batteryChargeInfoFields->PowerRole,
strChargerType[_batteryChargeInfoFields->ChargerType], _batteryChargeInfoFields->ChargerType,
_batteryChargeInfoFields->ChargerVoltageLimit,
_batteryChargeInfoFields->ChargerCurrentLimit,
(int32_t)_batteryChargeInfoFields->Flags,
IsEnoughPowerSupplied ? "Yes" : "No",
(double)_clkFields->cpu_out_hz / 1000000,
(double)_clkFields->cpu_out_volt / 1000,
(double)_clkFields->gpu_out_hz / 1000000,
(double)_clkFields->gpu_out_volt / 1000,
(double)_clkFields->emc_out_hz / 1000000,
(double)_clkFields->emc_out_volt / 1000,
(float)socTempMili / 1000,
rotationSpeedLevel * 100,
IS_SLOW_CHARGE_ON ? "ON" : "OFF",
!IS_BAT_CHARGE_ON ? "ON" : "OFF"
);
svcSleepThread(800'000'000);
}
delete _batteryChargeInfoFields;
delete _clkFields;
}
class GuiTest : public tsl::Gui {
public:
GuiTest(u8 arg1, u8 arg2, bool arg3) { }
// Called when this Gui gets loaded to create the UI
// Allocate all elements on the heap. libtesla will make sure to clean them up when not needed anymore
virtual tsl::elm::Element* createUI() override {
// A OverlayFrame is the base element every overlay consists of. This will draw the default Title and Subtitle.
// If you need more information in the header or want to change it's look, use a HeaderOverlayFrame.
auto frame = new tsl::elm::OverlayFrame("InfoNX", APP_VERSION);
// A list that can contain sub elements and handles scrolling
auto list = new tsl::elm::List();
list->addItem(new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {
renderer->drawString(Print_x, false, x, y+20, 15, renderer->a(0xFFFF));
}), 500);
// Add the list to the frame for it to be drawn
frame->setContent(list);
// Return the frame to have it become the top level element of this Gui
return frame;
}
// Called once every frame to update values
virtual void update() override {}
// Called once every frame to handle inputs not handled by other UI elements
virtual bool handleInput(u64 keysDown, u64 keysHeld, const HidTouchState &touchPos, HidAnalogStickState joyStickPosLeft, HidAnalogStickState joyStickPosRight) override {
if (keysHeld & HidNpadButton_A) {
tsl::hlp::requestForeground(false);
return true;
}
if (keysHeld & HidNpadButton_StickL) {
changeSlowChargingState++;
return true;
}
if (keysHeld & HidNpadButton_StickR) {
changeDisableChargingState++;
return true;
}
return false; // Return true here to singal the inputs have been consumed
}
};
class OverlayTest : public tsl::Overlay {
public:
// libtesla already initialized fs, hid, pl, pmdmnt, hid:sys and set:sys
virtual void initServices() override {
smInitialize();
psmInitialize();
tsInitialize();
fanInitialize();
fanOpenController(&g_ICon, 0x3D000001);
threadCreate(&t0, Loop, NULL, NULL, 0x4000, 0x3F, -2);
threadStart(&t0);
} // Called at the start to initialize all services necessary for this Overlay
virtual void exitServices() override {
threadexit = true;
threadWaitForExit(&t0);
threadClose(&t0);
fanControllerClose(&g_ICon);
fanExit();
tsExit();
psmExit();
smExit();
} // Callet at the end to clean up all services previously initialized
virtual void onShow() override {} // Called before overlay wants to change from invisible to visible state
virtual void onHide() override {} // Called before overlay wants to change from visible to invisible state
virtual std::unique_ptr<tsl::Gui> loadInitialGui() override {
return initially<GuiTest>(1, 2, true); // Initial Gui to load. It's possible to pass arguments to it's constructor like this
}
};
int main(int argc, char **argv) {
return tsl::loop<OverlayTest>(argc, argv);
}

View File

@@ -1,41 +0,0 @@
typedef enum {
PcvPowerDomain_Max77620_Sd0 = 0,
PcvPowerDomain_Max77620_Sd1 = 1,
PcvPowerDomain_Max77620_Sd2 = 2,
PcvPowerDomain_Max77620_Sd3 = 3,
PcvPowerDomain_Max77620_Ldo0 = 4,
PcvPowerDomain_Max77620_Ldo1 = 5,
PcvPowerDomain_Max77620_Ldo2 = 6,
PcvPowerDomain_Max77620_Ldo3 = 7,
PcvPowerDomain_Max77620_Ldo4 = 8,
PcvPowerDomain_Max77620_Ldo5 = 9,
PcvPowerDomain_Max77620_Ldo6 = 10,
PcvPowerDomain_Max77620_Ldo7 = 11,
PcvPowerDomain_Max77620_Ldo8 = 12,
PcvPowerDomain_Max77621_Cpu = 13,
PcvPowerDomain_Max77621_Gpu = 14,
PcvPowerDomain_Max77812_Cpu = 15,
PcvPowerDomain_Max77812_Gpu = 16,
PcvPowerDomain_Max77812_Dram = 17,
} PowerDomain;
typedef enum {
PcvPowerDomainId_Max77620_Sd0 = 0x3A000080,
PcvPowerDomainId_Max77620_Sd1 = 0x3A000081,
PcvPowerDomainId_Max77620_Sd2 = 0x3A000082,
PcvPowerDomainId_Max77620_Sd3 = 0x3A000083,
PcvPowerDomainId_Max77620_Ldo0 = 0x3A0000A0,
PcvPowerDomainId_Max77620_Ldo1 = 0x3A0000A1,
PcvPowerDomainId_Max77620_Ldo2 = 0x3A0000A2,
PcvPowerDomainId_Max77620_Ldo3 = 0x3A0000A3,
PcvPowerDomainId_Max77620_Ldo4 = 0x3A0000A4,
PcvPowerDomainId_Max77620_Ldo5 = 0x3A0000A5,
PcvPowerDomainId_Max77620_Ldo6 = 0x3A0000A6,
PcvPowerDomainId_Max77620_Ldo7 = 0x3A0000A7,
PcvPowerDomainId_Max77620_Ldo8 = 0x3A0000A8,
PcvPowerDomainId_Max77621_Cpu = 0x3A000003,
PcvPowerDomainId_Max77621_Gpu = 0x3A000004,
PcvPowerDomainId_Max77812_Cpu = 0x3A000003,
PcvPowerDomainId_Max77812_Gpu = 0x3A000004,
PcvPowerDomainId_Max77812_Dram = 0x3A000005,
} PowerDomainId;

View File

@@ -1,22 +0,0 @@
#pragma once
//#include "../types.h"
//#include "../sf/service.h"
//#include "../services/pcv.h"
#include <switch.h>
#include "pcv_types.h"
typedef struct {
Service s;
} RgltrSession;
Result rgltrInitialize(void);
void rgltrExit(void);
Service* rgltrGetServiceSession(void);
Result rgltrOpenSession(RgltrSession* session_out, PowerDomainId module_id);
void rgltrCloseSession(RgltrSession* session);
Result rgltrGetVoltage(RgltrSession* session, u32 *out_volt);
Result rgltrGetPowerModuleNumLimit(u32 *out);
Result rgltrGetVoltageEnabled(RgltrSession* session, u32 *out);

View File

@@ -384,10 +384,8 @@ int main(int argc, char* argv[])
for (int j = 0; j < testThreads; j++)
testJobId[j] = -1;
ull count = 0;
for (int j = 0; j < testThreads; )
{
count++;
switch (testWorkerReport[j])
{
case 0:

View File

@@ -1,5 +1,4 @@
/*
* --------------------------------------------------------------------------
/* --------------------------------------------------------------------------
* "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
@@ -27,7 +26,7 @@ void MiscGui::preDraw(tsl::gfx::Renderer* render)
{
BaseMenuGui::preDraw(render);
render->drawString(this->psmOutput, false, 40, 300, SMALL_TEXT_SIZE, DESC_COLOR);
render->drawString(this->infoOutput, false, 40, 300, SMALL_TEXT_SIZE, DESC_COLOR);
}
void MiscGui::listUI()
@@ -70,7 +69,7 @@ void MiscGui::update()
{
frameCounter = 0;
PsmUpdate();
PsmGetInfo(this->psmOutput, sizeof(this->psmOutput));
GetInfo(this->infoOutput, sizeof(this->infoOutput));
this->chargingToggle->setState(this->PsmIsCharging());
this->fastChargingToggle->setState(this->PsmIsFastCharging());
}

View File

@@ -1,5 +1,4 @@
/*
* --------------------------------------------------------------------------
/* --------------------------------------------------------------------------
* "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
@@ -102,6 +101,13 @@ class MiscGui : public BaseMenuGui
ChargeInfoFlags Flags; //Unknown flags
} ChargeInfo;
typedef enum
{
Max17050Reg_Current = 0x0A,
Max17050Reg_AvgCurrent = 0x0B,
Max17050Reg_Cycle = 0x17,
} Max17050Reg;
void PsmUpdate(uint32_t dispatchId = 0)
{
smInitialize();
@@ -140,35 +146,114 @@ class MiscGui : public BaseMenuGui
return this->isEnoughPowerSupplied;
}
void PsmGetInfo(char* out, size_t outsize)
Result I2cReadRegHandler(u8 reg, I2cDevice dev, u16 *out)
{
// ams::fatal::srv::StopSoundTask::StopSound()
// I2C Bus Communication Reference: https://www.ti.com/lit/an/slva704/slva704.pdf
struct { u8 reg; } __attribute__((packed)) cmd;
struct { u16 val; } __attribute__((packed)) rec;
I2cSession _session;
Result res = i2cOpenSession(&_session, dev);
if (res)
return res;
cmd.reg = reg;
res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All);
if (res)
{
i2csessionClose(&_session);
return res;
}
res = i2csessionReceiveAuto(&_session, &rec, sizeof(rec), I2cTransactionOption_All);
if (res)
{
i2csessionClose(&_session);
return res;
}
*out = rec.val;
i2csessionClose(&_session);
return 0;
}
bool Max17050ReadReg(u8 reg, u16 *out)
{
u16 data = 0;
Result res = I2cReadRegHandler(reg, I2cDevice_Max17050, &data);
if (res)
{
*out = res;
return false;
}
*out = data;
return true;
}
void GetInfo(char* out, size_t outsize)
{
float chargerVoltLimit = (float)chargeInfo->ChargerVoltageLimit / 1000;
float chargerCurrLimit = (float)chargeInfo->ChargerCurrentLimit / 1000;
float chargerOutWatts = chargerVoltLimit * chargerCurrLimit;
float batCurrent = 0;
float batCycleCount = 0;
char chargeVoltLimit[20] = "";
if (chargeInfo->ChargeVoltageLimit)
snprintf(chargeVoltLimit, sizeof(chargeVoltLimit), ", %u mV", chargeInfo->ChargeVoltageLimit);
// From Hekate, too lazy to query configuration from reg
constexpr float max17050SenseResistor = 5.; // in uOhm
constexpr float max17050CGain = 1.99993;
// Init, read registers and exit I2C service all here to save resources
{
smInitialize();
i2cInitialize();
u16 data = 0;
if (Max17050ReadReg(Max17050Reg_Cycle, &data))
batCycleCount = data / 100.;
if (Max17050ReadReg(Max17050Reg_Current, &data))
batCurrent = (s16)data * (1.5625 / (max17050SenseResistor * max17050CGain));
i2cExit();
smExit();
}
char batWattsInfo[20] = "";
if (std::abs(batCurrent) > 100)
snprintf(batWattsInfo, sizeof(batWattsInfo), " (%+.2f W)", batCurrent * (float)chargeInfo->VoltageAvg / 1000'000);
snprintf(out, outsize,
"Charger: %s %.1fV/%.1fA (%.1fW)"
"\n%s"
"\nBattery: %.3fV %.2f\u00B0C"
"\nCurrent Limit: %u mA IN, %u mA OUT"
"\nCharging Limit: %u mA%s"
"\nRaw Charge: %.2f%%"
"\nBattery Age: %.2f%%"
"\nPower Role: %s"
"%s"
"\nCharger: %s %.1fV/%.1fA (%.1fW)"
"\nBattery: %.3fV %.2f\u00B0C"
"\nCurrent Limit: %u mA IN, %u mA OUT"
"\nCharging Limit: %u mA%s"
"\nRaw Charge: %.2f%%"
"\nBattery Age: %.2f%%"
"\nPower Role: %s"
"\nCycle Count: %.2f (Reset at power-up)"
"\nCurrent Flow: %+.2f mA%s"
,
ChargeInfoChargerTypeToStr(chargeInfo->ChargerType), chargerVoltLimit, chargerCurrLimit, chargerOutWatts,
PsmIsEnoughPowerSupplied() ? "Enough Power Supplied" : "",
ChargeInfoChargerTypeToStr(chargeInfo->ChargerType), chargerVoltLimit, chargerCurrLimit, chargerOutWatts,
(float)chargeInfo->VoltageAvg / 1000,
(float)chargeInfo->BatteryTemperature / 1000,
chargeInfo->InputCurrentLimit, chargeInfo->VBUSCurrentLimit,
chargeInfo->ChargeCurrentLimit, chargeVoltLimit,
(float)chargeInfo->RawBatteryCharge / 1000,
(float)chargeInfo->BatteryAge / 1000,
ChargeInfoPowerRoleToStr(chargeInfo->PowerRole)
ChargeInfoPowerRoleToStr(chargeInfo->PowerRole),
batCycleCount,
batCurrent, batWattsInfo
);
}
@@ -196,6 +281,6 @@ class MiscGui : public BaseMenuGui
ChargeInfo* chargeInfo;
bool isEnoughPowerSupplied = false;
char psmOutput[800] = "";
char infoOutput[800] = "";
int frameCounter = 60;
};