- [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:
11
Source/InfoNX/.gitignore
vendored
11
Source/InfoNX/.gitignore
vendored
@@ -1,11 +0,0 @@
|
||||
|
||||
build/
|
||||
|
||||
*.ovl
|
||||
|
||||
*.elf
|
||||
|
||||
*.nacp
|
||||
|
||||
*.nro
|
||||
*.DS_Store
|
||||
@@ -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
|
||||
#---------------------------------------------------------------------------------------
|
||||
Submodule Source/InfoNX/libs/libtesla deleted from 640629f49f
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
@@ -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:
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user