cargo fmt and fix profile variant loading

This commit is contained in:
NGnius (Graham) 2024-01-29 21:32:18 -05:00
parent 85a9fc8f7e
commit 59a0727f88
40 changed files with 1640 additions and 720 deletions

View file

@ -67,4 +67,5 @@ pub struct GpuLimits {
pub struct VariantInfo { pub struct VariantInfo {
pub id: String, pub id: String,
pub name: String, pub name: String,
pub id_num: u64,
} }

View file

@ -59,7 +59,13 @@ pub fn load_settings(
sender sender
.lock() .lock()
.unwrap() .unwrap()
.send(ApiMessage::LoadSettings(id, name, variant, variant_name.unwrap_or_else(|| crate::consts::DEFAULT_SETTINGS_VARIANT_NAME.to_owned()))) .send(ApiMessage::LoadSettings(
id,
name,
variant,
variant_name
.unwrap_or_else(|| crate::consts::DEFAULT_SETTINGS_VARIANT_NAME.to_owned()),
))
.expect("load_settings send failed") .expect("load_settings send failed")
}; };
move |params_in: super::ApiParameterType| { move |params_in: super::ApiParameterType| {
@ -67,16 +73,20 @@ pub fn load_settings(
if let Some(Primitive::String(name)) = params_in.get(1) { if let Some(Primitive::String(name)) = params_in.get(1) {
if let Some(Primitive::String(variant_id)) = params_in.get(2) { if let Some(Primitive::String(variant_id)) = params_in.get(2) {
if let Some(Primitive::String(variant_name)) = params_in.get(3) { if let Some(Primitive::String(variant_name)) = params_in.get(3) {
setter(id.parse().unwrap_or_default(), setter(
name.to_owned(), id.parse().unwrap_or_default(),
variant_id.parse().unwrap_or_default(), name.to_owned(),
Some(variant_name.to_owned())); variant_id.parse().unwrap_or_default(),
Some(variant_name.to_owned()),
);
vec![true.into()] vec![true.into()]
} else { } else {
setter(id.parse().unwrap_or_default(), setter(
name.to_owned(), id.parse().unwrap_or_default(),
variant_id.parse().unwrap_or_default(), name.to_owned(),
None); variant_id.parse().unwrap_or_default(),
None,
);
vec![true.into()] vec![true.into()]
} }
} else { } else {
@ -101,26 +111,32 @@ pub fn load_variant(
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType { ) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let setter = move |variant: u64, variant_name: Option<String>| { let setter = move |variant: u64, variant_name: Option<String>| {
log::debug!("load_variant(variant: {}, variant_name: {:?})", variant, variant_name);
sender sender
.lock() .lock()
.unwrap() .unwrap()
.send(ApiMessage::LoadVariant(variant, variant_name.unwrap_or_else(|| crate::consts::DEFAULT_SETTINGS_VARIANT_NAME.to_owned()))) .send(ApiMessage::LoadVariant(
.expect("load_settings send failed") variant,
variant_name
.unwrap_or_else(|| "".to_owned()),
))
.expect("load_variant send failed")
}; };
move |params_in: super::ApiParameterType| { move |params_in: super::ApiParameterType| {
if let Some(Primitive::String(variant_id)) = params_in.get(0) { if let Some(Primitive::String(variant_id)) = params_in.get(0) {
if let Some(Primitive::String(variant_name)) = params_in.get(1) { if let Some(Primitive::String(variant_name)) = params_in.get(1) {
setter(variant_id.parse().unwrap_or(u64::MAX), setter(
Some(variant_name.to_owned())); variant_id.parse().unwrap_or(u64::MAX),
Some(variant_name.to_owned()),
);
vec![true.into()] vec![true.into()]
} else { } else {
setter(variant_id.parse().unwrap_or_default(), setter(variant_id.parse().unwrap_or(u64::MAX), None);
None);
vec![true.into()] vec![true.into()]
} }
} else { } else {
log::warn!("load_settings missing variant id parameter"); log::warn!("load_variant missing variant id parameter");
vec!["load_settings missing variant id parameter".into()] vec!["load_variant missing variant id parameter".into()]
} }
} }
} }
@ -375,32 +391,60 @@ pub fn get_periodicals(sender: Sender<ApiMessage>) -> impl AsyncCallable {
let sender2 = sender.clone(); let sender2 = sender.clone();
move || { move || {
let (rx_curr, callback_curr) = build_comms("battery current callback send failed"); let (rx_curr, callback_curr) = build_comms("battery current callback send failed");
let (rx_charge_now, callback_charge_now) = build_comms("battery charge now callback send failed"); let (rx_charge_now, callback_charge_now) =
let (rx_charge_full, callback_charge_full) = build_comms("battery charge full callback send failed"); build_comms("battery charge now callback send failed");
let (rx_charge_power, callback_charge_power) = build_comms("battery charge power callback send failed"); let (rx_charge_full, callback_charge_full) =
build_comms("battery charge full callback send failed");
let (rx_charge_power, callback_charge_power) =
build_comms("battery charge power callback send failed");
let (rx_path, callback_path) = build_comms("general get path (periodical) send failed"); let (rx_path, callback_path) = build_comms("general get path (periodical) send failed");
let sender_locked = sender2 let sender_locked = sender2.lock().unwrap();
.lock() let curr = wait_for_response(
.unwrap(); &*sender_locked,
let curr = wait_for_response(&*sender_locked, rx_curr, rx_curr,
ApiMessage::Battery(super::handler::BatteryMessage::ReadCurrentNow(callback_curr)), "battery current"); ApiMessage::Battery(super::handler::BatteryMessage::ReadCurrentNow(
let charge_now = wait_for_response(&*sender_locked, rx_charge_now, callback_curr,
ApiMessage::Battery(super::handler::BatteryMessage::ReadChargeNow(callback_charge_now)), "battery charge now"); )),
let charge_full = wait_for_response(&*sender_locked, rx_charge_full, "battery current",
ApiMessage::Battery(super::handler::BatteryMessage::ReadChargeFull(callback_charge_full)), "battery charge full"); );
let charge_power = wait_for_response(&*sender_locked, rx_charge_power, let charge_now = wait_for_response(
ApiMessage::Battery(super::handler::BatteryMessage::ReadChargePower(callback_charge_power)), "battery charge power"); &*sender_locked,
rx_charge_now,
ApiMessage::Battery(super::handler::BatteryMessage::ReadChargeNow(
callback_charge_now,
)),
"battery charge now",
);
let charge_full = wait_for_response(
&*sender_locked,
rx_charge_full,
ApiMessage::Battery(super::handler::BatteryMessage::ReadChargeFull(
callback_charge_full,
)),
"battery charge full",
);
let charge_power = wait_for_response(
&*sender_locked,
rx_charge_power,
ApiMessage::Battery(super::handler::BatteryMessage::ReadChargePower(
callback_charge_power,
)),
"battery charge power",
);
let settings_path = wait_for_response(&*sender_locked, rx_path, let settings_path = wait_for_response(
ApiMessage::General(GeneralMessage::GetPath(callback_path)), "general get path"); &*sender_locked,
rx_path,
ApiMessage::General(GeneralMessage::GetPath(callback_path)),
"general get path",
);
vec![ vec![
super::utility::map_optional(curr), super::utility::map_optional(curr),
super::utility::map_optional(charge_now), super::utility::map_optional(charge_now),
super::utility::map_optional(charge_full), super::utility::map_optional(charge_full),
super::utility::map_optional(charge_power), super::utility::map_optional(charge_power),
super::utility::map_optional(settings_path.to_str()), super::utility::map_optional(settings_path.to_str()),
] ]
} }
@ -411,13 +455,20 @@ pub fn get_periodicals(sender: Sender<ApiMessage>) -> impl AsyncCallable {
} }
} }
fn build_comms<'a, T: Send + 'a>(msg: &'static str) -> (mpsc::Receiver<T>, Box<dyn FnOnce(T) + Send + 'a>) { fn build_comms<'a, T: Send + 'a>(
msg: &'static str,
) -> (mpsc::Receiver<T>, Box<dyn FnOnce(T) + Send + 'a>) {
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
let callback = move |t: T| tx.send(t).expect(msg); let callback = move |t: T| tx.send(t).expect(msg);
(rx, Box::new(callback)) (rx, Box::new(callback))
} }
fn wait_for_response<T>(sender: &Sender<ApiMessage>, rx: mpsc::Receiver<T>, api_msg: ApiMessage, op: &str) -> T { fn wait_for_response<T>(
sender: &Sender<ApiMessage>,
rx: mpsc::Receiver<T>,
api_msg: ApiMessage,
op: &str,
) -> T {
sender.send(api_msg).expect(&format!("{} send failed", op)); sender.send(api_msg).expect(&format!("{} send failed", op));
rx.recv().expect(&format!("{} callback recv failed", op)) rx.recv().expect(&format!("{} callback recv failed", op))
} }
@ -429,8 +480,10 @@ pub fn get_all_variants(sender: Sender<ApiMessage>) -> impl AsyncCallable {
let sender2 = sender.clone(); let sender2 = sender.clone();
move || { move || {
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
let callback = let callback = move |variants: Vec<super::VariantInfo>| {
move |variants: Vec<super::VariantInfo>| tx.send(variants).expect("get_all_variants callback send failed"); tx.send(variants)
.expect("get_all_variants callback send failed")
};
sender2 sender2
.lock() .lock()
.unwrap() .unwrap()
@ -438,7 +491,9 @@ pub fn get_all_variants(sender: Sender<ApiMessage>) -> impl AsyncCallable {
Box::new(callback), Box::new(callback),
))) )))
.expect("get_all_variants send failed"); .expect("get_all_variants send failed");
rx.recv().expect("get_all_variants callback recv failed") let mut results = rx.recv().expect("get_all_variants callback recv failed");
results.sort_by_key(|info| info.id_num); // sort by variant id
results
} }
}; };
super::async_utils::AsyncIshGetter { super::async_utils::AsyncIshGetter {
@ -446,7 +501,10 @@ pub fn get_all_variants(sender: Sender<ApiMessage>) -> impl AsyncCallable {
trans_getter: |result| { trans_getter: |result| {
let mut output = Vec::with_capacity(result.len()); let mut output = Vec::with_capacity(result.len());
for status in result.iter() { for status in result.iter() {
output.push(Primitive::Json(serde_json::to_string(status).expect("Failed to serialize variant info to JSON"))); output.push(Primitive::Json(
serde_json::to_string(status)
.expect("Failed to serialize variant info to JSON"),
));
} }
output output
}, },
@ -460,8 +518,10 @@ pub fn get_current_variant(sender: Sender<ApiMessage>) -> impl AsyncCallable {
let sender2 = sender.clone(); let sender2 = sender.clone();
move || { move || {
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
let callback = let callback = move |variant: super::VariantInfo| {
move |variant: super::VariantInfo| tx.send(variant).expect("get_all_variants callback send failed"); tx.send(variant)
.expect("get_all_variants callback send failed")
};
sender2 sender2
.lock() .lock()
.unwrap() .unwrap()
@ -475,7 +535,9 @@ pub fn get_current_variant(sender: Sender<ApiMessage>) -> impl AsyncCallable {
super::async_utils::AsyncIshGetter { super::async_utils::AsyncIshGetter {
set_get: getter, set_get: getter,
trans_getter: |result| { trans_getter: |result| {
vec![Primitive::Json(serde_json::to_string(&result).expect("Failed to serialize variant info to JSON"))] vec![Primitive::Json(
serde_json::to_string(&result).expect("Failed to serialize variant info to JSON"),
)]
}, },
} }
} }

View file

@ -66,7 +66,10 @@ impl BatteryMessage {
/// Message instructs the driver to modify settings /// Message instructs the driver to modify settings
fn is_modify(&self) -> bool { fn is_modify(&self) -> bool {
matches!(self, Self::SetChargeRate(_) | Self::SetChargeMode(_) | Self::SetChargeLimit(_)) matches!(
self,
Self::SetChargeRate(_) | Self::SetChargeMode(_) | Self::SetChargeLimit(_)
)
} }
} }
@ -231,7 +234,10 @@ pub enum GeneralMessage {
GetPath(Callback<std::path::PathBuf>), GetPath(Callback<std::path::PathBuf>),
GetCurrentVariant(Callback<super::VariantInfo>), GetCurrentVariant(Callback<super::VariantInfo>),
GetAllVariants(Callback<Vec<super::VariantInfo>>), GetAllVariants(Callback<Vec<super::VariantInfo>>),
AddVariant(crate::persist::SettingsJson, Callback<Vec<super::VariantInfo>>), AddVariant(
crate::persist::SettingsJson,
Callback<Vec<super::VariantInfo>>,
),
ApplyNow, ApplyNow,
} }
@ -248,11 +254,14 @@ impl GeneralMessage {
Self::AddVariant(variant, cb) => match settings.add_variant(variant) { Self::AddVariant(variant, cb) => match settings.add_variant(variant) {
Ok(variants) => cb(variants), Ok(variants) => cb(variants),
Err(e) => { Err(e) => {
print_errors("GeneralMessage::AddVariant => TGeneral::add_variant", vec![e]); print_errors(
"GeneralMessage::AddVariant => TGeneral::add_variant",
vec![e],
);
cb(Vec::with_capacity(0)) cb(Vec::with_capacity(0))
}, }
}, },
Self::ApplyNow => {}, Self::ApplyNow => {}
} }
dirty dirty
} }
@ -300,13 +309,21 @@ impl ApiMessageHandler {
// save // save
log::debug!("api_worker is saving..."); log::debug!("api_worker is saving...");
let is_persistent = *settings.general.persistent(); let is_persistent = *settings.general.persistent();
let save_path = let save_path = crate::utility::settings_dir().join(settings.general.get_path());
crate::utility::settings_dir().join(settings.general.get_path());
if is_persistent { if is_persistent {
let settings_clone = settings.json(); let settings_clone = settings.json();
let save_json: SettingsJson = settings_clone.into(); let save_json: SettingsJson = settings_clone.into();
if let Err(e) = crate::persist::FileJson::update_variant_or_create(&save_path, settings.general.get_app_id(), save_json, settings.general.get_name().to_owned()) { if let Err(e) = crate::persist::FileJson::update_variant_or_create(
log::error!("Failed to create/update settings file {}: {}", save_path.display(), e); &save_path,
settings.general.get_app_id(),
save_json,
settings.general.get_name().to_owned(),
) {
log::error!(
"Failed to create/update settings file {}: {}",
save_path.display(),
e
);
} }
//unwrap_maybe_fatal(save_json.save(&save_path), "Failed to save settings"); //unwrap_maybe_fatal(save_json.save(&save_path), "Failed to save settings");
log::debug!("Saved settings to {}", save_path.display()); log::debug!("Saved settings to {}", save_path.display());
@ -393,8 +410,15 @@ impl ApiMessageHandler {
ApiMessage::LoadVariant(variant_id, variant_name) => { ApiMessage::LoadVariant(variant_id, variant_name) => {
let path = settings.general.get_path(); let path = settings.general.get_path();
let app_id = settings.general.get_app_id(); let app_id = settings.general.get_app_id();
match settings.load_file(path.into(), app_id, settings.general.get_name().to_owned(), variant_id, variant_name, false) { match settings.load_file(
Ok(success) => log::info!("Loaded settings file? {}", success), path.into(),
app_id,
settings.general.get_name().to_owned(),
variant_id,
variant_name,
false,
) {
Ok(success) => log::info!("Loaded variant settings file? {}", success),
Err(e) => log::warn!("Load file err: {}", e), Err(e) => log::warn!("Load file err: {}", e),
} }
true true
@ -414,7 +438,11 @@ impl ApiMessageHandler {
true true
} }
ApiMessage::LoadSystemSettings => { ApiMessage::LoadSystemSettings => {
settings.load_system_default(settings.general.get_name().to_owned(), settings.general.get_variant_id(), settings.general.get_variant_info().name); settings.load_system_default(
settings.general.get_name().to_owned(),
settings.general.get_variant_id(),
settings.general.get_variant_info().name,
);
true true
} }
ApiMessage::GetLimits(cb) => { ApiMessage::GetLimits(cb) => {
@ -434,13 +462,18 @@ impl ApiMessageHandler {
_ => settings.general.provider(), _ => settings.general.provider(),
}); });
false false
}, }
ApiMessage::UploadCurrentVariant(steam_id, steam_username) => { ApiMessage::UploadCurrentVariant(steam_id, steam_username) => {
//TODO //TODO
let steam_app_id = settings.general.get_app_id(); let steam_app_id = settings.general.get_app_id();
super::web::upload_settings(steam_app_id, steam_id, steam_username, settings.json()); super::web::upload_settings(
steam_app_id,
steam_id,
steam_username,
settings.json(),
);
false false
}, }
} }
} }

View file

@ -1,14 +1,17 @@
use std::sync::{atomic::{AtomicU64, Ordering}, Arc}; use std::sync::{
atomic::{AtomicU64, Ordering},
Arc,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use usdpl_back::AsyncCallable;
use usdpl_back::core::serdes::Primitive; use usdpl_back::core::serdes::Primitive;
use usdpl_back::AsyncCallable;
use limits_core::json::DeveloperMessage; use limits_core::json::DeveloperMessage;
use crate::MESSAGE_SEEN_ID_FILE;
use crate::utility::settings_dir; use crate::utility::settings_dir;
use crate::MESSAGE_SEEN_ID_FILE;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct ApiMessage { pub struct ApiMessage {
@ -34,7 +37,10 @@ impl std::convert::From<DeveloperMessage> for ApiMessage {
} }
fn get_dev_messages() -> Vec<ApiMessage> { fn get_dev_messages() -> Vec<ApiMessage> {
crate::settings::get_dev_messages().drain(..).map(|msg| ApiMessage::from(msg)).collect() crate::settings::get_dev_messages()
.drain(..)
.map(|msg| ApiMessage::from(msg))
.collect()
} }
pub struct MessageHandler { pub struct MessageHandler {
@ -43,8 +49,12 @@ pub struct MessageHandler {
impl MessageHandler { impl MessageHandler {
pub fn new() -> Self { pub fn new() -> Self {
let last_seen_id = if let Ok(last_seen_id_bytes) = std::fs::read(settings_dir().join(MESSAGE_SEEN_ID_FILE)) { let last_seen_id = if let Ok(last_seen_id_bytes) =
if last_seen_id_bytes.len() >= 8 /* bytes in u64 */ { std::fs::read(settings_dir().join(MESSAGE_SEEN_ID_FILE))
{
if last_seen_id_bytes.len() >= 8
/* bytes in u64 */
{
u64::from_le_bytes([ u64::from_le_bytes([
last_seen_id_bytes[0], last_seen_id_bytes[0],
last_seen_id_bytes[1], last_seen_id_bytes[1],
@ -73,7 +83,7 @@ impl MessageHandler {
}, },
AsyncMessageDismisser { AsyncMessageDismisser {
seen: self.seen.clone(), seen: self.seen.clone(),
} },
) )
} }
} }
@ -83,8 +93,17 @@ pub struct AsyncMessageGetter {
} }
impl AsyncMessageGetter { impl AsyncMessageGetter {
fn remove_before_id(id: u64, messages: impl Iterator<Item=ApiMessage>) -> impl Iterator<Item=ApiMessage> { fn remove_before_id(
messages.skip_while(move |msg| if let Some(msg_id) = msg.id { msg_id <= id } else { true }) id: u64,
messages: impl Iterator<Item = ApiMessage>,
) -> impl Iterator<Item = ApiMessage> {
messages.skip_while(move |msg| {
if let Some(msg_id) = msg.id {
msg_id <= id
} else {
true
}
})
} }
} }

View file

@ -14,12 +14,17 @@ pub fn search_by_app_id() -> impl AsyncCallable {
let req_url = format!("{}/api/setting/by_app_id/{}", BASE_URL, steam_app_id); let req_url = format!("{}/api/setting/by_app_id/{}", BASE_URL, steam_app_id);
match ureq::get(&req_url).call() { match ureq::get(&req_url).call() {
Ok(response) => { Ok(response) => {
let json_res: std::io::Result<Vec<community_settings_core::v1::Metadata>> = response.into_json(); let json_res: std::io::Result<Vec<community_settings_core::v1::Metadata>> =
response.into_json();
match json_res { match json_res {
Ok(search_results) => { Ok(search_results) => {
// search results may be quite large, so let's do the JSON string conversion in the background (blocking) thread // search results may be quite large, so let's do the JSON string conversion in the background (blocking) thread
match serde_json::to_string(&search_results) { match serde_json::to_string(&search_results) {
Err(e) => log::error!("Cannot convert search results from `{}` to JSON: {}", req_url, e), Err(e) => log::error!(
"Cannot convert search results from `{}` to JSON: {}",
req_url,
e
),
Ok(s) => return s, Ok(s) => return s,
} }
} }
@ -46,41 +51,58 @@ pub fn search_by_app_id() -> impl AsyncCallable {
} }
} }
fn web_config_to_settings_json(meta: community_settings_core::v1::Metadata) -> crate::persist::SettingsJson { fn web_config_to_settings_json(
meta: community_settings_core::v1::Metadata,
) -> crate::persist::SettingsJson {
crate::persist::SettingsJson { crate::persist::SettingsJson {
version: crate::persist::LATEST_VERSION, version: crate::persist::LATEST_VERSION,
name: meta.name, name: meta.name,
variant: u64::MAX, // TODO maybe change this to use the 64 low bits of id (u64::MAX will cause it to generate a new id when added to file variant map variant: u64::MAX, // TODO maybe change this to use the 64 low bits of id (u64::MAX will cause it to generate a new id when added to file variant map
persistent: true, persistent: true,
cpus: meta.config.cpus.into_iter().map(|cpu| crate::persist::CpuJson { cpus: meta
online: cpu.online, .config
clock_limits: cpu.clock_limits.map(|lim| crate::persist::MinMaxJson { .cpus
min: lim.min, .into_iter()
max: lim.max, .map(|cpu| crate::persist::CpuJson {
}), online: cpu.online,
governor: cpu.governor, clock_limits: cpu.clock_limits.map(|lim| crate::persist::MinMaxJson {
root: None, min: lim.min,
}).collect(), max: lim.max,
}),
governor: cpu.governor,
root: None,
})
.collect(),
gpu: crate::persist::GpuJson { gpu: crate::persist::GpuJson {
fast_ppt: meta.config.gpu.fast_ppt, fast_ppt: meta.config.gpu.fast_ppt,
slow_ppt: meta.config.gpu.slow_ppt, slow_ppt: meta.config.gpu.slow_ppt,
tdp: meta.config.gpu.tdp, tdp: meta.config.gpu.tdp,
tdp_boost: meta.config.gpu.tdp_boost, tdp_boost: meta.config.gpu.tdp_boost,
clock_limits: meta.config.gpu.clock_limits.map(|lim| crate::persist::MinMaxJson { clock_limits: meta
min: lim.min, .config
max: lim.max, .gpu
}), .clock_limits
.map(|lim| crate::persist::MinMaxJson {
min: lim.min,
max: lim.max,
}),
memory_clock: meta.config.gpu.memory_clock, memory_clock: meta.config.gpu.memory_clock,
root: None, root: None,
}, },
battery: crate::persist::BatteryJson { battery: crate::persist::BatteryJson {
charge_rate: meta.config.battery.charge_rate, charge_rate: meta.config.battery.charge_rate,
charge_mode: meta.config.battery.charge_mode, charge_mode: meta.config.battery.charge_mode,
events: meta.config.battery.events.into_iter().map(|be| crate::persist::BatteryEventJson { events: meta
charge_rate: be.charge_rate, .config
charge_mode: be.charge_mode, .battery
trigger: be.trigger, .events
}).collect(), .into_iter()
.map(|be| crate::persist::BatteryEventJson {
charge_rate: be.charge_rate,
charge_mode: be.charge_mode,
trigger: be.trigger,
})
.collect(),
root: None, root: None,
}, },
provider: Some(crate::persist::DriverJson::AutoDetect), provider: Some(crate::persist::DriverJson::AutoDetect),
@ -89,20 +111,33 @@ fn web_config_to_settings_json(meta: community_settings_core::v1::Metadata) -> c
fn download_config(id: u128) -> std::io::Result<community_settings_core::v1::Metadata> { fn download_config(id: u128) -> std::io::Result<community_settings_core::v1::Metadata> {
let req_url = format!("{}/api/setting/by_id/{}", BASE_URL, id); let req_url = format!("{}/api/setting/by_id/{}", BASE_URL, id);
let response = ureq::get(&req_url).call() let response = ureq::get(&req_url).call().map_err(|e| {
.map_err(|e| { log::warn!("GET to {} failed: {}", req_url, e);
log::warn!("GET to {} failed: {}", req_url, e); std::io::Error::new(std::io::ErrorKind::ConnectionAborted, e)
std::io::Error::new(std::io::ErrorKind::ConnectionAborted, e) })?;
})?;
response.into_json() response.into_json()
} }
pub fn upload_settings(id: u64, user_id: String, username: String, settings: crate::persist::SettingsJson) { pub fn upload_settings(
log::info!("Uploading settings {} by {} ({})", settings.name, username, user_id); id: u64,
user_id: String,
username: String,
settings: crate::persist::SettingsJson,
) {
log::info!(
"Uploading settings {} by {} ({})",
settings.name,
username,
user_id
);
let user_id: u64 = match user_id.parse() { let user_id: u64 = match user_id.parse() {
Ok(id) => id, Ok(id) => id,
Err(e) => { Err(e) => {
log::error!("Failed to parse `{}` as u64: {} (aborted upload_settings very early)", user_id, e); log::error!(
"Failed to parse `{}` as u64: {} (aborted upload_settings very early)",
user_id,
e
);
return; return;
} }
}; };
@ -112,7 +147,12 @@ pub fn upload_settings(id: u64, user_id: String, username: String, settings: cra
} }
} }
fn settings_to_web_config(app_id: u32, user_id: u64, username: String, settings: crate::persist::SettingsJson) -> community_settings_core::v1::Metadata { fn settings_to_web_config(
app_id: u32,
user_id: u64,
username: String,
settings: crate::persist::SettingsJson,
) -> community_settings_core::v1::Metadata {
community_settings_core::v1::Metadata { community_settings_core::v1::Metadata {
name: settings.name, name: settings.name,
steam_app_id: app_id, steam_app_id: app_id,
@ -121,33 +161,46 @@ fn settings_to_web_config(app_id: u32, user_id: u64, username: String, settings:
tags: vec!["wip".to_owned()], tags: vec!["wip".to_owned()],
id: "".to_owned(), id: "".to_owned(),
config: community_settings_core::v1::Config { config: community_settings_core::v1::Config {
cpus: settings.cpus.into_iter().map(|cpu| community_settings_core::v1::Cpu { cpus: settings
online: cpu.online, .cpus
clock_limits: cpu.clock_limits.map(|lim| community_settings_core::v1::MinMax { .into_iter()
min: lim.min, .map(|cpu| community_settings_core::v1::Cpu {
max: lim.max, online: cpu.online,
}), clock_limits: cpu
governor: cpu.governor, .clock_limits
}).collect(), .map(|lim| community_settings_core::v1::MinMax {
min: lim.min,
max: lim.max,
}),
governor: cpu.governor,
})
.collect(),
gpu: community_settings_core::v1::Gpu { gpu: community_settings_core::v1::Gpu {
fast_ppt: settings.gpu.fast_ppt, fast_ppt: settings.gpu.fast_ppt,
slow_ppt: settings.gpu.slow_ppt, slow_ppt: settings.gpu.slow_ppt,
tdp: settings.gpu.tdp, tdp: settings.gpu.tdp,
tdp_boost: settings.gpu.tdp_boost, tdp_boost: settings.gpu.tdp_boost,
clock_limits: settings.gpu.clock_limits.map(|lim| community_settings_core::v1::MinMax { clock_limits: settings.gpu.clock_limits.map(|lim| {
min: lim.min, community_settings_core::v1::MinMax {
max: lim.max, min: lim.min,
max: lim.max,
}
}), }),
memory_clock: settings.gpu.memory_clock, memory_clock: settings.gpu.memory_clock,
}, },
battery: community_settings_core::v1::Battery { battery: community_settings_core::v1::Battery {
charge_rate: settings.battery.charge_rate, charge_rate: settings.battery.charge_rate,
charge_mode: settings.battery.charge_mode, charge_mode: settings.battery.charge_mode,
events: settings.battery.events.into_iter().map(|batt_ev| community_settings_core::v1::BatteryEvent { events: settings
trigger: batt_ev.trigger, .battery
charge_rate: batt_ev.charge_rate, .events
charge_mode: batt_ev.charge_mode, .into_iter()
}).collect(), .map(|batt_ev| community_settings_core::v1::BatteryEvent {
trigger: batt_ev.trigger,
charge_rate: batt_ev.charge_rate,
charge_mode: batt_ev.charge_mode,
})
.collect(),
}, },
}, },
} }
@ -173,15 +226,20 @@ pub fn download_new_config(sender: Sender<ApiMessage>) -> impl AsyncCallable {
match download_config(id) { match download_config(id) {
Ok(meta) => { Ok(meta) => {
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
let callback = let callback = move |values: Vec<super::VariantInfo>| {
move |values: Vec<super::VariantInfo>| tx.send(values).expect("download_new_config callback send failed"); tx.send(values)
.expect("download_new_config callback send failed")
};
sender2 sender2
.lock() .lock()
.unwrap() .unwrap()
.send(ApiMessage::General(GeneralMessage::AddVariant(web_config_to_settings_json(meta), Box::new(callback)))) .send(ApiMessage::General(GeneralMessage::AddVariant(
web_config_to_settings_json(meta),
Box::new(callback),
)))
.expect("download_new_config send failed"); .expect("download_new_config send failed");
return rx.recv().expect("download_new_config callback recv failed"); return rx.recv().expect("download_new_config callback recv failed");
}, }
Err(e) => { Err(e) => {
log::error!("Invalid response from download: {}", e); log::error!("Invalid response from download: {}", e);
} }
@ -194,7 +252,10 @@ pub fn download_new_config(sender: Sender<ApiMessage>) -> impl AsyncCallable {
if let Some(Primitive::String(id)) = params.get(0) { if let Some(Primitive::String(id)) = params.get(0) {
match id.parse::<u128>() { match id.parse::<u128>() {
Ok(id) => Ok(id), Ok(id) => Ok(id),
Err(e) => Err(format!("download_new_config non-u128 string parameter 0: {} (got `{}`)", e, id)) Err(e) => Err(format!(
"download_new_config non-u128 string parameter 0: {} (got `{}`)",
e, id
)),
} }
} else { } else {
Err("download_new_config missing/invalid parameter 0".to_owned()) Err("download_new_config missing/invalid parameter 0".to_owned())
@ -204,7 +265,10 @@ pub fn download_new_config(sender: Sender<ApiMessage>) -> impl AsyncCallable {
trans_getter: |result| { trans_getter: |result| {
let mut output = Vec::with_capacity(result.len()); let mut output = Vec::with_capacity(result.len());
for status in result.iter() { for status in result.iter() {
output.push(Primitive::Json(serde_json::to_string(status).expect("Failed to serialize variant info to JSON"))); output.push(Primitive::Json(
serde_json::to_string(status)
.expect("Failed to serialize variant info to JSON"),
));
} }
output output
}, },
@ -238,8 +302,6 @@ pub fn upload_current_variant(sender: Sender<ApiMessage>) -> impl AsyncCallable
} }
}, },
set_get: getter, set_get: getter,
trans_getter: |result| { trans_getter: |result| vec![result.into()],
vec![result.into()]
},
} }
} }

View file

@ -10,5 +10,4 @@ pub const DEFAULT_SETTINGS_VARIANT_NAME: &str = "Primary";
pub const LIMITS_FILE: &str = "limits_cache.ron"; pub const LIMITS_FILE: &str = "limits_cache.ron";
pub const LIMITS_OVERRIDE_FILE: &str = "limits_override.ron"; pub const LIMITS_OVERRIDE_FILE: &str = "limits_override.ron";
pub const MESSAGE_SEEN_ID_FILE: &str = "seen_message.bin"; pub const MESSAGE_SEEN_ID_FILE: &str = "seen_message.bin";

View file

@ -76,14 +76,29 @@ fn main() -> Result<(), ()> {
let mut loaded_settings = let mut loaded_settings =
persist::FileJson::open(utility::settings_dir().join(DEFAULT_SETTINGS_FILE)) persist::FileJson::open(utility::settings_dir().join(DEFAULT_SETTINGS_FILE))
.map(|mut file| file.variants.remove(&0) .map(|mut file| {
.map(|settings| settings::Settings::from_json(DEFAULT_SETTINGS_NAME.into(), settings, DEFAULT_SETTINGS_FILE.into(), 0)) let mut keys: Vec<u64> = file.variants.keys().map(|x| *x).collect();
.unwrap_or_else(|| settings::Settings::system_default( keys.sort();
DEFAULT_SETTINGS_FILE.into(), keys.get(0)
0, .and_then(|id| file.variants.remove(id))
DEFAULT_SETTINGS_NAME.into(), .map(|settings| {
0, settings::Settings::from_json(
DEFAULT_SETTINGS_VARIANT_NAME.into()))) DEFAULT_SETTINGS_NAME.into(),
settings,
DEFAULT_SETTINGS_FILE.into(),
0,
)
})
.unwrap_or_else(|| {
settings::Settings::system_default(
DEFAULT_SETTINGS_FILE.into(),
0,
DEFAULT_SETTINGS_NAME.into(),
0,
DEFAULT_SETTINGS_VARIANT_NAME.into(),
)
})
})
.unwrap_or_else(|_| { .unwrap_or_else(|_| {
settings::Settings::system_default( settings::Settings::system_default(
DEFAULT_SETTINGS_FILE.into(), DEFAULT_SETTINGS_FILE.into(),
@ -96,7 +111,8 @@ fn main() -> Result<(), ()> {
log::info!( log::info!(
"Detected device automatically {:?}, using driver: {:?} (This can be overriden)", "Detected device automatically {:?}, using driver: {:?} (This can be overriden)",
crate::settings::auto_detect_provider(), loaded_settings.cpus.provider() crate::settings::auto_detect_provider(),
loaded_settings.cpus.provider()
); );
log::debug!("Settings: {:?}", loaded_settings); log::debug!("Settings: {:?}", loaded_settings);
@ -307,29 +323,26 @@ fn main() -> Result<(), ()> {
) )
.register_async( .register_async(
"GENERAL_get_periodicals", "GENERAL_get_periodicals",
api::general::get_periodicals(api_sender.clone()) api::general::get_periodicals(api_sender.clone()),
) )
.register_async( .register_async(
"GENERAL_get_all_variants", "GENERAL_get_all_variants",
api::general::get_all_variants(api_sender.clone()) api::general::get_all_variants(api_sender.clone()),
) )
.register_async( .register_async(
"GENERAL_get_current_variant", "GENERAL_get_current_variant",
api::general::get_current_variant(api_sender.clone()) api::general::get_current_variant(api_sender.clone()),
) )
.register_async("MESSAGE_get", message_getter) .register_async("MESSAGE_get", message_getter)
.register_async("MESSAGE_dismiss", message_dismisser) .register_async("MESSAGE_dismiss", message_dismisser)
.register_async( .register_async("WEB_search_by_app", api::web::search_by_app_id())
"WEB_search_by_app",
api::web::search_by_app_id()
)
.register_async( .register_async(
"WEB_download_new", "WEB_download_new",
api::web::download_new_config(api_sender.clone()) api::web::download_new_config(api_sender.clone()),
) )
.register_async( .register_async(
"WEB_upload_new", "WEB_upload_new",
api::web::upload_current_variant(api_sender.clone()) api::web::upload_current_variant(api_sender.clone()),
); );
utility::ioperm_power_ec(); utility::ioperm_power_ec();

View file

@ -22,7 +22,8 @@ impl FileJson {
std::fs::create_dir_all(parent).map_err(SerdeError::Io)?; std::fs::create_dir_all(parent).map_err(SerdeError::Io)?;
} }
let mut file = std::fs::File::create(path).map_err(SerdeError::Io)?; let mut file = std::fs::File::create(path).map_err(SerdeError::Io)?;
ron::ser::to_writer_pretty(&mut file, &self, crate::utility::ron_pretty_config()).map_err(|e| SerdeError::Serde(e.into())) ron::ser::to_writer_pretty(&mut file, &self, crate::utility::ron_pretty_config())
.map_err(|e| SerdeError::Serde(e.into()))
} else { } else {
if path.exists() { if path.exists() {
// remove settings file when persistence is turned off, to prevent it from be loaded next time. // remove settings file when persistence is turned off, to prevent it from be loaded next time.
@ -39,37 +40,61 @@ impl FileJson {
} }
fn next_available_id(&self) -> u64 { fn next_available_id(&self) -> u64 {
self.variants.keys() self.variants.keys().max().map(|k| k + 1).unwrap_or(0)
.max()
.map(|k| k+1)
.unwrap_or(0)
} }
pub fn update_variant_or_create<P: AsRef<std::path::Path>>(path: P, app_id: u64, mut setting: SettingsJson, given_name: String) -> Result<Self, SerdeError> { pub fn update_variant_or_create<P: AsRef<std::path::Path>>(
if !setting.persistent { path: P,
return Self::open(path) app_id: u64,
} mut setting: SettingsJson,
app_name: String,
) -> Result<(Self, SettingsJson), SerdeError> {
// returns (Self, updated/created variant id)
let path = path.as_ref(); let path = path.as_ref();
if !setting.persistent {
let file = if path.exists() {
let mut file = Self::open(path)?; let mut file = Self::open(path)?;
if file.variants.contains_key(&setting.variant) {
file.variants.remove(&setting.variant);
file.save(path)?;
}
return Ok((file, setting));
}
let (file, variant_id) = if path.exists() {
let mut file = Self::open(path)?;
// Generate new (available) id if max
if setting.variant == u64::MAX { if setting.variant == u64::MAX {
setting.variant = file.next_available_id(); setting.variant = file.next_available_id();
} }
file.variants.insert(setting.variant, setting); // Generate new name if empty
file if setting.name.is_empty() {
setting.name = format!("Variant {}", setting.variant);
}
log::debug!("Inserting setting variant `{}` ({}) for app `{}` ({})", setting.name, setting.variant, file.name, app_id);
file.variants.insert(setting.variant, setting.clone());
(file, setting)
} else { } else {
// Generate new id if max
if setting.variant == u64::MAX {
setting.variant = 1;
}
// Generate new name if empty
if setting.name.is_empty() {
setting.name = format!("Variant {}", setting.variant);
}
log::debug!("Creating new setting variant `{}` ({}) for app `{}` ({})", setting.name, setting.variant, app_name, app_id);
let mut setting_variants = HashMap::with_capacity(1); let mut setting_variants = HashMap::with_capacity(1);
setting_variants.insert(setting.variant, setting); setting_variants.insert(setting.variant, setting.clone());
Self { (Self {
version: 0, version: 0,
app_id: app_id, app_id: app_id,
name: given_name, name: app_name,
variants: setting_variants, variants: setting_variants,
} }, setting)
}; };
file.save(path)?; file.save(path)?;
Ok(file) Ok((file, variant_id))
} }
} }

View file

@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
use super::{BatteryJson, CpuJson, DriverJson, GpuJson}; use super::{BatteryJson, CpuJson, DriverJson, GpuJson};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Clone)]
pub struct SettingsJson { pub struct SettingsJson {
pub version: u64, pub version: u64,
pub name: String, pub name: String,

View file

@ -5,7 +5,7 @@ use regex::RegexBuilder;
use limits_core::json_v2::{BatteryLimitType, CpuLimitType, GpuLimitType, Limits}; use limits_core::json_v2::{BatteryLimitType, CpuLimitType, GpuLimitType, Limits};
use crate::persist::{DriverJson, SettingsJson}; use crate::persist::{DriverJson, SettingsJson};
use crate::settings::{Driver, General, TBattery, TCpus, TGeneral, TGpu, ProviderBuilder}; use crate::settings::{Driver, General, ProviderBuilder, TBattery, TCpus, TGeneral, TGpu};
fn get_limits() -> limits_core::json_v2::Base { fn get_limits() -> limits_core::json_v2::Base {
let limits_path = super::utility::limits_path(); let limits_path = super::utility::limits_path();
@ -151,20 +151,22 @@ pub fn auto_detect0(
if let Some(settings) = &settings_opt { if let Some(settings) = &settings_opt {
*general_driver.persistent() = true; *general_driver.persistent() = true;
let cpu_driver: Box<dyn TCpus> = match relevant_limits.cpu.provider { let cpu_driver: Box<dyn TCpus> = match relevant_limits.cpu.provider {
CpuLimitType::SteamDeck => { CpuLimitType::SteamDeck => Box::new(
Box::new(crate::settings::steam_deck::Cpus::from_json_and_limits( crate::settings::steam_deck::Cpus::from_json_and_limits(
settings.cpus.clone(), settings.cpus.clone(),
settings.version, settings.version,
relevant_limits.cpu.limits, relevant_limits.cpu.limits,
).variant(super::super::steam_deck::Model::LCD)) )
} .variant(super::super::steam_deck::Model::LCD),
CpuLimitType::SteamDeckOLED => { ),
Box::new(crate::settings::steam_deck::Cpus::from_json_and_limits( CpuLimitType::SteamDeckOLED => Box::new(
crate::settings::steam_deck::Cpus::from_json_and_limits(
settings.cpus.clone(), settings.cpus.clone(),
settings.version, settings.version,
relevant_limits.cpu.limits, relevant_limits.cpu.limits,
).variant(super::super::steam_deck::Model::OLED)) )
} .variant(super::super::steam_deck::Model::OLED),
),
CpuLimitType::Generic => Box::new(crate::settings::generic::Cpus::< CpuLimitType::Generic => Box::new(crate::settings::generic::Cpus::<
crate::settings::generic::Cpu, crate::settings::generic::Cpu,
>::from_json_and_limits( >::from_json_and_limits(
@ -172,20 +174,20 @@ pub fn auto_detect0(
settings.version, settings.version,
relevant_limits.cpu.limits, relevant_limits.cpu.limits,
)), )),
CpuLimitType::GenericAMD => Box::new( CpuLimitType::GenericAMD => {
crate::settings::generic_amd::Cpus::from_json_and_limits( Box::new(crate::settings::generic_amd::Cpus::from_json_and_limits(
settings.cpus.clone(), settings.cpus.clone(),
settings.version, settings.version,
relevant_limits.cpu.limits, relevant_limits.cpu.limits,
), ))
), }
CpuLimitType::Unknown => { CpuLimitType::Unknown => {
Box::new(crate::settings::unknown::Cpus::from_json_and_limits( Box::new(crate::settings::unknown::Cpus::from_json_and_limits(
settings.cpus.clone(), settings.cpus.clone(),
settings.version, settings.version,
relevant_limits.cpu.limits, relevant_limits.cpu.limits,
)) ))
}, }
CpuLimitType::DevMode => { CpuLimitType::DevMode => {
Box::new(crate::settings::dev_mode::Cpus::from_json_and_limits( Box::new(crate::settings::dev_mode::Cpus::from_json_and_limits(
settings.cpus.clone(), settings.cpus.clone(),
@ -196,20 +198,22 @@ pub fn auto_detect0(
}; };
let gpu_driver: Box<dyn TGpu> = match relevant_limits.gpu.provider { let gpu_driver: Box<dyn TGpu> = match relevant_limits.gpu.provider {
GpuLimitType::SteamDeck => { GpuLimitType::SteamDeck => Box::new(
Box::new(crate::settings::steam_deck::Gpu::from_json_and_limits( crate::settings::steam_deck::Gpu::from_json_and_limits(
settings.gpu.clone(), settings.gpu.clone(),
settings.version, settings.version,
relevant_limits.gpu.limits, relevant_limits.gpu.limits,
).variant(super::super::steam_deck::Model::LCD)) )
} .variant(super::super::steam_deck::Model::LCD),
GpuLimitType::SteamDeckOLED => { ),
Box::new(crate::settings::steam_deck::Gpu::from_json_and_limits( GpuLimitType::SteamDeckOLED => Box::new(
crate::settings::steam_deck::Gpu::from_json_and_limits(
settings.gpu.clone(), settings.gpu.clone(),
settings.version, settings.version,
relevant_limits.gpu.limits, relevant_limits.gpu.limits,
).variant(super::super::steam_deck::Model::OLED)) )
} .variant(super::super::steam_deck::Model::OLED),
),
GpuLimitType::Generic => { GpuLimitType::Generic => {
Box::new(crate::settings::generic::Gpu::from_json_and_limits( Box::new(crate::settings::generic::Gpu::from_json_and_limits(
settings.gpu.clone(), settings.gpu.clone(),
@ -217,20 +221,20 @@ pub fn auto_detect0(
relevant_limits.gpu.limits, relevant_limits.gpu.limits,
)) ))
} }
GpuLimitType::GenericAMD => Box::new( GpuLimitType::GenericAMD => {
crate::settings::generic_amd::Gpu::from_json_and_limits( Box::new(crate::settings::generic_amd::Gpu::from_json_and_limits(
settings.gpu.clone(), settings.gpu.clone(),
settings.version, settings.version,
relevant_limits.gpu.limits, relevant_limits.gpu.limits,
), ))
), }
GpuLimitType::Unknown => { GpuLimitType::Unknown => {
Box::new(crate::settings::unknown::Gpu::from_json_and_limits( Box::new(crate::settings::unknown::Gpu::from_json_and_limits(
settings.gpu.clone(), settings.gpu.clone(),
settings.version, settings.version,
relevant_limits.gpu.limits, relevant_limits.gpu.limits,
)) ))
}, }
GpuLimitType::DevMode => { GpuLimitType::DevMode => {
Box::new(crate::settings::dev_mode::Gpu::from_json_and_limits( Box::new(crate::settings::dev_mode::Gpu::from_json_and_limits(
settings.gpu.clone(), settings.gpu.clone(),
@ -240,34 +244,36 @@ pub fn auto_detect0(
} }
}; };
let battery_driver: Box<dyn TBattery> = match relevant_limits.battery.provider { let battery_driver: Box<dyn TBattery> = match relevant_limits.battery.provider {
BatteryLimitType::SteamDeck => { BatteryLimitType::SteamDeck => Box::new(
Box::new(crate::settings::steam_deck::Battery::from_json_and_limits( crate::settings::steam_deck::Battery::from_json_and_limits(
settings.battery.clone(), settings.battery.clone(),
settings.version, settings.version,
relevant_limits.battery.limits, relevant_limits.battery.limits,
).variant(super::super::steam_deck::Model::LCD)) )
} .variant(super::super::steam_deck::Model::LCD),
BatteryLimitType::SteamDeckOLED => {
Box::new(crate::settings::steam_deck::Battery::from_json_and_limits(
settings.battery.clone(),
settings.version,
relevant_limits.battery.limits,
).variant(super::super::steam_deck::Model::OLED))
}
BatteryLimitType::Generic => Box::new(
crate::settings::generic::Battery::from_json_and_limits(
settings.battery.clone(),
settings.version,
relevant_limits.battery.limits,
),
), ),
BatteryLimitType::SteamDeckOLED => Box::new(
crate::settings::steam_deck::Battery::from_json_and_limits(
settings.battery.clone(),
settings.version,
relevant_limits.battery.limits,
)
.variant(super::super::steam_deck::Model::OLED),
),
BatteryLimitType::Generic => {
Box::new(crate::settings::generic::Battery::from_json_and_limits(
settings.battery.clone(),
settings.version,
relevant_limits.battery.limits,
))
}
BatteryLimitType::Unknown => { BatteryLimitType::Unknown => {
Box::new(crate::settings::unknown::Battery::from_json_and_limits( Box::new(crate::settings::unknown::Battery::from_json_and_limits(
settings.battery.clone(), settings.battery.clone(),
settings.version, settings.version,
relevant_limits.battery.limits, relevant_limits.battery.limits,
)) ))
}, }
BatteryLimitType::DevMode => { BatteryLimitType::DevMode => {
Box::new(crate::settings::dev_mode::Battery::from_json_and_limits( Box::new(crate::settings::dev_mode::Battery::from_json_and_limits(
settings.battery.clone(), settings.battery.clone(),
@ -285,62 +291,78 @@ pub fn auto_detect0(
}; };
} else { } else {
let cpu_driver: Box<dyn TCpus> = match relevant_limits.cpu.provider { let cpu_driver: Box<dyn TCpus> = match relevant_limits.cpu.provider {
CpuLimitType::SteamDeck => { CpuLimitType::SteamDeck => Box::new(
Box::new(crate::settings::steam_deck::Cpus::from_limits(relevant_limits.cpu.limits).variant(super::super::steam_deck::Model::LCD)) crate::settings::steam_deck::Cpus::from_limits(relevant_limits.cpu.limits)
} .variant(super::super::steam_deck::Model::LCD),
CpuLimitType::SteamDeckOLED => { ),
Box::new(crate::settings::steam_deck::Cpus::from_limits(relevant_limits.cpu.limits).variant(super::super::steam_deck::Model::OLED)) CpuLimitType::SteamDeckOLED => Box::new(
} crate::settings::steam_deck::Cpus::from_limits(relevant_limits.cpu.limits)
CpuLimitType::Generic => { .variant(super::super::steam_deck::Model::OLED),
Box::new(crate::settings::generic::Cpus::< ),
crate::settings::generic::Cpu, CpuLimitType::Generic => Box::new(crate::settings::generic::Cpus::<
>::from_limits(relevant_limits.cpu.limits)) crate::settings::generic::Cpu,
} >::from_limits(
CpuLimitType::GenericAMD => { relevant_limits.cpu.limits
Box::new(crate::settings::generic_amd::Cpus::from_limits(relevant_limits.cpu.limits)) )),
} CpuLimitType::GenericAMD => Box::new(
CpuLimitType::Unknown => { crate::settings::generic_amd::Cpus::from_limits(relevant_limits.cpu.limits),
Box::new(crate::settings::unknown::Cpus::from_limits(relevant_limits.cpu.limits)) ),
} CpuLimitType::Unknown => Box::new(crate::settings::unknown::Cpus::from_limits(
CpuLimitType::DevMode => { relevant_limits.cpu.limits,
Box::new(crate::settings::dev_mode::Cpus::from_limits(relevant_limits.cpu.limits)) )),
} CpuLimitType::DevMode => Box::new(
crate::settings::dev_mode::Cpus::from_limits(relevant_limits.cpu.limits),
),
}; };
let gpu_driver: Box<dyn TGpu> = match relevant_limits.gpu.provider { let gpu_driver: Box<dyn TGpu> = match relevant_limits.gpu.provider {
GpuLimitType::SteamDeck => { GpuLimitType::SteamDeck => Box::new(
Box::new(crate::settings::steam_deck::Gpu::from_limits(relevant_limits.gpu.limits).variant(super::super::steam_deck::Model::LCD)) crate::settings::steam_deck::Gpu::from_limits(relevant_limits.gpu.limits)
} .variant(super::super::steam_deck::Model::LCD),
GpuLimitType::SteamDeckOLED => { ),
Box::new(crate::settings::steam_deck::Gpu::from_limits(relevant_limits.gpu.limits).variant(super::super::steam_deck::Model::OLED)) GpuLimitType::SteamDeckOLED => Box::new(
} crate::settings::steam_deck::Gpu::from_limits(relevant_limits.gpu.limits)
GpuLimitType::Generic => { .variant(super::super::steam_deck::Model::OLED),
Box::new(crate::settings::generic::Gpu::from_limits(relevant_limits.gpu.limits)) ),
} GpuLimitType::Generic => Box::new(crate::settings::generic::Gpu::from_limits(
GpuLimitType::GenericAMD => { relevant_limits.gpu.limits,
Box::new(crate::settings::generic_amd::Gpu::from_limits(relevant_limits.gpu.limits)) )),
} GpuLimitType::GenericAMD => Box::new(
GpuLimitType::Unknown => { crate::settings::generic_amd::Gpu::from_limits(relevant_limits.gpu.limits),
Box::new(crate::settings::unknown::Gpu::from_limits(relevant_limits.gpu.limits)) ),
} GpuLimitType::Unknown => Box::new(crate::settings::unknown::Gpu::from_limits(
GpuLimitType::DevMode => { relevant_limits.gpu.limits,
Box::new(crate::settings::dev_mode::Gpu::from_limits(relevant_limits.gpu.limits)) )),
} GpuLimitType::DevMode => Box::new(crate::settings::dev_mode::Gpu::from_limits(
relevant_limits.gpu.limits,
)),
}; };
let battery_driver: Box<dyn TBattery> = match relevant_limits.battery.provider { let battery_driver: Box<dyn TBattery> = match relevant_limits.battery.provider {
BatteryLimitType::SteamDeck => { BatteryLimitType::SteamDeck => Box::new(
Box::new(crate::settings::steam_deck::Battery::from_limits(relevant_limits.battery.limits).variant(super::super::steam_deck::Model::LCD)) crate::settings::steam_deck::Battery::from_limits(
} relevant_limits.battery.limits,
BatteryLimitType::SteamDeckOLED => { )
Box::new(crate::settings::steam_deck::Battery::from_limits(relevant_limits.battery.limits).variant(super::super::steam_deck::Model::OLED)) .variant(super::super::steam_deck::Model::LCD),
} ),
BatteryLimitType::SteamDeckOLED => Box::new(
crate::settings::steam_deck::Battery::from_limits(
relevant_limits.battery.limits,
)
.variant(super::super::steam_deck::Model::OLED),
),
BatteryLimitType::Generic => { BatteryLimitType::Generic => {
Box::new(crate::settings::generic::Battery::from_limits(relevant_limits.battery.limits)) Box::new(crate::settings::generic::Battery::from_limits(
relevant_limits.battery.limits,
))
} }
BatteryLimitType::Unknown => { BatteryLimitType::Unknown => {
Box::new(crate::settings::unknown::Battery::from_limits(relevant_limits.battery.limits)) Box::new(crate::settings::unknown::Battery::from_limits(
relevant_limits.battery.limits,
))
} }
BatteryLimitType::DevMode => { BatteryLimitType::DevMode => {
Box::new(crate::settings::dev_mode::Battery::from_limits(relevant_limits.battery.limits)) Box::new(crate::settings::dev_mode::Battery::from_limits(
relevant_limits.battery.limits,
))
} }
}; };
return Driver { return Driver {

View file

@ -93,14 +93,16 @@ pub fn get_limits_cached() -> Base {
fn save_base(new_base: &Base, path: impl AsRef<std::path::Path>) { fn save_base(new_base: &Base, path: impl AsRef<std::path::Path>) {
let limits_path = path.as_ref(); let limits_path = path.as_ref();
match std::fs::File::create(&limits_path) { match std::fs::File::create(&limits_path) {
Ok(f) => match ron::ser::to_writer_pretty(f, &new_base, crate::utility::ron_pretty_config()) { Ok(f) => {
Ok(_) => log::info!("Successfully saved new limits to {}", limits_path.display()), match ron::ser::to_writer_pretty(f, &new_base, crate::utility::ron_pretty_config()) {
Err(e) => log::error!( Ok(_) => log::info!("Successfully saved new limits to {}", limits_path.display()),
"Failed to save limits json to file `{}`: {}", Err(e) => log::error!(
limits_path.display(), "Failed to save limits json to file `{}`: {}",
e limits_path.display(),
), e
}, ),
}
}
Err(e) => log::error!("Cannot create {}: {}", limits_path.display(), e), Err(e) => log::error!("Cannot create {}: {}", limits_path.display(), e),
} }
} }

View file

@ -1,4 +1,4 @@
use limits_core::json::{DeveloperMessage, Base}; use limits_core::json::{Base, DeveloperMessage};
pub fn limits_path() -> std::path::PathBuf { pub fn limits_path() -> std::path::PathBuf {
crate::utility::settings_dir().join(crate::consts::LIMITS_FILE) crate::utility::settings_dir().join(crate::consts::LIMITS_FILE)

View file

@ -3,8 +3,8 @@ use std::convert::Into;
use limits_core::json_v2::GenericBatteryLimit; use limits_core::json_v2::GenericBatteryLimit;
use crate::persist::BatteryJson; use crate::persist::BatteryJson;
use crate::settings::{TBattery, ProviderBuilder};
use crate::settings::{OnResume, OnSet, SettingError}; use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{ProviderBuilder, TBattery};
#[derive(Clone)] #[derive(Clone)]
pub struct Battery { pub struct Battery {
@ -32,7 +32,11 @@ impl Into<BatteryJson> for Battery {
} }
impl ProviderBuilder<BatteryJson, GenericBatteryLimit> for Battery { impl ProviderBuilder<BatteryJson, GenericBatteryLimit> for Battery {
fn from_json_and_limits(persist: BatteryJson, version: u64, limits: GenericBatteryLimit) -> Self { fn from_json_and_limits(
persist: BatteryJson,
version: u64,
limits: GenericBatteryLimit,
) -> Self {
Battery { Battery {
persist, persist,
version, version,
@ -43,7 +47,12 @@ impl ProviderBuilder<BatteryJson, GenericBatteryLimit> for Battery {
fn from_limits(limits: GenericBatteryLimit) -> Self { fn from_limits(limits: GenericBatteryLimit) -> Self {
Battery { Battery {
persist: BatteryJson { charge_rate: None, charge_mode: None, events: vec![], root: None }, persist: BatteryJson {
charge_rate: None,
charge_mode: None,
events: vec![],
root: None,
},
version: 0, version: 0,
limits, limits,
charge_limit: None, charge_limit: None,
@ -71,10 +80,16 @@ impl TBattery for Battery {
fn limits(&self) -> crate::api::BatteryLimits { fn limits(&self) -> crate::api::BatteryLimits {
log::debug!("dev_mode_Battery::limits(self) -> {{...}}"); log::debug!("dev_mode_Battery::limits(self) -> {{...}}");
crate::api::BatteryLimits { crate::api::BatteryLimits {
charge_current: self.limits.charge_rate.map(|lim| crate::api::RangeLimit { min: lim.min.unwrap_or(11), max: lim.max.unwrap_or(1111) }), charge_current: self.limits.charge_rate.map(|lim| crate::api::RangeLimit {
min: lim.min.unwrap_or(11),
max: lim.max.unwrap_or(1111),
}),
charge_current_step: 10, charge_current_step: 10,
charge_modes: self.limits.charge_modes.clone(), charge_modes: self.limits.charge_modes.clone(),
charge_limit: self.limits.charge_limit.map(|lim| crate::api::RangeLimit { min: lim.min.unwrap_or(2.0), max: lim.max.unwrap_or(98.0) }), charge_limit: self.limits.charge_limit.map(|lim| crate::api::RangeLimit {
min: lim.min.unwrap_or(2.0),
max: lim.max.unwrap_or(98.0),
}),
charge_limit_step: 1.0, charge_limit_step: 1.0,
} }
} }
@ -90,7 +105,10 @@ impl TBattery for Battery {
} }
fn get_charge_rate(&self) -> Option<u64> { fn get_charge_rate(&self) -> Option<u64> {
log::debug!("dev_mode_Battery::get_charge_rate(self) -> {:?}", self.persist.charge_rate); log::debug!(
"dev_mode_Battery::get_charge_rate(self) -> {:?}",
self.persist.charge_rate
);
self.persist.charge_rate self.persist.charge_rate
} }
@ -100,7 +118,10 @@ impl TBattery for Battery {
} }
fn get_charge_mode(&self) -> Option<String> { fn get_charge_mode(&self) -> Option<String> {
log::debug!("dev_mode_Battery::get_charge_mode(self) -> {:?}", self.persist.charge_mode); log::debug!(
"dev_mode_Battery::get_charge_mode(self) -> {:?}",
self.persist.charge_mode
);
self.persist.charge_mode.clone() self.persist.charge_mode.clone()
} }
@ -135,7 +156,10 @@ impl TBattery for Battery {
} }
fn get_charge_limit(&self) -> Option<f64> { fn get_charge_limit(&self) -> Option<f64> {
log::debug!("dev_mode_Battery::get_charge_limit(self) -> {:?}", self.charge_limit); log::debug!(
"dev_mode_Battery::get_charge_limit(self) -> {:?}",
self.charge_limit
);
self.charge_limit self.charge_limit
} }

View file

@ -1,11 +1,11 @@
use std::convert::Into; use std::convert::Into;
use limits_core::json_v2::{GenericCpusLimit, GenericCpuLimit}; use limits_core::json_v2::{GenericCpuLimit, GenericCpusLimit};
use crate::persist::CpuJson; use crate::persist::CpuJson;
use crate::settings::MinMax; use crate::settings::MinMax;
use crate::settings::{OnResume, OnSet, SettingError}; use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{TCpu, TCpus, ProviderBuilder}; use crate::settings::{ProviderBuilder, TCpu, TCpus};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Cpus { pub struct Cpus {
@ -40,13 +40,22 @@ impl OnResume for Cpus {
impl crate::settings::OnPowerEvent for Cpus {} impl crate::settings::OnPowerEvent for Cpus {}
impl ProviderBuilder<Vec<CpuJson>, GenericCpusLimit> for Cpus { impl ProviderBuilder<Vec<CpuJson>, GenericCpusLimit> for Cpus {
fn from_json_and_limits(persistent: Vec<CpuJson>, version: u64, limits: GenericCpusLimit) -> Self { fn from_json_and_limits(
persistent: Vec<CpuJson>,
version: u64,
limits: GenericCpusLimit,
) -> Self {
let mut cpus = Vec::with_capacity(persistent.len()); let mut cpus = Vec::with_capacity(persistent.len());
for (i, cpu) in persistent.iter().enumerate() { for (i, cpu) in persistent.iter().enumerate() {
cpus.push(Cpu::from_json_and_limits(cpu.to_owned(), version, i, limits.cpus.get(i).map(|x| x.to_owned()).unwrap_or_else(|| { cpus.push(Cpu::from_json_and_limits(
log::warn!("No cpu limit for index {}, using default", i); cpu.to_owned(),
Default::default() version,
}))); i,
limits.cpus.get(i).map(|x| x.to_owned()).unwrap_or_else(|| {
log::warn!("No cpu limit for index {}, using default", i);
Default::default()
}),
));
} }
let smt_guess = crate::settings::util::guess_smt(&persistent); let smt_guess = crate::settings::util::guess_smt(&persistent);
Self { Self {
@ -78,7 +87,12 @@ impl TCpus for Cpus {
cpus: self.cpus.iter().map(|x| x.limits()).collect(), cpus: self.cpus.iter().map(|x| x.limits()).collect(),
count: self.cpus.len(), count: self.cpus.len(),
smt_capable: true, smt_capable: true,
governors: vec!["this".to_owned(), "is".to_owned(), "dev".to_owned(), "mode".to_owned()], governors: vec![
"this".to_owned(),
"is".to_owned(),
"dev".to_owned(),
"mode".to_owned(),
],
} }
} }
@ -130,8 +144,16 @@ impl std::fmt::Debug for Cpu {
impl Cpu { impl Cpu {
#[inline] #[inline]
pub fn from_json_and_limits(other: CpuJson, version: u64, i: usize, limits: GenericCpuLimit) -> Self { pub fn from_json_and_limits(
let clock_limits = other.clock_limits.clone().map(|lim| MinMax { min: lim.min, max: lim.max }); other: CpuJson,
version: u64,
i: usize,
limits: GenericCpuLimit,
) -> Self {
let clock_limits = other.clock_limits.clone().map(|lim| MinMax {
min: lim.min,
max: lim.max,
});
match version { match version {
0 => Self { 0 => Self {
persist: other, persist: other,
@ -153,7 +175,12 @@ impl Cpu {
#[inline] #[inline]
pub fn from_limits(i: usize, limits: GenericCpuLimit) -> Self { pub fn from_limits(i: usize, limits: GenericCpuLimit) -> Self {
Self { Self {
persist: CpuJson { online: true, clock_limits: None, governor: "".to_owned(), root: None }, persist: CpuJson {
online: true,
clock_limits: None,
governor: "".to_owned(),
root: None,
},
version: 0, version: 0,
index: i, index: i,
limits, limits,
@ -163,10 +190,21 @@ impl Cpu {
fn limits(&self) -> crate::api::CpuLimits { fn limits(&self) -> crate::api::CpuLimits {
crate::api::CpuLimits { crate::api::CpuLimits {
clock_min_limits: self.limits.clock_min.map(|lim| crate::api::RangeLimit { min: lim.min.unwrap_or(1100), max: lim.max.unwrap_or(6900) }), clock_min_limits: self.limits.clock_min.map(|lim| crate::api::RangeLimit {
clock_max_limits: self.limits.clock_max.map(|lim| crate::api::RangeLimit { min: lim.min.unwrap_or(4200), max: lim.max.unwrap_or(4300) }), min: lim.min.unwrap_or(1100),
max: lim.max.unwrap_or(6900),
}),
clock_max_limits: self.limits.clock_max.map(|lim| crate::api::RangeLimit {
min: lim.min.unwrap_or(4200),
max: lim.max.unwrap_or(4300),
}),
clock_step: self.limits.clock_step.unwrap_or(11), clock_step: self.limits.clock_step.unwrap_or(11),
governors: vec!["this".to_owned(), "is".to_owned(), "dev".to_owned(), "mode".to_owned()], governors: vec![
"this".to_owned(),
"is".to_owned(),
"dev".to_owned(),
"mode".to_owned(),
],
} }
} }
} }
@ -211,11 +249,20 @@ impl TCpu for Cpu {
fn clock_limits(&mut self, limits: Option<MinMax<u64>>) { fn clock_limits(&mut self, limits: Option<MinMax<u64>>) {
log::debug!("dev_mode_Cpu::clock_limits(self, {:?})", limits); log::debug!("dev_mode_Cpu::clock_limits(self, {:?})", limits);
self.clock_limits = limits; self.clock_limits = limits;
self.persist.clock_limits = self.clock_limits.clone().map(|lim| crate::persist::MinMaxJson { max: lim.max, min: lim.min }); self.persist.clock_limits =
self.clock_limits
.clone()
.map(|lim| crate::persist::MinMaxJson {
max: lim.max,
min: lim.min,
});
} }
fn get_clock_limits(&self) -> Option<&MinMax<u64>> { fn get_clock_limits(&self) -> Option<&MinMax<u64>> {
log::debug!("dev_mode_Cpu::get_clock_limits(self) -> {:?}", self.clock_limits.as_ref()); log::debug!(
"dev_mode_Cpu::get_clock_limits(self) -> {:?}",
self.clock_limits.as_ref()
);
self.clock_limits.as_ref() self.clock_limits.as_ref()
} }
} }

View file

@ -4,8 +4,8 @@ use limits_core::json_v2::GenericGpuLimit;
use crate::persist::GpuJson; use crate::persist::GpuJson;
use crate::settings::MinMax; use crate::settings::MinMax;
use crate::settings::{TGpu, ProviderBuilder};
use crate::settings::{OnResume, OnSet, SettingError}; use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{ProviderBuilder, TGpu};
#[derive(Clone)] #[derive(Clone)]
pub struct Gpu { pub struct Gpu {
@ -27,7 +27,10 @@ impl std::fmt::Debug for Gpu {
impl ProviderBuilder<GpuJson, GenericGpuLimit> for Gpu { impl ProviderBuilder<GpuJson, GenericGpuLimit> for Gpu {
fn from_json_and_limits(persist: GpuJson, version: u64, limits: GenericGpuLimit) -> Self { fn from_json_and_limits(persist: GpuJson, version: u64, limits: GenericGpuLimit) -> Self {
let clock_limits = persist.clock_limits.clone().map(|lim| MinMax { min: lim.min, max: lim.max }); let clock_limits = persist.clock_limits.clone().map(|lim| MinMax {
min: lim.min,
max: lim.max,
});
Self { Self {
persist, persist,
version, version,
@ -83,16 +86,37 @@ impl TGpu for Gpu {
let ppt_divisor = self.limits.ppt_divisor.unwrap_or(1_000_000); let ppt_divisor = self.limits.ppt_divisor.unwrap_or(1_000_000);
let tdp_divisor = self.limits.tdp_divisor.unwrap_or(1_000_000); let tdp_divisor = self.limits.tdp_divisor.unwrap_or(1_000_000);
crate::api::GpuLimits { crate::api::GpuLimits {
fast_ppt_limits: self.limits.fast_ppt.map(|lim| crate::api::RangeLimit { min: lim.min.unwrap_or(11_000_000) / ppt_divisor, max: lim.max.unwrap_or(42_000_000) / ppt_divisor }), fast_ppt_limits: self.limits.fast_ppt.map(|lim| crate::api::RangeLimit {
slow_ppt_limits: self.limits.slow_ppt.map(|lim| crate::api::RangeLimit { min: lim.min.unwrap_or(7_000_000) / ppt_divisor, max: lim.max.unwrap_or(69_000_000) / ppt_divisor }), min: lim.min.unwrap_or(11_000_000) / ppt_divisor,
max: lim.max.unwrap_or(42_000_000) / ppt_divisor,
}),
slow_ppt_limits: self.limits.slow_ppt.map(|lim| crate::api::RangeLimit {
min: lim.min.unwrap_or(7_000_000) / ppt_divisor,
max: lim.max.unwrap_or(69_000_000) / ppt_divisor,
}),
ppt_step: self.limits.ppt_step.unwrap_or(1), ppt_step: self.limits.ppt_step.unwrap_or(1),
tdp_limits: self.limits.tdp.map(|lim| crate::api::RangeLimit { min: lim.min.unwrap_or(11_000_000) / tdp_divisor, max: lim.max.unwrap_or(69_000_000) / tdp_divisor }), tdp_limits: self.limits.tdp.map(|lim| crate::api::RangeLimit {
tdp_boost_limits: self.limits.tdp_boost.map(|lim| crate::api::RangeLimit { min: lim.min.unwrap_or(7_000_000) / tdp_divisor, max: lim.max.unwrap_or(69_000_000) / tdp_divisor }), min: lim.min.unwrap_or(11_000_000) / tdp_divisor,
max: lim.max.unwrap_or(69_000_000) / tdp_divisor,
}),
tdp_boost_limits: self.limits.tdp_boost.map(|lim| crate::api::RangeLimit {
min: lim.min.unwrap_or(7_000_000) / tdp_divisor,
max: lim.max.unwrap_or(69_000_000) / tdp_divisor,
}),
tdp_step: self.limits.tdp_step.unwrap_or(1), tdp_step: self.limits.tdp_step.unwrap_or(1),
clock_min_limits: self.limits.clock_min.map(|lim| crate::api::RangeLimit { min: lim.min.unwrap_or(1100), max: lim.max.unwrap_or(6900) }), clock_min_limits: self.limits.clock_min.map(|lim| crate::api::RangeLimit {
clock_max_limits: self.limits.clock_max.map(|lim| crate::api::RangeLimit { min: lim.min.unwrap_or(1100), max: lim.max.unwrap_or(4200) }), min: lim.min.unwrap_or(1100),
max: lim.max.unwrap_or(6900),
}),
clock_max_limits: self.limits.clock_max.map(|lim| crate::api::RangeLimit {
min: lim.min.unwrap_or(1100),
max: lim.max.unwrap_or(4200),
}),
clock_step: self.limits.clock_step.unwrap_or(100), clock_step: self.limits.clock_step.unwrap_or(100),
memory_control: self.limits.memory_clock.map(|lim| crate::api::RangeLimit { min: lim.min.unwrap_or(100), max: lim.max.unwrap_or(1100) }), memory_control: self.limits.memory_clock.map(|lim| crate::api::RangeLimit {
min: lim.min.unwrap_or(100),
max: lim.max.unwrap_or(1100),
}),
memory_step: self.limits.memory_clock_step.unwrap_or(400), memory_step: self.limits.memory_clock_step.unwrap_or(400),
} }
} }
@ -103,24 +127,41 @@ impl TGpu for Gpu {
} }
fn ppt(&mut self, fast: Option<u64>, slow: Option<u64>) { fn ppt(&mut self, fast: Option<u64>, slow: Option<u64>) {
log::debug!("dev_mode_Gpu::ppt(self, fast: {:?}, slow: {:?})", fast, slow); log::debug!(
"dev_mode_Gpu::ppt(self, fast: {:?}, slow: {:?})",
fast,
slow
);
self.persist.fast_ppt = fast; self.persist.fast_ppt = fast;
self.persist.slow_ppt = slow; self.persist.slow_ppt = slow;
} }
fn get_ppt(&self) -> (Option<u64>, Option<u64>) { fn get_ppt(&self) -> (Option<u64>, Option<u64>) {
log::debug!("dev_mode_Gpu::get_ppt(self) -> (fast: {:?}, slow: {:?})", self.persist.fast_ppt, self.persist.slow_ppt); log::debug!(
"dev_mode_Gpu::get_ppt(self) -> (fast: {:?}, slow: {:?})",
self.persist.fast_ppt,
self.persist.slow_ppt
);
(self.persist.fast_ppt, self.persist.slow_ppt) (self.persist.fast_ppt, self.persist.slow_ppt)
} }
fn clock_limits(&mut self, limits: Option<MinMax<u64>>) { fn clock_limits(&mut self, limits: Option<MinMax<u64>>) {
log::debug!("dev_mode_Gpu::clock_limits(self, {:?})", limits); log::debug!("dev_mode_Gpu::clock_limits(self, {:?})", limits);
self.clock_limits = limits; self.clock_limits = limits;
self.persist.clock_limits = self.clock_limits.clone().map(|lim| crate::persist::MinMaxJson { max: lim.max, min: lim.min }); self.persist.clock_limits =
self.clock_limits
.clone()
.map(|lim| crate::persist::MinMaxJson {
max: lim.max,
min: lim.min,
});
} }
fn get_clock_limits(&self) -> Option<&MinMax<u64>> { fn get_clock_limits(&self) -> Option<&MinMax<u64>> {
log::debug!("dev_mode_Gpu::get_clock_limits(self) -> {:?}", self.clock_limits.as_ref()); log::debug!(
"dev_mode_Gpu::get_clock_limits(self) -> {:?}",
self.clock_limits.as_ref()
);
self.clock_limits.as_ref() self.clock_limits.as_ref()
} }
@ -130,7 +171,10 @@ impl TGpu for Gpu {
} }
fn get_memory_clock(&self) -> Option<u64> { fn get_memory_clock(&self) -> Option<u64> {
log::debug!("dev_mode_Gpu::memory_clock(self) -> {:?}", self.persist.memory_clock); log::debug!(
"dev_mode_Gpu::memory_clock(self) -> {:?}",
self.persist.memory_clock
);
self.persist.memory_clock self.persist.memory_clock
} }

View file

@ -9,7 +9,15 @@ pub use gpu::Gpu;
fn _impl_checker() { fn _impl_checker() {
fn impl_provider_builder<T: crate::settings::ProviderBuilder<J, L>, J, L>() {} fn impl_provider_builder<T: crate::settings::ProviderBuilder<J, L>, J, L>() {}
impl_provider_builder::<Battery, crate::persist::BatteryJson, limits_core::json_v2::GenericBatteryLimit>(); impl_provider_builder::<
impl_provider_builder::<Cpus, Vec<crate::persist::CpuJson>, limits_core::json_v2::GenericCpusLimit>(); Battery,
crate::persist::BatteryJson,
limits_core::json_v2::GenericBatteryLimit,
>();
impl_provider_builder::<
Cpus,
Vec<crate::persist::CpuJson>,
limits_core::json_v2::GenericCpusLimit,
>();
impl_provider_builder::<Gpu, crate::persist::GpuJson, limits_core::json_v2::GenericGpuLimit>(); impl_provider_builder::<Gpu, crate::persist::GpuJson, limits_core::json_v2::GenericGpuLimit>();
} }

View file

@ -20,7 +20,13 @@ impl Driver {
auto_detect0(Some(settings), json_path, app_id, name, id_bup, name_bup) auto_detect0(Some(settings), json_path, app_id, name, id_bup, name_bup)
} }
pub fn system_default(json_path: std::path::PathBuf, app_id: u64, name: String, variant_id: u64, variant_name: String) -> Self { pub fn system_default(
json_path: std::path::PathBuf,
app_id: u64,
name: String,
variant_id: u64,
variant_name: String,
) -> Self {
auto_detect0(None, json_path, app_id, name, variant_id, variant_name) auto_detect0(None, json_path, app_id, name, variant_id, variant_name)
} }
} }

View file

@ -4,7 +4,7 @@ use std::path::PathBuf;
//use super::{Battery, Cpus, Gpu}; //use super::{Battery, Cpus, Gpu};
use super::{OnResume, OnSet, SettingError}; use super::{OnResume, OnSet, SettingError};
use super::{TBattery, TCpus, TGeneral, TGpu}; use super::{TBattery, TCpus, TGeneral, TGpu};
use crate::persist::{SettingsJson, FileJson}; use crate::persist::{FileJson, SettingsJson};
//use crate::utility::unwrap_lock; //use crate::utility::unwrap_lock;
const LATEST_VERSION: u64 = 0; const LATEST_VERSION: u64 = 0;
@ -103,11 +103,14 @@ impl TGeneral for General {
} }
fn get_variants(&self) -> Vec<crate::api::VariantInfo> { fn get_variants(&self) -> Vec<crate::api::VariantInfo> {
if let Ok(file) = crate::persist::FileJson::open(self.get_path()) { let json_path = crate::utility::settings_dir().join(self.get_path());
file.variants.into_iter() if let Ok(file) = crate::persist::FileJson::open(json_path) {
file.variants
.into_iter()
.map(|(id, conf)| crate::api::VariantInfo { .map(|(id, conf)| crate::api::VariantInfo {
id: id.to_string(), id: id.to_string(),
name: conf.name, name: conf.name,
id_num: id,
}) })
.collect() .collect()
} else { } else {
@ -115,25 +118,40 @@ impl TGeneral for General {
} }
} }
fn add_variant(&self, variant: crate::persist::SettingsJson) -> Result<Vec<crate::api::VariantInfo>, SettingError> { fn add_variant(
&self,
variant: crate::persist::SettingsJson,
) -> Result<Vec<crate::api::VariantInfo>, SettingError> {
let variant_name = variant.name.clone(); let variant_name = variant.name.clone();
crate::persist::FileJson::update_variant_or_create(self.get_path(), self.get_app_id(), variant, variant_name) let json_path = crate::utility::settings_dir().join(self.get_path());
.map_err(|e| SettingError { crate::persist::FileJson::update_variant_or_create(
msg: format!("failed to add variant: {}", e), json_path,
setting: SettingVariant::General, self.get_app_id(),
}) variant,
.map(|file| file.variants.into_iter() variant_name,
)
.map_err(|e| SettingError {
msg: format!("failed to add variant: {}", e),
setting: SettingVariant::General,
})
.map(|file| {
file.0.variants
.into_iter()
.map(|(id, conf)| crate::api::VariantInfo { .map(|(id, conf)| crate::api::VariantInfo {
id: id.to_string(), id: id.to_string(),
name: conf.name, name: conf.name,
id_num: id,
}) })
.collect()) .collect()
})
} }
fn get_variant_info(&self) -> crate::api::VariantInfo { fn get_variant_info(&self) -> crate::api::VariantInfo {
log::debug!("Current variant `{}` ({})", self.variant_name, self.variant_id);
crate::api::VariantInfo { crate::api::VariantInfo {
id: self.variant_id.to_string(), id: self.variant_id.to_string(),
name: self.variant_name.clone(), name: self.variant_name.clone(),
id_num: self.variant_id,
} }
} }
@ -199,8 +217,15 @@ impl Settings {
} }
} }
pub fn system_default(json_path: PathBuf, app_id: u64, name: String, variant_id: u64, variant_name: String) -> Self { pub fn system_default(
let driver = super::Driver::system_default(json_path, app_id, name, variant_id, variant_name); json_path: PathBuf,
app_id: u64,
name: String,
variant_id: u64,
variant_name: String,
) -> Self {
let driver =
super::Driver::system_default(json_path, app_id, name, variant_id, variant_name);
Self { Self {
general: driver.general, general: driver.general,
cpus: driver.cpus, cpus: driver.cpus,
@ -210,19 +235,47 @@ impl Settings {
} }
pub fn load_system_default(&mut self, name: String, variant_id: u64, variant_name: String) { pub fn load_system_default(&mut self, name: String, variant_id: u64, variant_name: String) {
let driver = super::Driver::system_default(self.general.get_path().to_owned(), self.general.get_app_id(), name, variant_id, variant_name); let driver = super::Driver::system_default(
self.general.get_path().to_owned(),
self.general.get_app_id(),
name,
variant_id,
variant_name,
);
self.cpus = driver.cpus; self.cpus = driver.cpus;
self.gpu = driver.gpu; self.gpu = driver.gpu;
self.battery = driver.battery; self.battery = driver.battery;
self.general = driver.general; self.general = driver.general;
} }
pub fn get_variant<'a>(settings_file: &'a FileJson, variant_id: u64, variant_name: String) -> Result<&'a SettingsJson, SettingError> { pub fn get_variant<'a>(
settings_file: &'a FileJson,
variant_id: u64,
variant_name: String,
) -> Result<&'a SettingsJson, SettingError> {
if let Some(variant) = settings_file.variants.get(&variant_id) { if let Some(variant) = settings_file.variants.get(&variant_id) {
Ok(variant) Ok(variant)
} else if variant_id == 0 {
// special case: requesting primary variant for settings with non-persistent primary
let mut valid_ids: Vec<&u64> = settings_file.variants.keys().collect();
valid_ids.sort();
if let Some(id) = valid_ids.get(0) {
Ok(settings_file.variants.get(id).expect("variant id key magically disappeared"))
} else {
Err(SettingError {
msg: format!(
"Cannot get variant `{}` (id:{}) from empty settings file",
variant_name, variant_id
),
setting: SettingVariant::General,
})
}
} else { } else {
Err(SettingError { Err(SettingError {
msg: format!("Cannot get non-existent variant `{}` (id:{})", variant_name, variant_id), msg: format!(
"Cannot get non-existent variant `{}` (id:{})",
variant_name, variant_id
),
setting: SettingVariant::General, setting: SettingVariant::General,
}) })
} }
@ -240,13 +293,8 @@ impl Settings {
let json_path = crate::utility::settings_dir().join(&filename); let json_path = crate::utility::settings_dir().join(&filename);
if json_path.exists() { if json_path.exists() {
if variant == u64::MAX { if variant == u64::MAX {
*self.general.persistent() = true; log::debug!("Creating new variant `{}` in existing settings file {}", variant_name, json_path.display());
let file_json = FileJson::update_variant_or_create(&json_path, app_id, self.json(), variant_name.clone()).map_err(|e| SettingError { self.create_and_load_variant(&json_path, app_id, variant_name)?;
msg: format!("Failed to open settings {}: {}", json_path.display(), e),
setting: SettingVariant::General,
})?;
self.general.variant_id(file_json.variants.iter().find(|(_key, val)| val.name == variant_name).map(|(key, _val)| *key).expect("Setting variant was not added properly"));
self.general.variant_name(variant_name);
} else { } else {
let file_json = FileJson::open(&json_path).map_err(|e| SettingError { let file_json = FileJson::open(&json_path).map_err(|e| SettingError {
msg: format!("Failed to open settings {}: {}", json_path.display(), e), msg: format!("Failed to open settings {}: {}", json_path.display(), e),
@ -261,31 +309,61 @@ impl Settings {
); );
*self.general.persistent() = false; *self.general.persistent() = false;
self.general.name(name); self.general.name(name);
self.general.variant_name(settings_json.name.clone());
self.general.variant_id(settings_json.variant);
} else { } else {
let x = super::Driver::init(name, settings_json, json_path.clone(), app_id); let x = super::Driver::init(name, settings_json, json_path.clone(), app_id);
log::info!("Loaded settings with drivers general:{:?},cpus:{:?},gpu:{:?},battery:{:?}", x.general.provider(), x.cpus.provider(), x.gpu.provider(), x.battery.provider()); log::info!(
"Loaded settings with drivers general:{:?},cpus:{:?},gpu:{:?},battery:{:?}",
x.general.provider(),
x.cpus.provider(),
x.gpu.provider(),
x.battery.provider()
);
self.general = x.general; self.general = x.general;
self.cpus = x.cpus; self.cpus = x.cpus;
self.gpu = x.gpu; self.gpu = x.gpu;
self.battery = x.battery; self.battery = x.battery;
} }
} }
} else { } else {
if system_defaults { if system_defaults {
self.load_system_default(name, variant, variant_name); self.load_system_default(name, variant, variant_name.clone());
} else { } else {
self.general.name(name); self.general.name(name);
self.general.variant_name(variant_name); self.general.variant_name(variant_name.clone());
self.general.variant_id(variant);
} }
*self.general.persistent() = false; *self.general.persistent() = false;
if variant == u64::MAX {
log::debug!("Creating new variant `{}` in new settings file {}", variant_name, json_path.display());
self.create_and_load_variant(&json_path, app_id, variant_name)?;
}
} }
*self.general.app_id() = app_id; *self.general.app_id() = app_id;
self.general.path(filename); self.general.path(filename);
self.general.variant_id(variant);
Ok(*self.general.persistent()) Ok(*self.general.persistent())
} }
fn create_and_load_variant(&mut self, json_path: &PathBuf, app_id: u64, variant_name: String) -> Result<(), SettingError> {
*self.general.persistent() = true;
self.general.variant_id(u64::MAX);
self.general.variant_name(variant_name.clone());
let (_file_json, new_variant) = FileJson::update_variant_or_create(
json_path,
app_id,
self.json(),
self.general.get_name().to_owned(),
)
.map_err(|e| SettingError {
msg: format!("Failed to open settings {}: {}", json_path.display(), e),
setting: SettingVariant::General,
})?;
self.general.variant_id(new_variant.variant);
self.general.variant_name(new_variant.name);
Ok(())
}
/* /*
pub fn load_file(&mut self, filename: PathBuf, name: String, system_defaults: bool) -> Result<bool, SettingError> { pub fn load_file(&mut self, filename: PathBuf, name: String, system_defaults: bool) -> Result<bool, SettingError> {
let json_path = crate::utility::settings_dir().join(filename); let json_path = crate::utility::settings_dir().join(filename);

View file

@ -4,8 +4,8 @@ use limits_core::json_v2::GenericBatteryLimit;
use sysfuss::{SysEntity, SysEntityAttributesExt}; use sysfuss::{SysEntity, SysEntityAttributesExt};
use crate::persist::BatteryJson; use crate::persist::BatteryJson;
use crate::settings::{TBattery, ProviderBuilder};
use crate::settings::{OnResume, OnSet, SettingError}; use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{ProviderBuilder, TBattery};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Battery { pub struct Battery {
@ -21,7 +21,10 @@ impl Into<BatteryJson> for Battery {
charge_rate: None, charge_rate: None,
charge_mode: None, charge_mode: None,
events: Vec::default(), events: Vec::default(),
root: self.sysfs.root().and_then(|p| p.as_ref().to_str().map(|s| s.to_owned())), root: self
.sysfs
.root()
.and_then(|p| p.as_ref().to_str().map(|s| s.to_owned())),
} }
} }
} }
@ -59,16 +62,26 @@ impl Battery {
} }
fn get_design_voltage(&self) -> Option<f64> { fn get_design_voltage(&self) -> Option<f64> {
match self.sysfs.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::VoltageMax) { match self
Ok(x) => Some(x/1000000.0), .sysfs
.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::VoltageMax)
{
Ok(x) => Some(x / 1000000.0),
Err(e) => { Err(e) => {
log::debug!("get_design_voltage voltage_max err: {}", e); log::debug!("get_design_voltage voltage_max err: {}", e);
match sysfuss::SysEntityRawExt::attribute::<_, f64, _>(&self.sysfs, "voltage_min_design".to_owned()) { // Framework 13 AMD match sysfuss::SysEntityRawExt::attribute::<_, f64, _>(
Ok(x) => Some(x/1000000.0), &self.sysfs,
"voltage_min_design".to_owned(),
) {
// Framework 13 AMD
Ok(x) => Some(x / 1000000.0),
Err(e) => { Err(e) => {
log::debug!("get_design_voltage voltage_min_design err: {}", e); log::debug!("get_design_voltage voltage_min_design err: {}", e);
match self.sysfs.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::VoltageMin) { match self
Ok(x) => Some(x/1000000.0), .sysfs
.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::VoltageMin)
{
Ok(x) => Some(x / 1000000.0),
Err(e) => { Err(e) => {
log::debug!("get_design_voltage voltage_min err: {}", e); log::debug!("get_design_voltage voltage_min err: {}", e);
None None
@ -90,7 +103,7 @@ impl ProviderBuilder<BatteryJson, GenericBatteryLimit> for Battery {
// TODO // TODO
Self { Self {
limits, limits,
sysfs: Self::find_psu_sysfs(persistent.root) sysfs: Self::find_psu_sysfs(persistent.root),
} }
} }
@ -148,8 +161,11 @@ impl TBattery for Battery {
fn read_charge_full(&self) -> Option<f64> { fn read_charge_full(&self) -> Option<f64> {
if let Some(battery_voltage) = self.get_design_voltage() { if let Some(battery_voltage) = self.get_design_voltage() {
match self.sysfs.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::ChargeFull) { match self
Ok(x) => Some(x/1000000.0 * battery_voltage), .sysfs
.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::ChargeFull)
{
Ok(x) => Some(x / 1000000.0 * battery_voltage),
Err(e) => { Err(e) => {
log::warn!("read_charge_full err: {}", e); log::warn!("read_charge_full err: {}", e);
None None
@ -162,8 +178,11 @@ impl TBattery for Battery {
fn read_charge_now(&self) -> Option<f64> { fn read_charge_now(&self) -> Option<f64> {
if let Some(battery_voltage) = self.get_design_voltage() { if let Some(battery_voltage) = self.get_design_voltage() {
match self.sysfs.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::ChargeNow) { match self
Ok(x) => Some(x/1000000.0 * battery_voltage), .sysfs
.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::ChargeNow)
{
Ok(x) => Some(x / 1000000.0 * battery_voltage),
Err(e) => { Err(e) => {
log::warn!("read_charge_now err: {}", e); log::warn!("read_charge_now err: {}", e);
None None
@ -176,8 +195,11 @@ impl TBattery for Battery {
fn read_charge_design(&self) -> Option<f64> { fn read_charge_design(&self) -> Option<f64> {
if let Some(battery_voltage) = self.get_design_voltage() { if let Some(battery_voltage) = self.get_design_voltage() {
match self.sysfs.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::ChargeFullDesign) { match self
Ok(x) => Some(x/1000000.0 * battery_voltage), .sysfs
.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::ChargeFullDesign)
{
Ok(x) => Some(x / 1000000.0 * battery_voltage),
Err(e) => { Err(e) => {
log::warn!("read_charge_design err: {}", e); log::warn!("read_charge_design err: {}", e);
None None
@ -189,8 +211,11 @@ impl TBattery for Battery {
} }
fn read_current_now(&self) -> Option<f64> { fn read_current_now(&self) -> Option<f64> {
match self.sysfs.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::CurrentNow) { match self
Ok(x) => Some(x/1000.0), // expects mA, reads uA .sysfs
.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::CurrentNow)
{
Ok(x) => Some(x / 1000.0), // expects mA, reads uA
Err(e) => { Err(e) => {
log::warn!("read_current_now err: {}", e); log::warn!("read_current_now err: {}", e);
None None

View file

@ -1,13 +1,13 @@
use std::convert::{AsMut, AsRef, Into}; use std::convert::{AsMut, AsRef, Into};
use limits_core::json_v2::{GenericCpusLimit, GenericCpuLimit}; use limits_core::json_v2::{GenericCpuLimit, GenericCpusLimit};
use super::FromGenericCpuInfo; use super::FromGenericCpuInfo;
use crate::api::RangeLimit; use crate::api::RangeLimit;
use crate::persist::CpuJson; use crate::persist::CpuJson;
use crate::settings::{min_max_from_json, MinMax}; use crate::settings::{min_max_from_json, MinMax};
use crate::settings::{OnResume, OnSet, SettingError}; use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{TCpu, TCpus, ProviderBuilder}; use crate::settings::{ProviderBuilder, TCpu, TCpus};
const CPU_PRESENT_PATH: &str = "/sys/devices/system/cpu/present"; const CPU_PRESENT_PATH: &str = "/sys/devices/system/cpu/present";
const CPU_SMT_PATH: &str = "/sys/devices/system/cpu/smt/control"; const CPU_SMT_PATH: &str = "/sys/devices/system/cpu/smt/control";
@ -89,8 +89,14 @@ impl<C: AsMut<Cpu> + AsRef<Cpu> + TCpu + FromGenericCpuInfo> Cpus<C> {
} }
} }
impl<C: AsMut<Cpu> + AsRef<Cpu> + TCpu + FromGenericCpuInfo> ProviderBuilder<Vec<CpuJson>, GenericCpusLimit> for Cpus<C> { impl<C: AsMut<Cpu> + AsRef<Cpu> + TCpu + FromGenericCpuInfo>
fn from_json_and_limits(mut other: Vec<CpuJson>, version: u64, limits: GenericCpusLimit) -> Self { ProviderBuilder<Vec<CpuJson>, GenericCpusLimit> for Cpus<C>
{
fn from_json_and_limits(
mut other: Vec<CpuJson>,
version: u64,
limits: GenericCpusLimit,
) -> Self {
let (_, can_smt) = Self::system_smt_capabilities(); let (_, can_smt) = Self::system_smt_capabilities();
let mut result = Vec::with_capacity(other.len()); let mut result = Vec::with_capacity(other.len());
let max_cpus = Self::cpu_count(); let max_cpus = Self::cpu_count();
@ -103,9 +109,12 @@ impl<C: AsMut<Cpu> + AsRef<Cpu> + TCpu + FromGenericCpuInfo> ProviderBuilder<Vec
break; break;
} }
} }
let cpu_limit = limits.cpus.get(i) let cpu_limit = limits
.cpus
.get(i)
.or_else(|| limits.cpus.get(0)) .or_else(|| limits.cpus.get(0))
.unwrap_or_else(|| &fallback_cpu_limit).clone(); .unwrap_or_else(|| &fallback_cpu_limit)
.clone();
let new_cpu = C::from_json_and_limits(cpu, version, i, cpu_limit); let new_cpu = C::from_json_and_limits(cpu, version, i, cpu_limit);
result.push(new_cpu); result.push(new_cpu);
} }
@ -130,9 +139,12 @@ impl<C: AsMut<Cpu> + AsRef<Cpu> + TCpu + FromGenericCpuInfo> ProviderBuilder<Vec
let mut new_cpus = Vec::with_capacity(cpu_count); let mut new_cpus = Vec::with_capacity(cpu_count);
let fallback_cpu_limit = GenericCpuLimit::default(); let fallback_cpu_limit = GenericCpuLimit::default();
for i in 0..cpu_count { for i in 0..cpu_count {
let cpu_limit = limits.cpus.get(i) let cpu_limit = limits
.cpus
.get(i)
.or_else(|| limits.cpus.get(0)) .or_else(|| limits.cpus.get(0))
.unwrap_or_else(|| &fallback_cpu_limit).clone(); .unwrap_or_else(|| &fallback_cpu_limit)
.clone();
let new_cpu = C::from_limits(i, cpu_limit); let new_cpu = C::from_limits(i, cpu_limit);
new_cpus.push(new_cpu); new_cpus.push(new_cpu);
} }
@ -221,7 +233,8 @@ pub struct Cpu {
impl Cpu { impl Cpu {
#[inline] #[inline]
fn current_governor(index: usize) -> String { fn current_governor(index: usize) -> String {
usdpl_back::api::files::read_single(cpu_governor_path(index)).unwrap_or_else(|_| "schedutil".to_owned()) usdpl_back::api::files::read_single(cpu_governor_path(index))
.unwrap_or_else(|_| "schedutil".to_owned())
} }
} }

View file

@ -5,9 +5,9 @@ use sysfuss::{BasicEntityPath, SysEntity};
use crate::api::RangeLimit; use crate::api::RangeLimit;
use crate::persist::GpuJson; use crate::persist::GpuJson;
use crate::settings::{TGpu, ProviderBuilder};
use crate::settings::{min_max_from_json, MinMax}; use crate::settings::{min_max_from_json, MinMax};
use crate::settings::{OnResume, OnSet, SettingError}; use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{ProviderBuilder, TGpu};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Gpu { pub struct Gpu {
@ -38,15 +38,17 @@ impl Gpu {
fn find_card_sysfs(root: Option<impl AsRef<std::path::Path>>) -> BasicEntityPath { fn find_card_sysfs(root: Option<impl AsRef<std::path::Path>>) -> BasicEntityPath {
let root = crate::settings::util::root_or_default_sysfs(root); let root = crate::settings::util::root_or_default_sysfs(root);
match root.class("drm", crate::settings::util::always_satisfied) { match root.class("drm", crate::settings::util::always_satisfied) {
Ok(mut iter) => { Ok(mut iter) => iter.next().unwrap_or_else(|| {
iter.next() log::error!(
.unwrap_or_else(|| { "Failed to find generic gpu drm in sysfs (no results), using naive fallback"
log::error!("Failed to find generic gpu drm in sysfs (no results), using naive fallback"); );
BasicEntityPath::new(root.as_ref().join("sys/class/drm/card0")) BasicEntityPath::new(root.as_ref().join("sys/class/drm/card0"))
}) }),
},
Err(e) => { Err(e) => {
log::error!("Failed to find generic gpu drm in sysfs ({}), using naive fallback", e); log::error!(
"Failed to find generic gpu drm in sysfs ({}), using naive fallback",
e
);
BasicEntityPath::new(root.as_ref().join("sys/class/drm/card0")) BasicEntityPath::new(root.as_ref().join("sys/class/drm/card0"))
} }
} }
@ -56,7 +58,9 @@ impl Gpu {
impl ProviderBuilder<GpuJson, GenericGpuLimit> for Gpu { impl ProviderBuilder<GpuJson, GenericGpuLimit> for Gpu {
fn from_json_and_limits(persistent: GpuJson, version: u64, limits: GenericGpuLimit) -> Self { fn from_json_and_limits(persistent: GpuJson, version: u64, limits: GenericGpuLimit) -> Self {
let clock_lims = if limits.clock_min.is_some() && limits.clock_max.is_some() { let clock_lims = if limits.clock_min.is_some() && limits.clock_max.is_some() {
persistent.clock_limits.map(|x| min_max_from_json(x, version)) persistent
.clock_limits
.map(|x| min_max_from_json(x, version))
} else { } else {
None None
}; };
@ -84,7 +88,7 @@ impl ProviderBuilder<GpuJson, GenericGpuLimit> for Gpu {
}, },
clock_limits: clock_lims, clock_limits: clock_lims,
limits, limits,
sysfs: Self::find_card_sysfs(persistent.root) sysfs: Self::find_card_sysfs(persistent.root),
} }
} }
@ -112,7 +116,10 @@ impl Into<GpuJson> for Gpu {
tdp_boost: self.tdp_boost, tdp_boost: self.tdp_boost,
clock_limits: self.clock_limits.map(|x| x.into()), clock_limits: self.clock_limits.map(|x| x.into()),
memory_clock: None, memory_clock: None,
root: self.sysfs.root().and_then(|p| p.as_ref().to_str().map(|s| s.to_owned())) root: self
.sysfs
.root()
.and_then(|p| p.as_ref().to_str().map(|s| s.to_owned())),
} }
} }
} }
@ -139,21 +146,29 @@ impl TGpu for Gpu {
.fast_ppt .fast_ppt
.clone() .clone()
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15))) .map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15)))
.map(|mut x| if let Some(ppt_divisor) = self.limits.ppt_divisor { .map(|mut x| {
x.min /= ppt_divisor; if let Some(ppt_divisor) = self.limits.ppt_divisor {
x.max /= ppt_divisor; x.min /= ppt_divisor;
x x.max /= ppt_divisor;
} else {x}), x
} else {
x
}
}),
slow_ppt_limits: self slow_ppt_limits: self
.limits .limits
.slow_ppt .slow_ppt
.clone() .clone()
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15))) .map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15)))
.map(|mut x| if let Some(ppt_divisor) = self.limits.ppt_divisor { .map(|mut x| {
x.min /= ppt_divisor; if let Some(ppt_divisor) = self.limits.ppt_divisor {
x.max /= ppt_divisor; x.min /= ppt_divisor;
x x.max /= ppt_divisor;
} else {x}), x
} else {
x
}
}),
ppt_step: self.limits.ppt_step.unwrap_or(1), ppt_step: self.limits.ppt_step.unwrap_or(1),
tdp_limits: self tdp_limits: self
.limits .limits
@ -188,28 +203,56 @@ impl TGpu for Gpu {
fn ppt(&mut self, fast: Option<u64>, slow: Option<u64>) { fn ppt(&mut self, fast: Option<u64>, slow: Option<u64>) {
if let Some(fast_lims) = &self.limits.fast_ppt { if let Some(fast_lims) = &self.limits.fast_ppt {
self.fast_ppt = fast.map(|x| if let Some(ppt_divisor) = self.limits.ppt_divisor { x * ppt_divisor } else { x }) self.fast_ppt = fast
.map(|x| { .map(|x| {
x.clamp( if let Some(ppt_divisor) = self.limits.ppt_divisor {
fast_lims.min.unwrap_or(0), x * ppt_divisor
fast_lims.max.unwrap_or(u64::MAX), } else {
) x
}); }
})
.map(|x| {
x.clamp(
fast_lims.min.unwrap_or(0),
fast_lims.max.unwrap_or(u64::MAX),
)
});
} }
if let Some(slow_lims) = &self.limits.slow_ppt { if let Some(slow_lims) = &self.limits.slow_ppt {
self.slow_ppt = slow.map(|x| if let Some(ppt_divisor) = self.limits.ppt_divisor { x * ppt_divisor } else { x }) self.slow_ppt = slow
.map(|x| { .map(|x| {
x.clamp( if let Some(ppt_divisor) = self.limits.ppt_divisor {
slow_lims.min.unwrap_or(0), x * ppt_divisor
slow_lims.max.unwrap_or(u64::MAX), } else {
) x
}); }
})
.map(|x| {
x.clamp(
slow_lims.min.unwrap_or(0),
slow_lims.max.unwrap_or(u64::MAX),
)
});
} }
} }
fn get_ppt(&self) -> (Option<u64>, Option<u64>) { fn get_ppt(&self) -> (Option<u64>, Option<u64>) {
(self.fast_ppt.map(|x| if let Some(ppt_divisor) = self.limits.ppt_divisor { x / ppt_divisor } else { x }), (
self.slow_ppt.map(|x| if let Some(ppt_divisor) = self.limits.ppt_divisor { x / ppt_divisor } else { x })) self.fast_ppt.map(|x| {
if let Some(ppt_divisor) = self.limits.ppt_divisor {
x / ppt_divisor
} else {
x
}
}),
self.slow_ppt.map(|x| {
if let Some(ppt_divisor) = self.limits.ppt_divisor {
x / ppt_divisor
} else {
x
}
}),
)
} }
fn clock_limits(&mut self, limits: Option<MinMax<u64>>) { fn clock_limits(&mut self, limits: Option<MinMax<u64>>) {

View file

@ -11,7 +11,15 @@ pub use traits::FromGenericCpuInfo;
fn _impl_checker() { fn _impl_checker() {
fn impl_provider_builder<T: crate::settings::ProviderBuilder<J, L>, J, L>() {} fn impl_provider_builder<T: crate::settings::ProviderBuilder<J, L>, J, L>() {}
impl_provider_builder::<Battery, crate::persist::BatteryJson, limits_core::json_v2::GenericBatteryLimit>(); impl_provider_builder::<
impl_provider_builder::<Cpus<Cpu>, Vec<crate::persist::CpuJson>, limits_core::json_v2::GenericCpusLimit>(); Battery,
crate::persist::BatteryJson,
limits_core::json_v2::GenericBatteryLimit,
>();
impl_provider_builder::<
Cpus<Cpu>,
Vec<crate::persist::CpuJson>,
limits_core::json_v2::GenericCpusLimit,
>();
impl_provider_builder::<Gpu, crate::persist::GpuJson, limits_core::json_v2::GenericGpuLimit>(); impl_provider_builder::<Gpu, crate::persist::GpuJson, limits_core::json_v2::GenericGpuLimit>();
} }

View file

@ -2,7 +2,7 @@ use crate::persist::CpuJson;
use crate::settings::generic::{Cpu as GenericCpu, Cpus as GenericCpus, FromGenericCpuInfo}; use crate::settings::generic::{Cpu as GenericCpu, Cpus as GenericCpus, FromGenericCpuInfo};
use crate::settings::MinMax; use crate::settings::MinMax;
use crate::settings::{OnResume, OnSet, SettingError}; use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{TCpu, TCpus, ProviderBuilder}; use crate::settings::{ProviderBuilder, TCpu, TCpus};
#[derive(Debug)] #[derive(Debug)]
pub struct Cpus { pub struct Cpus {

View file

@ -4,10 +4,14 @@ use std::sync::Mutex;
use crate::persist::GpuJson; use crate::persist::GpuJson;
use crate::settings::generic::Gpu as GenericGpu; use crate::settings::generic::Gpu as GenericGpu;
use crate::settings::MinMax; use crate::settings::MinMax;
use crate::settings::{TGpu, ProviderBuilder};
use crate::settings::{OnResume, OnSet, SettingError, SettingVariant}; use crate::settings::{OnResume, OnSet, SettingError, SettingVariant};
use crate::settings::{ProviderBuilder, TGpu};
fn msg_or_err<D: std::fmt::Display, E: std::fmt::Display>(output: &mut String, msg: &str, result: Result<D, E>) { fn msg_or_err<D: std::fmt::Display, E: std::fmt::Display>(
output: &mut String,
msg: &str,
result: Result<D, E>,
) {
use std::fmt::Write; use std::fmt::Write;
match result { match result {
Ok(val) => writeln!(output, "{}: {}", msg, val).unwrap(), Ok(val) => writeln!(output, "{}: {}", msg, val).unwrap(),
@ -16,20 +20,41 @@ fn msg_or_err<D: std::fmt::Display, E: std::fmt::Display>(output: &mut String, m
} }
fn log_capabilities(ryzenadj: &RyzenAdj) { fn log_capabilities(ryzenadj: &RyzenAdj) {
log::info!("RyzenAdj v{}.{}.{}", libryzenadj::libryzenadj_sys::RYZENADJ_REVISION_VER, libryzenadj::libryzenadj_sys::RYZENADJ_MAJOR_VER, libryzenadj::libryzenadj_sys::RYZENADJ_MINIOR_VER); log::info!(
"RyzenAdj v{}.{}.{}",
libryzenadj::libryzenadj_sys::RYZENADJ_REVISION_VER,
libryzenadj::libryzenadj_sys::RYZENADJ_MAJOR_VER,
libryzenadj::libryzenadj_sys::RYZENADJ_MINIOR_VER
);
#[cfg(feature = "experimental")] #[cfg(feature = "experimental")]
if let Some(x) = ryzenadj.get_init_table_err() { if let Some(x) = ryzenadj.get_init_table_err() {
log::warn!("RyzenAdj table init error: {}", x); log::warn!("RyzenAdj table init error: {}", x);
} }
let mut log_msg = String::new(); let mut log_msg = String::new();
msg_or_err(&mut log_msg, "bios version", ryzenadj.get_bios_if_ver()); msg_or_err(&mut log_msg, "bios version", ryzenadj.get_bios_if_ver());
msg_or_err(&mut log_msg, "refresh", ryzenadj.refresh().map(|_| "success")); msg_or_err(
msg_or_err(&mut log_msg, "CPU family", ryzenadj.get_cpu_family().map(|fam| { &mut log_msg,
let fam_dbg = format!("{:?}", fam); "refresh",
format!("{} (#{})", fam_dbg, fam as i32) ryzenadj.refresh().map(|_| "success"),
})); );
msg_or_err(&mut log_msg, "get_fast_value (PPT)", ryzenadj.get_fast_value()); msg_or_err(
msg_or_err(&mut log_msg, "get_slow_value (PPT)", ryzenadj.get_slow_value()); &mut log_msg,
"CPU family",
ryzenadj.get_cpu_family().map(|fam| {
let fam_dbg = format!("{:?}", fam);
format!("{} (#{})", fam_dbg, fam as i32)
}),
);
msg_or_err(
&mut log_msg,
"get_fast_value (PPT)",
ryzenadj.get_fast_value(),
);
msg_or_err(
&mut log_msg,
"get_slow_value (PPT)",
ryzenadj.get_slow_value(),
);
msg_or_err(&mut log_msg, "get_gfx_clk", ryzenadj.get_gfx_clk()); msg_or_err(&mut log_msg, "get_gfx_clk", ryzenadj.get_gfx_clk());
msg_or_err(&mut log_msg, "get_gfx_volt", ryzenadj.get_gfx_volt()); msg_or_err(&mut log_msg, "get_gfx_volt", ryzenadj.get_gfx_volt());
@ -41,7 +66,7 @@ fn ryzen_adj_or_log() -> Option<Mutex<RyzenAdj>> {
Ok(x) => { Ok(x) => {
log_capabilities(&x); log_capabilities(&x);
Some(Mutex::new(x)) Some(Mutex::new(x))
}, }
Err(e) => { Err(e) => {
log::error!("RyzenAdj init error: {}", e); log::error!("RyzenAdj init error: {}", e);
None None
@ -90,7 +115,6 @@ impl ProviderBuilder<GpuJson, limits_core::json_v2::GenericGpuLimit> for Gpu {
} }
impl Gpu { impl Gpu {
fn set_all(&mut self) -> Result<(), Vec<SettingError>> { fn set_all(&mut self) -> Result<(), Vec<SettingError>> {
let mutex = match &self.implementor { let mutex = match &self.implementor {
Some(x) => x, Some(x) => x,

View file

@ -7,6 +7,10 @@ pub use gpu::Gpu;
fn _impl_checker() { fn _impl_checker() {
fn impl_provider_builder<T: crate::settings::ProviderBuilder<J, L>, J, L>() {} fn impl_provider_builder<T: crate::settings::ProviderBuilder<J, L>, J, L>() {}
impl_provider_builder::<Cpus, Vec<crate::persist::CpuJson>, limits_core::json_v2::GenericCpusLimit>(); impl_provider_builder::<
Cpus,
Vec<crate::persist::CpuJson>,
limits_core::json_v2::GenericCpusLimit,
>();
impl_provider_builder::<Gpu, crate::persist::GpuJson, limits_core::json_v2::GenericGpuLimit>(); impl_provider_builder::<Gpu, crate::persist::GpuJson, limits_core::json_v2::GenericGpuLimit>();
} }

View file

@ -6,25 +6,37 @@ mod min_max;
mod traits; mod traits;
mod util; mod util;
pub mod dev_mode;
pub mod generic; pub mod generic;
pub mod generic_amd; pub mod generic_amd;
pub mod steam_deck; pub mod steam_deck;
pub mod unknown; pub mod unknown;
pub mod dev_mode;
pub use detect::{auto_detect0, auto_detect_provider, limits_worker::spawn as limits_worker_spawn, get_dev_messages}; pub use detect::{
auto_detect0, auto_detect_provider, get_dev_messages,
limits_worker::spawn as limits_worker_spawn,
};
pub use driver::Driver; pub use driver::Driver;
pub use general::{General, SettingVariant, Settings}; pub use general::{General, SettingVariant, Settings};
pub use min_max::{min_max_from_json, MinMax}; pub use min_max::{min_max_from_json, MinMax};
pub use error::SettingError; pub use error::SettingError;
pub use traits::{OnPowerEvent, OnResume, OnSet, PowerMode, TBattery, TCpu, TCpus, TGeneral, TGpu, ProviderBuilder}; pub use traits::{
OnPowerEvent, OnResume, OnSet, PowerMode, ProviderBuilder, TBattery, TCpu, TCpus, TGeneral,
TGpu,
};
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#[test] #[test]
fn system_defaults_test() { fn system_defaults_test() {
let settings = super::Settings::system_default("idc".into(), 0, "Cool name".into(), 0, "Variant 0".into()); let settings = super::Settings::system_default(
"idc".into(),
0,
"Cool name".into(),
0,
"Variant 0".into(),
);
println!("Loaded system settings: {:?}", settings); println!("Loaded system settings: {:?}", settings);
} }
} }

View file

@ -1,16 +1,22 @@
use std::convert::Into; use std::convert::Into;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use sysfuss::{PowerSupplyAttribute, PowerSupplyPath, HwMonAttribute, HwMonAttributeItem, HwMonAttributeType, HwMonPath, SysEntity, SysEntityAttributesExt, SysAttribute};
use sysfuss::capability::attributes; use sysfuss::capability::attributes;
use sysfuss::{
HwMonAttribute, HwMonAttributeItem, HwMonAttributeType, HwMonPath, PowerSupplyAttribute,
PowerSupplyPath, SysAttribute, SysEntity, SysEntityAttributesExt,
};
use limits_core::json_v2::GenericBatteryLimit; use limits_core::json_v2::GenericBatteryLimit;
use smokepatio::ec::{ControllerSet, unnamed_power::{UnnamedPowerEC, ChargeMode}};
use crate::api::RangeLimit; use crate::api::RangeLimit;
use crate::persist::{BatteryEventJson, BatteryJson}; use crate::persist::{BatteryEventJson, BatteryJson};
use crate::settings::{TBattery, ProviderBuilder};
use crate::settings::{OnPowerEvent, OnResume, OnSet, PowerMode, SettingError}; use crate::settings::{OnPowerEvent, OnResume, OnSet, PowerMode, SettingError};
use crate::settings::{ProviderBuilder, TBattery};
use smokepatio::ec::{
unnamed_power::{ChargeMode, UnnamedPowerEC},
ControllerSet,
};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Battery { pub struct Battery {
@ -121,7 +127,12 @@ impl EventInstruction {
} }
} }
fn from_json(other: BatteryEventJson, _version: u64, hwmon: Arc<HwMonPath>, ec: Arc<Mutex<UnnamedPowerEC>>) -> Self { fn from_json(
other: BatteryEventJson,
_version: u64,
hwmon: Arc<HwMonPath>,
ec: Arc<Mutex<UnnamedPowerEC>>,
) -> Self {
Self { Self {
trigger: Self::str_to_trigger(&other.trigger).unwrap_or(EventTrigger::Ignored), trigger: Self::str_to_trigger(&other.trigger).unwrap_or(EventTrigger::Ignored),
charge_rate: other.charge_rate, charge_rate: other.charge_rate,
@ -137,7 +148,10 @@ impl EventInstruction {
fn set_charge_mode(&self) -> Result<(), SettingError> { fn set_charge_mode(&self) -> Result<(), SettingError> {
if let Some(charge_mode) = self.charge_mode { if let Some(charge_mode) = self.charge_mode {
let mut lock = self.bat_ec.lock().expect("failed to lock battery controller"); let mut lock = self
.bat_ec
.lock()
.expect("failed to lock battery controller");
lock.set(charge_mode).map_err(|_| SettingError { lock.set(charge_mode).map_err(|_| SettingError {
msg: format!("Failed to set charge mode"), msg: format!("Failed to set charge mode"),
setting: crate::settings::SettingVariant::Battery, setting: crate::settings::SettingVariant::Battery,
@ -149,12 +163,15 @@ impl EventInstruction {
fn set_charge_rate(&self) -> Result<(), SettingError> { fn set_charge_rate(&self) -> Result<(), SettingError> {
if let Some(charge_rate) = self.charge_rate { if let Some(charge_rate) = self.charge_rate {
self.sysfs_hwmon.set(MAX_BATTERY_CHARGE_RATE_ATTR, charge_rate).map_err( self.sysfs_hwmon
|e| SettingError { .set(MAX_BATTERY_CHARGE_RATE_ATTR, charge_rate)
msg: format!("Failed to write to `{:?}`: {}", MAX_BATTERY_CHARGE_RATE_ATTR, e), .map_err(|e| SettingError {
msg: format!(
"Failed to write to `{:?}`: {}",
MAX_BATTERY_CHARGE_RATE_ATTR, e
),
setting: crate::settings::SettingVariant::Battery, setting: crate::settings::SettingVariant::Battery,
}, })
)
} else { } else {
Ok(()) Ok(())
} }
@ -194,7 +211,6 @@ const BATTERY_CHARGE_DESIGN_PATH: &str = "/sys/class/power_supply/BAT1/charge_fu
const USB_PD_IN_MVOLTAGE_PATH: &str = "/sys/class/hwmon/hwmon5/in0_input"; // read-only const USB_PD_IN_MVOLTAGE_PATH: &str = "/sys/class/hwmon/hwmon5/in0_input"; // read-only
const USB_PD_IN_CURRENT_PATH: &str = "/sys/class/hwmon/hwmon5/curr1_input"; // read-only*/ const USB_PD_IN_CURRENT_PATH: &str = "/sys/class/hwmon/hwmon5/curr1_input"; // read-only*/
const BATTERY_NEEDS: &[PowerSupplyAttribute] = &[ const BATTERY_NEEDS: &[PowerSupplyAttribute] = &[
PowerSupplyAttribute::Type, PowerSupplyAttribute::Type,
PowerSupplyAttribute::CurrentNow, PowerSupplyAttribute::CurrentNow,
@ -213,8 +229,10 @@ const HWMON_NEEDS: &[HwMonAttribute] = &[
//HwMonAttribute::custom("maximum_battery_charge_rate"), // NOTE: Cannot filter by custom capabilities //HwMonAttribute::custom("maximum_battery_charge_rate"), // NOTE: Cannot filter by custom capabilities
]; ];
const MAX_BATTERY_CHARGE_RATE_ATTR: HwMonAttribute = HwMonAttribute::custom("maximum_battery_charge_rate"); const MAX_BATTERY_CHARGE_RATE_ATTR: HwMonAttribute =
const MAX_BATTERY_CHARGE_LEVEL_ATTR: HwMonAttribute = HwMonAttribute::custom("max_battery_charge_level"); HwMonAttribute::custom("maximum_battery_charge_rate");
const MAX_BATTERY_CHARGE_LEVEL_ATTR: HwMonAttribute =
HwMonAttribute::custom("max_battery_charge_level");
const MAX_CHARGE_RATE: u64 = 2500; const MAX_CHARGE_RATE: u64 = 2500;
const MIN_CHARGE_RATE: u64 = 250; const MIN_CHARGE_RATE: u64 = 250;
@ -229,9 +247,12 @@ impl Battery {
log::error!("Failed to find SteamDeck battery power_supply in sysfs (no results), using naive fallback"); log::error!("Failed to find SteamDeck battery power_supply in sysfs (no results), using naive fallback");
root.power_supply_by_name("BAT1") root.power_supply_by_name("BAT1")
}); });
log::info!("Found SteamDeck battery power_supply in sysfs: {}", psu.as_ref().display()); log::info!(
"Found SteamDeck battery power_supply in sysfs: {}",
psu.as_ref().display()
);
psu psu
}, }
Err(e) => { Err(e) => {
log::error!("Failed to find SteamDeck battery power_supply in sysfs ({}), using naive fallback", e); log::error!("Failed to find SteamDeck battery power_supply in sysfs ({}), using naive fallback", e);
root.power_supply_by_name("BAT1") root.power_supply_by_name("BAT1")
@ -245,11 +266,15 @@ impl Battery {
Ok(hwmon) => { Ok(hwmon) => {
if !hwmon.capable(attributes(HWMON_NEEDS.into_iter().copied())) { if !hwmon.capable(attributes(HWMON_NEEDS.into_iter().copied())) {
log::warn!("Found incapable SteamDeck battery hwmon in sysfs (hwmon by name {} exists but missing attributes), persevering because ignorance is bliss", super::util::JUPITER_HWMON_NAME); log::warn!("Found incapable SteamDeck battery hwmon in sysfs (hwmon by name {} exists but missing attributes), persevering because ignorance is bliss", super::util::JUPITER_HWMON_NAME);
} else { } else {
log::info!("Found SteamDeck battery hwmon {} in sysfs: {}", super::util::JUPITER_HWMON_NAME, hwmon.as_ref().display()); log::info!(
"Found SteamDeck battery hwmon {} in sysfs: {}",
super::util::JUPITER_HWMON_NAME,
hwmon.as_ref().display()
);
} }
hwmon hwmon
}, }
Err(e) => { Err(e) => {
log::warn!("Failed to find SteamDeck battery hwmon {} in sysfs ({}), trying alternate name", log::warn!("Failed to find SteamDeck battery hwmon {} in sysfs ({}), trying alternate name",
super::util::JUPITER_HWMON_NAME, e); super::util::JUPITER_HWMON_NAME, e);
@ -258,10 +283,14 @@ impl Battery {
if !hwmon.capable(attributes(HWMON_NEEDS.into_iter().copied())) { if !hwmon.capable(attributes(HWMON_NEEDS.into_iter().copied())) {
log::warn!("Found incapable SteamDeck battery hwmon in sysfs (hwmon by name {} exists but missing attributes), persevering because ignorance is bliss", super::util::STEAMDECK_HWMON_NAME); log::warn!("Found incapable SteamDeck battery hwmon in sysfs (hwmon by name {} exists but missing attributes), persevering because ignorance is bliss", super::util::STEAMDECK_HWMON_NAME);
} else { } else {
log::info!("Found SteamDeck battery hwmon {} in sysfs: {}", super::util::STEAMDECK_HWMON_NAME, hwmon.as_ref().display()); log::info!(
"Found SteamDeck battery hwmon {} in sysfs: {}",
super::util::STEAMDECK_HWMON_NAME,
hwmon.as_ref().display()
);
} }
hwmon hwmon
}, }
Err(e) => { Err(e) => {
log::error!("Failed to find SteamDeck battery hwmon {} in sysfs ({}), using naive fallback", super::util::STEAMDECK_HWMON_NAME, e); log::error!("Failed to find SteamDeck battery hwmon {} in sysfs ({}), using naive fallback", super::util::STEAMDECK_HWMON_NAME, e);
root.hwmon_by_index(5) root.hwmon_by_index(5)
@ -295,21 +324,27 @@ impl Battery {
if let Some(charge_rate) = self.charge_rate { if let Some(charge_rate) = self.charge_rate {
self.state.charge_rate_set = true; self.state.charge_rate_set = true;
let path = MAX_BATTERY_CHARGE_RATE_ATTR.path(&*self.sysfs_hwmon); let path = MAX_BATTERY_CHARGE_RATE_ATTR.path(&*self.sysfs_hwmon);
self.sysfs_hwmon.set(MAX_BATTERY_CHARGE_RATE_ATTR, charge_rate).map_err( self.sysfs_hwmon
|e| SettingError { .set(MAX_BATTERY_CHARGE_RATE_ATTR, charge_rate)
.map_err(|e| SettingError {
msg: format!("Failed to write to `{}`: {}", path.display(), e), msg: format!("Failed to write to `{}`: {}", path.display(), e),
setting: crate::settings::SettingVariant::Battery, setting: crate::settings::SettingVariant::Battery,
}, })
)
} else if self.state.charge_rate_set { } else if self.state.charge_rate_set {
self.state.charge_rate_set = false; self.state.charge_rate_set = false;
let path = MAX_BATTERY_CHARGE_RATE_ATTR.path(&*self.sysfs_hwmon); let path = MAX_BATTERY_CHARGE_RATE_ATTR.path(&*self.sysfs_hwmon);
self.sysfs_hwmon.set(MAX_BATTERY_CHARGE_RATE_ATTR, self.limits.charge_rate.and_then(|lim| lim.max).unwrap_or(2500)).map_err( self.sysfs_hwmon
|e| SettingError { .set(
MAX_BATTERY_CHARGE_RATE_ATTR,
self.limits
.charge_rate
.and_then(|lim| lim.max)
.unwrap_or(2500),
)
.map_err(|e| SettingError {
msg: format!("Failed to write to `{}`: {}", path.display(), e), msg: format!("Failed to write to `{}`: {}", path.display(), e),
setting: crate::settings::SettingVariant::Battery, setting: crate::settings::SettingVariant::Battery,
}, })
)
} else { } else {
Ok(()) Ok(())
} }
@ -318,14 +353,20 @@ impl Battery {
fn set_charge_mode(&mut self) -> Result<(), SettingError> { fn set_charge_mode(&mut self) -> Result<(), SettingError> {
if let Some(charge_mode) = self.charge_mode { if let Some(charge_mode) = self.charge_mode {
self.state.charge_mode_set = true; self.state.charge_mode_set = true;
let mut lock = self.bat_ec.lock().expect("Failed to lock battery controller"); let mut lock = self
.bat_ec
.lock()
.expect("Failed to lock battery controller");
lock.set(charge_mode).map_err(|_| SettingError { lock.set(charge_mode).map_err(|_| SettingError {
msg: format!("Failed to set charge mode"), msg: format!("Failed to set charge mode"),
setting: crate::settings::SettingVariant::Battery, setting: crate::settings::SettingVariant::Battery,
}) })
} else if self.state.charge_mode_set { } else if self.state.charge_mode_set {
self.state.charge_mode_set = false; self.state.charge_mode_set = false;
let mut lock = self.bat_ec.lock().expect("Failed to lock battery controller"); let mut lock = self
.bat_ec
.lock()
.expect("Failed to lock battery controller");
lock.set(ChargeMode::Normal).map_err(|_| SettingError { lock.set(ChargeMode::Normal).map_err(|_| SettingError {
msg: format!("Failed to set charge mode"), msg: format!("Failed to set charge mode"),
setting: crate::settings::SettingVariant::Battery, setting: crate::settings::SettingVariant::Battery,
@ -337,23 +378,35 @@ impl Battery {
fn set_charge_limit(&mut self) -> Result<(), SettingError> { fn set_charge_limit(&mut self) -> Result<(), SettingError> {
let attr_exists = MAX_BATTERY_CHARGE_LEVEL_ATTR.exists(&*self.sysfs_hwmon); let attr_exists = MAX_BATTERY_CHARGE_LEVEL_ATTR.exists(&*self.sysfs_hwmon);
log::debug!("Does battery limit attribute (max_battery_charge_level) exist? {}", attr_exists); log::debug!(
"Does battery limit attribute (max_battery_charge_level) exist? {}",
attr_exists
);
if let Some(charge_limit) = self.charge_limit { if let Some(charge_limit) = self.charge_limit {
self.state.charge_limit_set = true; self.state.charge_limit_set = true;
self.sysfs_hwmon.set(MAX_BATTERY_CHARGE_LEVEL_ATTR, (charge_limit * 100.0).round() as u64) self.sysfs_hwmon
.map_err(|e| SettingError { .set(
msg: format!("Failed to write to {:?}: {}", MAX_BATTERY_CHARGE_LEVEL_ATTR, e), MAX_BATTERY_CHARGE_LEVEL_ATTR,
setting: crate::settings::SettingVariant::Battery, (charge_limit * 100.0).round() as u64,
}
) )
.map_err(|e| SettingError {
msg: format!(
"Failed to write to {:?}: {}",
MAX_BATTERY_CHARGE_LEVEL_ATTR, e
),
setting: crate::settings::SettingVariant::Battery,
})
} else if self.state.charge_limit_set { } else if self.state.charge_limit_set {
self.state.charge_limit_set = false; self.state.charge_limit_set = false;
self.sysfs_hwmon.set(MAX_BATTERY_CHARGE_LEVEL_ATTR, 0) self.sysfs_hwmon
.set(MAX_BATTERY_CHARGE_LEVEL_ATTR, 0)
.map_err(|e| SettingError { .map_err(|e| SettingError {
msg: format!("Failed to reset (write to) {:?}: {}", MAX_BATTERY_CHARGE_LEVEL_ATTR, e), msg: format!(
setting: crate::settings::SettingVariant::Battery, "Failed to reset (write to) {:?}: {}",
} MAX_BATTERY_CHARGE_LEVEL_ATTR, e
) ),
setting: crate::settings::SettingVariant::Battery,
})
} else { } else {
Ok(()) Ok(())
} }
@ -373,8 +426,16 @@ impl Battery {
fn clamp_all(&mut self) { fn clamp_all(&mut self) {
if let Some(charge_rate) = &mut self.charge_rate { if let Some(charge_rate) = &mut self.charge_rate {
*charge_rate = *charge_rate = (*charge_rate).clamp(
(*charge_rate).clamp(self.limits.charge_rate.and_then(|lim| lim.min).unwrap_or(MIN_CHARGE_RATE), self.limits.charge_rate.and_then(|lim| lim.max).unwrap_or(MAX_CHARGE_RATE)); self.limits
.charge_rate
.and_then(|lim| lim.min)
.unwrap_or(MIN_CHARGE_RATE),
self.limits
.charge_rate
.and_then(|lim| lim.max)
.unwrap_or(MAX_CHARGE_RATE),
);
} }
} }
@ -558,13 +619,21 @@ impl Into<BatteryJson> for Battery {
charge_rate: self.charge_rate, charge_rate: self.charge_rate,
charge_mode: self.charge_mode.map(Self::charge_mode_to_str), charge_mode: self.charge_mode.map(Self::charge_mode_to_str),
events: events.into_iter().map(|x| x.into()).collect(), events: events.into_iter().map(|x| x.into()).collect(),
root: self.sysfs_bat.root().or(self.sysfs_hwmon.root()).and_then(|p| p.as_ref().to_str().map(|x| x.to_owned())) root: self
.sysfs_bat
.root()
.or(self.sysfs_hwmon.root())
.and_then(|p| p.as_ref().to_str().map(|x| x.to_owned())),
} }
} }
} }
impl ProviderBuilder<BatteryJson, GenericBatteryLimit> for Battery { impl ProviderBuilder<BatteryJson, GenericBatteryLimit> for Battery {
fn from_json_and_limits(persistent: BatteryJson, version: u64, limits: GenericBatteryLimit) -> Self { fn from_json_and_limits(
persistent: BatteryJson,
version: u64,
limits: GenericBatteryLimit,
) -> Self {
let hwmon_sys = Arc::new(Self::find_hwmon_sysfs(None::<&'static str>)); let hwmon_sys = Arc::new(Self::find_hwmon_sysfs(None::<&'static str>));
let ec = Arc::new(Mutex::new(UnnamedPowerEC::new())); let ec = Arc::new(Mutex::new(UnnamedPowerEC::new()));
match version { match version {
@ -586,14 +655,15 @@ impl ProviderBuilder<BatteryJson, GenericBatteryLimit> for Battery {
sysfs_hwmon: hwmon_sys, sysfs_hwmon: hwmon_sys,
bat_ec: ec, bat_ec: ec,
variant: super::Model::LCD, variant: super::Model::LCD,
}.remove_charge_limit_instructions(), }
.remove_charge_limit_instructions(),
_ => Self { _ => Self {
charge_rate: persistent.charge_rate, charge_rate: persistent.charge_rate,
charge_mode: persistent charge_mode: persistent
.charge_mode .charge_mode
.map(|x| Self::str_to_charge_mode(&x)) .map(|x| Self::str_to_charge_mode(&x))
.flatten(), .flatten(),
charge_limit: None, charge_limit: None,
events: persistent events: persistent
.events .events
.into_iter() .into_iter()
@ -605,7 +675,8 @@ impl ProviderBuilder<BatteryJson, GenericBatteryLimit> for Battery {
sysfs_hwmon: hwmon_sys, sysfs_hwmon: hwmon_sys,
bat_ec: ec, bat_ec: ec,
variant: super::Model::LCD, variant: super::Model::LCD,
}.remove_charge_limit_instructions(), }
.remove_charge_limit_instructions(),
} }
} }
@ -621,7 +692,8 @@ impl ProviderBuilder<BatteryJson, GenericBatteryLimit> for Battery {
sysfs_hwmon: Arc::new(Self::find_hwmon_sysfs(None::<&'static str>)), sysfs_hwmon: Arc::new(Self::find_hwmon_sysfs(None::<&'static str>)),
bat_ec: Arc::new(Mutex::new(UnnamedPowerEC::new())), bat_ec: Arc::new(Mutex::new(UnnamedPowerEC::new())),
variant: super::Model::LCD, variant: super::Model::LCD,
}.remove_charge_limit_instructions() }
.remove_charge_limit_instructions()
} }
} }
@ -675,8 +747,16 @@ impl TBattery for Battery {
fn limits(&self) -> crate::api::BatteryLimits { fn limits(&self) -> crate::api::BatteryLimits {
crate::api::BatteryLimits { crate::api::BatteryLimits {
charge_current: Some(RangeLimit { charge_current: Some(RangeLimit {
min: self.limits.charge_rate.and_then(|lim| lim.min).unwrap_or(MIN_CHARGE_RATE), min: self
max: self.limits.charge_rate.and_then(|lim| lim.max).unwrap_or(MAX_CHARGE_RATE), .limits
.charge_rate
.and_then(|lim| lim.min)
.unwrap_or(MIN_CHARGE_RATE),
max: self
.limits
.charge_rate
.and_then(|lim| lim.max)
.unwrap_or(MAX_CHARGE_RATE),
}), }),
charge_current_step: 50, charge_current_step: 50,
charge_modes: vec![ charge_modes: vec![

View file

@ -2,22 +2,20 @@ use std::convert::Into;
use sysfuss::{BasicEntityPath, SysEntity, SysEntityAttributesExt}; use sysfuss::{BasicEntityPath, SysEntity, SysEntityAttributesExt};
use limits_core::json_v2::{GenericCpusLimit, GenericCpuLimit}; use limits_core::json_v2::{GenericCpuLimit, GenericCpusLimit};
use super::POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT;
use super::util::{range_max_or_fallback, range_min_or_fallback}; use super::util::{range_max_or_fallback, range_min_or_fallback};
use super::POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT;
use crate::api::RangeLimit; use crate::api::RangeLimit;
use crate::persist::CpuJson; use crate::persist::CpuJson;
use crate::settings::{min_max_from_json, MinMax}; use crate::settings::{min_max_from_json, MinMax};
use crate::settings::{OnResume, OnSet, SettingError}; use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{TCpu, TCpus, ProviderBuilder}; use crate::settings::{ProviderBuilder, TCpu, TCpus};
const CPU_PRESENT_PATH: &str = "/sys/devices/system/cpu/present"; const CPU_PRESENT_PATH: &str = "/sys/devices/system/cpu/present";
const CPU_SMT_PATH: &str = "/sys/devices/system/cpu/smt/control"; const CPU_SMT_PATH: &str = "/sys/devices/system/cpu/smt/control";
const CARD_EXTENSIONS: &[&'static str] = &[ const CARD_EXTENSIONS: &[&'static str] = &[super::DPM_FORCE_LIMITS_ATTRIBUTE];
super::DPM_FORCE_LIMITS_ATTRIBUTE
];
const MAX_CLOCK: u64 = 3500; const MAX_CLOCK: u64 = 3500;
const MIN_MAX_CLOCK: u64 = 200; // minimum value allowed for maximum CPU clock, MHz const MIN_MAX_CLOCK: u64 = 200; // minimum value allowed for maximum CPU clock, MHz
@ -109,7 +107,11 @@ impl Cpus {
} }
impl ProviderBuilder<Vec<CpuJson>, GenericCpusLimit> for Cpus { impl ProviderBuilder<Vec<CpuJson>, GenericCpusLimit> for Cpus {
fn from_json_and_limits(mut persistent: Vec<CpuJson>, version: u64, limits: GenericCpusLimit) -> Self { fn from_json_and_limits(
mut persistent: Vec<CpuJson>,
version: u64,
limits: GenericCpusLimit,
) -> Self {
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.reset(); POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.reset();
let (_, can_smt) = Self::system_smt_capabilities(); let (_, can_smt) = Self::system_smt_capabilities();
let mut result = Vec::with_capacity(persistent.len()); let mut result = Vec::with_capacity(persistent.len());
@ -123,18 +125,9 @@ impl ProviderBuilder<Vec<CpuJson>, GenericCpusLimit> for Cpus {
} }
} }
let new_cpu = if let Some(cpu_limit) = limits.cpus.get(i) { let new_cpu = if let Some(cpu_limit) = limits.cpus.get(i) {
Cpu::from_json_and_limits( Cpu::from_json_and_limits(cpu, version, i, cpu_limit.to_owned())
cpu,
version,
i,
cpu_limit.to_owned()
)
} else { } else {
Cpu::from_json( Cpu::from_json(cpu, version, i)
cpu,
version,
i,
)
}; };
result.push(new_cpu); result.push(new_cpu);
} }
@ -160,10 +153,7 @@ impl ProviderBuilder<Vec<CpuJson>, GenericCpusLimit> for Cpus {
let mut sys_cpus = Vec::with_capacity(max_cpu); let mut sys_cpus = Vec::with_capacity(max_cpu);
for i in 0..max_cpu { for i in 0..max_cpu {
let new_cpu = if let Some(cpu_limit) = limits.cpus.get(i) { let new_cpu = if let Some(cpu_limit) = limits.cpus.get(i) {
Cpu::from_limits( Cpu::from_limits(i, cpu_limit.to_owned())
i,
cpu_limit.to_owned()
)
} else { } else {
Cpu::system_default(i) Cpu::system_default(i)
}; };
@ -255,7 +245,12 @@ enum ClockType {
impl Cpu { impl Cpu {
#[inline] #[inline]
fn from_json_and_limits(other: CpuJson, version: u64, i: usize, oc_limits: GenericCpuLimit) -> Self { fn from_json_and_limits(
other: CpuJson,
version: u64,
i: usize,
oc_limits: GenericCpuLimit,
) -> Self {
match version { match version {
0 => Self { 0 => Self {
online: other.online, online: other.online,
@ -280,13 +275,21 @@ impl Cpu {
#[inline] #[inline]
fn from_json(other: CpuJson, version: u64, i: usize) -> Self { fn from_json(other: CpuJson, version: u64, i: usize) -> Self {
let oc_limits = GenericCpuLimit::default_for(&limits_core::json_v2::CpuLimitType::SteamDeck, i); let oc_limits =
GenericCpuLimit::default_for(&limits_core::json_v2::CpuLimitType::SteamDeck, i);
Self::from_json_and_limits(other, version, i, oc_limits) Self::from_json_and_limits(other, version, i, oc_limits)
} }
fn find_card_sysfs(root: Option<impl AsRef<std::path::Path>>) -> BasicEntityPath { fn find_card_sysfs(root: Option<impl AsRef<std::path::Path>>) -> BasicEntityPath {
let root = crate::settings::util::root_or_default_sysfs(root); let root = crate::settings::util::root_or_default_sysfs(root);
match root.class("drm", sysfuss::capability::attributes(crate::settings::util::CARD_NEEDS.into_iter().map(|s| s.to_string()))) { match root.class(
"drm",
sysfuss::capability::attributes(
crate::settings::util::CARD_NEEDS
.into_iter()
.map(|s| s.to_string()),
),
) {
Ok(iter) => { Ok(iter) => {
let card = iter let card = iter
.filter(|ent| if let Ok(name) = ent.name() { name.starts_with("card")} else { false }) .filter(|ent| if let Ok(name) = ent.name() { name.starts_with("card")} else { false })
@ -298,37 +301,45 @@ impl Cpu {
}); });
log::info!("Found SteamDeck drm in sysfs: {}", card.as_ref().display()); log::info!("Found SteamDeck drm in sysfs: {}", card.as_ref().display());
card card
}, }
Err(e) => { Err(e) => {
log::error!("Failed to find SteamDeck drm in sysfs ({}), using naive fallback", e); log::error!(
"Failed to find SteamDeck drm in sysfs ({}), using naive fallback",
e
);
BasicEntityPath::new(root.as_ref().join("sys/class/drm/card0")) BasicEntityPath::new(root.as_ref().join("sys/class/drm/card0"))
} }
} }
} }
fn set_clock_limit(&self, index: usize, speed: u64, mode: ClockType) -> Result<(), SettingError> { fn set_clock_limit(
&self,
index: usize,
speed: u64,
mode: ClockType,
) -> Result<(), SettingError> {
let payload = format!("p {} {} {}\n", index / 2, mode as u8, speed); let payload = format!("p {} {} {}\n", index / 2, mode as u8, speed);
self.sysfs.set(CPU_CLOCK_LIMITS_ATTRIBUTE.to_owned(), &payload).map_err(|e| { self.sysfs
SettingError { .set(CPU_CLOCK_LIMITS_ATTRIBUTE.to_owned(), &payload)
.map_err(|e| SettingError {
msg: format!( msg: format!(
"Failed to write `{}` to `{}`: {}", "Failed to write `{}` to `{}`: {}",
&payload, CPU_CLOCK_LIMITS_ATTRIBUTE, e &payload, CPU_CLOCK_LIMITS_ATTRIBUTE, e
), ),
setting: crate::settings::SettingVariant::Cpu, setting: crate::settings::SettingVariant::Cpu,
} })
})
} }
fn reset_clock_limits(&self) -> Result<(), SettingError> { fn reset_clock_limits(&self) -> Result<(), SettingError> {
self.sysfs.set(CPU_CLOCK_LIMITS_ATTRIBUTE.to_owned(), "r\n").map_err(|e| { self.sysfs
SettingError { .set(CPU_CLOCK_LIMITS_ATTRIBUTE.to_owned(), "r\n")
.map_err(|e| SettingError {
msg: format!( msg: format!(
"Failed to write `r` to `{}`: {}", "Failed to write `r` to `{}`: {}",
CPU_CLOCK_LIMITS_ATTRIBUTE, e CPU_CLOCK_LIMITS_ATTRIBUTE, e
), ),
setting: crate::settings::SettingVariant::Cpu, setting: crate::settings::SettingVariant::Cpu,
} })
})
} }
fn set_clock_limits(&mut self) -> Result<(), Vec<SettingError>> { fn set_clock_limits(&mut self) -> Result<(), Vec<SettingError>> {
@ -350,11 +361,12 @@ impl Cpu {
} }
// min clock // min clock
if let Some(min) = clock_limits.min { if let Some(min) = clock_limits.min {
let valid_min = if min < range_min_or_fallback(&self.limits.clock_min, MIN_MIN_CLOCK) { let valid_min =
range_min_or_fallback(&self.limits.clock_min, MIN_MIN_CLOCK) if min < range_min_or_fallback(&self.limits.clock_min, MIN_MIN_CLOCK) {
} else { range_min_or_fallback(&self.limits.clock_min, MIN_MIN_CLOCK)
min } else {
}; min
};
self.set_clock_limit(self.index, valid_min, ClockType::Min) self.set_clock_limit(self.index, valid_min, ClockType::Min)
.unwrap_or_else(|e| errors.push(e)); .unwrap_or_else(|e| errors.push(e));
} }
@ -371,22 +383,30 @@ impl Cpu {
let mut errors = Vec::new(); let mut errors = Vec::new();
self.state.clock_limits_set = false; self.state.clock_limits_set = false;
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_cpu(false, self.index); POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_cpu(false, self.index);
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level(&self.sysfs)?;
.enforce_level(&self.sysfs)?;
if POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.needs_manual() { if POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.needs_manual() {
// always set clock speeds, since it doesn't reset correctly (kernel/hardware bug) // always set clock speeds, since it doesn't reset correctly (kernel/hardware bug)
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level(&self.sysfs)?; POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level(&self.sysfs)?;
// disable manual clock limits // disable manual clock limits
log::debug!("Setting CPU {} to default clockspeed", self.index); log::debug!("Setting CPU {} to default clockspeed", self.index);
// max clock // max clock
self.set_clock_limit(self.index, range_max_or_fallback(&self.limits.clock_max, MAX_CLOCK), ClockType::Max) self.set_clock_limit(
.unwrap_or_else(|e| errors.push(e)); self.index,
range_max_or_fallback(&self.limits.clock_max, MAX_CLOCK),
ClockType::Max,
)
.unwrap_or_else(|e| errors.push(e));
// min clock // min clock
self.set_clock_limit(self.index, range_min_or_fallback(&self.limits.clock_min, MIN_MIN_CLOCK), ClockType::Min) self.set_clock_limit(
.unwrap_or_else(|e| errors.push(e)); self.index,
range_min_or_fallback(&self.limits.clock_min, MIN_MIN_CLOCK),
ClockType::Min,
)
.unwrap_or_else(|e| errors.push(e));
} }
// TODO remove this when it's no longer needed // TODO remove this when it's no longer needed
self.clock_unset_workaround().unwrap_or_else(|mut e| errors.append(&mut e)); self.clock_unset_workaround()
.unwrap_or_else(|mut e| errors.append(&mut e));
if errors.is_empty() { if errors.is_empty() {
Ok(()) Ok(())
} else { } else {
@ -407,11 +427,19 @@ impl Cpu {
// disable manual clock limits // disable manual clock limits
log::debug!("Setting CPU {} to default clockspeed", self.index); log::debug!("Setting CPU {} to default clockspeed", self.index);
// max clock // max clock
self.set_clock_limit(self.index, range_max_or_fallback(&self.limits.clock_max, MAX_CLOCK), ClockType::Max) self.set_clock_limit(
.unwrap_or_else(|e| errors.push(e)); self.index,
range_max_or_fallback(&self.limits.clock_max, MAX_CLOCK),
ClockType::Max,
)
.unwrap_or_else(|e| errors.push(e));
// min clock // min clock
self.set_clock_limit(self.index, range_min_or_fallback(&self.limits.clock_min, MIN_MIN_CLOCK), ClockType::Min) self.set_clock_limit(
.unwrap_or_else(|e| errors.push(e)); self.index,
range_min_or_fallback(&self.limits.clock_min, MIN_MIN_CLOCK),
ClockType::Min,
)
.unwrap_or_else(|e| errors.push(e));
self.set_confirm().unwrap_or_else(|e| errors.push(e)); self.set_confirm().unwrap_or_else(|e| errors.push(e));
@ -430,12 +458,15 @@ impl Cpu {
} }
fn set_confirm(&self) -> Result<(), SettingError> { fn set_confirm(&self) -> Result<(), SettingError> {
self.sysfs.set(CPU_CLOCK_LIMITS_ATTRIBUTE.to_owned(), "c\n").map_err(|e| { self.sysfs
SettingError { .set(CPU_CLOCK_LIMITS_ATTRIBUTE.to_owned(), "c\n")
msg: format!("Failed to write `c` to `{}`: {}", CPU_CLOCK_LIMITS_ATTRIBUTE, e), .map_err(|e| SettingError {
msg: format!(
"Failed to write `c` to `{}`: {}",
CPU_CLOCK_LIMITS_ATTRIBUTE, e
),
setting: crate::settings::SettingVariant::Cpu, setting: crate::settings::SettingVariant::Cpu,
} })
})
} }
fn set_force_performance_related(&mut self) -> Result<(), Vec<SettingError>> { fn set_force_performance_related(&mut self) -> Result<(), Vec<SettingError>> {
@ -504,12 +535,16 @@ impl Cpu {
fn clamp_all(&mut self) { fn clamp_all(&mut self) {
if let Some(clock_limits) = &mut self.clock_limits { if let Some(clock_limits) = &mut self.clock_limits {
if let Some(min) = clock_limits.min { if let Some(min) = clock_limits.min {
clock_limits.min = clock_limits.min = Some(min.clamp(
Some(min.clamp(range_min_or_fallback(&self.limits.clock_max, MIN_MAX_CLOCK), range_max_or_fallback(&self.limits.clock_min, MAX_CLOCK))); range_min_or_fallback(&self.limits.clock_max, MIN_MAX_CLOCK),
range_max_or_fallback(&self.limits.clock_min, MAX_CLOCK),
));
} }
if let Some(max) = clock_limits.max { if let Some(max) = clock_limits.max {
clock_limits.max = clock_limits.max = Some(max.clamp(
Some(max.clamp(range_min_or_fallback(&self.limits.clock_max, MIN_MAX_CLOCK), range_max_or_fallback(&self.limits.clock_max, MAX_CLOCK))); range_min_or_fallback(&self.limits.clock_max, MIN_MAX_CLOCK),
range_max_or_fallback(&self.limits.clock_max, MAX_CLOCK),
));
} }
} }
} }
@ -534,12 +569,15 @@ impl Cpu {
limits: oc_limits, limits: oc_limits,
index: cpu_index, index: cpu_index,
state: crate::state::steam_deck::Cpu::default(), state: crate::state::steam_deck::Cpu::default(),
sysfs: Self::find_card_sysfs(None::<&'static str>) sysfs: Self::find_card_sysfs(None::<&'static str>),
} }
} }
fn system_default(cpu_index: usize) -> Self { fn system_default(cpu_index: usize) -> Self {
Self::from_limits(cpu_index, GenericCpuLimit::default_for(&limits_core::json_v2::CpuLimitType::SteamDeck, cpu_index)) Self::from_limits(
cpu_index,
GenericCpuLimit::default_for(&limits_core::json_v2::CpuLimitType::SteamDeck, cpu_index),
)
} }
fn limits(&self) -> crate::api::CpuLimits { fn limits(&self) -> crate::api::CpuLimits {
@ -578,7 +616,10 @@ impl Into<CpuJson> for Cpu {
online: self.online, online: self.online,
clock_limits: self.clock_limits.map(|x| x.into()), clock_limits: self.clock_limits.map(|x| x.into()),
governor: self.governor, governor: self.governor,
root: self.sysfs.root().and_then(|p| p.as_ref().to_str().map(|r| r.to_owned())) root: self
.sysfs
.root()
.and_then(|p| p.as_ref().to_str().map(|r| r.to_owned())),
} }
} }
} }

View file

@ -1,15 +1,18 @@
use std::convert::Into; use std::convert::Into;
use sysfuss::{BasicEntityPath, HwMonPath, SysEntity, capability::attributes, SysEntityAttributes, SysEntityAttributesExt, SysAttribute}; use sysfuss::{
capability::attributes, BasicEntityPath, HwMonPath, SysAttribute, SysEntity,
SysEntityAttributes, SysEntityAttributesExt,
};
use limits_core::json_v2::GenericGpuLimit; use limits_core::json_v2::GenericGpuLimit;
use super::POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT; use super::POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT;
use crate::api::RangeLimit; use crate::api::RangeLimit;
use crate::persist::GpuJson; use crate::persist::GpuJson;
use crate::settings::{TGpu, ProviderBuilder};
use crate::settings::{min_max_from_json, MinMax}; use crate::settings::{min_max_from_json, MinMax};
use crate::settings::{OnResume, OnSet, SettingError}; use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{ProviderBuilder, TGpu};
// usually in /sys/class/hwmon/hwmon4/<attribute> // usually in /sys/class/hwmon/hwmon4/<attribute>
const SLOW_PPT_ATTRIBUTE: sysfuss::HwMonAttribute = sysfuss::HwMonAttribute::custom("power1_cap"); const SLOW_PPT_ATTRIBUTE: sysfuss::HwMonAttribute = sysfuss::HwMonAttribute::custom("power1_cap");
@ -60,7 +63,14 @@ const PPT_DIVISOR: u64 = 1_000;
impl Gpu { impl Gpu {
fn find_card_sysfs(root: Option<impl AsRef<std::path::Path>>) -> BasicEntityPath { fn find_card_sysfs(root: Option<impl AsRef<std::path::Path>>) -> BasicEntityPath {
let root = crate::settings::util::root_or_default_sysfs(root); let root = crate::settings::util::root_or_default_sysfs(root);
match root.class("drm", attributes(crate::settings::util::CARD_NEEDS.into_iter().map(|s| s.to_string()))) { match root.class(
"drm",
attributes(
crate::settings::util::CARD_NEEDS
.into_iter()
.map(|s| s.to_string()),
),
) {
Ok(iter) => { Ok(iter) => {
let card = iter let card = iter
.filter(|ent| if let Ok(name) = ent.name() { name.starts_with("card")} else { false }) .filter(|ent| if let Ok(name) = ent.name() { name.starts_with("card")} else { false })
@ -70,11 +80,17 @@ impl Gpu {
log::error!("Failed to find SteamDeck gpu drm in sysfs (no results), using naive fallback"); log::error!("Failed to find SteamDeck gpu drm in sysfs (no results), using naive fallback");
BasicEntityPath::new(root.as_ref().join("sys/class/drm/card0")) BasicEntityPath::new(root.as_ref().join("sys/class/drm/card0"))
}); });
log::info!("Found SteamDeck gpu drm in sysfs: {}", card.as_ref().display()); log::info!(
"Found SteamDeck gpu drm in sysfs: {}",
card.as_ref().display()
);
card card
}, }
Err(e) => { Err(e) => {
log::error!("Failed to find SteamDeck gpu drm in sysfs ({}), using naive fallback", e); log::error!(
"Failed to find SteamDeck gpu drm in sysfs ({}), using naive fallback",
e
);
BasicEntityPath::new(root.as_ref().join("sys/class/drm/card0")) BasicEntityPath::new(root.as_ref().join("sys/class/drm/card0"))
} }
} }
@ -82,33 +98,47 @@ impl Gpu {
fn find_hwmon_sysfs(root: Option<impl AsRef<std::path::Path>>) -> HwMonPath { fn find_hwmon_sysfs(root: Option<impl AsRef<std::path::Path>>) -> HwMonPath {
let root = crate::settings::util::root_or_default_sysfs(root); let root = crate::settings::util::root_or_default_sysfs(root);
let hwmon = root.hwmon_by_name(super::util::GPU_HWMON_NAME).unwrap_or_else(|e| { let hwmon = root
log::error!("Failed to find SteamDeck gpu hwmon in sysfs ({}), using naive fallback", e); .hwmon_by_name(super::util::GPU_HWMON_NAME)
root.hwmon_by_index(4) .unwrap_or_else(|e| {
}); log::error!(
log::info!("Found SteamDeck gpu hwmon {} in sysfs: {}", super::util::GPU_HWMON_NAME, hwmon.as_ref().display()); "Failed to find SteamDeck gpu hwmon in sysfs ({}), using naive fallback",
e
);
root.hwmon_by_index(4)
});
log::info!(
"Found SteamDeck gpu hwmon {} in sysfs: {}",
super::util::GPU_HWMON_NAME,
hwmon.as_ref().display()
);
hwmon hwmon
} }
fn set_clock_limit(&self, speed: u64, mode: ClockType) -> Result<(), SettingError> { fn set_clock_limit(&self, speed: u64, mode: ClockType) -> Result<(), SettingError> {
let payload = format!("s {} {}\n", mode as u8, speed); let payload = format!("s {} {}\n", mode as u8, speed);
let path = GPU_CLOCK_LIMITS_ATTRIBUTE.path(&self.sysfs_card); let path = GPU_CLOCK_LIMITS_ATTRIBUTE.path(&self.sysfs_card);
self.sysfs_card.set(GPU_CLOCK_LIMITS_ATTRIBUTE.to_owned(), &payload).map_err(|e| { self.sysfs_card
SettingError { .set(GPU_CLOCK_LIMITS_ATTRIBUTE.to_owned(), &payload)
msg: format!("Failed to write `{}` to `{}`: {}", &payload, path.display(), e), .map_err(|e| SettingError {
msg: format!(
"Failed to write `{}` to `{}`: {}",
&payload,
path.display(),
e
),
setting: crate::settings::SettingVariant::Gpu, setting: crate::settings::SettingVariant::Gpu,
} })
})
} }
fn set_confirm(&self) -> Result<(), SettingError> { fn set_confirm(&self) -> Result<(), SettingError> {
let path = GPU_CLOCK_LIMITS_ATTRIBUTE.path(&self.sysfs_card); let path = GPU_CLOCK_LIMITS_ATTRIBUTE.path(&self.sysfs_card);
self.sysfs_card.set(GPU_CLOCK_LIMITS_ATTRIBUTE.to_owned(), "c\n").map_err(|e| { self.sysfs_card
SettingError { .set(GPU_CLOCK_LIMITS_ATTRIBUTE.to_owned(), "c\n")
.map_err(|e| SettingError {
msg: format!("Failed to write `c` to `{}`: {}", path.display(), e), msg: format!("Failed to write `c` to `{}`: {}", path.display(), e),
setting: crate::settings::SettingVariant::Gpu, setting: crate::settings::SettingVariant::Gpu,
} })
})
} }
fn is_memory_clock_maxed(&self) -> bool { fn is_memory_clock_maxed(&self) -> bool {
@ -116,7 +146,12 @@ impl Gpu {
if let Some(limit) = &self.limits.memory_clock { if let Some(limit) = &self.limits.memory_clock {
if let Some(limit) = &limit.max { if let Some(limit) = &limit.max {
if let Some(step) = &self.limits.memory_clock_step { if let Some(step) = &self.limits.memory_clock_step {
log::debug!("chosen_clock: {}, limit_clock: {}, step: {}", clock, limit, step); log::debug!(
"chosen_clock: {}, limit_clock: {}, step: {}",
clock,
limit,
step
);
return clock > &(limit - step); return clock > &(limit - step);
} else { } else {
log::debug!("chosen_clock: {}, limit_clock: {}", clock, limit); log::debug!("chosen_clock: {}, limit_clock: {}", clock, limit);
@ -129,7 +164,10 @@ impl Gpu {
} }
fn quantize_memory_clock(&self, clock: u64) -> u64 { fn quantize_memory_clock(&self, clock: u64) -> u64 {
if let Ok(f) = self.sysfs_card.read_value(GPU_MEMORY_DOWNCLOCK_ATTRIBUTE.to_owned()) { if let Ok(f) = self
.sysfs_card
.read_value(GPU_MEMORY_DOWNCLOCK_ATTRIBUTE.to_owned())
{
let options = parse_pp_dpm_fclk(&String::from_utf8_lossy(&f)); let options = parse_pp_dpm_fclk(&String::from_utf8_lossy(&f));
// round (and find) nearest valid clock step // round (and find) nearest valid clock step
// roughly price is right strategy (clock step will always be lower or equal to chosen) // roughly price is right strategy (clock step will always be lower or equal to chosen)
@ -142,7 +180,7 @@ impl Gpu {
if i == 0 { if i == 0 {
return *current_val_opt as _; return *current_val_opt as _;
} else { } else {
return options[i-1].0 as _; return options[i - 1].0 as _;
} }
} }
} }
@ -160,9 +198,11 @@ impl Gpu {
use std::fmt::Write; use std::fmt::Write;
let mut payload = String::from("0"); let mut payload = String::from("0");
for i in 1..max_val { for i in 1..max_val {
write!(payload, " {}", i).expect("Failed to write to memory payload (should be infallible!?)"); 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!?)"); write!(payload, " {}\n", max_val)
.expect("Failed to write to memory payload (should be infallible!?)");
payload payload
} }
} }
@ -177,11 +217,13 @@ impl Gpu {
self.state.clock_limits_set = true; self.state.clock_limits_set = true;
// max clock // max clock
if let Some(max) = clock_limits.max { if let Some(max) = clock_limits.max {
self.set_clock_limit(max, ClockType::Max).unwrap_or_else(|e| errors.push(e)); self.set_clock_limit(max, ClockType::Max)
.unwrap_or_else(|e| errors.push(e));
} }
// min clock // min clock
if let Some(min) = clock_limits.min { if let Some(min) = clock_limits.min {
self.set_clock_limit(min, ClockType::Min).unwrap_or_else(|e| errors.push(e)); self.set_clock_limit(min, ClockType::Min)
.unwrap_or_else(|e| errors.push(e));
} }
self.set_confirm().unwrap_or_else(|e| errors.push(e)); self.set_confirm().unwrap_or_else(|e| errors.push(e));
@ -195,11 +237,23 @@ impl Gpu {
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level(&self.sysfs_card)?; POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level(&self.sysfs_card)?;
// disable manual clock limits // disable manual clock limits
// max clock // max clock
self.set_clock_limit(self.limits.clock_max.and_then(|lim| lim.max).unwrap_or(MAX_CLOCK), ClockType::Max) self.set_clock_limit(
.unwrap_or_else(|e| errors.push(e)); self.limits
.clock_max
.and_then(|lim| lim.max)
.unwrap_or(MAX_CLOCK),
ClockType::Max,
)
.unwrap_or_else(|e| errors.push(e));
// min clock // min clock
self.set_clock_limit(self.limits.clock_min.and_then(|lim| lim.min).unwrap_or(MIN_CLOCK), ClockType::Min) self.set_clock_limit(
.unwrap_or_else(|e| errors.push(e)); self.limits
.clock_min
.and_then(|lim| lim.min)
.unwrap_or(MIN_CLOCK),
ClockType::Min,
)
.unwrap_or_else(|e| errors.push(e));
self.set_confirm().unwrap_or_else(|e| errors.push(e)); self.set_confirm().unwrap_or_else(|e| errors.push(e));
} else { } else {
@ -218,28 +272,37 @@ impl Gpu {
fn set_memory_speed(&self, clock: u64) -> Result<(), SettingError> { fn set_memory_speed(&self, clock: u64) -> Result<(), SettingError> {
let path = GPU_MEMORY_DOWNCLOCK_ATTRIBUTE.path(&self.sysfs_card); let path = GPU_MEMORY_DOWNCLOCK_ATTRIBUTE.path(&self.sysfs_card);
let payload = self.build_memory_clock_payload(clock); let payload = self.build_memory_clock_payload(clock);
log::debug!("Generated payload for gpu fclk (memory): `{}` (is maxed? {})", payload, self.is_memory_clock_maxed()); log::debug!(
self.sysfs_card.set(GPU_MEMORY_DOWNCLOCK_ATTRIBUTE.to_owned(), payload).map_err(|e| { "Generated payload for gpu fclk (memory): `{}` (is maxed? {})",
SettingError { payload,
self.is_memory_clock_maxed()
);
self.sysfs_card
.set(GPU_MEMORY_DOWNCLOCK_ATTRIBUTE.to_owned(), payload)
.map_err(|e| SettingError {
msg: format!("Failed to write to `{}`: {}", path.display(), e), msg: format!("Failed to write to `{}`: {}", path.display(), e),
setting: crate::settings::SettingVariant::Gpu, setting: crate::settings::SettingVariant::Gpu,
} })
})
} }
fn set_force_performance_related(&mut self) -> Result<(), Vec<SettingError>> { fn set_force_performance_related(&mut self) -> Result<(), Vec<SettingError>> {
let mut errors = Vec::new(); let mut errors = Vec::new();
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_gpu(!self.is_memory_clock_maxed() || self.clock_limits.is_some());
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT
.enforce_level(&self.sysfs_card) .set_gpu(!self.is_memory_clock_maxed() || self.clock_limits.is_some());
.unwrap_or_else(|mut e| errors.append(&mut e)); POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT
.enforce_level(&self.sysfs_card)
.unwrap_or_else(|mut e| errors.append(&mut e));
// enable/disable downclock of GPU memory (to 400Mhz?) // enable/disable downclock of GPU memory (to 400Mhz?)
self.set_memory_speed( self.set_memory_speed(
self.memory_clock self.memory_clock
.or_else(|| self.limits.memory_clock .or_else(|| {
.map(|lim| lim.max.unwrap_or(MAX_MEMORY_CLOCK)) self.limits
).unwrap_or(MAX_MEMORY_CLOCK) .memory_clock
).unwrap_or_else(|e| errors.push(e)); .map(|lim| lim.max.unwrap_or(MAX_MEMORY_CLOCK))
})
.unwrap_or(MAX_MEMORY_CLOCK),
)
.unwrap_or_else(|e| errors.push(e));
self.set_clocks() self.set_clocks()
.unwrap_or_else(|mut e| errors.append(&mut e)); .unwrap_or_else(|mut e| errors.append(&mut e));
// commit changes (if no errors have already occured) // commit changes (if no errors have already occured)
@ -262,7 +325,8 @@ impl Gpu {
// set fast PPT // set fast PPT
if let Some(fast_ppt) = &self.fast_ppt { if let Some(fast_ppt) = &self.fast_ppt {
self.state.fast_ppt_set = true; self.state.fast_ppt_set = true;
self.sysfs_hwmon.set(FAST_PPT_ATTRIBUTE, fast_ppt) self.sysfs_hwmon
.set(FAST_PPT_ATTRIBUTE, fast_ppt)
.map_err(|e| SettingError { .map_err(|e| SettingError {
msg: format!( msg: format!(
"Failed to write `{}` to `{:?}`: {}", "Failed to write `{}` to `{:?}`: {}",
@ -276,7 +340,8 @@ impl Gpu {
} else if self.state.fast_ppt_set { } else if self.state.fast_ppt_set {
self.state.fast_ppt_set = false; self.state.fast_ppt_set = false;
let fast_ppt = self.limits.fast_ppt_default.unwrap_or(MIDDLE_PPT); let fast_ppt = self.limits.fast_ppt_default.unwrap_or(MIDDLE_PPT);
self.sysfs_hwmon.set(FAST_PPT_ATTRIBUTE, fast_ppt) self.sysfs_hwmon
.set(FAST_PPT_ATTRIBUTE, fast_ppt)
.map_err(|e| SettingError { .map_err(|e| SettingError {
msg: format!( msg: format!(
"Failed to write `{}` to `{:?}`: {}", "Failed to write `{}` to `{:?}`: {}",
@ -291,7 +356,8 @@ impl Gpu {
// set slow PPT // set slow PPT
if let Some(slow_ppt) = &self.slow_ppt { if let Some(slow_ppt) = &self.slow_ppt {
self.state.slow_ppt_set = true; self.state.slow_ppt_set = true;
self.sysfs_hwmon.set(SLOW_PPT_ATTRIBUTE, slow_ppt) self.sysfs_hwmon
.set(SLOW_PPT_ATTRIBUTE, slow_ppt)
.map_err(|e| SettingError { .map_err(|e| SettingError {
msg: format!( msg: format!(
"Failed to write `{}` to `{:?}`: {}", "Failed to write `{}` to `{:?}`: {}",
@ -305,7 +371,8 @@ impl Gpu {
} else if self.state.slow_ppt_set { } else if self.state.slow_ppt_set {
self.state.slow_ppt_set = false; self.state.slow_ppt_set = false;
let slow_ppt = self.limits.slow_ppt_default.unwrap_or(MIDDLE_PPT); let slow_ppt = self.limits.slow_ppt_default.unwrap_or(MIDDLE_PPT);
self.sysfs_hwmon.set(SLOW_PPT_ATTRIBUTE, slow_ppt) self.sysfs_hwmon
.set(SLOW_PPT_ATTRIBUTE, slow_ppt)
.map_err(|e| SettingError { .map_err(|e| SettingError {
msg: format!( msg: format!(
"Failed to write `{}` to `{:?}`: {}", "Failed to write `{}` to `{:?}`: {}",
@ -328,23 +395,72 @@ impl Gpu {
fn clamp_all(&mut self) { fn clamp_all(&mut self) {
if let Some(fast_ppt) = &mut self.fast_ppt { if let Some(fast_ppt) = &mut self.fast_ppt {
*fast_ppt = (*fast_ppt).clamp(self.limits.fast_ppt.and_then(|lim| lim.min).unwrap_or(MIN_FAST_PPT), self.limits.fast_ppt.and_then(|lim| lim.max).unwrap_or(MAX_FAST_PPT)); *fast_ppt = (*fast_ppt).clamp(
self.limits
.fast_ppt
.and_then(|lim| lim.min)
.unwrap_or(MIN_FAST_PPT),
self.limits
.fast_ppt
.and_then(|lim| lim.max)
.unwrap_or(MAX_FAST_PPT),
);
} }
if let Some(slow_ppt) = &mut self.slow_ppt { if let Some(slow_ppt) = &mut self.slow_ppt {
*slow_ppt = (*slow_ppt).clamp(self.limits.slow_ppt.and_then(|lim| lim.min).unwrap_or(MIN_SLOW_PPT), self.limits.slow_ppt.and_then(|lim| lim.max).unwrap_or(MAX_SLOW_PPT)); *slow_ppt = (*slow_ppt).clamp(
self.limits
.slow_ppt
.and_then(|lim| lim.min)
.unwrap_or(MIN_SLOW_PPT),
self.limits
.slow_ppt
.and_then(|lim| lim.max)
.unwrap_or(MAX_SLOW_PPT),
);
} }
if let Some(clock_limits) = &mut self.clock_limits { if let Some(clock_limits) = &mut self.clock_limits {
if let Some(min) = clock_limits.min { if let Some(min) = clock_limits.min {
clock_limits.min = clock_limits.min = Some(
Some(min.clamp(self.limits.clock_min.and_then(|lim| lim.min).unwrap_or(MIN_CLOCK), self.limits.clock_min.and_then(|lim| lim.max).unwrap_or(MAX_CLOCK))); min.clamp(
self.limits
.clock_min
.and_then(|lim| lim.min)
.unwrap_or(MIN_CLOCK),
self.limits
.clock_min
.and_then(|lim| lim.max)
.unwrap_or(MAX_CLOCK),
),
);
} }
if let Some(max) = clock_limits.max { if let Some(max) = clock_limits.max {
clock_limits.max = clock_limits.max = Some(
Some(max.clamp(self.limits.clock_max.and_then(|lim| lim.min).unwrap_or(MIN_CLOCK), self.limits.clock_max.and_then(|lim| lim.max).unwrap_or(MAX_CLOCK))); max.clamp(
self.limits
.clock_max
.and_then(|lim| lim.min)
.unwrap_or(MIN_CLOCK),
self.limits
.clock_max
.and_then(|lim| lim.max)
.unwrap_or(MAX_CLOCK),
),
);
} }
} }
if let Some(mem_clock) = self.memory_clock { if let Some(mem_clock) = self.memory_clock {
self.memory_clock = Some(mem_clock.clamp(self.limits.memory_clock.and_then(|lim| lim.min).unwrap_or(MIN_MEMORY_CLOCK), self.limits.memory_clock.and_then(|lim| lim.max).unwrap_or(MAX_MEMORY_CLOCK))); self.memory_clock = Some(
mem_clock.clamp(
self.limits
.memory_clock
.and_then(|lim| lim.min)
.unwrap_or(MIN_MEMORY_CLOCK),
self.limits
.memory_clock
.and_then(|lim| lim.max)
.unwrap_or(MAX_MEMORY_CLOCK),
),
);
} }
} }
@ -364,7 +480,11 @@ impl Into<GpuJson> for Gpu {
tdp_boost: None, tdp_boost: None,
clock_limits: self.clock_limits.map(|x| x.into()), clock_limits: self.clock_limits.map(|x| x.into()),
memory_clock: self.memory_clock, memory_clock: self.memory_clock,
root: self.sysfs_card.root().or(self.sysfs_hwmon.root()).and_then(|p| p.as_ref().to_str().map(|r| r.to_owned())) root: self
.sysfs_card
.root()
.or(self.sysfs_hwmon.root())
.and_then(|p| p.as_ref().to_str().map(|r| r.to_owned())),
} }
} }
} }
@ -375,7 +495,9 @@ impl ProviderBuilder<GpuJson, GenericGpuLimit> for Gpu {
0 => Self { 0 => Self {
fast_ppt: persistent.fast_ppt, fast_ppt: persistent.fast_ppt,
slow_ppt: persistent.slow_ppt, slow_ppt: persistent.slow_ppt,
clock_limits: persistent.clock_limits.map(|x| min_max_from_json(x, version)), clock_limits: persistent
.clock_limits
.map(|x| min_max_from_json(x, version)),
memory_clock: persistent.memory_clock, memory_clock: persistent.memory_clock,
limits: limits, limits: limits,
state: crate::state::steam_deck::Gpu::default(), state: crate::state::steam_deck::Gpu::default(),
@ -386,7 +508,9 @@ impl ProviderBuilder<GpuJson, GenericGpuLimit> for Gpu {
_ => Self { _ => Self {
fast_ppt: persistent.fast_ppt, fast_ppt: persistent.fast_ppt,
slow_ppt: persistent.slow_ppt, slow_ppt: persistent.slow_ppt,
clock_limits: persistent.clock_limits.map(|x| min_max_from_json(x, version)), clock_limits: persistent
.clock_limits
.map(|x| min_max_from_json(x, version)),
memory_clock: persistent.memory_clock, memory_clock: persistent.memory_clock,
limits: limits, limits: limits,
state: crate::state::steam_deck::Gpu::default(), state: crate::state::steam_deck::Gpu::default(),
@ -433,12 +557,16 @@ impl TGpu for Gpu {
fn limits(&self) -> crate::api::GpuLimits { fn limits(&self) -> crate::api::GpuLimits {
crate::api::GpuLimits { crate::api::GpuLimits {
fast_ppt_limits: Some(RangeLimit { fast_ppt_limits: Some(RangeLimit {
min: super::util::range_min_or_fallback(&self.limits.fast_ppt, MIN_FAST_PPT) / self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR), min: super::util::range_min_or_fallback(&self.limits.fast_ppt, MIN_FAST_PPT)
max: super::util::range_max_or_fallback(&self.limits.fast_ppt, MAX_FAST_PPT) / self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR), / self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR),
max: super::util::range_max_or_fallback(&self.limits.fast_ppt, MAX_FAST_PPT)
/ self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR),
}), }),
slow_ppt_limits: Some(RangeLimit { slow_ppt_limits: Some(RangeLimit {
min: super::util::range_min_or_fallback(&self.limits.slow_ppt, MIN_SLOW_PPT) / self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR), min: super::util::range_min_or_fallback(&self.limits.slow_ppt, MIN_SLOW_PPT)
max: super::util::range_max_or_fallback(&self.limits.slow_ppt, MIN_SLOW_PPT) / self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR), / self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR),
max: super::util::range_max_or_fallback(&self.limits.slow_ppt, MIN_SLOW_PPT)
/ self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR),
}), }),
ppt_step: self.limits.ppt_step.unwrap_or(1), ppt_step: self.limits.ppt_step.unwrap_or(1),
tdp_limits: None, tdp_limits: None,
@ -454,8 +582,14 @@ impl TGpu for Gpu {
}), }),
clock_step: self.limits.clock_step.unwrap_or(100), clock_step: self.limits.clock_step.unwrap_or(100),
memory_control: Some(RangeLimit { memory_control: Some(RangeLimit {
min: super::util::range_min_or_fallback(&self.limits.memory_clock, MIN_MEMORY_CLOCK), min: super::util::range_min_or_fallback(
max: super::util::range_max_or_fallback(&self.limits.memory_clock, MAX_MEMORY_CLOCK), &self.limits.memory_clock,
MIN_MEMORY_CLOCK,
),
max: super::util::range_max_or_fallback(
&self.limits.memory_clock,
MAX_MEMORY_CLOCK,
),
}), }),
memory_step: self.limits.memory_clock_step.unwrap_or(400), memory_step: self.limits.memory_clock_step.unwrap_or(400),
} }
@ -472,8 +606,10 @@ impl TGpu for Gpu {
fn get_ppt(&self) -> (Option<u64>, Option<u64>) { fn get_ppt(&self) -> (Option<u64>, Option<u64>) {
( (
self.fast_ppt.map(|x| x / self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR)), self.fast_ppt
self.slow_ppt.map(|x| x / self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR)), .map(|x| x / self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR)),
self.slow_ppt
.map(|x| x / self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR)),
) )
} }
@ -501,13 +637,16 @@ impl TGpu for Gpu {
} }
} }
fn parse_pp_dpm_fclk(s: &str) -> Vec<(usize, usize)> { // (value, MHz) fn parse_pp_dpm_fclk(s: &str) -> Vec<(usize, usize)> {
// (value, MHz)
let mut result = Vec::new(); let mut result = Vec::new();
for line in s.split('\n') { for line in s.split('\n') {
if !line.is_empty() { if !line.is_empty() {
if let Some((val, freq_mess)) = line.split_once(':') { if let Some((val, freq_mess)) = line.split_once(':') {
if let Ok(val) = val.parse::<usize>() { if let Ok(val) = val.parse::<usize>() {
if let Some((freq, _unit)) = freq_mess.trim().split_once(|c: char| !c.is_digit(10)) { if let Some((freq, _unit)) =
freq_mess.trim().split_once(|c: char| !c.is_digit(10))
{
if let Ok(freq) = freq.parse::<usize>() { if let Ok(freq) = freq.parse::<usize>() {
result.push((val, freq)); result.push((val, freq));
} }

View file

@ -7,7 +7,9 @@ mod util;
pub use battery::Battery; pub use battery::Battery;
pub use cpu::Cpus; pub use cpu::Cpus;
pub use gpu::Gpu; pub use gpu::Gpu;
pub(self) use power_dpm_force::{POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT, DPM_FORCE_LIMITS_ATTRIBUTE}; pub(self) use power_dpm_force::{
DPM_FORCE_LIMITS_ATTRIBUTE, POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT,
};
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Model { pub enum Model {
@ -20,7 +22,15 @@ pub use util::flash_led;
fn _impl_checker() { fn _impl_checker() {
fn impl_provider_builder<T: crate::settings::ProviderBuilder<J, L>, J, L>() {} fn impl_provider_builder<T: crate::settings::ProviderBuilder<J, L>, J, L>() {}
impl_provider_builder::<Battery, crate::persist::BatteryJson, limits_core::json_v2::GenericBatteryLimit>(); impl_provider_builder::<
impl_provider_builder::<Cpus, Vec<crate::persist::CpuJson>, limits_core::json_v2::GenericCpusLimit>(); Battery,
crate::persist::BatteryJson,
limits_core::json_v2::GenericBatteryLimit,
>();
impl_provider_builder::<
Cpus,
Vec<crate::persist::CpuJson>,
limits_core::json_v2::GenericCpusLimit,
>();
impl_provider_builder::<Gpu, crate::persist::GpuJson, limits_core::json_v2::GenericGpuLimit>(); impl_provider_builder::<Gpu, crate::persist::GpuJson, limits_core::json_v2::GenericGpuLimit>();
} }

View file

@ -5,7 +5,7 @@
use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::atomic::{AtomicU64, Ordering};
use sysfuss::{BasicEntityPath, SysEntityAttributesExt, SysAttribute}; use sysfuss::{BasicEntityPath, SysAttribute, SysEntityAttributesExt};
use crate::settings::SettingError; use crate::settings::SettingError;
@ -63,7 +63,8 @@ impl PDFPLManager {
let needs = self.needs_manual(); let needs = self.needs_manual();
let mut errors = Vec::new(); let mut errors = Vec::new();
let path = DPM_FORCE_LIMITS_ATTRIBUTE.path(entity); let path = DPM_FORCE_LIMITS_ATTRIBUTE.path(entity);
let mode: String = entity.attribute(DPM_FORCE_LIMITS_ATTRIBUTE.to_owned()) let mode: String = entity
.attribute(DPM_FORCE_LIMITS_ATTRIBUTE.to_owned())
.map_err(|e| { .map_err(|e| {
vec![SettingError { vec![SettingError {
msg: format!("Failed to read `{}`: {}", path.display(), e), msg: format!("Failed to read `{}`: {}", path.display(), e),
@ -73,7 +74,8 @@ impl PDFPLManager {
if mode != "manual" && needs { if mode != "manual" && needs {
log::info!("Setting `{}` to manual", path.display()); log::info!("Setting `{}` to manual", path.display());
// set manual control // set manual control
entity.set(DPM_FORCE_LIMITS_ATTRIBUTE.to_owned(), "manual") entity
.set(DPM_FORCE_LIMITS_ATTRIBUTE.to_owned(), "manual")
.map_err(|e| { .map_err(|e| {
errors.push(SettingError { errors.push(SettingError {
msg: format!("Failed to write `manual` to `{}`: {}", path.display(), e), msg: format!("Failed to write `manual` to `{}`: {}", path.display(), e),
@ -84,7 +86,8 @@ impl PDFPLManager {
} else if mode != "auto" && !needs { } else if mode != "auto" && !needs {
log::info!("Setting `{}` to auto", path.display()); log::info!("Setting `{}` to auto", path.display());
// unset manual control // unset manual control
entity.set(DPM_FORCE_LIMITS_ATTRIBUTE.to_owned(), "auto") entity
.set(DPM_FORCE_LIMITS_ATTRIBUTE.to_owned(), "auto")
.map_err(|e| { .map_err(|e| {
errors.push(SettingError { errors.push(SettingError {
msg: format!("Failed to write `auto` to `{}`: {}", path.display(), e), msg: format!("Failed to write `auto` to `{}`: {}", path.display(), e),
@ -93,10 +96,13 @@ impl PDFPLManager {
}) })
.unwrap_or(()); .unwrap_or(());
} }
if let Ok(mode_now) = if let Ok(mode_now) = entity.attribute::<String, _>(DPM_FORCE_LIMITS_ATTRIBUTE.to_owned()) {
entity.attribute::<String, _>(DPM_FORCE_LIMITS_ATTRIBUTE.to_owned()) log::debug!(
{ "Mode for `{}` is now `{}` ({:#b})",
log::debug!("Mode for `{}` is now `{}` ({:#b})", path.display(), mode_now, self.get()); path.display(),
mode_now,
self.get()
);
} else { } else {
log::debug!("Error getting new mode for debugging purposes"); log::debug!("Error getting new mode for debugging purposes");
} }

View file

@ -4,16 +4,23 @@ pub const JUPITER_HWMON_NAME: &'static str = "jupiter";
pub const STEAMDECK_HWMON_NAME: &'static str = "steamdeck_hwmon"; pub const STEAMDECK_HWMON_NAME: &'static str = "steamdeck_hwmon";
pub const GPU_HWMON_NAME: &'static str = "amdgpu"; pub const GPU_HWMON_NAME: &'static str = "amdgpu";
pub fn range_min_or_fallback<I: Copy>(range: &Option<limits_core::json_v2::RangeLimit<I>>, fallback: I) -> I { pub fn range_min_or_fallback<I: Copy>(
range: &Option<limits_core::json_v2::RangeLimit<I>>,
fallback: I,
) -> I {
range.and_then(|lim| lim.min).unwrap_or(fallback) range.and_then(|lim| lim.min).unwrap_or(fallback)
} }
pub fn range_max_or_fallback<I: Copy>(range: &Option<limits_core::json_v2::RangeLimit<I>>, fallback: I) -> I { pub fn range_max_or_fallback<I: Copy>(
range: &Option<limits_core::json_v2::RangeLimit<I>>,
fallback: I,
) -> I {
range.and_then(|lim| lim.max).unwrap_or(fallback) range.and_then(|lim| lim.max).unwrap_or(fallback)
} }
pub fn card_also_has(card: &dyn sysfuss::SysEntity, extensions: &'static [&'static str]) -> bool { pub fn card_also_has(card: &dyn sysfuss::SysEntity, extensions: &'static [&'static str]) -> bool {
extensions.iter() extensions
.iter()
.all(|ext| card.as_ref().join(ext).exists()) .all(|ext| card.as_ref().join(ext).exists())
} }
@ -31,7 +38,11 @@ pub fn flash_led() {
let mut ec = smokepatio::ec::unnamed_power::UnnamedPowerEC::new(); let mut ec = smokepatio::ec::unnamed_power::UnnamedPowerEC::new();
for &code in THINGS { for &code in THINGS {
let on = code != 0; let on = code != 0;
let colour = if on { smokepatio::ec::unnamed_power::StaticColour::Red } else { smokepatio::ec::unnamed_power::StaticColour::Off }; let colour = if on {
smokepatio::ec::unnamed_power::StaticColour::Red
} else {
smokepatio::ec::unnamed_power::StaticColour::Off
};
if let Err(e) = ec.set(colour) { if let Err(e) = ec.set(colour) {
log::error!("Thing err: {}", e); log::error!("Thing err: {}", e);
} }

View file

@ -125,7 +125,10 @@ pub trait TGeneral: OnSet + OnResume + OnPowerEvent + Debug + Send {
fn get_variant_info(&self) -> crate::api::VariantInfo; fn get_variant_info(&self) -> crate::api::VariantInfo;
fn add_variant(&self, variant: crate::persist::SettingsJson) -> Result<Vec<crate::api::VariantInfo>, SettingError>; fn add_variant(
&self,
variant: crate::persist::SettingsJson,
) -> Result<Vec<crate::api::VariantInfo>, SettingError>;
fn provider(&self) -> crate::persist::DriverJson; fn provider(&self) -> crate::persist::DriverJson;
} }

View file

@ -3,8 +3,8 @@ use std::convert::Into;
use limits_core::json_v2::GenericBatteryLimit; use limits_core::json_v2::GenericBatteryLimit;
use crate::persist::BatteryJson; use crate::persist::BatteryJson;
use crate::settings::{TBattery, ProviderBuilder};
use crate::settings::{OnResume, OnSet, SettingError}; use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{ProviderBuilder, TBattery};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Battery; pub struct Battery;
@ -29,7 +29,11 @@ impl Into<BatteryJson> for Battery {
} }
impl ProviderBuilder<BatteryJson, GenericBatteryLimit> for Battery { impl ProviderBuilder<BatteryJson, GenericBatteryLimit> for Battery {
fn from_json_and_limits(_persistent: BatteryJson, _version: u64, _limits: GenericBatteryLimit) -> Self { fn from_json_and_limits(
_persistent: BatteryJson,
_version: u64,
_limits: GenericBatteryLimit,
) -> Self {
Battery::system_default() Battery::system_default()
} }

View file

@ -5,7 +5,7 @@ use limits_core::json_v2::GenericCpusLimit;
use crate::persist::CpuJson; use crate::persist::CpuJson;
use crate::settings::MinMax; use crate::settings::MinMax;
use crate::settings::{OnResume, OnSet, SettingError}; use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{TCpu, TCpus, ProviderBuilder}; use crate::settings::{ProviderBuilder, TCpu, TCpus};
const CPU_PRESENT_PATH: &str = "/sys/devices/system/cpu/present"; const CPU_PRESENT_PATH: &str = "/sys/devices/system/cpu/present";
const CPU_SMT_PATH: &str = "/sys/devices/system/cpu/smt/control"; const CPU_SMT_PATH: &str = "/sys/devices/system/cpu/smt/control";
@ -146,7 +146,11 @@ impl Cpus {
} }
impl ProviderBuilder<Vec<CpuJson>, GenericCpusLimit> for Cpus { impl ProviderBuilder<Vec<CpuJson>, GenericCpusLimit> for Cpus {
fn from_json_and_limits(mut persistent: Vec<CpuJson>, version: u64, _limits: GenericCpusLimit) -> Self { fn from_json_and_limits(
mut persistent: Vec<CpuJson>,
version: u64,
_limits: GenericCpusLimit,
) -> Self {
let (_, can_smt) = Self::system_smt_capabilities(); let (_, can_smt) = Self::system_smt_capabilities();
let mut result = Vec::with_capacity(persistent.len()); let mut result = Vec::with_capacity(persistent.len());
let max_cpus = Self::cpu_count(); let max_cpus = Self::cpu_count();
@ -284,7 +288,7 @@ impl Cpu {
.unwrap_or("schedutil".to_owned()), .unwrap_or("schedutil".to_owned()),
index: cpu_index, index: cpu_index,
state: crate::state::steam_deck::Cpu::default(), state: crate::state::steam_deck::Cpu::default(),
root: "/".into() root: "/".into(),
} }
} }

View file

@ -4,15 +4,15 @@ use limits_core::json_v2::GenericGpuLimit;
use crate::persist::GpuJson; use crate::persist::GpuJson;
use crate::settings::MinMax; use crate::settings::MinMax;
use crate::settings::{TGpu, ProviderBuilder};
use crate::settings::{OnResume, OnSet, SettingError}; use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{ProviderBuilder, TGpu};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Gpu {} pub struct Gpu {}
impl Gpu { impl Gpu {
pub fn system_default() -> Self { pub fn system_default() -> Self {
Self { } Self {}
} }
} }

View file

@ -9,7 +9,15 @@ pub use gpu::Gpu;
fn _impl_checker() { fn _impl_checker() {
fn impl_provider_builder<T: crate::settings::ProviderBuilder<J, L>, J, L>() {} fn impl_provider_builder<T: crate::settings::ProviderBuilder<J, L>, J, L>() {}
impl_provider_builder::<Battery, crate::persist::BatteryJson, limits_core::json_v2::GenericBatteryLimit>(); impl_provider_builder::<
impl_provider_builder::<Cpus, Vec<crate::persist::CpuJson>, limits_core::json_v2::GenericCpusLimit>(); Battery,
crate::persist::BatteryJson,
limits_core::json_v2::GenericBatteryLimit,
>();
impl_provider_builder::<
Cpus,
Vec<crate::persist::CpuJson>,
limits_core::json_v2::GenericCpusLimit,
>();
impl_provider_builder::<Gpu, crate::persist::GpuJson, limits_core::json_v2::GenericGpuLimit>(); impl_provider_builder::<Gpu, crate::persist::GpuJson, limits_core::json_v2::GenericGpuLimit>();
} }

View file

@ -18,10 +18,7 @@ pub fn always_satisfied<'a, X>(_: &'a X) -> bool {
true true
} }
pub const CARD_NEEDS: &[&'static str] = &[ pub const CARD_NEEDS: &[&'static str] = &["dev", "uevent"];
"dev",
"uevent"
];
#[cfg(test)] #[cfg(test)]
mod test { mod test {

View file

@ -120,51 +120,66 @@ mod generate {
let limits = limits_core::json_v2::Limits { let limits = limits_core::json_v2::Limits {
cpu: limits_core::json_v2::Limit { cpu: limits_core::json_v2::Limit {
provider: limits_core::json_v2::CpuLimitType::SteamDeck, provider: limits_core::json_v2::CpuLimitType::SteamDeck,
limits: limits_core::json_v2::GenericCpusLimit::default_for(limits_core::json_v2::CpuLimitType::SteamDeck), limits: limits_core::json_v2::GenericCpusLimit::default_for(
limits_core::json_v2::CpuLimitType::SteamDeck,
),
}, },
gpu: limits_core::json_v2::Limit { gpu: limits_core::json_v2::Limit {
provider: limits_core::json_v2::GpuLimitType::SteamDeck, provider: limits_core::json_v2::GpuLimitType::SteamDeck,
limits: limits_core::json_v2::GenericGpuLimit::default_for(limits_core::json_v2::GpuLimitType::SteamDeck), limits: limits_core::json_v2::GenericGpuLimit::default_for(
limits_core::json_v2::GpuLimitType::SteamDeck,
),
}, },
battery: limits_core::json_v2::Limit { battery: limits_core::json_v2::Limit {
provider: limits_core::json_v2::BatteryLimitType::SteamDeck, provider: limits_core::json_v2::BatteryLimitType::SteamDeck,
limits: limits_core::json_v2::GenericBatteryLimit::default_for(limits_core::json_v2::BatteryLimitType::SteamDeck), limits: limits_core::json_v2::GenericBatteryLimit::default_for(
limits_core::json_v2::BatteryLimitType::SteamDeck,
),
}, },
}; };
let output_file = std::fs::File::create(format!("../{}", crate::consts::LIMITS_OVERRIDE_FILE)).unwrap(); let output_file =
ron::ser::to_writer_pretty(output_file, &limits, crate::utility::ron_pretty_config()).unwrap(); std::fs::File::create(format!("../{}", crate::consts::LIMITS_OVERRIDE_FILE)).unwrap();
ron::ser::to_writer_pretty(output_file, &limits, crate::utility::ron_pretty_config())
.unwrap();
} }
#[test] #[test]
fn generate_default_minimal_save_file() { fn generate_default_minimal_save_file() {
let mut mini_variants = std::collections::HashMap::with_capacity(2); let mut mini_variants = std::collections::HashMap::with_capacity(2);
mini_variants.insert(0, crate::persist::SettingsJson { mini_variants.insert(
version: 0, 0,
name: crate::consts::DEFAULT_SETTINGS_VARIANT_NAME.to_owned(), crate::persist::SettingsJson {
variant: 0, version: 0,
persistent: false, name: crate::consts::DEFAULT_SETTINGS_VARIANT_NAME.to_owned(),
cpus: vec![crate::persist::CpuJson::default(); 8], variant: 0,
gpu: crate::persist::GpuJson::default(), persistent: false,
battery: crate::persist::BatteryJson::default(), cpus: vec![crate::persist::CpuJson::default(); 8],
provider: None, gpu: crate::persist::GpuJson::default(),
}); battery: crate::persist::BatteryJson::default(),
mini_variants.insert(42, crate::persist::SettingsJson { provider: None,
version: 0, },
name: "FortySecondary".to_owned(), );
variant: 42, mini_variants.insert(
persistent: false, 42,
cpus: vec![crate::persist::CpuJson::default(); 8], crate::persist::SettingsJson {
gpu: crate::persist::GpuJson::default(), version: 0,
battery: crate::persist::BatteryJson::default(), name: "FortySecondary".to_owned(),
provider: None, variant: 42,
}); persistent: false,
cpus: vec![crate::persist::CpuJson::default(); 8],
gpu: crate::persist::GpuJson::default(),
battery: crate::persist::BatteryJson::default(),
provider: None,
},
);
let savefile = crate::persist::FileJson { let savefile = crate::persist::FileJson {
version: 0, version: 0,
name: crate::consts::DEFAULT_SETTINGS_NAME.to_owned(), name: crate::consts::DEFAULT_SETTINGS_NAME.to_owned(),
variants: mini_variants, variants: mini_variants,
}; };
let output_file = std::fs::File::create(format!("../{}", crate::consts::DEFAULT_SETTINGS_FILE)).unwrap(); let output_file =
ron::ser::to_writer_pretty(output_file, &savefile, crate::utility::ron_pretty_config()).unwrap(); std::fs::File::create(format!("../{}", crate::consts::DEFAULT_SETTINGS_FILE)).unwrap();
ron::ser::to_writer_pretty(output_file, &savefile, crate::utility::ron_pretty_config())
.unwrap();
} }
} }

View file

@ -16,6 +16,8 @@ import {
Dropdown, Dropdown,
SingleDropdownOption, SingleDropdownOption,
Navigation, Navigation,
Focusable,
Spinner,
//NotchLabel //NotchLabel
//gamepadDialogClasses, //gamepadDialogClasses,
//joinClassNames, //joinClassNames,
@ -89,6 +91,7 @@ var startHook: any = null;
var endHook: any = null; var endHook: any = null;
var userHook: any = null; var userHook: any = null;
var usdplReady = false; var usdplReady = false;
var isVariantLoading = false;
var tryNotifyProfileChange = function() {}; var tryNotifyProfileChange = function() {};
@ -343,6 +346,12 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
data: elem, data: elem,
label: <span>{elem.name}</span>, label: <span>{elem.name}</span>,
};}); };});
console.log("variant options", variantOptions);
console.log("current variant", get_value(CURRENT_VARIANT_GEN));
console.log("variant selected", variantOptions.find((val: SingleDropdownOption, _index, _arr) => {
backend.log(backend.LogLevel.Debug, "POWERTOOLS: looking for variant data.id " + (get_value(CURRENT_VARIANT_GEN) as backend.VariantInfo).id.toString());
return (val.data as backend.VariantInfo).id == (get_value(CURRENT_VARIANT_GEN) as backend.VariantInfo).id;
}));
return ( return (
<PanelSection> <PanelSection>
@ -383,83 +392,102 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
<Field <Field
label={tr("Profile Variant")} // TODO translate label={tr("Profile Variant")} // TODO translate
> >
<Dropdown {(!isVariantLoading && <Dropdown
menuLabel={tr("Profile Variant")} menuLabel={tr("Profile Variant")}
rgOptions={variantOptions} rgOptions={variantOptions}
selectedOption={variantOptions.find((val: SingleDropdownOption, _index, _arr) => { selectedOption={variantOptions.find((val: SingleDropdownOption, _index, _arr) => {
backend.log(backend.LogLevel.Debug, "POWERTOOLS: looking for data " + (get_value(CURRENT_VARIANT_GEN) as backend.VariantInfo).toString()); backend.log(backend.LogLevel.Debug, "POWERTOOLS: looking for variant data.id " + (get_value(CURRENT_VARIANT_GEN) as backend.VariantInfo).id.toString());
return (val.data as backend.VariantInfo).id == (get_value(CURRENT_VARIANT_GEN) as backend.VariantInfo).id; return (val.data as backend.VariantInfo).id == (get_value(CURRENT_VARIANT_GEN) as backend.VariantInfo).id;
})} })}
strDefaultLabel={(get_value(VARIANTS_GEN) as backend.VariantInfo[])[0].name} strDefaultLabel={(get_value(CURRENT_VARIANT_GEN) as backend.VariantInfo | undefined)?.name?? (get_value(VARIANTS_GEN) as backend.VariantInfo[])[0].name}
onChange={(elem: SingleDropdownOption) => { onChange={(elem: SingleDropdownOption) => {
let data = elem.data as backend.VariantInfo; if (elem.data.id != (get_value(CURRENT_VARIANT_GEN) as backend.VariantInfo).id) {
backend.log(backend.LogLevel.Debug, "Profile variant dropdown selected " + elem.data.toString()); isVariantLoading = true;
backend.loadGeneralSettingsVariant(data.id, data.name); let data = elem.data as backend.VariantInfo;
set_value(CURRENT_VARIANT_GEN, elem.data as backend.VariantInfo); backend.log(backend.LogLevel.Debug, "Profile variant dropdown selected " + elem.data.id.toString());
reloadGUI("ProfileVariantGovernor"); //set_value(CURRENT_VARIANT_GEN, elem.data as backend.VariantInfo);
backend.resolve(
backend.loadGeneralSettingsVariant(data.id, data.name),
(ok: boolean) => {
backend.log(backend.LogLevel.Debug, "Loaded settings variant ok? " + ok);
reload();
isVariantLoading = false;
backend.resolve(backend.waitForComplete(), (_) => {
backend.log(backend.LogLevel.Debug, "Trying to tell UI to re-render due to newly-selected settings variant");
tryNotifyProfileChange();
//reloadGUI("ProfileVariantSelected");
});
}
);
}
}} }}
/> />)}
{(isVariantLoading && <Spinner/>)}
</Field> </Field>
</PanelSectionRow> </PanelSectionRow>
<PanelSectionRow style={{ <PanelSectionRow>
alignItems: "center", <Focusable style={{
display: "flex", alignItems: "center",
justifyContent: "space-around", display: "flex",
}}> justifyContent: "space-around",
<DialogButton }}
style={{ flow-children="horizontal"
maxWidth: "30%", >
minWidth: "auto", <DialogButton
}} style={{
//layout="below" maxWidth: "30%",
onClick={(_: MouseEvent) => { minWidth: "auto",
backend.log(backend.LogLevel.Debug, "Creating new PowerTools settings variant"); }}
backend.resolve( //layout="below"
backend.loadGeneralSettingsVariant("please give me a new ID k thx bye" /* anything that cannot be parsed as a u64 will be set to u64::MAX, which will cause the back-end to auto-generate an ID */, undefined), onClick={(_: MouseEvent) => {
(ok: boolean) => { backend.log(backend.LogLevel.Debug, "Creating new PowerTools settings variant");
backend.log(backend.LogLevel.Debug, "New settings variant ok? " + ok); backend.resolve(
reload(); backend.loadGeneralSettingsVariant("please give me a new ID k thx bye" /* anything that cannot be parsed as a u64 will be set to u64::MAX, which will cause the back-end to auto-generate an ID */, undefined),
backend.resolve(backend.waitForComplete(), (_) => { (ok: boolean) => {
backend.log(backend.LogLevel.Debug, "Trying to tell UI to re-render due to new settings variant"); backend.log(backend.LogLevel.Debug, "New settings variant ok? " + ok);
tryNotifyProfileChange(); reload();
}); backend.resolve(backend.waitForComplete(), (_) => {
backend.log(backend.LogLevel.Debug, "Trying to tell UI to re-render due to new settings variant");
tryNotifyProfileChange();
});
}
);
}}
>
<HiPlus/>
</DialogButton>
<DialogButton
style={{
maxWidth: "30%",
minWidth: "auto",
}}
//layout="below"
onClick={(_: MouseEvent) => {
const steamId = get_value(INTERNAL_STEAM_ID);
const steamName = get_value(INTERNAL_STEAM_USERNAME);
if (steamId && steamName) {
backend.storeUpload(steamId, steamName);
} else {
backend.log(backend.LogLevel.Warn, "Cannot upload with null steamID (is null: " + !steamId + ") and/or username (is null: " + !steamName + ")");
} }
); }}
}} >
> <HiUpload/>
<HiPlus/> </DialogButton>
</DialogButton> <DialogButton
<DialogButton style={{
style={{ maxWidth: "30%",
maxWidth: "30%", minWidth: "auto",
minWidth: "auto", }}
}} //layout="below"
//layout="below" onClick={(_: MouseEvent) => {
onClick={(_: MouseEvent) => { Navigation.Navigate(STORE_RESULTS_URI);
const steamId = get_value(INTERNAL_STEAM_ID); Navigation.CloseSideMenus();
const steamName = get_value(INTERNAL_STEAM_USERNAME); }}
if (steamId && steamName) { >
backend.storeUpload(steamId, steamName); <TbWorldPlus />
} else { </DialogButton>
backend.log(backend.LogLevel.Warn, "Cannot upload with null steamID (is null: " + !steamId + ") and/or username (is null: " + !steamName + ")"); </Focusable>
}
}}
>
<HiUpload/>
</DialogButton>
<DialogButton
style={{
maxWidth: "30%",
minWidth: "auto",
}}
//layout="below"
onClick={(_: MouseEvent) => {
Navigation.Navigate(STORE_RESULTS_URI);
Navigation.CloseSideMenus();
}}
>
<TbWorldPlus />
</DialogButton>
</PanelSectionRow> </PanelSectionRow>
<Debug idc={idc}/> <Debug idc={idc}/>