Send front-end logs to back and improve Steam Deck driver display

This commit is contained in:
NGnius (Graham) 2023-01-04 19:42:59 -05:00
parent cda1111cd3
commit 13bf31611d
8 changed files with 113 additions and 44 deletions

View file

@ -215,3 +215,36 @@ pub fn gunter(_: super::ApiParameterType) -> super::ApiParameterType {
});
vec![true.into()]
}
/// API web method to send log messages to the back-end log, callable from the front-end
pub fn log_it() -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
move |params| {
if let Some(Primitive::F64(level)) = params.get(0) {
if let Some(Primitive::String(msg)) = params.get(1) {
log_msg_by_level(*level as u8, msg);
vec![true.into()]
} else if let Some(Primitive::Json(msg)) = params.get(1) {
log_msg_by_level(*level as u8, msg);
vec![true.into()]
} else {
log::warn!("Got log_it call with wrong/missing 2nd parameter");
vec![false.into()]
}
} else {
log::warn!("Got log_it call with wrong/missing 1st parameter");
vec![false.into()]
}
}
}
fn log_msg_by_level(level: u8, msg: &str) {
match level {
1 => log::trace!("FRONT-END: {}", msg),
2 => log::debug!("FRONT-END: {}", msg),
3 => log::info!("FRONT-END: {}", msg),
4 => log::warn!("FRONT-END: {}", msg),
5 => log::error!("FRONT-END: {}", msg),
_ => log::trace!("FRONT-END: {}", msg),
}
}

View file

@ -75,6 +75,7 @@ fn main() -> Result<(), ()> {
.register("V_INFO", |_: Vec<Primitive>| {
vec![format!("{} v{}", PACKAGE_NAME, PACKAGE_VERSION).into()]
})
.register("LOG", api::general::log_it())
// battery API functions
.register_async("BATTERY_current_now", api::battery::current_now(api_sender.clone()))
.register_async("BATTERY_charge_now", api::battery::charge_now(api_sender.clone()))

View file

@ -13,6 +13,7 @@ pub struct Battery {
pub charge_mode: Option<ChargeMode>,
limits: BatteryLimits,
state: crate::state::steam_deck::Battery,
driver_mode: crate::persist::DriverJson,
}
const BATTERY_VOLTAGE: f64 = 7.7;
@ -26,19 +27,23 @@ const BATTERY_CHARGE_DESIGN_PATH: &str = "/sys/class/hwmon/hwmon2/device/charge_
impl Battery {
#[inline]
pub fn from_json(other: BatteryJson, version: u64) -> Self {
let oc_limits = OverclockLimits::load_or_default().battery;
let (oc_limits, is_default) = OverclockLimits::load_or_default();
let oc_limits = oc_limits.battery;
let driver = if is_default { crate::persist::DriverJson::SteamDeck } else { crate::persist::DriverJson::SteamDeckAdvance };
match version {
0 => Self {
charge_rate: other.charge_rate,
charge_mode: other.charge_mode.map(|x| Self::str_to_charge_mode(&x)).flatten(),
limits: oc_limits,
state: crate::state::steam_deck::Battery::default(),
driver_mode: driver,
},
_ => Self {
charge_rate: other.charge_rate,
charge_mode: other.charge_mode.map(|x| Self::str_to_charge_mode(&x)).flatten(),
limits: oc_limits,
state: crate::state::steam_deck::Battery::default(),
driver_mode: driver,
},
}
}
@ -184,12 +189,15 @@ impl Battery {
}
pub fn system_default() -> Self {
let oc_limits = OverclockLimits::load_or_default().battery;
let (oc_limits, is_default) = OverclockLimits::load_or_default();
let oc_limits = oc_limits.battery;
let driver = if is_default { crate::persist::DriverJson::SteamDeck } else { crate::persist::DriverJson::SteamDeckAdvance };
Self {
charge_rate: None,
charge_mode: None,
limits: oc_limits,
state: crate::state::steam_deck::Battery::default(),
driver_mode: driver,
}
}
}
@ -290,6 +298,6 @@ impl TBattery for Battery {
}
fn provider(&self) -> crate::persist::DriverJson {
crate::persist::DriverJson::SteamDeck
self.driver_mode.clone()
}
}

View file

@ -17,6 +17,7 @@ pub struct Cpus {
pub smt_capable: bool,
#[allow(dead_code)] // in case this may be useful in the future
pub(super) limits: CpusLimits,
driver_mode: crate::persist::DriverJson,
}
impl OnSet for Cpus {
@ -84,7 +85,9 @@ impl Cpus {
}
pub fn system_default() -> Self {
let oc_limits = OverclockLimits::load_or_default().cpus;
let (oc_limits, is_default) = OverclockLimits::load_or_default();
let oc_limits = oc_limits.cpus;
let driver = if is_default { crate::persist::DriverJson::SteamDeck } else { crate::persist::DriverJson::SteamDeckAdvance };
if let Some(max_cpu) = Self::cpu_count() {
let mut sys_cpus = Vec::with_capacity(max_cpu);
for i in 0..max_cpu {
@ -96,6 +99,7 @@ impl Cpus {
smt: true,
smt_capable: can_smt,
limits: oc_limits,
driver_mode: driver,
}
} else {
Self {
@ -103,13 +107,16 @@ impl Cpus {
smt: false,
smt_capable: false,
limits: oc_limits,
driver_mode: driver,
}
}
}
#[inline]
pub fn from_json(mut other: Vec<CpuJson>, version: u64) -> Self {
let oc_limits = OverclockLimits::load_or_default().cpus;
let (oc_limits, is_default) = OverclockLimits::load_or_default();
let oc_limits = oc_limits.cpus;
let driver = if is_default { crate::persist::DriverJson::SteamDeck } else { crate::persist::DriverJson::SteamDeckAdvance };
let (_, can_smt) = Self::system_smt_capabilities();
let mut result = Vec::with_capacity(other.len());
let max_cpus = Self::cpu_count();
@ -138,6 +145,7 @@ impl Cpus {
smt: !smt_disabled,
smt_capable: can_smt,
limits: oc_limits,
driver_mode: driver,
}
}
}
@ -168,7 +176,7 @@ impl TCpus for Cpus {
}
fn provider(&self) -> crate::persist::DriverJson {
crate::persist::DriverJson::SteamDeck
self.driver_mode.clone()
}
}

View file

@ -18,6 +18,7 @@ pub struct Gpu {
pub slow_memory: bool,
limits: GpuLimits,
state: crate::state::steam_deck::Gpu,
driver_mode: crate::persist::DriverJson,
}
// same as CPU
@ -28,23 +29,26 @@ const GPU_MEMORY_DOWNCLOCK_PATH: &str = "/sys/class/drm/card0/device/pp_dpm_fclk
impl Gpu {
#[inline]
pub fn from_json(other: GpuJson, version: u64) -> Self {
let oc_limits = OverclockLimits::load_or_default().gpu;
let (oc_limits, is_default) = OverclockLimits::load_or_default();
let driver = if is_default { crate::persist::DriverJson::SteamDeck } else { crate::persist::DriverJson::SteamDeckAdvance };
match version {
0 => Self {
fast_ppt: other.fast_ppt,
slow_ppt: other.slow_ppt,
clock_limits: other.clock_limits.map(|x| min_max_from_json(x, version)),
slow_memory: other.slow_memory,
limits: oc_limits,
limits: oc_limits.gpu,
state: crate::state::steam_deck::Gpu::default(),
driver_mode: driver,
},
_ => Self {
fast_ppt: other.fast_ppt,
slow_ppt: other.slow_ppt,
clock_limits: other.clock_limits.map(|x| min_max_from_json(x, version)),
slow_memory: other.slow_memory,
limits: oc_limits,
limits: oc_limits.gpu,
state: crate::state::steam_deck::Gpu::default(),
driver_mode: driver,
},
}
}
@ -178,14 +182,15 @@ impl Gpu {
}
pub fn system_default() -> Self {
let oc_limits = OverclockLimits::load_or_default().gpu;
let (oc_limits, is_default) = OverclockLimits::load_or_default();
Self {
fast_ppt: None,
slow_ppt: None,
clock_limits: None,
slow_memory: false,
limits: oc_limits,
limits: oc_limits.gpu,
state: crate::state::steam_deck::Gpu::default(),
driver_mode: if is_default { crate::persist::DriverJson::SteamDeck } else { crate::persist::DriverJson::SteamDeckAdvance },
}
}
}
@ -273,7 +278,7 @@ impl TGpu for Gpu {
}
fn provider(&self) -> crate::persist::DriverJson {
crate::persist::DriverJson::SteamDeck
self.driver_mode.clone()
}
}

View file

@ -21,7 +21,8 @@ impl Default for OverclockLimits {
}
impl OverclockLimits {
pub fn load_or_default() -> Self {
/// (Self, is_default)
pub fn load_or_default() -> (Self, bool) {
let path = std::path::Path::new(OC_LIMITS_FILEPATH);
if path.exists() {
log::info!("Steam Deck limits file {} found", path.display());
@ -29,22 +30,22 @@ impl OverclockLimits {
Ok(f) => f,
Err(e) => {
log::warn!("Steam Deck limits file {} err: {} (using default fallback)", path.display(), e);
return Self::default();
return (Self::default(), true);
},
};
match serde_json::from_reader(&mut file) {
Ok(result) => {
log::debug!("Steam Deck limits file {} successfully loaded", path.display());
result
(result, false)
},
Err(e) => {
log::warn!("Steam Deck limits file {} json err: {} (using default fallback)", path.display(), e);
Self::default()
(Self::default(), true)
}
}
} else {
log::info!("Steam Deck limits file {} not found (using default fallback)", path.display());
Self::default()
(Self::default(), true)
}
}
}

View file

@ -12,6 +12,7 @@ export function resolve<T>(promise: Promise<T>, setter: (t: T) => void) {
setter(data);
} else {
console.warn("Resolve failed:", data);
log(LogLevel.Warn, "");
}
})();
}
@ -231,6 +232,18 @@ export async function getDriverProviderName(name: string): Promise<string> {
return (await call_backend("GENERAL_get_provider", [name]))[0];
}
export enum LogLevel {
Trace = 1,
Debug = 2,
Info = 3,
Warn = 4,
Error = 5,
}
export async function log(level: LogLevel, msg: string): Promise<boolean> {
return (await call_backend("LOG", [level, msg]))[0];
}
export async function idk(): Promise<boolean> {
return (await call_backend("GENERAL_idk", []))[0];
}

View file

@ -104,7 +104,7 @@ const reload = function() {
backend.resolve(backend.getLimits(), (limits) => {
set_value(LIMITS_INFO, limits);
console.debug("POWERTOOLS: got limits", limits);
console.debug("POWERTOOLS: got limits ", limits);
});
backend.resolve(backend.getBatteryCurrent(), (rate: number) => { set_value(CURRENT_BATT, rate) });
@ -128,7 +128,7 @@ const reload = function() {
});
backend.resolve(backend.getCpusGovernor(), (governors: string[]) => {
set_value(GOVERNOR_CPU, governors);
console.log("POWERTOOLS: Governors from backend", governors);
backend.log(backend.LogLevel.Info, "POWERTOOLS: Governors from backend " + governors.toString());
});
backend.resolve(backend.getGpuPpt(), (ppts: number[]) => {
@ -159,12 +159,12 @@ const reload = function() {
//@ts-ignore
lifetimeHook = SteamClient.GameSessions.RegisterForAppLifetimeNotifications((update) => {
if (update.bRunning) {
//console.debug("AppID " + update.unAppID.toString() + " is now running");
//backend.log(backend.LogLevel.Debug, "AppID " + update.unAppID.toString() + " is now running");
} else {
//console.debug("AppID " + update.unAppID.toString() + " is no longer running");
//backend.log(backend.LogLevel.Debug, "AppID " + update.unAppID.toString() + " is no longer running");
backend.resolve(
backend.loadGeneralDefaultSettings(),
(ok: boolean) => {console.debug("Loading default settings ok? " + ok)}
(ok: boolean) => {backend.log(backend.LogLevel.Debug, "Loading default settings ok? " + ok)}
);
}
});
@ -175,11 +175,11 @@ const reload = function() {
// don't use gameInfo.appid, haha
backend.resolve(
backend.loadGeneralSettings(id.toString() + ".json", gameInfo.display_name),
(ok: boolean) => {console.debug("Loading settings ok? " + ok)}
(ok: boolean) => {backend.log(backend.LogLevel.Debug, "Loading settings ok? " + ok)}
);
});
console.debug("Registered PowerTools callbacks, hello!");
backend.log(backend.LogLevel.Debug, "Registered PowerTools callbacks, hello!");
})();
const periodicals = function() {
@ -250,7 +250,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
label="SMT"
description="Enables odd-numbered CPUs"
onChange={(smt: boolean) => {
console.debug("SMT is now " + smt.toString());
backend.log(backend.LogLevel.Debug, "SMT is now " + smt.toString());
const cpus = get_value(ONLINE_CPUS);
const smtNow = smt && smtAllowed;
backend.resolve(backend.setCpuSmt(smtNow), (newVal: boolean) => {
@ -280,7 +280,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
min={1}
showValue={true}
onChange={(cpus: number) => {
console.debug("CPU slider is now " + cpus.toString());
backend.log(backend.LogLevel.Debug, "CPU slider is now " + cpus.toString());
const onlines = get_value(ONLINE_CPUS);
if (cpus != onlines) {
set_value(ONLINE_CPUS, cpus);
@ -340,7 +340,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
showValue={true}
disabled={get_value(CLOCK_MIN_CPU) == null}
onChange={(freq: number) => {
console.debug("Min freq slider is now " + freq.toString());
backend.log(backend.LogLevel.Debug, "Min freq slider is now " + freq.toString());
const freqNow = get_value(CLOCK_MIN_CPU);
if (freq != freqNow) {
set_value(CLOCK_MIN_CPU, freq);
@ -370,7 +370,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
showValue={true}
disabled={get_value(CLOCK_MAX_CPU) == null}
onChange={(freq: number) => {
console.debug("Max freq slider is now " + freq.toString());
backend.log(backend.LogLevel.Debug, "Max freq slider is now " + freq.toString());
const freqNow = get_value(CLOCK_MAX_CPU);
if (freq != freqNow) {
set_value(CLOCK_MAX_CPU, freq);
@ -410,7 +410,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
label="Online"
description="Allow the CPU thread to do work"
onChange={(status: boolean) => {
console.debug("CPU " + advancedCpu.toString() + " is now " + status.toString());
backend.log(backend.LogLevel.Debug, "CPU " + advancedCpu.toString() + " is now " + status.toString());
if (get_value(SMT_CPU)) {
backend.resolve(backend.setCpuSmt(false), (newVal: boolean) => {
set_value(SMT_CPU, newVal);
@ -463,7 +463,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
showValue={true}
disabled={get_value(CLOCK_MIN_MAX_CPU)[advancedCpuIndex].min == null}
onChange={(freq: number) => {
console.debug("Min freq slider for " + advancedCpu.toString() + " is now " + freq.toString());
backend.log(backend.LogLevel.Debug, "Min freq slider for " + advancedCpu.toString() + " is now " + freq.toString());
const freqNow = get_value(CLOCK_MIN_MAX_CPU)[advancedCpuIndex] as MinMax;
if (freq != freqNow.min) {
backend.resolve(backend.setCpuClockLimits(advancedCpuIndex, freq, freqNow.max!),
@ -488,7 +488,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
showValue={true}
disabled={get_value(CLOCK_MIN_MAX_CPU)[advancedCpuIndex].max == null}
onChange={(freq: number) => {
console.debug("Max freq slider for " + advancedCpu.toString() + " is now " + freq.toString());
backend.log(backend.LogLevel.Debug, "Max freq slider for " + advancedCpu.toString() + " is now " + freq.toString());
const freqNow = get_value(CLOCK_MIN_MAX_CPU)[advancedCpuIndex] as MinMax;
if (freq != freqNow.max) {
backend.resolve(backend.setCpuClockLimits(advancedCpuIndex, freqNow.min!, freq),
@ -511,13 +511,13 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
menuLabel="Governor"
rgOptions={governorOptions}
selectedOption={governorOptions.find((val: SingleDropdownOption, _index, _arr) => {
console.debug("POWERTOOLS: array item", val);
console.debug("POWERTOOLS: looking for data", get_value(GOVERNOR_CPU)[advancedCpuIndex]);
backend.log(backend.LogLevel.Debug, "POWERTOOLS: array item " + val.toString());
backend.log(backend.LogLevel.Debug, "POWERTOOLS: looking for data " + get_value(GOVERNOR_CPU)[advancedCpuIndex].toString());
return val.data == get_value(GOVERNOR_CPU)[advancedCpuIndex];
})}
strDefaultLabel={get_value(GOVERNOR_CPU)[advancedCpuIndex]}
onChange={(elem: SingleDropdownOption) => {
console.debug("Governor dropdown selected", elem);
backend.log(backend.LogLevel.Debug, "Governor dropdown selected " + elem.data.toString());
backend.resolve(backend.setCpuGovernor(advancedCpuIndex, elem.data as string), (gov: string) => {
const governors = get_value(GOVERNOR_CPU);
governors[advancedCpuIndex] = gov;
@ -567,7 +567,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
showValue={true}
disabled={get_value(SLOW_PPT_GPU) == null}
onChange={(ppt: number) => {
console.debug("SlowPPT is now " + ppt.toString());
backend.log(backend.LogLevel.Debug, "SlowPPT is now " + ppt.toString());
const pptNow = get_value(SLOW_PPT_GPU);
const realPpt = ppt;
if (realPpt != pptNow) {
@ -591,7 +591,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
showValue={true}
disabled={get_value(FAST_PPT_GPU) == null}
onChange={(ppt: number) => {
console.debug("FastPPT is now " + ppt.toString());
backend.log(backend.LogLevel.Debug, "FastPPT is now " + ppt.toString());
const pptNow = get_value(FAST_PPT_GPU);
const realPpt = ppt;
if (realPpt != pptNow) {
@ -641,7 +641,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
showValue={true}
disabled={get_value(CLOCK_MIN_GPU) == null}
onChange={(val: number) => {
console.debug("GPU Clock Min is now " + val.toString());
backend.log(backend.LogLevel.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)),
@ -664,7 +664,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
showValue={true}
disabled={get_value(CLOCK_MAX_GPU) == null}
onChange={(val: number) => {
console.debug("GPU Clock Max is now " + val.toString());
backend.log(backend.LogLevel.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),
@ -736,7 +736,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
showValue={true}
disabled={get_value(CHARGE_RATE_BATT) == null}
onChange={(val: number) => {
console.debug("Charge rate is now " + val.toString());
backend.log(backend.LogLevel.Debug, "Charge rate is now " + val.toString());
const rateNow = get_value(CHARGE_RATE_BATT);
if (val != rateNow) {
backend.resolve(backend.setBatteryChargeRate(val),
@ -776,7 +776,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
})}
strDefaultLabel={get_value(CHARGE_MODE_BATT)}
onChange={(elem: SingleDropdownOption) => {
console.debug("Charge mode dropdown selected", elem);
backend.log(backend.LogLevel.Debug, "Charge mode dropdown selected " + elem.data.toString());
backend.resolve(backend.setBatteryChargeMode(elem.data as string), (mode: string) => {
set_value(CHARGE_MODE_BATT, mode);
reloadGUI("BATTChargeMode");
@ -803,7 +803,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
label="Persistent"
description="Save profile and load it next time"
onChange={(persist: boolean) => {
console.debug("Persist is now " + persist.toString());
backend.log(backend.LogLevel.Debug, "Persist is now " + persist.toString());
backend.resolve(
backend.setGeneralPersistent(persist),
(val: boolean) => {set_value(PERSISTENT_GEN, val)}
@ -879,7 +879,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
<ButtonItem
layout="below"
onClick={(_: MouseEvent) => {
console.debug("Loading default PowerTools settings");
backend.log(backend.LogLevel.Debug, "Loading default PowerTools settings");
backend.resolve(
backend.setGeneralPersistent(false),
(val: boolean) => {
@ -905,13 +905,13 @@ export default definePlugin((serverApi: ServerAPI) => {
content: <Content serverAPI={serverApi} />,
icon: <GiDrill />,
onDismount() {
console.debug("PowerTools shutting down");
backend.log(backend.LogLevel.Debug, "PowerTools shutting down");
clearInterval(periodicHook!);
periodicHook = null;
lifetimeHook!.unregister();
startHook!.unregister();
serverApi.routerHook.removeRoute("/decky-plugin-test");
console.debug("Unregistered PowerTools callbacks, goodbye.");
backend.log(backend.LogLevel.Debug, "Unregistered PowerTools callbacks, goodbye.");
},
};
});