hoc-overlay: add fan control feature to sysmodule
This commit is contained in:
@@ -16,16 +16,16 @@
|
||||
#include "errors.h"
|
||||
#include "ipc_service.h"
|
||||
|
||||
ClockManager* ClockManager::instance = NULL;
|
||||
ClockManager *ClockManager::instance = NULL;
|
||||
|
||||
ClockManager* ClockManager::GetInstance()
|
||||
ClockManager *ClockManager::GetInstance()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
void ClockManager::Exit()
|
||||
{
|
||||
if(instance)
|
||||
if (instance)
|
||||
{
|
||||
delete instance;
|
||||
}
|
||||
@@ -33,7 +33,7 @@ void ClockManager::Exit()
|
||||
|
||||
void ClockManager::Initialize()
|
||||
{
|
||||
if(!instance)
|
||||
if (!instance)
|
||||
{
|
||||
instance = new ClockManager();
|
||||
}
|
||||
@@ -60,7 +60,6 @@ ClockManager::ClockManager()
|
||||
this->lastCsvWriteNs = 0;
|
||||
|
||||
this->rnxSync = new ReverseNXSync;
|
||||
|
||||
}
|
||||
|
||||
ClockManager::~ClockManager()
|
||||
@@ -119,13 +118,13 @@ std::uint32_t ClockManager::GetMaxAllowedHz(SysClkModule module, SysClkProfile p
|
||||
}
|
||||
else
|
||||
{
|
||||
if(module == SysClkModule_GPU)
|
||||
if (module == SysClkModule_GPU)
|
||||
{
|
||||
if(profile < SysClkProfile_HandheldCharging)
|
||||
if (profile < SysClkProfile_HandheldCharging)
|
||||
{
|
||||
return Board::GetSocType() == SysClkSocType_Mariko ? 614400000 : 460800000;
|
||||
}
|
||||
else if(profile <= SysClkProfile_HandheldChargingUSB)
|
||||
else if (profile <= SysClkProfile_HandheldChargingUSB)
|
||||
{
|
||||
return 768000000;
|
||||
}
|
||||
@@ -211,31 +210,46 @@ void ClockManager::Tick()
|
||||
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++)
|
||||
{
|
||||
targetHz = this->context->overrideFreqs[module];
|
||||
|
||||
if (!targetHz)
|
||||
{
|
||||
targetHz = this->config->GetAutoClockHz(this->context->applicationId, (SysClkModule)module, this->context->profile);
|
||||
}
|
||||
|
||||
if (targetHz)
|
||||
{
|
||||
maxHz = this->GetMaxAllowedHz((SysClkModule)module, this->context->profile);
|
||||
nearestHz = this->GetNearestHz((SysClkModule)module, targetHz, maxHz);
|
||||
|
||||
if (nearestHz != this->context->freqs[module] && this->context->enabled && !apmExtIsBoostMode(this->context->perfConfId) && this->config->GetConfigValue(HocClkConfigValue_OverwriteBoostMode))
|
||||
// if (!this->config->GetConfigValue(HocClkConfigValue_DockedGovernor) || !this->config->GetConfigValue(HocClkConfigValue_HandheldGovernor))
|
||||
// {
|
||||
if (!targetHz)
|
||||
{
|
||||
FileUtils::LogLine(
|
||||
"[mgr] %s clock set : %u.%u MHz (target = %u.%u MHz)",
|
||||
Board::GetModuleName((SysClkModule)module, true),
|
||||
nearestHz / 1000000, nearestHz / 100000 - nearestHz / 1000000 * 10,
|
||||
targetHz / 1000000, targetHz / 100000 - targetHz / 1000000 * 10);
|
||||
|
||||
Board::SetHz((SysClkModule)module, nearestHz);
|
||||
this->context->freqs[module] = nearestHz;
|
||||
} else {
|
||||
Board::ResetToStockCpu();
|
||||
Board::ResetToStockGpu();
|
||||
targetHz = this->config->GetAutoClockHz(this->context->applicationId, (SysClkModule)module, this->context->profile);
|
||||
}
|
||||
|
||||
if (targetHz)
|
||||
{
|
||||
maxHz = this->GetMaxAllowedHz((SysClkModule)module, this->context->profile);
|
||||
nearestHz = this->GetNearestHz((SysClkModule)module, targetHz, maxHz);
|
||||
|
||||
if (nearestHz != this->context->freqs[module] && this->context->enabled && !apmExtIsBoostMode(this->context->perfConfId) && this->config->GetConfigValue(HocClkConfigValue_OverwriteBoostMode))
|
||||
{
|
||||
FileUtils::LogLine(
|
||||
"[mgr] %s clock set : %u.%u MHz (target = %u.%u MHz)",
|
||||
Board::GetModuleName((SysClkModule)module, true),
|
||||
nearestHz / 1000000, nearestHz / 100000 - nearestHz / 1000000 * 10,
|
||||
targetHz / 1000000, targetHz / 100000 - targetHz / 1000000 * 10);
|
||||
|
||||
Board::SetHz((SysClkModule)module, nearestHz);
|
||||
this->context->freqs[module] = nearestHz;
|
||||
}
|
||||
else
|
||||
{
|
||||
Board::ResetToStockCpu();
|
||||
Board::ResetToStockGpu();
|
||||
}
|
||||
// }
|
||||
// } else {
|
||||
// #define GOVERNOR_LOAD_THRESHOLD 80
|
||||
// if(apmExtIsBoostMode(this->context->perfConfId)) {
|
||||
// Board::ResetToStockCpu(); // GOVERNOR: Reset to stock clocks if boost mode (dont use governor when boosted)
|
||||
// Board::ResetToStockGpu();
|
||||
// } else {
|
||||
// // Actually run the CPU governor
|
||||
// if(t210EmcLoadCpu() > GOVERNOR_LOAD_THRESHOLD) {
|
||||
// realHz = targetHz / 1000000
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -265,7 +279,6 @@ bool ClockManager::RefreshContext()
|
||||
this->context->applicationId = applicationId;
|
||||
hasChanged = true;
|
||||
this->rnxSync->Reset(applicationId);
|
||||
|
||||
}
|
||||
|
||||
SysClkProfile profile = Board::GetProfile();
|
||||
@@ -378,6 +391,7 @@ bool ClockManager::RefreshContext()
|
||||
return hasChanged;
|
||||
}
|
||||
|
||||
void ClockManager::SetRNXRTMode(ReverseNXMode mode) {
|
||||
void ClockManager::SetRNXRTMode(ReverseNXMode mode)
|
||||
{
|
||||
this->rnxSync->SetRTMode(mode);
|
||||
}
|
||||
@@ -39,6 +39,10 @@ class ClockManager
|
||||
void Tick();
|
||||
void WaitForNextTick();
|
||||
void SetRNXRTMode(ReverseNXMode mode);
|
||||
struct {
|
||||
std::uint32_t count;
|
||||
std::uint32_t list[SYSCLK_FREQ_LIST_MAX];
|
||||
} freqTable[SysClkModule_EnumMax];
|
||||
|
||||
protected:
|
||||
bool IsAssignableHz(SysClkModule module, std::uint32_t hz);
|
||||
@@ -52,10 +56,6 @@ class ClockManager
|
||||
|
||||
std::atomic_bool running;
|
||||
LockableMutex contextMutex;
|
||||
struct {
|
||||
std::uint32_t count;
|
||||
std::uint32_t list[SYSCLK_FREQ_LIST_MAX];
|
||||
} freqTable[SysClkModule_EnumMax];
|
||||
Config* config;
|
||||
SysClkContext* context;
|
||||
std::uint64_t lastTempLogNs;
|
||||
|
||||
250
Source/sys-clk/sysmodule/src/fancontrol.c
Normal file
250
Source/sys-clk/sysmodule/src/fancontrol.c
Normal file
@@ -0,0 +1,250 @@
|
||||
#include "fancontrol.h"
|
||||
#include "tmp451.h"
|
||||
|
||||
//Fan curve table
|
||||
const TemperaturePoint defaultTable[] =
|
||||
{
|
||||
{ .temperature_c = 25.0, .fanLevel_f = 0.10 },
|
||||
{ .temperature_c = 30.0, .fanLevel_f = 0.20 },
|
||||
{ .temperature_c = 35.0, .fanLevel_f = 0.30 },
|
||||
{ .temperature_c = 40.0, .fanLevel_f = 0.40 },
|
||||
{ .temperature_c = 45.0, .fanLevel_f = 0.50 },
|
||||
{ .temperature_c = 50.0, .fanLevel_f = 0.60 },
|
||||
{ .temperature_c = 55.0, .fanLevel_f = 0.70 },
|
||||
{ .temperature_c = 60.0, .fanLevel_f = 0.80 },
|
||||
{ .temperature_c = 65.0, .fanLevel_f = 0.90 },
|
||||
{ .temperature_c = 70.0, .fanLevel_f = 1.00 }
|
||||
};
|
||||
|
||||
|
||||
TemperaturePoint *fanControllerTable;
|
||||
|
||||
//Fan
|
||||
Thread FanControllerThread;
|
||||
bool fanControllerThreadExit = false;
|
||||
|
||||
//Log
|
||||
char logPath[PATH_MAX];
|
||||
|
||||
//Power management
|
||||
Event powerStateChangeEvent;
|
||||
bool isPowerStateInitialized = false;
|
||||
|
||||
void CreateDir(char *dir)
|
||||
{
|
||||
char dirPath[PATH_MAX];
|
||||
|
||||
for(int i = 0; i < PATH_MAX; i++)
|
||||
{
|
||||
if(*(dir + i) == '/' && access(dirPath, F_OK) == -1)
|
||||
{
|
||||
mkdir(dirPath, 0777);
|
||||
}
|
||||
dirPath[i] = *(dir + i);
|
||||
}
|
||||
}
|
||||
|
||||
void InitLog()
|
||||
{
|
||||
if(access(LOG_DIR, F_OK) == -1)
|
||||
CreateDir(LOG_DIR);
|
||||
|
||||
if(access(LOG_FILE, F_OK) != -1)
|
||||
remove(LOG_FILE);
|
||||
}
|
||||
|
||||
void WriteLog(char *buffer)
|
||||
{
|
||||
FILE *log = fopen(LOG_FILE, "a");
|
||||
if(log != NULL)
|
||||
{
|
||||
fprintf(log, "%s\n", buffer);
|
||||
}
|
||||
fclose(log);
|
||||
}
|
||||
|
||||
void WriteConfigFile(TemperaturePoint *table)
|
||||
{
|
||||
if(table == NULL)
|
||||
{
|
||||
table = malloc(sizeof(defaultTable));
|
||||
memcpy(table, defaultTable, sizeof(defaultTable));
|
||||
}
|
||||
|
||||
if(access(CONFIG_DIR, F_OK) == -1)
|
||||
CreateDir(CONFIG_DIR);
|
||||
|
||||
FILE *config = fopen(CONFIG_FILE, "w");
|
||||
fwrite(table, TABLE_SIZE, 1, config);
|
||||
fclose(config);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ReadConfigFile(TemperaturePoint **table_out)
|
||||
{
|
||||
InitLog();
|
||||
|
||||
*table_out = malloc(sizeof(defaultTable));
|
||||
memcpy(*table_out, defaultTable, sizeof(defaultTable));
|
||||
|
||||
if(access(CONFIG_DIR, F_OK) == -1)
|
||||
{
|
||||
CreateDir(CONFIG_DIR);
|
||||
WriteConfigFile(NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(access(CONFIG_FILE, F_OK) == -1)
|
||||
{
|
||||
WriteConfigFile(NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
FILE *config = fopen(CONFIG_FILE, "r");
|
||||
fread(*table_out, TABLE_SIZE, 1, config);
|
||||
fclose(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IsSystemAwake()
|
||||
{
|
||||
// Check if system is in sleep mode by checking applet state
|
||||
// appletGetOperationMode returns the current operation mode
|
||||
AppletOperationMode opMode = appletGetOperationMode();
|
||||
|
||||
// If in handheld or console mode, system is awake
|
||||
// If in any other mode (like sleep), we consider it asleep
|
||||
return (opMode == AppletOperationMode_Handheld || opMode == AppletOperationMode_Console);
|
||||
}
|
||||
|
||||
void InitFanController(TemperaturePoint *table)
|
||||
{
|
||||
fanControllerTable = table;
|
||||
|
||||
if(R_FAILED(threadCreate(&FanControllerThread, FanControllerThreadFunction, NULL, NULL, 0x4000, 0x3F, -2)))
|
||||
{
|
||||
WriteLog("Error creating FanControllerThread");
|
||||
diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen));
|
||||
}
|
||||
}
|
||||
|
||||
void FanControllerThreadFunction(void*)
|
||||
{
|
||||
FanController fc;
|
||||
float fanLevelSet_f = 0;
|
||||
float temperatureC_f = 0;
|
||||
u64 awakeSleepTime = 250000000ULL; // 0.25 second when awake (250ms - responsive)
|
||||
u64 sleepSleepTime = 5000000000ULL; // 5 seconds when in sleep
|
||||
int sleepCheckCounter = 0;
|
||||
|
||||
Result rs = fanOpenController(&fc, 0x3D000001);
|
||||
if(R_FAILED(rs))
|
||||
{
|
||||
WriteLog("Error opening fanController");
|
||||
diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen));
|
||||
}
|
||||
|
||||
while(!fanControllerThreadExit)
|
||||
{
|
||||
// Check if system is awake every 20 iterations (~5 seconds) to reduce overhead
|
||||
sleepCheckCounter++;
|
||||
if(sleepCheckCounter >= 20)
|
||||
{
|
||||
bool isAwake = IsSystemAwake();
|
||||
sleepCheckCounter = 0;
|
||||
|
||||
// If system is asleep, use longer sleep interval
|
||||
if(!isAwake)
|
||||
{
|
||||
svcSleepThread(sleepSleepTime);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
rs = Tmp451GetSocTemp(&temperatureC_f);
|
||||
if(R_FAILED(rs))
|
||||
{
|
||||
WriteLog("tsSessionGetTemperature error");
|
||||
diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen));
|
||||
}
|
||||
|
||||
if(temperatureC_f >= 0 && temperatureC_f <= fanControllerTable->temperature_c)
|
||||
{
|
||||
float m = 0;
|
||||
float q = 0;
|
||||
|
||||
m = fanControllerTable->fanLevel_f / fanControllerTable->temperature_c;
|
||||
q = 0 - m;
|
||||
|
||||
fanLevelSet_f = (m * temperatureC_f) + q;
|
||||
|
||||
}else if(temperatureC_f >= (fanControllerTable + 9)->temperature_c)
|
||||
{
|
||||
fanLevelSet_f = (fanControllerTable + 9)->fanLevel_f;
|
||||
}else
|
||||
{
|
||||
for(int i = 0; i < (TABLE_SIZE/sizeof(TemperaturePoint)) - 1; i++)
|
||||
{
|
||||
if(temperatureC_f >= (fanControllerTable + i)->temperature_c && temperatureC_f <= (fanControllerTable + i + 1)->temperature_c)
|
||||
{
|
||||
float m = 0;
|
||||
float q = 0;
|
||||
|
||||
m = ((fanControllerTable + i + 1)->fanLevel_f - (fanControllerTable + i)->fanLevel_f ) / ((fanControllerTable + i + 1)->temperature_c - (fanControllerTable + i)->temperature_c);
|
||||
q = (fanControllerTable + i)->fanLevel_f - (m * (fanControllerTable + i)->temperature_c);
|
||||
|
||||
fanLevelSet_f = (m * temperatureC_f) + q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Always update fan speed for immediate response
|
||||
rs = fanControllerSetRotationSpeedLevel(&fc, fanLevelSet_f);
|
||||
if(R_FAILED(rs))
|
||||
{
|
||||
WriteLog("fanControllerSetRotationSpeedLevel error");
|
||||
diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen));
|
||||
}
|
||||
|
||||
// Use responsive sleep time when awake (250ms)
|
||||
svcSleepThread(awakeSleepTime);
|
||||
}
|
||||
|
||||
fanControllerClose(&fc);
|
||||
}
|
||||
|
||||
void StartFanControllerThread()
|
||||
{
|
||||
if(R_FAILED(threadStart(&FanControllerThread)))
|
||||
{
|
||||
WriteLog("Error starting FanControllerThread");
|
||||
diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen));
|
||||
}
|
||||
}
|
||||
|
||||
void CloseFanControllerThread()
|
||||
{
|
||||
Result rs;
|
||||
fanControllerThreadExit = true;
|
||||
rs = threadWaitForExit(&FanControllerThread);
|
||||
if(R_FAILED(rs))
|
||||
{
|
||||
WriteLog("Error waiting fanControllerThread");
|
||||
diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen));
|
||||
}
|
||||
threadClose(&FanControllerThread);
|
||||
fanControllerThreadExit = false;
|
||||
free(fanControllerTable);
|
||||
}
|
||||
|
||||
void WaitFanController()
|
||||
{
|
||||
if(R_FAILED(threadWaitForExit(&FanControllerThread)))
|
||||
{
|
||||
WriteLog("Error waiting fanControllerThread");
|
||||
diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen));
|
||||
}
|
||||
}
|
||||
41
Source/sys-clk/sysmodule/src/fancontrol.h
Normal file
41
Source/sys-clk/sysmodule/src/fancontrol.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syslimits.h>
|
||||
#include <switch.h>
|
||||
|
||||
#define LOG_DIR "./config/hoc-clk/"
|
||||
#define LOG_FILE "./config/hoc-clk/fan_log.txt"
|
||||
#define CONFIG_DIR "./config/hoc-clk/"
|
||||
#define CONFIG_FILE "./config/hoc-clk/config.dat"
|
||||
#define TABLE_SIZE sizeof(TemperaturePoint) * 10
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int temperature_c;
|
||||
float fanLevel_f;
|
||||
} TemperaturePoint;
|
||||
|
||||
void WriteConfigFile(TemperaturePoint *table);
|
||||
void ReadConfigFile(TemperaturePoint **table_out);
|
||||
|
||||
void InitFanController(TemperaturePoint *table);
|
||||
void FanControllerThreadFunction(void*);
|
||||
void StartFanControllerThread();
|
||||
void CloseFanControllerThread();
|
||||
void WaitFanController();
|
||||
void WriteLog(char *buffer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
82
Source/sys-clk/sysmodule/src/i2c.h
Normal file
82
Source/sys-clk/sysmodule/src/i2c.h
Normal file
@@ -0,0 +1,82 @@
|
||||
#ifndef I2C_H
|
||||
#define I2C_H
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
Result I2cReadRegHandler16(u8 reg, I2cDevice dev, u16 *out)
|
||||
{
|
||||
struct readReg {
|
||||
u8 send;
|
||||
u8 sendLength;
|
||||
u8 sendData;
|
||||
u8 receive;
|
||||
u8 receiveLength;
|
||||
};
|
||||
|
||||
I2cSession _session;
|
||||
|
||||
Result res = i2cOpenSession(&_session, dev);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
u16 val;
|
||||
|
||||
struct readReg readRegister = {
|
||||
.send = 0 | (I2cTransactionOption_Start << 6),
|
||||
.sendLength = sizeof(reg),
|
||||
.sendData = reg,
|
||||
.receive = 1 | (I2cTransactionOption_All << 6),
|
||||
.receiveLength = sizeof(val),
|
||||
};
|
||||
|
||||
res = i2csessionExecuteCommandList(&_session, &val, sizeof(val), &readRegister, sizeof(readRegister));
|
||||
if (res)
|
||||
{
|
||||
i2csessionClose(&_session);
|
||||
return res;
|
||||
}
|
||||
|
||||
*out = val;
|
||||
i2csessionClose(&_session);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result I2cReadRegHandler8(u8 reg, I2cDevice dev, u8 *out)
|
||||
{
|
||||
struct readReg {
|
||||
u8 send;
|
||||
u8 sendLength;
|
||||
u8 sendData;
|
||||
u8 receive;
|
||||
u8 receiveLength;
|
||||
};
|
||||
|
||||
I2cSession _session;
|
||||
|
||||
Result res = i2cOpenSession(&_session, dev);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
u8 val;
|
||||
|
||||
struct readReg readRegister = {
|
||||
.send = 0 | (I2cTransactionOption_Start << 6),
|
||||
.sendLength = sizeof(reg),
|
||||
.sendData = reg,
|
||||
.receive = 1 | (I2cTransactionOption_All << 6),
|
||||
.receiveLength = sizeof(val),
|
||||
};
|
||||
|
||||
res = i2csessionExecuteCommandList(&_session, &val, sizeof(val), &readRegister, sizeof(readRegister));
|
||||
if (res)
|
||||
{
|
||||
i2csessionClose(&_session);
|
||||
return res;
|
||||
}
|
||||
|
||||
*out = val;
|
||||
i2csessionClose(&_session);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "errors.h"
|
||||
#include "file_utils.h"
|
||||
|
||||
#include "clock_manager.h"
|
||||
|
||||
class ReverseNXSync {
|
||||
public:
|
||||
ReverseNXSync ();
|
||||
@@ -30,4 +32,4 @@ protected:
|
||||
|
||||
ReverseNXMode GetToolModeFromPatch(const char* patch_path);
|
||||
ReverseNXMode RecheckToolMode();
|
||||
};
|
||||
};
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "process_management.h"
|
||||
#include "clock_manager.h"
|
||||
#include "ipc_service.h"
|
||||
|
||||
#include "fancontrol.h"
|
||||
#define INNER_HEAP_SIZE 0x30000
|
||||
|
||||
extern "C"
|
||||
@@ -63,12 +63,24 @@ extern "C"
|
||||
hosversionSet(MAKEHOSVERSION(fw.major, fw.minor, fw.micro));
|
||||
setsysExit();
|
||||
}
|
||||
|
||||
rc = fanInitialize();
|
||||
if (R_FAILED(rc))
|
||||
diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen));
|
||||
|
||||
rc = i2cInitialize();
|
||||
if (R_FAILED(rc))
|
||||
diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen));
|
||||
}
|
||||
|
||||
void __appExit(void)
|
||||
{
|
||||
smExit();
|
||||
}
|
||||
CloseFanControllerThread();
|
||||
fanExit();
|
||||
i2cExit();
|
||||
fsExit();
|
||||
fsdevUnmountAll();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
@@ -95,6 +107,10 @@ int main(int argc, char** argv)
|
||||
clockMgr->SetRunning(true);
|
||||
clockMgr->GetConfig()->SetEnabled(true);
|
||||
ipcSrv->SetRunning(true);
|
||||
TemperaturePoint *table;
|
||||
ReadConfigFile(&table);
|
||||
InitFanController(table);
|
||||
StartFanControllerThread();
|
||||
|
||||
while (clockMgr->Running())
|
||||
{
|
||||
@@ -121,5 +137,6 @@ int main(int argc, char** argv)
|
||||
FileUtils::LogLine("Exit");
|
||||
svcSleepThread(1000000ULL);
|
||||
FileUtils::Exit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
98
Source/sys-clk/sysmodule/src/tmp451.h
Normal file
98
Source/sys-clk/sysmodule/src/tmp451.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* SOC/PCB Temperature driver for Nintendo Switch's TI TMP451
|
||||
*
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by: MasaGratoR
|
||||
*/
|
||||
|
||||
//#include <utils/types.h>
|
||||
#include "i2c.h"
|
||||
|
||||
//#define TMP451_I2C_ADDR 0x4C
|
||||
|
||||
#define TMP451_PCB_TEMP_REG 0x00
|
||||
#define TMP451_SOC_TEMP_REG 0x01
|
||||
|
||||
/*
|
||||
#define TMP451_CONFIG_REG 0x09
|
||||
#define TMP451_CNV_RATE_REG 0x0A
|
||||
*/
|
||||
|
||||
#define TMP451_SOC_TEMP_DEC_REG 0x10
|
||||
#define TMP451_PCB_TEMP_DEC_REG 0x15
|
||||
|
||||
/*
|
||||
#define TMP451_SOC_TMP_OFH_REG 0x11
|
||||
#define TMP451_SOC_TMP_OFL_REG 0x12
|
||||
*/
|
||||
|
||||
// If input is false, the return value is packed. MSByte is the integer in oC
|
||||
// and the LSByte is the decimal point truncated to 2 decimal places.
|
||||
// Otherwise it's an integer oC.
|
||||
/*
|
||||
u16 tmp451_get_soc_temp(bool integer);
|
||||
u16 tmp451_get_pcb_temp(bool integer);
|
||||
void tmp451_init();
|
||||
void tmp451_end();
|
||||
*/
|
||||
|
||||
Result Tmp451ReadReg(u8 reg, u8 *out)
|
||||
{
|
||||
u8 data = 0;
|
||||
Result res = I2cReadRegHandler8(reg, I2cDevice_Tmp451, &data);
|
||||
|
||||
if (R_FAILED(res))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
*out = data;
|
||||
return res;
|
||||
}
|
||||
|
||||
Result Tmp451GetSocTemp(float* temperature) {
|
||||
u8 integer = 0;
|
||||
u8 decimals = 0;
|
||||
|
||||
Result rc = Tmp451ReadReg(TMP451_SOC_TEMP_REG, &integer);
|
||||
if (R_FAILED(rc))
|
||||
return rc;
|
||||
rc = Tmp451ReadReg(TMP451_SOC_TEMP_DEC_REG, &decimals);
|
||||
if (R_FAILED(rc))
|
||||
return rc;
|
||||
|
||||
decimals = ((u16)(decimals >> 4) * 625) / 100;
|
||||
*temperature = (float)(integer) + ((float)(decimals) / 100);
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result Tmp451GetPcbTemp(float* temperature) {
|
||||
u8 integer = 0;
|
||||
u8 decimals = 0;
|
||||
|
||||
Result rc = Tmp451ReadReg(TMP451_PCB_TEMP_REG, &integer);
|
||||
if (R_FAILED(rc))
|
||||
return rc;
|
||||
rc = Tmp451ReadReg(TMP451_PCB_TEMP_DEC_REG, &decimals);
|
||||
if (R_FAILED(rc))
|
||||
return rc;
|
||||
|
||||
decimals = ((u16)(decimals >> 4) * 625) / 100;
|
||||
*temperature = (float)(integer) + ((float)(decimals) / 100);
|
||||
return rc;
|
||||
}
|
||||
Reference in New Issue
Block a user