sysclk: move governor to thread and remove nx fancontrol
This commit is contained in:
@@ -39,7 +39,7 @@
|
|||||||
#define HOSPPC_HAS_BOOST (hosversionAtLeast(7,0,0))
|
#define HOSPPC_HAS_BOOST (hosversionAtLeast(7,0,0))
|
||||||
|
|
||||||
ClockManager *ClockManager::instance = NULL;
|
ClockManager *ClockManager::instance = NULL;
|
||||||
|
Thread governorTHREAD;
|
||||||
|
|
||||||
ClockManager *ClockManager::GetInstance()
|
ClockManager *ClockManager::GetInstance()
|
||||||
{
|
{
|
||||||
@@ -84,13 +84,26 @@ ClockManager::ClockManager()
|
|||||||
this->rnxSync = new ReverseNXSync;
|
this->rnxSync = new ReverseNXSync;
|
||||||
|
|
||||||
if(this->config->GetConfigValue(HocClkConfigValue_KipEditing))
|
if(this->config->GetConfigValue(HocClkConfigValue_KipEditing))
|
||||||
this->GetKipData();
|
this->GetKipData();
|
||||||
|
threadCreate(
|
||||||
|
&governorTHREAD,
|
||||||
|
ClockManager::GovernorThread,
|
||||||
|
this,
|
||||||
|
NULL,
|
||||||
|
0x2000,
|
||||||
|
0x3F,
|
||||||
|
-2
|
||||||
|
);
|
||||||
|
|
||||||
|
threadStart(&governorTHREAD);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClockManager::~ClockManager()
|
ClockManager::~ClockManager()
|
||||||
{
|
{
|
||||||
delete this->config;
|
delete this->config;
|
||||||
delete this->context;
|
delete this->context;
|
||||||
|
threadClose(&governorTHREAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
SysClkContext ClockManager::GetCurrentContext()
|
SysClkContext ClockManager::GetCurrentContext()
|
||||||
@@ -249,6 +262,105 @@ u32 findIndexMHz(u32 arr[], u32 size, u32 value) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClockManager::GovernorThread(void* arg)
|
||||||
|
{
|
||||||
|
ClockManager* mgr = static_cast<ClockManager*>(arg);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (!mgr->running)
|
||||||
|
{
|
||||||
|
svcSleepThread(50'000'000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::scoped_lock lock{mgr->contextMutex};
|
||||||
|
|
||||||
|
if (!mgr->config->GetConfigValue(HocClkConfigValue_HandheldGovernor))
|
||||||
|
{
|
||||||
|
svcSleepThread(50'000'000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& table = mgr->freqTable[SysClkModule_GPU];
|
||||||
|
if (table.count == 0)
|
||||||
|
{
|
||||||
|
svcSleepThread(50'000'000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 currentHz = Board::GetHz(SysClkModule_GPU);
|
||||||
|
|
||||||
|
u32 index = 0;
|
||||||
|
for (u32 i = 0; i < table.count; i++)
|
||||||
|
{
|
||||||
|
if (table.list[i] == currentHz)
|
||||||
|
{
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 targetHz = mgr->context->overrideFreqs[SysClkModule_GPU];
|
||||||
|
if (!targetHz)
|
||||||
|
{
|
||||||
|
targetHz = mgr->config->GetAutoClockHz(
|
||||||
|
mgr->context->applicationId,
|
||||||
|
SysClkModule_GPU,
|
||||||
|
mgr->context->profile
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!targetHz)
|
||||||
|
{
|
||||||
|
targetHz = mgr->config->GetAutoClockHz(
|
||||||
|
GLOBAL_PROFILE_ID,
|
||||||
|
SysClkModule_GPU,
|
||||||
|
mgr->context->profile
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int load = Board::GetPartLoad(HocClkPartLoad_GPU);
|
||||||
|
|
||||||
|
if (load < 600 && index > 0)
|
||||||
|
{
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
else if (load > 800 && index + 1 < table.count)
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetHz)
|
||||||
|
{
|
||||||
|
u32 targetIndex = index;
|
||||||
|
for (u32 i = 0; i < table.count; i++)
|
||||||
|
{
|
||||||
|
if (table.list[i] >= targetHz)
|
||||||
|
{
|
||||||
|
targetIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index > targetIndex && index > 0)
|
||||||
|
index--;
|
||||||
|
else if (index < targetIndex && index + 1 < table.count)
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 newHz = table.list[index];
|
||||||
|
if (mgr->IsAssignableHz(SysClkModule_GPU, newHz))
|
||||||
|
{
|
||||||
|
Board::SetHz(SysClkModule_GPU, newHz);
|
||||||
|
mgr->context->freqs[SysClkModule_GPU] = newHz;
|
||||||
|
}
|
||||||
|
|
||||||
|
svcSleepThread(50'000'000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ClockManager::Tick()
|
void ClockManager::Tick()
|
||||||
{
|
{
|
||||||
std::scoped_lock lock{this->contextMutex};
|
std::scoped_lock lock{this->contextMutex};
|
||||||
@@ -281,50 +393,6 @@ void ClockManager::Tick()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 currentFreqIndex = findIndex(freqTable[SysClkModule_GPU].list, SYSCLK_FREQ_LIST_MAX, Board::GetHz(SysClkModule_GPU));
|
|
||||||
if(this->config->GetConfigValue(HocClkConfigValue_HandheldGovernor)) {
|
|
||||||
u64 targetHz = this->context->overrideFreqs[SysClkModule_GPU];
|
|
||||||
if (!targetHz)
|
|
||||||
{
|
|
||||||
targetHz = this->config->GetAutoClockHz(this->context->applicationId, SysClkModule_GPU, this->context->profile);
|
|
||||||
if(!targetHz)
|
|
||||||
targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, SysClkModule_GPU, this->context->profile);
|
|
||||||
}
|
|
||||||
if(Board::GetPartLoad(HocClkPartLoad_GPU) < 600) {
|
|
||||||
currentFreqIndex--;
|
|
||||||
if(currentFreqIndex < 0) {
|
|
||||||
currentFreqIndex = 0;
|
|
||||||
}
|
|
||||||
Board::SetHz(SysClkModule_GPU, freqTable[SysClkModule_GPU].list[currentFreqIndex]);
|
|
||||||
}
|
|
||||||
if(Board::GetPartLoad(HocClkPartLoad_GPU) > 800) {
|
|
||||||
currentFreqIndex++;
|
|
||||||
|
|
||||||
if(!targetHz) {
|
|
||||||
if(IsAssignableHz(SysClkModule_GPU, freqTable[SysClkModule_GPU].list[currentFreqIndex])) {
|
|
||||||
if(Board::GetSocType() == SysClkSocType_Mariko) {
|
|
||||||
if(freqTable[SysClkModule_GPU].list[currentFreqIndex] / 1000000 < this->config->GetConfigValue(HocClkConfigValue_MarikoMaxGpuClock))
|
|
||||||
currentFreqIndex++; // TODO: make this properly go back to target freq if the old target freq is more than one index away
|
|
||||||
else // probably needs the max clocks to be stored in hz instead of mhz to compare easily
|
|
||||||
currentFreqIndex--;
|
|
||||||
} else {
|
|
||||||
if(freqTable[SysClkModule_GPU].list[currentFreqIndex] / 1000000 < this->config->GetConfigValue(HocClkConfigValue_EristaMaxGpuClock))
|
|
||||||
currentFreqIndex++;
|
|
||||||
else
|
|
||||||
currentFreqIndex--;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
currentFreqIndex--;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(currentFreqIndex > findIndex(freqTable[SysClkModule_GPU].list, SYSCLK_FREQ_LIST_MAX, targetHz))
|
|
||||||
currentFreqIndex--;
|
|
||||||
}
|
|
||||||
Board::SetHz(SysClkModule_GPU, freqTable[SysClkModule_GPU].list[currentFreqIndex]);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool noGPU = false;
|
bool noGPU = false;
|
||||||
|
|
||||||
if (this->RefreshContext() || this->config->Refresh())
|
if (this->RefreshContext() || this->config->Refresh())
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include "board.h"
|
#include "board.h"
|
||||||
#include <nxExt/cpp/lockable_mutex.h>
|
#include <nxExt/cpp/lockable_mutex.h>
|
||||||
#include "integrations.h"
|
#include "integrations.h"
|
||||||
|
void governorThread(void*);
|
||||||
|
|
||||||
class ReverseNXSync;
|
class ReverseNXSync;
|
||||||
|
|
||||||
@@ -60,6 +61,7 @@ class ClockManager
|
|||||||
void SetRNXRTMode(ReverseNXMode mode);
|
void SetRNXRTMode(ReverseNXMode mode);
|
||||||
void SetKipData();
|
void SetKipData();
|
||||||
void GetKipData();
|
void GetKipData();
|
||||||
|
static void GovernorThread(void* arg);
|
||||||
struct {
|
struct {
|
||||||
std::uint32_t count;
|
std::uint32_t count;
|
||||||
std::uint32_t list[SYSCLK_FREQ_LIST_MAX];
|
std::uint32_t list[SYSCLK_FREQ_LIST_MAX];
|
||||||
|
|||||||
@@ -1,250 +0,0 @@
|
|||||||
#include "fancontrol.h"
|
|
||||||
#include "tmp451.h"
|
|
||||||
|
|
||||||
//Fan curve table
|
|
||||||
TemperaturePoint defaultTable[] =
|
|
||||||
{
|
|
||||||
{ .temperature_c = 25.0, .fanLevel_f = 0.00 },
|
|
||||||
{ .temperature_c = 30.0, .fanLevel_f = 0.00 },
|
|
||||||
{ .temperature_c = 35.0, .fanLevel_f = 0.00 },
|
|
||||||
{ .temperature_c = 40.0, .fanLevel_f = 0.00 },
|
|
||||||
{ .temperature_c = 45.0, .fanLevel_f = 0.30 },
|
|
||||||
{ .temperature_c = 50.0, .fanLevel_f = 0.50 },
|
|
||||||
{ .temperature_c = 55.0, .fanLevel_f = 0.60 },
|
|
||||||
{ .temperature_c = 60.0, .fanLevel_f = 0.85 },
|
|
||||||
{ .temperature_c = 65.0, .fanLevel_f = 0.95 },
|
|
||||||
{ .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 = 1000000000ULL; // 1 second when awake
|
|
||||||
u64 sleepSleepTime = 10000000000ULL; // 10 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 40 iterations (~10 seconds) to reduce overhead
|
|
||||||
sleepCheckCounter++;
|
|
||||||
if(sleepCheckCounter >= 40)
|
|
||||||
{
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
#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/horizon-oc/"
|
|
||||||
#define LOG_FILE "./config/horizon-oc/fan_log.txt"
|
|
||||||
#define CONFIG_DIR "./config/horizon-oc/"
|
|
||||||
#define CONFIG_FILE "./config/horizon-oc/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
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -37,7 +37,6 @@
|
|||||||
#include "process_management.h"
|
#include "process_management.h"
|
||||||
#include "clock_manager.h"
|
#include "clock_manager.h"
|
||||||
#include "ipc_service.h"
|
#include "ipc_service.h"
|
||||||
#include "fancontrol.h"
|
|
||||||
#define INNER_HEAP_SIZE 0x30000
|
#define INNER_HEAP_SIZE 0x30000
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
|
|||||||
@@ -1,98 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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