diff --git a/backend/limits_core/src/json_v2/base.rs b/backend/limits_core/src/json_v2/base.rs index 7733759..e066c71 100644 --- a/backend/limits_core/src/json_v2/base.rs +++ b/backend/limits_core/src/json_v2/base.rs @@ -8,6 +8,8 @@ pub struct Base { pub configs: Vec, /// Server messages pub messages: Vec, + /// Base URL for the config store + pub store: String, /// URL from which to grab the next update pub refresh: Option, } @@ -110,7 +112,7 @@ impl Default for Base { ..Default::default() }; 4], global_governors: true, - experiments: false, + ..Default::default() } }, gpu: super::GpuLimit { @@ -154,7 +156,7 @@ impl Default for Base { ..Default::default() }; 12], // 6 cores with SMTx2 global_governors: true, - experiments: false, + ..Default::default() } }, gpu: super::GpuLimit { @@ -198,7 +200,7 @@ impl Default for Base { ..Default::default() }; 16], // 8 cores with SMTx2 global_governors: true, - experiments: false, + ..Default::default() } }, gpu: super::GpuLimit { @@ -242,7 +244,7 @@ impl Default for Base { ..Default::default() }; 16], // 8 cores with SMTx2 global_governors: true, - experiments: false, + ..Default::default() } }, gpu: super::GpuLimit { @@ -286,7 +288,7 @@ impl Default for Base { ..Default::default() }; 16], // 8 cores with SMTx2 global_governors: true, - experiments: false, + ..Default::default() } }, gpu: super::GpuLimit { @@ -341,6 +343,7 @@ impl Default for Base { url: Some("https://git.ngni.us/NG-SD-Plugins/PowerTools/wiki".to_owned()), } ], + store: "https://powertools.ngni.us".to_owned(), refresh: Some("http://limits.ngni.us:45000/powertools/v2".to_owned()) } } diff --git a/backend/limits_core/src/json_v2/battery_limit.rs b/backend/limits_core/src/json_v2/battery_limit.rs index 0c3de9d..3506d4b 100644 --- a/backend/limits_core/src/json_v2/battery_limit.rs +++ b/backend/limits_core/src/json_v2/battery_limit.rs @@ -19,7 +19,7 @@ pub struct GenericBatteryLimit { pub charge_modes: Vec, pub charge_limit: Option>, // battery charge % pub extra_readouts: bool, - pub experiments: bool, + pub extras: super::LimitExtras, } impl GenericBatteryLimit { @@ -47,7 +47,7 @@ impl GenericBatteryLimit { max: Some(90.0), }), extra_readouts: false, - experiments: false, + extras: Default::default(), } } @@ -67,7 +67,10 @@ impl GenericBatteryLimit { max: Some(99.0), }), extra_readouts: true, - experiments: true, + extras: super::LimitExtras { + experiments: true, + quirks: vec!["".to_owned()].into_iter().collect(), + }, } } @@ -91,6 +94,6 @@ impl GenericBatteryLimit { } } self.extra_readouts = limit_override.extra_readouts; - self.experiments = limit_override.experiments; + self.extras = limit_override.extras; } } diff --git a/backend/limits_core/src/json_v2/cpu_limit.rs b/backend/limits_core/src/json_v2/cpu_limit.rs index 58af870..24b7fde 100644 --- a/backend/limits_core/src/json_v2/cpu_limit.rs +++ b/backend/limits_core/src/json_v2/cpu_limit.rs @@ -19,7 +19,7 @@ pub enum CpuLimitType { pub struct GenericCpusLimit { pub cpus: Vec, pub global_governors: bool, - pub experiments: bool, + pub extras: super::LimitExtras, } impl GenericCpusLimit { @@ -29,14 +29,17 @@ impl GenericCpusLimit { Self { cpus: [(); 8].iter().enumerate().map(|(i, _)| GenericCpuLimit::default_for(&t, i)).collect(), global_governors: true, - experiments: false, + extras: Default::default(), } }, CpuLimitType::DevMode => { Self { cpus: [(); 11].iter().enumerate().map(|(i, _)| GenericCpuLimit::default_for(&t, i)).collect(), global_governors: true, - experiments: true, + extras: super::LimitExtras { + experiments: true, + quirks: vec!["".to_owned()].into_iter().collect(), + }, } }, t => { @@ -48,7 +51,7 @@ impl GenericCpusLimit { Self { cpus, global_governors: true, - experiments: false, + extras: Default::default(), } } } @@ -76,7 +79,7 @@ impl GenericCpusLimit { .for_each(|(cpu, limit_override)| cpu.apply_override(limit_override)); } self.global_governors = limit_override.global_governors; - self.experiments = limit_override.experiments; + self.extras = limit_override.extras; } } diff --git a/backend/limits_core/src/json_v2/gpu_limit.rs b/backend/limits_core/src/json_v2/gpu_limit.rs index f7d1dbe..f5a326a 100644 --- a/backend/limits_core/src/json_v2/gpu_limit.rs +++ b/backend/limits_core/src/json_v2/gpu_limit.rs @@ -32,7 +32,7 @@ pub struct GenericGpuLimit { pub memory_clock: Option>, pub memory_clock_step: Option, pub skip_resume_reclock: bool, - pub experiments: bool, + pub extras: super::LimitExtras, } impl GenericGpuLimit { @@ -72,16 +72,21 @@ impl GenericGpuLimit { max: Some(1600), }), clock_step: Some(100), - // Disabled for now since LCD version is a bit broken on sysfs right now - /*memory_clock: Some(RangeLimit { + // LCD version is a bit broken on sysfs, but it's ok + memory_clock: Some(RangeLimit { min: Some(400), max: Some(800), }), - memory_clock_step: Some(400),*/ - memory_clock: None, - memory_clock_step: None, + memory_clock_step: Some(400), skip_resume_reclock: false, - experiments: false, + extras: super::LimitExtras { + experiments: false, + quirks: vec![ + "pp_dpm_fclk-reversed".to_owned(), + "pp_dpm_fclk-not-updated-on-LCD".to_owned(), + //"pp_dpm_fclk-static".to_owned(), + ].into_iter().collect(), + } } } @@ -124,7 +129,10 @@ impl GenericGpuLimit { }), memory_clock_step: Some(100), skip_resume_reclock: false, - experiments: true, + extras: super::LimitExtras { + experiments: true, + quirks: vec!["dev".to_owned()].into_iter().collect(), + }, } } @@ -190,6 +198,6 @@ impl GenericGpuLimit { self.clock_step = Some(val); } self.skip_resume_reclock = limit_override.skip_resume_reclock; - self.experiments = limit_override.experiments; + self.extras = limit_override.extras; } } diff --git a/backend/limits_core/src/json_v2/limits.rs b/backend/limits_core/src/json_v2/limits.rs index b983603..516d31c 100644 --- a/backend/limits_core/src/json_v2/limits.rs +++ b/backend/limits_core/src/json_v2/limits.rs @@ -26,3 +26,9 @@ pub struct Limit { pub type CpuLimit = Limit; pub type GpuLimit = Limit; pub type BatteryLimit = Limit; + +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct LimitExtras { + pub experiments: bool, + pub quirks: std::collections::HashSet, +} diff --git a/backend/limits_core/src/json_v2/mod.rs b/backend/limits_core/src/json_v2/mod.rs index c5bfeb6..d863d7f 100644 --- a/backend/limits_core/src/json_v2/mod.rs +++ b/backend/limits_core/src/json_v2/mod.rs @@ -16,6 +16,6 @@ pub use cpu_limit::{CpuLimitType, GenericCpusLimit, GenericCpuLimit}; pub use devel_message::DeveloperMessage; pub use gpu_limit::{GpuLimitType, GenericGpuLimit}; pub use config::Config; -pub use limits::{Limits, Limit, CpuLimit, GpuLimit, BatteryLimit}; +pub use limits::{Limits, Limit, CpuLimit, GpuLimit, BatteryLimit, LimitExtras}; pub use range::RangeLimit; pub use target::Target; diff --git a/backend/src/api/web.rs b/backend/src/api/web.rs index 385ec92..1001e49 100644 --- a/backend/src/api/web.rs +++ b/backend/src/api/web.rs @@ -1,17 +1,40 @@ use std::sync::mpsc::{self, Sender}; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, RwLock}; use usdpl_back::core::serdes::Primitive; use usdpl_back::AsyncCallable; use super::handler::{ApiMessage, GeneralMessage}; -const BASE_URL: &'static str = "http://powertools.ngni.us"; +const BASE_URL_FALLBACK: &'static str = "https://powertools.ngni.us"; +static BASE_URL: RwLock> = RwLock::new(None); + +pub fn set_base_url(base_url: String) { + *BASE_URL.write().expect("Failed to acquire write lock for store base url") = Some(base_url); +} + +fn get_base_url() -> String { + BASE_URL.read().expect("Failed to acquire read lock for store base url") + .clone() + .unwrap_or_else(|| BASE_URL_FALLBACK.to_owned()) +} + +fn url_search_by_app_id(steam_app_id: u32) -> String { + format!("{}/api/setting/by_app_id/{}", get_base_url(), steam_app_id) +} + +fn url_download_config_by_id(id: u128) -> String { + format!("{}/api/setting/by_id/{}", get_base_url(), id) +} + +fn url_upload_config() -> String { + format!("{}/api/setting", get_base_url()) +} /// Get search results web method pub fn search_by_app_id() -> impl AsyncCallable { let getter = move || { move |steam_app_id: u32| { - let req_url = format!("{}/api/setting/by_app_id/{}", BASE_URL, steam_app_id); + let req_url = url_search_by_app_id(steam_app_id); match ureq::get(&req_url).call() { Ok(response) => { let json_res: std::io::Result> = @@ -110,7 +133,7 @@ fn web_config_to_settings_json( } fn download_config(id: u128) -> std::io::Result { - let req_url = format!("{}/api/setting/by_id/{}", BASE_URL, id); + let req_url = url_download_config_by_id(id); let response = ureq::get(&req_url).call().map_err(|e| { log::warn!("GET to {} failed: {}", req_url, e); std::io::Error::new(std::io::ErrorKind::ConnectionAborted, e) @@ -207,7 +230,7 @@ fn settings_to_web_config( } fn upload_config(config: community_settings_core::v1::Metadata) -> std::io::Result<()> { - let req_url = format!("{}/api/setting", BASE_URL); + let req_url = url_upload_config(); ureq::post(&req_url) .send_json(&config) .map_err(|e| { diff --git a/backend/src/settings/detect/limits_worker.rs b/backend/src/settings/detect/limits_worker.rs index 3665b11..4bdad39 100644 --- a/backend/src/settings/detect/limits_worker.rs +++ b/backend/src/settings/detect/limits_worker.rs @@ -32,6 +32,7 @@ pub fn spawn() -> JoinHandle<()> { save_base(&base, &limits_path); base }; + crate::api::web::set_base_url(base.store); if let Some(refresh) = &base.refresh { // try to retrieve newer version match ureq::get(refresh).call() { diff --git a/backend/src/settings/steam_deck/gpu.rs b/backend/src/settings/steam_deck/gpu.rs index 8ca3faa..beb0a47 100644 --- a/backend/src/settings/steam_deck/gpu.rs +++ b/backend/src/settings/steam_deck/gpu.rs @@ -192,18 +192,50 @@ impl Gpu { fn build_memory_clock_payload(&self, clock: u64) -> String { let max_val = self.quantize_memory_clock(clock); - match max_val { - 0 => "0\n".to_owned(), - max_val => { - use std::fmt::Write; - let mut payload = String::from("0"); - for i in 1..max_val { - write!(payload, " {}", i) + let is_oled = matches!(self.variant, super::Model::OLED); + let is_lcd = matches!(self.variant, super::Model::LCD); + let is_lock_feature_enabled = self.limits.extras.quirks.contains("pp_dpm_fclk-static"); + + if (is_oled && self.limits.extras.quirks.contains("pp_dpm_fclk-reversed-on-OLED")) + || (is_lcd && self.limits.extras.quirks.contains("pp_dpm_fclk-reversed-on-LCD")) + || self.limits.extras.quirks.contains("pp_dpm_fclk-reversed") { + let options_count = self + .sysfs_card + .read_value(GPU_MEMORY_DOWNCLOCK_ATTRIBUTE.to_owned()) + .map(|b| parse_pp_dpm_fclk(&String::from_utf8_lossy(&b)).len()) + .unwrap_or_else(|_| if is_oled { 4 } else { 2 }); + let modifier = (options_count - 1) as u64; + if is_lock_feature_enabled { + format!("{}\n", modifier - max_val) + } else { + if max_val == 0 as u64 { + format!("{}\n", modifier) + } else { + use std::fmt::Write; + let mut payload = format!("{}", modifier - max_val); + for i in (0..max_val).rev(/* rev() isn't necessary but it creates a nicer (ascending) order */) { + write!(payload, " {}", modifier - i) + .expect("Failed to write to memory payload (should be infallible!?)"); + } + write!(payload, "\n") .expect("Failed to write to memory payload (should be infallible!?)"); + payload + } + } + } else { + match max_val { + 0 => "0\n".to_owned(), + max_val => { + use std::fmt::Write; + let mut payload = String::from("0"); + for i in 1..max_val { + write!(payload, " {}", i) + .expect("Failed to write to memory payload (should be infallible!?)"); + } + write!(payload, " {}\n", max_val) + .expect("Failed to write to memory payload (should be infallible!?)"); + payload } - write!(payload, " {}\n", max_val) - .expect("Failed to write to memory payload (should be infallible!?)"); - payload } } } diff --git a/src/index.tsx b/src/index.tsx index e3b8e95..8fb9f4d 100755 --- a/src/index.tsx +++ b/src/index.tsx @@ -23,7 +23,7 @@ import { //joinClassNames, } from "decky-frontend-lib"; import { VFC, useState } from "react"; -import { GiDrill, GiTimeBomb, GiTimeTrap, GiDynamite } from "react-icons/gi"; +import { GiDrill, GiFireExtinguisher, GiFireBomb, GiMineExplosion } from "react-icons/gi"; import { HiRefresh, HiTrash, HiPlus, HiUpload } from "react-icons/hi"; import { TbWorldPlus } from "react-icons/tb"; @@ -532,7 +532,7 @@ export default definePlugin((serverApi: ServerAPI) => { let ico = ; let now = new Date(); if (now.getDate() == 1 && now.getMonth() == 3) { - ico = ; + ico = ; } //registerCallbacks(false); serverApi.routerHook.addRoute(STORE_RESULTS_URI, StoreResultsPage);