2022-06-11 01:02:05 +01:00
|
|
|
import {
|
2022-09-01 01:18:15 +01:00
|
|
|
ButtonItem,
|
2022-06-11 01:02:05 +01:00
|
|
|
definePlugin,
|
2022-09-01 01:18:15 +01:00
|
|
|
//DialogButton,
|
2022-06-11 01:02:05 +01:00
|
|
|
//Menu,
|
|
|
|
//MenuItem,
|
|
|
|
PanelSection,
|
|
|
|
PanelSectionRow,
|
|
|
|
//Router,
|
|
|
|
ServerAPI,
|
|
|
|
//showContextMenu,
|
|
|
|
staticClasses,
|
2022-07-04 22:12:13 +01:00
|
|
|
SliderField,
|
|
|
|
ToggleField,
|
2022-06-11 01:02:05 +01:00
|
|
|
//NotchLabel
|
|
|
|
gamepadDialogClasses,
|
|
|
|
joinClassNames,
|
|
|
|
} from "decky-frontend-lib";
|
|
|
|
import { VFC, useState } from "react";
|
2022-06-11 01:34:19 +01:00
|
|
|
import { GiDrill } from "react-icons/gi";
|
2022-06-11 01:02:05 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
//import * as python from "./python";
|
|
|
|
import * as backend from "./backend";
|
|
|
|
import {set_value, get_value, target_usdpl, version_usdpl} from "usdpl-front";
|
2022-06-11 01:02:05 +01:00
|
|
|
|
|
|
|
var periodicHook: NodeJS.Timer | null = null;
|
|
|
|
var lifetimeHook: any = null;
|
|
|
|
var startHook: any = null;
|
2022-09-01 01:18:15 +01:00
|
|
|
var usdplReady = false;
|
2022-06-11 01:02:05 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
var smtAllowed = true;
|
|
|
|
var smtGlobal = smtAllowed;
|
2022-07-10 19:04:50 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
// usdpl persistent store keys
|
2022-07-10 19:04:50 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
const BACKEND_INFO = "VINFO";
|
2022-07-10 19:04:50 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
const CURRENT_BATT = "BATTERY_current_now";
|
|
|
|
const CHARGE_RATE_BATT = "BATTERY_charge_rate";
|
2022-09-05 22:02:02 +01:00
|
|
|
const CHARGE_NOW_BATT = "BATTERY_charge_now";
|
|
|
|
const CHARGE_FULL_BATT = "BATTERY_charge_full";
|
|
|
|
const CHARGE_DESIGN_BATT = "BATTERY_charge_design"
|
2022-07-10 19:04:50 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
const TOTAL_CPUS = "CPUs_total";
|
|
|
|
const ONLINE_CPUS = "CPUs_online";
|
|
|
|
const CLOCK_MIN_CPU = "CPUs_min_clock";
|
|
|
|
const CLOCK_MAX_CPU = "CPUs_max_clock";
|
|
|
|
const GOVERNOR_CPU = "CPUs_governor";
|
2022-06-11 01:02:05 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
const FAST_PPT_GPU = "GPU_fastPPT";
|
|
|
|
const SLOW_PPT_GPU = "GPU_slowPPT";
|
|
|
|
const CLOCK_MIN_GPU = "GPU_min_clock";
|
|
|
|
const CLOCK_MAX_GPU = "GPU_max_clock";
|
|
|
|
const SLOW_MEMORY_GPU = "GPU_slow_memory";
|
2022-06-11 01:02:05 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
const PERSISTENT_GEN = "GENERAL_persistent";
|
|
|
|
const NAME_GEN = "GENERAL_name";
|
2022-06-11 01:02:05 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
const reload = function() {
|
|
|
|
if (!usdplReady) {return;}
|
2022-07-10 19:04:50 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
backend.resolve(backend.getBatteryCurrent(), (rate: number) => { set_value(CURRENT_BATT, rate) });
|
|
|
|
backend.resolve(backend.getBatteryChargeRate(), (rate: number) => { set_value(CHARGE_RATE_BATT, rate) });
|
2022-09-05 22:02:02 +01:00
|
|
|
backend.resolve(backend.getBatteryChargeNow(), (rate: number) => { set_value(CHARGE_NOW_BATT, rate) });
|
|
|
|
backend.resolve(backend.getBatteryChargeFull(), (rate: number) => { set_value(CHARGE_FULL_BATT, rate) });
|
|
|
|
backend.resolve(backend.getBatteryChargeDesign(), (rate: number) => { set_value(CHARGE_DESIGN_BATT, rate) });
|
2022-06-11 01:02:05 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
backend.resolve(backend.getCpuCount(), (count: number) => { set_value(TOTAL_CPUS, count)});
|
|
|
|
backend.resolve(backend.getCpusOnline(), (statii: boolean[]) => {
|
|
|
|
// TODO: allow for per-core control of online status
|
|
|
|
let count = 0;
|
|
|
|
for (let i = 0; i < statii.length; i++) {
|
|
|
|
if (statii[i]) {
|
|
|
|
count += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
set_value(ONLINE_CPUS, count);
|
|
|
|
smtGlobal = statii.length > 3 && statii[0] == statii[1] && statii[2] == statii[3] && smtAllowed;
|
|
|
|
});
|
|
|
|
// TODO: allow for per-core control of clock limits
|
|
|
|
backend.resolve(backend.getCpuClockLimits(0), (limits: number[]) => {
|
|
|
|
set_value(CLOCK_MIN_CPU, limits[0]);
|
|
|
|
set_value(CLOCK_MAX_CPU, limits[1]);
|
|
|
|
});
|
|
|
|
// TODO: allow for control of governor
|
|
|
|
backend.resolve(backend.getCpusGovernor(), (governors: string[]) => { set_value(GOVERNOR_CPU, governors[0]) });
|
2022-06-11 01:02:05 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
backend.resolve(backend.getGpuPpt(), (ppts: number[]) => {
|
|
|
|
set_value(FAST_PPT_GPU, ppts[0]);
|
|
|
|
set_value(SLOW_PPT_GPU, ppts[1]);
|
|
|
|
});
|
|
|
|
backend.resolve(backend.getGpuClockLimits(), (limits: number[]) => {
|
|
|
|
set_value(CLOCK_MIN_GPU, limits[0]);
|
|
|
|
set_value(CLOCK_MAX_GPU, limits[1]);
|
|
|
|
});
|
|
|
|
backend.resolve(backend.getGpuSlowMemory(), (status: boolean) => { set_value(SLOW_MEMORY_GPU, status) });
|
2022-06-11 01:02:05 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
backend.resolve(backend.getGeneralPersistent(), (value: boolean) => { set_value(PERSISTENT_GEN, value) });
|
|
|
|
backend.resolve(backend.getGeneralSettingsName(), (name: string) => { set_value(NAME_GEN, name) });
|
2022-06-11 01:02:05 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
backend.resolve(backend.getInfo(), (info: string) => { set_value(BACKEND_INFO, info) });
|
|
|
|
};
|
2022-06-11 01:02:05 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
// init USDPL WASM and connection to back-end
|
|
|
|
(async function(){
|
|
|
|
await backend.initBackend();
|
|
|
|
usdplReady = true;
|
|
|
|
set_value(NAME_GEN, "Default");
|
|
|
|
reload(); // technically this is only a load
|
2022-07-05 23:14:50 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
// register Steam callbacks
|
|
|
|
//@ts-ignore
|
|
|
|
lifetimeHook = SteamClient.GameSessions.RegisterForAppLifetimeNotifications((update) => {
|
|
|
|
if (update.bRunning) {
|
|
|
|
//console.debug("AppID " + update.unAppID.toString() + " is now running");
|
|
|
|
} else {
|
|
|
|
//console.debug("AppID " + update.unAppID.toString() + " is no longer running");
|
|
|
|
backend.resolve(
|
|
|
|
backend.loadGeneralDefaultSettings(),
|
|
|
|
(ok: boolean) => {console.debug("Loading default settings ok? " + ok)}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
//@ts-ignore
|
|
|
|
startHook = SteamClient.Apps.RegisterForGameActionStart((actionType, id) => {
|
|
|
|
//@ts-ignore
|
|
|
|
let gameInfo: any = appStore.GetAppOverviewByGameID(id);
|
|
|
|
backend.resolve(
|
|
|
|
backend.loadGeneralSettings(gameInfo.appid.toString() + ".json", gameInfo.display_name),
|
|
|
|
(ok: boolean) => {console.debug("Loading settings ok? " + ok)}
|
|
|
|
);
|
|
|
|
});
|
2022-06-11 01:02:05 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
console.debug("Registered PowerTools callbacks, hello!");
|
|
|
|
})();
|
2022-06-11 01:02:05 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
const periodicals = function() {
|
|
|
|
backend.resolve(backend.getBatteryCurrent(), (rate: number) => { set_value(CURRENT_BATT, rate) });
|
2022-09-05 22:02:02 +01:00
|
|
|
backend.resolve(backend.getBatteryChargeNow(), (rate: number) => { set_value(CHARGE_NOW_BATT, rate) });
|
|
|
|
backend.resolve(backend.getBatteryChargeFull(), (rate: number) => { set_value(CHARGE_FULL_BATT, rate) });
|
2022-06-11 01:02:05 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
backend.resolve(backend.getGeneralPersistent(), (value: boolean) => { set_value(PERSISTENT_GEN, value) });
|
|
|
|
backend.resolve(backend.getGeneralSettingsName(), (name: string) => {
|
|
|
|
const oldValue = get_value(NAME_GEN);
|
|
|
|
set_value(NAME_GEN, name);
|
|
|
|
if (name != oldValue) {
|
|
|
|
reload();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
2022-06-11 01:02:05 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
|
2022-06-11 01:02:05 +01:00
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
const [_idc, reloadGUI] = useState<any>("/shrug");
|
2022-06-11 01:02:05 +01:00
|
|
|
|
2022-07-10 19:04:50 +01:00
|
|
|
if (periodicHook != null) {
|
|
|
|
clearInterval(periodicHook);
|
|
|
|
periodicHook = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
periodicHook = setInterval(function() {
|
2022-09-01 01:18:15 +01:00
|
|
|
periodicals();
|
|
|
|
reloadGUI("periodic" + (new Date()).getTime().toString());
|
2022-07-10 19:04:50 +01:00
|
|
|
}, 1000);
|
|
|
|
|
2022-06-11 01:02:05 +01:00
|
|
|
const FieldWithSeparator = joinClassNames(gamepadDialogClasses.Field, gamepadDialogClasses.WithBottomSeparatorStandard);
|
|
|
|
|
2022-09-01 01:18:15 +01:00
|
|
|
const total_cpus = get_value(TOTAL_CPUS);
|
|
|
|
|
2022-06-11 01:02:05 +01:00
|
|
|
return (
|
|
|
|
<PanelSection>
|
2022-09-01 01:18:15 +01:00
|
|
|
{/* CPU */ /* TODO: set per-core stuff*/}
|
2022-06-11 01:02:05 +01:00
|
|
|
<div className={staticClasses.PanelSectionTitle}>
|
|
|
|
CPU
|
|
|
|
</div>
|
2022-09-01 01:18:15 +01:00
|
|
|
{smtAllowed && <PanelSectionRow>
|
2022-07-04 22:12:13 +01:00
|
|
|
<ToggleField
|
2022-06-11 01:02:05 +01:00
|
|
|
checked={smtGlobal}
|
|
|
|
label="SMT"
|
|
|
|
description="Enables odd-numbered CPUs"
|
|
|
|
onChange={(smt: boolean) => {
|
2022-09-01 01:18:15 +01:00
|
|
|
console.debug("SMT is now " + smt.toString());
|
|
|
|
const cpus = get_value(ONLINE_CPUS);
|
|
|
|
smtGlobal = smt && smtAllowed;
|
|
|
|
for (let i = 0; i < total_cpus; i++) {
|
|
|
|
const online = (smtGlobal? i < cpus : (i % 2 == 0) && (i < cpus * 2))
|
|
|
|
|| (!smtGlobal && cpus == 4);
|
2022-09-05 19:24:01 +01:00
|
|
|
backend.resolve(backend.setCpuOnline(i, online), (_value: boolean) => {});
|
2022-09-01 01:18:15 +01:00
|
|
|
}
|
2022-09-05 19:24:01 +01:00
|
|
|
backend.resolve(backend.getCpusOnline(), (statii: boolean[]) => {
|
|
|
|
// TODO: allow for per-core control of online status
|
|
|
|
let count = 0;
|
|
|
|
for (let i = 0; i < statii.length; i++) {
|
|
|
|
if (statii[i]) {
|
|
|
|
count += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
set_value(ONLINE_CPUS, count);
|
2022-09-01 01:18:15 +01:00
|
|
|
reloadGUI("SMT");
|
|
|
|
});
|
2022-06-11 01:02:05 +01:00
|
|
|
}}
|
|
|
|
/>
|
2022-09-01 01:18:15 +01:00
|
|
|
</PanelSectionRow>}
|
2022-06-11 01:02:05 +01:00
|
|
|
<PanelSectionRow>
|
2022-07-04 22:12:13 +01:00
|
|
|
<SliderField
|
2022-06-11 01:02:05 +01:00
|
|
|
label="Threads"
|
2022-09-01 01:18:15 +01:00
|
|
|
value={get_value(ONLINE_CPUS)}
|
2022-06-11 01:02:05 +01:00
|
|
|
step={1}
|
2022-09-01 01:18:15 +01:00
|
|
|
max={smtGlobal? total_cpus : total_cpus/2}
|
2022-06-11 01:02:05 +01:00
|
|
|
min={1}
|
|
|
|
showValue={true}
|
|
|
|
onChange={(cpus: number) => {
|
2022-09-01 01:18:15 +01:00
|
|
|
console.debug("CPU slider is now " + cpus.toString());
|
|
|
|
const onlines = get_value(ONLINE_CPUS);
|
|
|
|
if (cpus != onlines) {
|
|
|
|
for (let i = 0; i < total_cpus; i++) {
|
|
|
|
const online = smtGlobal? i < cpus : (i % 2 == 0) && (i < cpus * 2);
|
|
|
|
backend.resolve(backend.setCpuOnline(i, online), (value: boolean) => {
|
|
|
|
if (value) {set_value(ONLINE_CPUS, get_value(ONLINE_CPUS) + 1)}
|
|
|
|
})
|
|
|
|
}
|
2022-09-05 19:24:01 +01:00
|
|
|
backend.resolve(backend.getCpusOnline(), (statii: boolean[]) => {
|
|
|
|
// TODO: allow for per-core control of online status
|
|
|
|
let count = 0;
|
|
|
|
for (let i = 0; i < statii.length; i++) {
|
|
|
|
if (statii[i]) {
|
|
|
|
count += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
set_value(ONLINE_CPUS, count);
|
2022-09-01 01:18:15 +01:00
|
|
|
reloadGUI("CPUs");
|
|
|
|
});
|
2022-06-11 01:02:05 +01:00
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</PanelSectionRow>
|
|
|
|
<PanelSectionRow>
|
2022-07-04 22:12:13 +01:00
|
|
|
<ToggleField
|
2022-09-01 01:18:15 +01:00
|
|
|
checked={get_value(CLOCK_MIN_CPU) != null && get_value(CLOCK_MAX_CPU) != null}
|
|
|
|
label="Frequency Limits"
|
2022-09-05 19:24:01 +01:00
|
|
|
description="Set bounds on clock speed"
|
2022-09-01 01:18:15 +01:00
|
|
|
onChange={(value: boolean) => {
|
|
|
|
if (value) {
|
|
|
|
set_value(CLOCK_MIN_CPU, 1400);
|
|
|
|
set_value(CLOCK_MAX_CPU, 3500);
|
|
|
|
reloadGUI("CPUFreqToggle");
|
|
|
|
} else {
|
|
|
|
set_value(CLOCK_MIN_CPU, null);
|
|
|
|
set_value(CLOCK_MAX_CPU, null);
|
|
|
|
for (let i = 0; i < total_cpus; i++) {
|
|
|
|
backend.resolve(backend.unsetCpuClockLimits(i), (_idc: any[]) => {});
|
|
|
|
}
|
|
|
|
backend.resolve(backend.waitForComplete(), (_: boolean[]) => {
|
|
|
|
reloadGUI("CPUUnsetFreq");
|
|
|
|
});
|
|
|
|
}
|
2022-06-11 01:02:05 +01:00
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</PanelSectionRow>
|
|
|
|
<PanelSectionRow>
|
2022-09-01 01:18:15 +01:00
|
|
|
{get_value(CLOCK_MIN_CPU) != null && <SliderField
|
|
|
|
label="Minimum (MHz)"
|
|
|
|
value={get_value(CLOCK_MIN_CPU)}
|
|
|
|
max={3500}
|
|
|
|
min={1400}
|
|
|
|
step={100}
|
|
|
|
showValue={true}
|
|
|
|
disabled={get_value(CLOCK_MIN_CPU) == null}
|
2022-06-11 01:02:05 +01:00
|
|
|
onChange={(freq: number) => {
|
2022-09-01 01:18:15 +01:00
|
|
|
console.debug("Min freq slider is now " + freq.toString());
|
|
|
|
const freqNow = get_value(CLOCK_MIN_CPU);
|
|
|
|
if (freq != freqNow) {
|
|
|
|
for (let i = 0; i < total_cpus; i++) {
|
|
|
|
backend.resolve(backend.setCpuClockLimits(i, freq, get_value(CLOCK_MAX_CPU)),
|
|
|
|
(limits: number[]) => {
|
|
|
|
set_value(CLOCK_MIN_CPU, limits[0]);
|
|
|
|
set_value(CLOCK_MAX_CPU, limits[1]);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
backend.resolve(backend.waitForComplete(), (_: boolean[]) => {
|
|
|
|
reloadGUI("CPUMinFreq");
|
|
|
|
});
|
2022-06-11 01:02:05 +01:00
|
|
|
}
|
|
|
|
}}
|
2022-09-01 01:18:15 +01:00
|
|
|
/>}
|
|
|
|
</PanelSectionRow>
|
|
|
|
<PanelSectionRow>
|
|
|
|
{get_value(CLOCK_MAX_CPU) != null && <SliderField
|
|
|
|
label="Maximum (MHz)"
|
|
|
|
value={get_value(CLOCK_MAX_CPU)}
|
|
|
|
max={3500}
|
|
|
|
min={500}
|
|
|
|
step={100}
|
|
|
|
showValue={true}
|
|
|
|
disabled={get_value(CLOCK_MAX_CPU) == null}
|
|
|
|
onChange={(freq: number) => {
|
|
|
|
console.debug("Max freq slider is now " + freq.toString());
|
|
|
|
const freqNow = get_value(CLOCK_MAX_CPU);
|
|
|
|
if (freq != freqNow) {
|
|
|
|
for (let i = 0; i < total_cpus; i++) {
|
|
|
|
backend.resolve(backend.setCpuClockLimits(i, get_value(CLOCK_MIN_CPU), freq),
|
|
|
|
(limits: number[]) => {
|
|
|
|
set_value(CLOCK_MIN_CPU, limits[0]);
|
|
|
|
set_value(CLOCK_MAX_CPU, limits[1]);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
backend.resolve(backend.waitForComplete(), (_: boolean[]) => {
|
|
|
|
reloadGUI("CPUMaxFreq");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>}
|
2022-06-11 01:02:05 +01:00
|
|
|
</PanelSectionRow>
|
2022-09-01 01:18:15 +01:00
|
|
|
{/* TODO: CPU governor */}
|
2022-06-11 01:02:05 +01:00
|
|
|
{/* GPU */}
|
|
|
|
<div className={staticClasses.PanelSectionTitle}>
|
|
|
|
GPU
|
|
|
|
</div>
|
|
|
|
<PanelSectionRow>
|
2022-09-01 01:18:15 +01:00
|
|
|
<ToggleField
|
|
|
|
checked={get_value(SLOW_PPT_GPU) != null && get_value(FAST_PPT_GPU) != null}
|
|
|
|
label="PowerPlay Limits"
|
|
|
|
description="Override APU TDP settings"
|
|
|
|
onChange={(value: boolean) => {
|
|
|
|
if (value) {
|
|
|
|
set_value(SLOW_PPT_GPU, 15000000);
|
|
|
|
set_value(FAST_PPT_GPU, 15000000);
|
|
|
|
reloadGUI("GPUPPTToggle");
|
|
|
|
} else {
|
|
|
|
set_value(SLOW_PPT_GPU, null);
|
|
|
|
set_value(FAST_PPT_GPU, null);
|
|
|
|
backend.resolve(backend.unsetGpuPpt(), (_: any[]) => {
|
|
|
|
reloadGUI("GPUUnsetPPT");
|
|
|
|
});
|
2022-06-11 01:02:05 +01:00
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</PanelSectionRow>
|
|
|
|
<PanelSectionRow>
|
2022-09-01 01:18:15 +01:00
|
|
|
{ get_value(SLOW_PPT_GPU) != null && <SliderField
|
|
|
|
label="SlowPPT (uW)"
|
|
|
|
value={get_value(SLOW_PPT_GPU)}
|
|
|
|
max={29000000}
|
|
|
|
min={1000000}
|
|
|
|
step={1000000}
|
|
|
|
showValue={true}
|
|
|
|
disabled={get_value(SLOW_PPT_GPU) == null}
|
|
|
|
onChange={(ppt: number) => {
|
|
|
|
console.debug("SlowPPT is now " + ppt.toString());
|
|
|
|
const pptNow = get_value(SLOW_PPT_GPU);
|
|
|
|
if (ppt != pptNow) {
|
|
|
|
backend.resolve(backend.setGpuPpt(get_value(FAST_PPT_GPU), ppt),
|
|
|
|
(limits: number[]) => {
|
|
|
|
set_value(FAST_PPT_GPU, limits[0]);
|
|
|
|
set_value(SLOW_PPT_GPU, limits[1]);
|
|
|
|
reloadGUI("GPUSlowPPT");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>}
|
|
|
|
</PanelSectionRow>
|
|
|
|
<PanelSectionRow>
|
|
|
|
{get_value(FAST_PPT_GPU) != null && <SliderField
|
|
|
|
label="FastPPT (uW)"
|
|
|
|
value={get_value(FAST_PPT_GPU)}
|
|
|
|
max={29000000}
|
|
|
|
min={1000000}
|
|
|
|
step={1000000}
|
|
|
|
showValue={true}
|
|
|
|
disabled={get_value(FAST_PPT_GPU) == null}
|
2022-06-11 01:02:05 +01:00
|
|
|
onChange={(ppt: number) => {
|
2022-09-01 01:18:15 +01:00
|
|
|
console.debug("FastPPT is now " + ppt.toString());
|
|
|
|
const pptNow = get_value(FAST_PPT_GPU);
|
|
|
|
if (ppt != pptNow) {
|
|
|
|
backend.resolve(backend.setGpuPpt(get_value(SLOW_PPT_GPU), ppt),
|
|
|
|
(limits: number[]) => {
|
|
|
|
set_value(FAST_PPT_GPU, limits[0]);
|
|
|
|
set_value(SLOW_PPT_GPU, limits[1]);
|
|
|
|
reloadGUI("GPUFastPPT");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>}
|
|
|
|
</PanelSectionRow>
|
|
|
|
<PanelSectionRow>
|
|
|
|
<ToggleField
|
|
|
|
checked={get_value(CLOCK_MIN_GPU) != null && get_value(CLOCK_MAX_GPU) != null}
|
|
|
|
label="Frequency Limits"
|
2022-09-05 19:24:01 +01:00
|
|
|
description="Override bounds on gpu clock"
|
2022-09-01 01:18:15 +01:00
|
|
|
onChange={(value: boolean) => {
|
|
|
|
if (value) {
|
|
|
|
set_value(CLOCK_MIN_GPU, 200);
|
|
|
|
set_value(CLOCK_MAX_GPU, 1600);
|
|
|
|
reloadGUI("GPUFreqToggle");
|
|
|
|
} else {
|
|
|
|
set_value(CLOCK_MIN_GPU, null);
|
2022-09-01 01:29:08 +01:00
|
|
|
set_value(CLOCK_MAX_GPU, null);
|
2022-09-01 01:18:15 +01:00
|
|
|
backend.resolve(backend.unsetGpuClockLimits(), (_: any[]) => {
|
|
|
|
reloadGUI("GPUUnsetFreq");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</PanelSectionRow>
|
|
|
|
<PanelSectionRow>
|
|
|
|
{ get_value(CLOCK_MIN_GPU) != null && <SliderField
|
|
|
|
label="Minimum (MHz)"
|
|
|
|
value={get_value(CLOCK_MIN_GPU)}
|
|
|
|
max={1600}
|
|
|
|
min={200}
|
|
|
|
step={100}
|
|
|
|
showValue={true}
|
|
|
|
disabled={get_value(CLOCK_MIN_GPU) == null}
|
|
|
|
onChange={(val: number) => {
|
|
|
|
console.debug("GPU Clock Min is now " + val.toString());
|
|
|
|
const valNow = get_value(CLOCK_MIN_GPU);
|
|
|
|
if (val != valNow) {
|
|
|
|
backend.resolve(backend.setGpuClockLimits(val, get_value(CLOCK_MAX_GPU)),
|
|
|
|
(limits: number[]) => {
|
|
|
|
set_value(CLOCK_MIN_GPU, limits[0]);
|
|
|
|
set_value(CLOCK_MAX_GPU, limits[1]);
|
|
|
|
reloadGUI("GPUMinClock");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>}
|
|
|
|
</PanelSectionRow>
|
|
|
|
<PanelSectionRow>
|
|
|
|
{get_value(CLOCK_MAX_GPU) != null && <SliderField
|
|
|
|
label="Maximum (MHz)"
|
|
|
|
value={get_value(CLOCK_MAX_GPU)}
|
|
|
|
max={1600}
|
|
|
|
min={200}
|
|
|
|
step={100}
|
|
|
|
showValue={true}
|
|
|
|
disabled={get_value(CLOCK_MAX_GPU) == null}
|
|
|
|
onChange={(val: number) => {
|
|
|
|
console.debug("GPU Clock Max is now " + val.toString());
|
|
|
|
const valNow = get_value(CLOCK_MAX_GPU);
|
|
|
|
if (val != valNow) {
|
|
|
|
backend.resolve(backend.setGpuClockLimits(get_value(CLOCK_MIN_GPU), val),
|
|
|
|
(limits: number[]) => {
|
|
|
|
set_value(CLOCK_MIN_GPU, limits[0]);
|
|
|
|
set_value(CLOCK_MAX_GPU, limits[1]);
|
|
|
|
reloadGUI("GPUMaxClock");
|
|
|
|
});
|
2022-06-11 01:02:05 +01:00
|
|
|
}
|
|
|
|
}}
|
2022-09-01 01:18:15 +01:00
|
|
|
/>}
|
|
|
|
</PanelSectionRow>
|
|
|
|
<PanelSectionRow>
|
|
|
|
<ToggleField
|
|
|
|
checked={get_value(SLOW_MEMORY_GPU)}
|
|
|
|
label="Downclock Memory"
|
|
|
|
description="Force RAM into low-power mode"
|
|
|
|
onChange={(value: boolean) => {
|
|
|
|
backend.resolve(backend.setGpuSlowMemory(value), (val: boolean) => {
|
|
|
|
set_value(SLOW_MEMORY_GPU, val);
|
|
|
|
reloadGUI("GPUSlowMemory");
|
|
|
|
})
|
|
|
|
}}
|
2022-06-11 01:02:05 +01:00
|
|
|
/>
|
|
|
|
</PanelSectionRow>
|
|
|
|
{/* Battery */}
|
|
|
|
<div className={staticClasses.PanelSectionTitle}>
|
|
|
|
Battery
|
|
|
|
</div>
|
2022-09-05 22:02:02 +01:00
|
|
|
<PanelSectionRow>
|
2022-06-11 01:02:05 +01:00
|
|
|
<div className={FieldWithSeparator}>
|
|
|
|
<div className={gamepadDialogClasses.FieldLabelRow}>
|
|
|
|
<div className={gamepadDialogClasses.FieldLabel}>
|
|
|
|
Now (Charge)
|
|
|
|
</div>
|
|
|
|
<div className={gamepadDialogClasses.FieldChildren}>
|
2022-09-05 22:02:02 +01:00
|
|
|
{get_value(CHARGE_NOW_BATT).toFixed(1)} Wh ({(100 * get_value(CHARGE_NOW_BATT) / get_value(CHARGE_FULL_BATT)).toFixed(1)}%)
|
2022-09-01 01:18:15 +01:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2022-09-05 22:02:02 +01:00
|
|
|
</PanelSectionRow>
|
|
|
|
<PanelSectionRow>
|
2022-09-01 01:18:15 +01:00
|
|
|
<div className={FieldWithSeparator}>
|
|
|
|
<div className={gamepadDialogClasses.FieldLabelRow}>
|
|
|
|
<div className={gamepadDialogClasses.FieldLabel}>
|
|
|
|
Max (Design)
|
|
|
|
</div>
|
|
|
|
<div className={gamepadDialogClasses.FieldChildren}>
|
2022-09-05 22:02:02 +01:00
|
|
|
{get_value(CHARGE_FULL_BATT).toFixed(1)} Wh ({(100 * get_value(CHARGE_FULL_BATT) / get_value(CHARGE_DESIGN_BATT)).toFixed(1)}%)
|
2022-06-11 01:02:05 +01:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2022-09-05 22:02:02 +01:00
|
|
|
</PanelSectionRow>
|
2022-09-01 01:18:15 +01:00
|
|
|
<PanelSectionRow>
|
|
|
|
<ToggleField
|
|
|
|
checked={get_value(CHARGE_RATE_BATT) != null}
|
|
|
|
label="Charge Current Limits"
|
|
|
|
description="Control battery charge rate"
|
|
|
|
onChange={(value: boolean) => {
|
|
|
|
if (value) {
|
|
|
|
set_value(CHARGE_RATE_BATT, 2500);
|
|
|
|
reloadGUI("BATTChargeRateToggle");
|
|
|
|
} else {
|
|
|
|
set_value(CHARGE_RATE_BATT, null);
|
|
|
|
backend.resolve(backend.unsetBatteryChargeRate(), (_: any[]) => {
|
|
|
|
reloadGUI("BATTUnsetChargeRate");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
{ get_value(CHARGE_RATE_BATT) != null && <SliderField
|
|
|
|
label="Maximum (mA)"
|
|
|
|
value={get_value(CHARGE_RATE_BATT)}
|
|
|
|
max={2500}
|
|
|
|
min={250}
|
|
|
|
step={50}
|
|
|
|
showValue={true}
|
|
|
|
disabled={get_value(CHARGE_RATE_BATT) == null}
|
|
|
|
onChange={(val: number) => {
|
|
|
|
console.debug("Charge rate is now " + val.toString());
|
|
|
|
const rateNow = get_value(CHARGE_RATE_BATT);
|
|
|
|
if (val != rateNow) {
|
|
|
|
backend.resolve(backend.setBatteryChargeRate(val),
|
|
|
|
(rate: number) => {
|
|
|
|
set_value(CHARGE_RATE_BATT, rate);
|
|
|
|
reloadGUI("BATTChargeRate");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>}
|
2022-06-11 01:02:05 +01:00
|
|
|
</PanelSectionRow>
|
|
|
|
<PanelSectionRow>
|
|
|
|
<div className={FieldWithSeparator}>
|
|
|
|
<div className={gamepadDialogClasses.FieldLabelRow}>
|
|
|
|
<div className={gamepadDialogClasses.FieldLabel}>
|
2022-09-01 01:18:15 +01:00
|
|
|
Current
|
2022-06-11 01:02:05 +01:00
|
|
|
</div>
|
|
|
|
<div className={gamepadDialogClasses.FieldChildren}>
|
2022-09-01 01:18:15 +01:00
|
|
|
{get_value(CURRENT_BATT)} mA
|
2022-06-11 01:02:05 +01:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</PanelSectionRow>
|
|
|
|
{/* Persistence */}
|
2022-09-01 01:18:15 +01:00
|
|
|
<div className={staticClasses.PanelSectionTitle}>
|
|
|
|
Miscellaneous
|
|
|
|
</div>
|
2022-06-11 01:02:05 +01:00
|
|
|
<PanelSectionRow>
|
2022-07-04 22:12:13 +01:00
|
|
|
<ToggleField
|
2022-09-01 01:18:15 +01:00
|
|
|
checked={get_value(PERSISTENT_GEN)}
|
2022-06-11 01:02:05 +01:00
|
|
|
label="Persistent"
|
|
|
|
description="Restores settings after an app or OS restart"
|
|
|
|
onChange={(persist: boolean) => {
|
2022-09-01 01:18:15 +01:00
|
|
|
console.debug("Persist is now " + persist.toString());
|
|
|
|
backend.resolve(
|
|
|
|
backend.setGeneralPersistent(persist),
|
|
|
|
(val: boolean) => {set_value(PERSISTENT_GEN, val)}
|
|
|
|
);
|
2022-06-11 01:02:05 +01:00
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</PanelSectionRow>
|
|
|
|
<PanelSectionRow>
|
|
|
|
<div className={FieldWithSeparator}>
|
|
|
|
<div className={gamepadDialogClasses.FieldLabelRow}>
|
|
|
|
<div className={gamepadDialogClasses.FieldLabel}>
|
2022-09-05 22:02:02 +01:00
|
|
|
Profile
|
2022-06-11 01:02:05 +01:00
|
|
|
</div>
|
|
|
|
<div className={gamepadDialogClasses.FieldChildren}>
|
2022-09-01 01:18:15 +01:00
|
|
|
{get_value(NAME_GEN)}
|
2022-06-11 01:02:05 +01:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</PanelSectionRow>
|
2022-09-01 01:18:15 +01:00
|
|
|
{/* Version Info */}
|
2022-06-11 01:02:05 +01:00
|
|
|
<div className={staticClasses.PanelSectionTitle}>
|
|
|
|
Debug
|
|
|
|
</div>
|
|
|
|
<PanelSectionRow>
|
|
|
|
<div className={FieldWithSeparator}>
|
|
|
|
<div className={gamepadDialogClasses.FieldLabelRow}>
|
|
|
|
<div className={gamepadDialogClasses.FieldLabel}>
|
2022-09-01 01:18:15 +01:00
|
|
|
Native
|
2022-06-11 01:02:05 +01:00
|
|
|
</div>
|
|
|
|
<div className={gamepadDialogClasses.FieldChildren}>
|
2022-09-01 01:18:15 +01:00
|
|
|
{get_value(BACKEND_INFO)}
|
2022-06-11 01:02:05 +01:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</PanelSectionRow>
|
2022-09-01 01:18:15 +01:00
|
|
|
<PanelSectionRow>
|
|
|
|
<div className={FieldWithSeparator}>
|
|
|
|
<div className={gamepadDialogClasses.FieldLabelRow}>
|
|
|
|
<div className={gamepadDialogClasses.FieldLabel}>
|
|
|
|
Framework
|
|
|
|
</div>
|
|
|
|
<div className={gamepadDialogClasses.FieldChildren}>
|
|
|
|
{target_usdpl()}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</PanelSectionRow>
|
|
|
|
<PanelSectionRow>
|
|
|
|
<div className={FieldWithSeparator}>
|
|
|
|
<div className={gamepadDialogClasses.FieldLabelRow}>
|
|
|
|
<div className={gamepadDialogClasses.FieldLabel}>
|
|
|
|
USDPL
|
|
|
|
</div>
|
|
|
|
<div className={gamepadDialogClasses.FieldChildren}>
|
|
|
|
v{version_usdpl()}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</PanelSectionRow>
|
|
|
|
<PanelSectionRow>
|
|
|
|
<ButtonItem
|
|
|
|
layout="below"
|
|
|
|
onClick={(_: MouseEvent) => {
|
|
|
|
console.debug("Loading default PowerTools settings");
|
|
|
|
backend.resolve(
|
|
|
|
backend.setGeneralPersistent(false),
|
|
|
|
(val: boolean) => {
|
|
|
|
set_value(PERSISTENT_GEN, val);
|
|
|
|
backend.resolve(backend.loadGeneralDefaultSettings(), (_: any[]) => {
|
|
|
|
reload();
|
|
|
|
backend.resolve(backend.waitForComplete(), (_: any[]) => {reloadGUI("LoadDefaults")});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
Defaults
|
|
|
|
</ButtonItem>
|
|
|
|
</PanelSectionRow>
|
2022-06-11 01:02:05 +01:00
|
|
|
</PanelSection>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default definePlugin((serverApi: ServerAPI) => {
|
|
|
|
return {
|
|
|
|
title: <div className={staticClasses.Title}>PowerTools</div>,
|
|
|
|
content: <Content serverAPI={serverApi} />,
|
2022-06-11 01:34:19 +01:00
|
|
|
icon: <GiDrill />,
|
2022-06-11 01:02:05 +01:00
|
|
|
onDismount() {
|
2022-09-01 01:18:15 +01:00
|
|
|
console.debug("PowerTools shutting down");
|
2022-06-11 01:02:05 +01:00
|
|
|
clearInterval(periodicHook!);
|
2022-07-10 19:04:50 +01:00
|
|
|
periodicHook = null;
|
2022-07-05 23:14:50 +01:00
|
|
|
lifetimeHook!.unregister();
|
|
|
|
startHook!.unregister();
|
2022-06-11 01:02:05 +01:00
|
|
|
serverApi.routerHook.removeRoute("/decky-plugin-test");
|
2022-09-01 01:18:15 +01:00
|
|
|
console.debug("Unregistered PowerTools callbacks, goodbye.");
|
2022-06-11 01:02:05 +01:00
|
|
|
},
|
|
|
|
};
|
|
|
|
});
|