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 id: String,
pub name: String,
pub id_num: u64,
}

View file

@ -59,7 +59,13 @@ pub fn load_settings(
sender
.lock()
.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")
};
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(variant_id)) = params_in.get(2) {
if let Some(Primitive::String(variant_name)) = params_in.get(3) {
setter(id.parse().unwrap_or_default(),
name.to_owned(),
variant_id.parse().unwrap_or_default(),
Some(variant_name.to_owned()));
setter(
id.parse().unwrap_or_default(),
name.to_owned(),
variant_id.parse().unwrap_or_default(),
Some(variant_name.to_owned()),
);
vec![true.into()]
} else {
setter(id.parse().unwrap_or_default(),
name.to_owned(),
variant_id.parse().unwrap_or_default(),
None);
setter(
id.parse().unwrap_or_default(),
name.to_owned(),
variant_id.parse().unwrap_or_default(),
None,
);
vec![true.into()]
}
} else {
@ -101,26 +111,32 @@ pub fn load_variant(
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let setter = move |variant: u64, variant_name: Option<String>| {
log::debug!("load_variant(variant: {}, variant_name: {:?})", variant, variant_name);
sender
.lock()
.unwrap()
.send(ApiMessage::LoadVariant(variant, variant_name.unwrap_or_else(|| crate::consts::DEFAULT_SETTINGS_VARIANT_NAME.to_owned())))
.expect("load_settings send failed")
.send(ApiMessage::LoadVariant(
variant,
variant_name
.unwrap_or_else(|| "".to_owned()),
))
.expect("load_variant send failed")
};
move |params_in: super::ApiParameterType| {
if let Some(Primitive::String(variant_id)) = params_in.get(0) {
if let Some(Primitive::String(variant_name)) = params_in.get(1) {
setter(variant_id.parse().unwrap_or(u64::MAX),
Some(variant_name.to_owned()));
setter(
variant_id.parse().unwrap_or(u64::MAX),
Some(variant_name.to_owned()),
);
vec![true.into()]
} else {
setter(variant_id.parse().unwrap_or_default(),
None);
setter(variant_id.parse().unwrap_or(u64::MAX), None);
vec![true.into()]
}
} else {
log::warn!("load_settings missing variant id parameter");
vec!["load_settings missing variant id parameter".into()]
log::warn!("load_variant missing variant id parameter");
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();
move || {
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_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_charge_now, callback_charge_now) =
build_comms("battery charge now 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 sender_locked = sender2
.lock()
.unwrap();
let curr = wait_for_response(&*sender_locked, rx_curr,
ApiMessage::Battery(super::handler::BatteryMessage::ReadCurrentNow(callback_curr)), "battery current");
let charge_now = wait_for_response(&*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 sender_locked = sender2.lock().unwrap();
let curr = wait_for_response(
&*sender_locked,
rx_curr,
ApiMessage::Battery(super::handler::BatteryMessage::ReadCurrentNow(
callback_curr,
)),
"battery current",
);
let charge_now = wait_for_response(
&*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,
ApiMessage::General(GeneralMessage::GetPath(callback_path)), "general get path");
let settings_path = wait_for_response(
&*sender_locked,
rx_path,
ApiMessage::General(GeneralMessage::GetPath(callback_path)),
"general get path",
);
vec![
super::utility::map_optional(curr),
super::utility::map_optional(charge_now),
super::utility::map_optional(charge_full),
super::utility::map_optional(charge_power),
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 callback = move |t: T| tx.send(t).expect(msg);
(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));
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();
move || {
let (tx, rx) = mpsc::channel();
let callback =
move |variants: Vec<super::VariantInfo>| tx.send(variants).expect("get_all_variants callback send failed");
let callback = move |variants: Vec<super::VariantInfo>| {
tx.send(variants)
.expect("get_all_variants callback send failed")
};
sender2
.lock()
.unwrap()
@ -438,7 +491,9 @@ pub fn get_all_variants(sender: Sender<ApiMessage>) -> impl AsyncCallable {
Box::new(callback),
)))
.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 {
@ -446,7 +501,10 @@ pub fn get_all_variants(sender: Sender<ApiMessage>) -> impl AsyncCallable {
trans_getter: |result| {
let mut output = Vec::with_capacity(result.len());
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
},
@ -460,8 +518,10 @@ pub fn get_current_variant(sender: Sender<ApiMessage>) -> impl AsyncCallable {
let sender2 = sender.clone();
move || {
let (tx, rx) = mpsc::channel();
let callback =
move |variant: super::VariantInfo| tx.send(variant).expect("get_all_variants callback send failed");
let callback = move |variant: super::VariantInfo| {
tx.send(variant)
.expect("get_all_variants callback send failed")
};
sender2
.lock()
.unwrap()
@ -475,7 +535,9 @@ pub fn get_current_variant(sender: Sender<ApiMessage>) -> impl AsyncCallable {
super::async_utils::AsyncIshGetter {
set_get: getter,
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
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>),
GetCurrentVariant(Callback<super::VariantInfo>),
GetAllVariants(Callback<Vec<super::VariantInfo>>),
AddVariant(crate::persist::SettingsJson, Callback<Vec<super::VariantInfo>>),
AddVariant(
crate::persist::SettingsJson,
Callback<Vec<super::VariantInfo>>,
),
ApplyNow,
}
@ -248,11 +254,14 @@ impl GeneralMessage {
Self::AddVariant(variant, cb) => match settings.add_variant(variant) {
Ok(variants) => cb(variants),
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))
},
}
},
Self::ApplyNow => {},
Self::ApplyNow => {}
}
dirty
}
@ -300,13 +309,21 @@ impl ApiMessageHandler {
// save
log::debug!("api_worker is saving...");
let is_persistent = *settings.general.persistent();
let save_path =
crate::utility::settings_dir().join(settings.general.get_path());
let save_path = crate::utility::settings_dir().join(settings.general.get_path());
if is_persistent {
let settings_clone = settings.json();
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()) {
log::error!("Failed to create/update settings file {}: {}", save_path.display(), e);
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(),
) {
log::error!(
"Failed to create/update settings file {}: {}",
save_path.display(),
e
);
}
//unwrap_maybe_fatal(save_json.save(&save_path), "Failed to save settings");
log::debug!("Saved settings to {}", save_path.display());
@ -393,8 +410,15 @@ impl ApiMessageHandler {
ApiMessage::LoadVariant(variant_id, variant_name) => {
let path = settings.general.get_path();
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) {
Ok(success) => log::info!("Loaded settings file? {}", success),
match settings.load_file(
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),
}
true
@ -414,7 +438,11 @@ impl ApiMessageHandler {
true
}
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
}
ApiMessage::GetLimits(cb) => {
@ -434,13 +462,18 @@ impl ApiMessageHandler {
_ => settings.general.provider(),
});
false
},
}
ApiMessage::UploadCurrentVariant(steam_id, steam_username) => {
//TODO
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
},
}
}
}

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 usdpl_back::AsyncCallable;
use usdpl_back::core::serdes::Primitive;
use usdpl_back::AsyncCallable;
use limits_core::json::DeveloperMessage;
use crate::MESSAGE_SEEN_ID_FILE;
use crate::utility::settings_dir;
use crate::MESSAGE_SEEN_ID_FILE;
#[derive(Serialize, Deserialize)]
pub struct ApiMessage {
@ -34,7 +37,10 @@ impl std::convert::From<DeveloperMessage> for 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 {
@ -43,8 +49,12 @@ pub struct MessageHandler {
impl MessageHandler {
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)) {
if last_seen_id_bytes.len() >= 8 /* bytes in u64 */ {
let last_seen_id = if let Ok(last_seen_id_bytes) =
std::fs::read(settings_dir().join(MESSAGE_SEEN_ID_FILE))
{
if last_seen_id_bytes.len() >= 8
/* bytes in u64 */
{
u64::from_le_bytes([
last_seen_id_bytes[0],
last_seen_id_bytes[1],
@ -73,7 +83,7 @@ impl MessageHandler {
},
AsyncMessageDismisser {
seen: self.seen.clone(),
}
},
)
}
}
@ -83,8 +93,17 @@ pub struct AsyncMessageGetter {
}
impl AsyncMessageGetter {
fn remove_before_id(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 })
fn remove_before_id(
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);
match ureq::get(&req_url).call() {
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 {
Ok(search_results) => {
// 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) {
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,
}
}
@ -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 {
version: crate::persist::LATEST_VERSION,
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
persistent: true,
cpus: meta.config.cpus.into_iter().map(|cpu| crate::persist::CpuJson {
online: cpu.online,
clock_limits: cpu.clock_limits.map(|lim| crate::persist::MinMaxJson {
min: lim.min,
max: lim.max,
}),
governor: cpu.governor,
root: None,
}).collect(),
cpus: meta
.config
.cpus
.into_iter()
.map(|cpu| crate::persist::CpuJson {
online: cpu.online,
clock_limits: cpu.clock_limits.map(|lim| crate::persist::MinMaxJson {
min: lim.min,
max: lim.max,
}),
governor: cpu.governor,
root: None,
})
.collect(),
gpu: crate::persist::GpuJson {
fast_ppt: meta.config.gpu.fast_ppt,
slow_ppt: meta.config.gpu.slow_ppt,
tdp: meta.config.gpu.tdp,
tdp_boost: meta.config.gpu.tdp_boost,
clock_limits: meta.config.gpu.clock_limits.map(|lim| crate::persist::MinMaxJson {
min: lim.min,
max: lim.max,
}),
clock_limits: meta
.config
.gpu
.clock_limits
.map(|lim| crate::persist::MinMaxJson {
min: lim.min,
max: lim.max,
}),
memory_clock: meta.config.gpu.memory_clock,
root: None,
},
battery: crate::persist::BatteryJson {
charge_rate: meta.config.battery.charge_rate,
charge_mode: meta.config.battery.charge_mode,
events: meta.config.battery.events.into_iter().map(|be| crate::persist::BatteryEventJson {
charge_rate: be.charge_rate,
charge_mode: be.charge_mode,
trigger: be.trigger,
}).collect(),
events: meta
.config
.battery
.events
.into_iter()
.map(|be| crate::persist::BatteryEventJson {
charge_rate: be.charge_rate,
charge_mode: be.charge_mode,
trigger: be.trigger,
})
.collect(),
root: None,
},
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> {
let req_url = format!("{}/api/setting/by_id/{}", BASE_URL, id);
let response = ureq::get(&req_url).call()
.map_err(|e| {
log::warn!("GET to {} failed: {}", req_url, e);
std::io::Error::new(std::io::ErrorKind::ConnectionAborted, e)
})?;
let response = ureq::get(&req_url).call().map_err(|e| {
log::warn!("GET to {} failed: {}", req_url, e);
std::io::Error::new(std::io::ErrorKind::ConnectionAborted, e)
})?;
response.into_json()
}
pub fn upload_settings(id: u64, user_id: String, username: String, settings: crate::persist::SettingsJson) {
log::info!("Uploading settings {} by {} ({})", settings.name, username, user_id);
pub fn upload_settings(
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() {
Ok(id) => id,
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;
}
};
@ -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 {
name: settings.name,
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()],
id: "".to_owned(),
config: community_settings_core::v1::Config {
cpus: settings.cpus.into_iter().map(|cpu| community_settings_core::v1::Cpu {
online: cpu.online,
clock_limits: cpu.clock_limits.map(|lim| community_settings_core::v1::MinMax {
min: lim.min,
max: lim.max,
}),
governor: cpu.governor,
}).collect(),
cpus: settings
.cpus
.into_iter()
.map(|cpu| community_settings_core::v1::Cpu {
online: cpu.online,
clock_limits: cpu
.clock_limits
.map(|lim| community_settings_core::v1::MinMax {
min: lim.min,
max: lim.max,
}),
governor: cpu.governor,
})
.collect(),
gpu: community_settings_core::v1::Gpu {
fast_ppt: settings.gpu.fast_ppt,
slow_ppt: settings.gpu.slow_ppt,
tdp: settings.gpu.tdp,
tdp_boost: settings.gpu.tdp_boost,
clock_limits: settings.gpu.clock_limits.map(|lim| community_settings_core::v1::MinMax {
min: lim.min,
max: lim.max,
clock_limits: settings.gpu.clock_limits.map(|lim| {
community_settings_core::v1::MinMax {
min: lim.min,
max: lim.max,
}
}),
memory_clock: settings.gpu.memory_clock,
},
battery: community_settings_core::v1::Battery {
charge_rate: settings.battery.charge_rate,
charge_mode: settings.battery.charge_mode,
events: settings.battery.events.into_iter().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(),
events: settings
.battery
.events
.into_iter()
.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) {
Ok(meta) => {
let (tx, rx) = mpsc::channel();
let callback =
move |values: Vec<super::VariantInfo>| tx.send(values).expect("download_new_config callback send failed");
let callback = move |values: Vec<super::VariantInfo>| {
tx.send(values)
.expect("download_new_config callback send failed")
};
sender2
.lock()
.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");
return rx.recv().expect("download_new_config callback recv failed");
},
}
Err(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) {
match id.parse::<u128>() {
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 {
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| {
let mut output = Vec::with_capacity(result.len());
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
},
@ -238,8 +302,6 @@ pub fn upload_current_variant(sender: Sender<ApiMessage>) -> impl AsyncCallable
}
},
set_get: getter,
trans_getter: |result| {
vec![result.into()]
},
trans_getter: |result| 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_OVERRIDE_FILE: &str = "limits_override.ron";
pub const MESSAGE_SEEN_ID_FILE: &str = "seen_message.bin";

View file

@ -76,14 +76,29 @@ fn main() -> Result<(), ()> {
let mut loaded_settings =
persist::FileJson::open(utility::settings_dir().join(DEFAULT_SETTINGS_FILE))
.map(|mut file| file.variants.remove(&0)
.map(|settings| settings::Settings::from_json(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())))
.map(|mut file| {
let mut keys: Vec<u64> = file.variants.keys().map(|x| *x).collect();
keys.sort();
keys.get(0)
.and_then(|id| file.variants.remove(id))
.map(|settings| {
settings::Settings::from_json(
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(|_| {
settings::Settings::system_default(
DEFAULT_SETTINGS_FILE.into(),
@ -96,7 +111,8 @@ fn main() -> Result<(), ()> {
log::info!(
"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);
@ -307,29 +323,26 @@ fn main() -> Result<(), ()> {
)
.register_async(
"GENERAL_get_periodicals",
api::general::get_periodicals(api_sender.clone())
api::general::get_periodicals(api_sender.clone()),
)
.register_async(
"GENERAL_get_all_variants",
api::general::get_all_variants(api_sender.clone())
api::general::get_all_variants(api_sender.clone()),
)
.register_async(
"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_dismiss", message_dismisser)
.register_async(
"WEB_search_by_app",
api::web::search_by_app_id()
)
.register_async("WEB_search_by_app", api::web::search_by_app_id())
.register_async(
"WEB_download_new",
api::web::download_new_config(api_sender.clone())
api::web::download_new_config(api_sender.clone()),
)
.register_async(
"WEB_upload_new",
api::web::upload_current_variant(api_sender.clone())
api::web::upload_current_variant(api_sender.clone()),
);
utility::ioperm_power_ec();

View file

@ -22,7 +22,8 @@ impl FileJson {
std::fs::create_dir_all(parent).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 {
if path.exists() {
// 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 {
self.variants.keys()
.max()
.map(|k| k+1)
.unwrap_or(0)
self.variants.keys().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> {
if !setting.persistent {
return Self::open(path)
}
pub fn update_variant_or_create<P: AsRef<std::path::Path>>(
path: P,
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 file = if path.exists() {
if !setting.persistent {
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 {
setting.variant = file.next_available_id();
}
file.variants.insert(setting.variant, setting);
file
// Generate new name if empty
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 {
// 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);
setting_variants.insert(setting.variant, setting);
Self {
setting_variants.insert(setting.variant, setting.clone());
(Self {
version: 0,
app_id: app_id,
name: given_name,
name: app_name,
variants: setting_variants,
}
}, setting)
};
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};
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Clone)]
pub struct SettingsJson {
pub version: u64,
pub name: String,

View file

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

View file

@ -93,14 +93,16 @@ pub fn get_limits_cached() -> Base {
fn save_base(new_base: &Base, path: impl AsRef<std::path::Path>) {
let limits_path = path.as_ref();
match std::fs::File::create(&limits_path) {
Ok(f) => match ron::ser::to_writer_pretty(f, &new_base, crate::utility::ron_pretty_config()) {
Ok(_) => log::info!("Successfully saved new limits to {}", limits_path.display()),
Err(e) => log::error!(
"Failed to save limits json to file `{}`: {}",
limits_path.display(),
e
),
},
Ok(f) => {
match ron::ser::to_writer_pretty(f, &new_base, crate::utility::ron_pretty_config()) {
Ok(_) => log::info!("Successfully saved new limits to {}", limits_path.display()),
Err(e) => log::error!(
"Failed to save limits json to file `{}`: {}",
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 {
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 crate::persist::BatteryJson;
use crate::settings::{TBattery, ProviderBuilder};
use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{ProviderBuilder, TBattery};
#[derive(Clone)]
pub struct Battery {
@ -32,7 +32,11 @@ impl Into<BatteryJson> 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 {
persist,
version,
@ -43,7 +47,12 @@ impl ProviderBuilder<BatteryJson, GenericBatteryLimit> for Battery {
fn from_limits(limits: GenericBatteryLimit) -> Self {
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,
limits,
charge_limit: None,
@ -71,10 +80,16 @@ impl TBattery for Battery {
fn limits(&self) -> crate::api::BatteryLimits {
log::debug!("dev_mode_Battery::limits(self) -> {{...}}");
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_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,
}
}
@ -90,7 +105,10 @@ impl TBattery for Battery {
}
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
}
@ -100,7 +118,10 @@ impl TBattery for Battery {
}
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()
}
@ -135,7 +156,10 @@ impl TBattery for Battery {
}
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
}

View file

@ -1,11 +1,11 @@
use std::convert::Into;
use limits_core::json_v2::{GenericCpusLimit, GenericCpuLimit};
use limits_core::json_v2::{GenericCpuLimit, GenericCpusLimit};
use crate::persist::CpuJson;
use crate::settings::MinMax;
use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{TCpu, TCpus, ProviderBuilder};
use crate::settings::{ProviderBuilder, TCpu, TCpus};
#[derive(Debug, Clone)]
pub struct Cpus {
@ -40,13 +40,22 @@ impl OnResume for Cpus {
impl crate::settings::OnPowerEvent 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());
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(|| {
log::warn!("No cpu limit for index {}, using default", i);
Default::default()
})));
cpus.push(Cpu::from_json_and_limits(
cpu.to_owned(),
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);
Self {
@ -78,7 +87,12 @@ impl TCpus for Cpus {
cpus: self.cpus.iter().map(|x| x.limits()).collect(),
count: self.cpus.len(),
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 {
#[inline]
pub fn from_json_and_limits(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 });
pub fn from_json_and_limits(
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 {
0 => Self {
persist: other,
@ -153,7 +175,12 @@ impl Cpu {
#[inline]
pub fn from_limits(i: usize, limits: GenericCpuLimit) -> 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,
index: i,
limits,
@ -163,10 +190,21 @@ impl Cpu {
fn limits(&self) -> 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_max_limits: self.limits.clock_max.map(|lim| crate::api::RangeLimit { min: lim.min.unwrap_or(4200), max: lim.max.unwrap_or(4300) }),
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_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),
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>>) {
log::debug!("dev_mode_Cpu::clock_limits(self, {:?})", 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>> {
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()
}
}

View file

@ -4,8 +4,8 @@ use limits_core::json_v2::GenericGpuLimit;
use crate::persist::GpuJson;
use crate::settings::MinMax;
use crate::settings::{TGpu, ProviderBuilder};
use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{ProviderBuilder, TGpu};
#[derive(Clone)]
pub struct Gpu {
@ -27,7 +27,10 @@ impl std::fmt::Debug for Gpu {
impl ProviderBuilder<GpuJson, GenericGpuLimit> for Gpu {
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 {
persist,
version,
@ -83,16 +86,37 @@ impl TGpu for Gpu {
let ppt_divisor = self.limits.ppt_divisor.unwrap_or(1_000_000);
let tdp_divisor = self.limits.tdp_divisor.unwrap_or(1_000_000);
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 }),
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 }),
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,
}),
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),
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_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_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_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),
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_max_limits: self.limits.clock_max.map(|lim| crate::api::RangeLimit { min: lim.min.unwrap_or(1100), max: lim.max.unwrap_or(4200) }),
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_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),
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),
}
}
@ -103,24 +127,41 @@ impl TGpu for Gpu {
}
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.slow_ppt = slow;
}
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)
}
fn clock_limits(&mut self, limits: Option<MinMax<u64>>) {
log::debug!("dev_mode_Gpu::clock_limits(self, {:?})", 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>> {
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()
}
@ -130,7 +171,10 @@ impl TGpu for Gpu {
}
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
}

View file

@ -9,7 +9,15 @@ pub use gpu::Gpu;
fn _impl_checker() {
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::<Cpus, Vec<crate::persist::CpuJson>, limits_core::json_v2::GenericCpusLimit>();
impl_provider_builder::<
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>();
}

View file

@ -20,7 +20,13 @@ impl Driver {
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)
}
}

View file

@ -4,7 +4,7 @@ use std::path::PathBuf;
//use super::{Battery, Cpus, Gpu};
use super::{OnResume, OnSet, SettingError};
use super::{TBattery, TCpus, TGeneral, TGpu};
use crate::persist::{SettingsJson, FileJson};
use crate::persist::{FileJson, SettingsJson};
//use crate::utility::unwrap_lock;
const LATEST_VERSION: u64 = 0;
@ -103,11 +103,14 @@ impl TGeneral for General {
}
fn get_variants(&self) -> Vec<crate::api::VariantInfo> {
if let Ok(file) = crate::persist::FileJson::open(self.get_path()) {
file.variants.into_iter()
let json_path = crate::utility::settings_dir().join(self.get_path());
if let Ok(file) = crate::persist::FileJson::open(json_path) {
file.variants
.into_iter()
.map(|(id, conf)| crate::api::VariantInfo {
id: id.to_string(),
name: conf.name,
id_num: id,
})
.collect()
} 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();
crate::persist::FileJson::update_variant_or_create(self.get_path(), self.get_app_id(), variant, variant_name)
.map_err(|e| SettingError {
msg: format!("failed to add variant: {}", e),
setting: SettingVariant::General,
})
.map(|file| file.variants.into_iter()
let json_path = crate::utility::settings_dir().join(self.get_path());
crate::persist::FileJson::update_variant_or_create(
json_path,
self.get_app_id(),
variant,
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 {
id: id.to_string(),
name: conf.name,
id_num: id,
})
.collect())
.collect()
})
}
fn get_variant_info(&self) -> crate::api::VariantInfo {
log::debug!("Current variant `{}` ({})", self.variant_name, self.variant_id);
crate::api::VariantInfo {
id: self.variant_id.to_string(),
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 {
let driver = super::Driver::system_default(json_path, app_id, name, variant_id, variant_name);
pub fn system_default(
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 {
general: driver.general,
cpus: driver.cpus,
@ -210,19 +235,47 @@ impl Settings {
}
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.gpu = driver.gpu;
self.battery = driver.battery;
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) {
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 {
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,
})
}
@ -240,13 +293,8 @@ impl Settings {
let json_path = crate::utility::settings_dir().join(&filename);
if json_path.exists() {
if variant == u64::MAX {
*self.general.persistent() = true;
let file_json = FileJson::update_variant_or_create(&json_path, app_id, self.json(), variant_name.clone()).map_err(|e| SettingError {
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);
log::debug!("Creating new variant `{}` in existing settings file {}", variant_name, json_path.display());
self.create_and_load_variant(&json_path, app_id, variant_name)?;
} else {
let file_json = FileJson::open(&json_path).map_err(|e| SettingError {
msg: format!("Failed to open settings {}: {}", json_path.display(), e),
@ -261,31 +309,61 @@ impl Settings {
);
*self.general.persistent() = false;
self.general.name(name);
self.general.variant_name(settings_json.name.clone());
self.general.variant_id(settings_json.variant);
} else {
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.cpus = x.cpus;
self.gpu = x.gpu;
self.battery = x.battery;
}
}
} else {
if system_defaults {
self.load_system_default(name, variant, variant_name);
self.load_system_default(name, variant, variant_name.clone());
} else {
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;
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.path(filename);
self.general.variant_id(variant);
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> {
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 crate::persist::BatteryJson;
use crate::settings::{TBattery, ProviderBuilder};
use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{ProviderBuilder, TBattery};
#[derive(Debug, Clone)]
pub struct Battery {
@ -21,7 +21,10 @@ impl Into<BatteryJson> for Battery {
charge_rate: None,
charge_mode: None,
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> {
match self.sysfs.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::VoltageMax) {
Ok(x) => Some(x/1000000.0),
match self
.sysfs
.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::VoltageMax)
{
Ok(x) => Some(x / 1000000.0),
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
Ok(x) => Some(x/1000000.0),
match sysfuss::SysEntityRawExt::attribute::<_, f64, _>(
&self.sysfs,
"voltage_min_design".to_owned(),
) {
// Framework 13 AMD
Ok(x) => Some(x / 1000000.0),
Err(e) => {
log::debug!("get_design_voltage voltage_min_design err: {}", e);
match self.sysfs.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::VoltageMin) {
Ok(x) => Some(x/1000000.0),
match self
.sysfs
.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::VoltageMin)
{
Ok(x) => Some(x / 1000000.0),
Err(e) => {
log::debug!("get_design_voltage voltage_min err: {}", e);
None
@ -90,7 +103,7 @@ impl ProviderBuilder<BatteryJson, GenericBatteryLimit> for Battery {
// TODO
Self {
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> {
if let Some(battery_voltage) = self.get_design_voltage() {
match self.sysfs.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::ChargeFull) {
Ok(x) => Some(x/1000000.0 * battery_voltage),
match self
.sysfs
.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::ChargeFull)
{
Ok(x) => Some(x / 1000000.0 * battery_voltage),
Err(e) => {
log::warn!("read_charge_full err: {}", e);
None
@ -162,8 +178,11 @@ impl TBattery for Battery {
fn read_charge_now(&self) -> Option<f64> {
if let Some(battery_voltage) = self.get_design_voltage() {
match self.sysfs.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::ChargeNow) {
Ok(x) => Some(x/1000000.0 * battery_voltage),
match self
.sysfs
.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::ChargeNow)
{
Ok(x) => Some(x / 1000000.0 * battery_voltage),
Err(e) => {
log::warn!("read_charge_now err: {}", e);
None
@ -176,8 +195,11 @@ impl TBattery for Battery {
fn read_charge_design(&self) -> Option<f64> {
if let Some(battery_voltage) = self.get_design_voltage() {
match self.sysfs.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::ChargeFullDesign) {
Ok(x) => Some(x/1000000.0 * battery_voltage),
match self
.sysfs
.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::ChargeFullDesign)
{
Ok(x) => Some(x / 1000000.0 * battery_voltage),
Err(e) => {
log::warn!("read_charge_design err: {}", e);
None
@ -189,8 +211,11 @@ impl TBattery for Battery {
}
fn read_current_now(&self) -> Option<f64> {
match self.sysfs.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::CurrentNow) {
Ok(x) => Some(x/1000.0), // expects mA, reads uA
match self
.sysfs
.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::CurrentNow)
{
Ok(x) => Some(x / 1000.0), // expects mA, reads uA
Err(e) => {
log::warn!("read_current_now err: {}", e);
None

View file

@ -1,13 +1,13 @@
use std::convert::{AsMut, AsRef, Into};
use limits_core::json_v2::{GenericCpusLimit, GenericCpuLimit};
use limits_core::json_v2::{GenericCpuLimit, GenericCpusLimit};
use super::FromGenericCpuInfo;
use crate::api::RangeLimit;
use crate::persist::CpuJson;
use crate::settings::{min_max_from_json, MinMax};
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_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> {
fn from_json_and_limits(mut other: Vec<CpuJson>, version: u64, limits: GenericCpusLimit) -> Self {
impl<C: AsMut<Cpu> + AsRef<Cpu> + TCpu + FromGenericCpuInfo>
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 mut result = Vec::with_capacity(other.len());
let max_cpus = Self::cpu_count();
@ -103,9 +109,12 @@ impl<C: AsMut<Cpu> + AsRef<Cpu> + TCpu + FromGenericCpuInfo> ProviderBuilder<Vec
break;
}
}
let cpu_limit = limits.cpus.get(i)
let cpu_limit = limits
.cpus
.get(i)
.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);
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 fallback_cpu_limit = GenericCpuLimit::default();
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))
.unwrap_or_else(|| &fallback_cpu_limit).clone();
.unwrap_or_else(|| &fallback_cpu_limit)
.clone();
let new_cpu = C::from_limits(i, cpu_limit);
new_cpus.push(new_cpu);
}
@ -221,7 +233,8 @@ pub struct Cpu {
impl Cpu {
#[inline]
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::persist::GpuJson;
use crate::settings::{TGpu, ProviderBuilder};
use crate::settings::{min_max_from_json, MinMax};
use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{ProviderBuilder, TGpu};
#[derive(Debug, Clone)]
pub struct Gpu {
@ -38,15 +38,17 @@ impl Gpu {
fn find_card_sysfs(root: Option<impl AsRef<std::path::Path>>) -> BasicEntityPath {
let root = crate::settings::util::root_or_default_sysfs(root);
match root.class("drm", crate::settings::util::always_satisfied) {
Ok(mut iter) => {
iter.next()
.unwrap_or_else(|| {
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"))
})
},
Ok(mut iter) => iter.next().unwrap_or_else(|| {
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"))
}),
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"))
}
}
@ -56,7 +58,9 @@ impl Gpu {
impl ProviderBuilder<GpuJson, GenericGpuLimit> for Gpu {
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() {
persistent.clock_limits.map(|x| min_max_from_json(x, version))
persistent
.clock_limits
.map(|x| min_max_from_json(x, version))
} else {
None
};
@ -84,7 +88,7 @@ impl ProviderBuilder<GpuJson, GenericGpuLimit> for Gpu {
},
clock_limits: clock_lims,
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,
clock_limits: self.clock_limits.map(|x| x.into()),
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
.clone()
.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 {
x.min /= ppt_divisor;
x.max /= ppt_divisor;
x
} else {x}),
.map(|mut x| {
if let Some(ppt_divisor) = self.limits.ppt_divisor {
x.min /= ppt_divisor;
x.max /= ppt_divisor;
x
} else {
x
}
}),
slow_ppt_limits: self
.limits
.slow_ppt
.clone()
.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 {
x.min /= ppt_divisor;
x.max /= ppt_divisor;
x
} else {x}),
.map(|mut x| {
if let Some(ppt_divisor) = self.limits.ppt_divisor {
x.min /= ppt_divisor;
x.max /= ppt_divisor;
x
} else {
x
}
}),
ppt_step: self.limits.ppt_step.unwrap_or(1),
tdp_limits: self
.limits
@ -188,28 +203,56 @@ impl TGpu for Gpu {
fn ppt(&mut self, fast: Option<u64>, slow: Option<u64>) {
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 })
.map(|x| {
x.clamp(
fast_lims.min.unwrap_or(0),
fast_lims.max.unwrap_or(u64::MAX),
)
});
self.fast_ppt = fast
.map(|x| {
if let Some(ppt_divisor) = self.limits.ppt_divisor {
x * ppt_divisor
} 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 {
self.slow_ppt = slow.map(|x| if let Some(ppt_divisor) = self.limits.ppt_divisor { x * ppt_divisor } else { x })
.map(|x| {
x.clamp(
slow_lims.min.unwrap_or(0),
slow_lims.max.unwrap_or(u64::MAX),
)
});
self.slow_ppt = slow
.map(|x| {
if let Some(ppt_divisor) = self.limits.ppt_divisor {
x * ppt_divisor
} 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>) {
(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>>) {

View file

@ -11,7 +11,15 @@ pub use traits::FromGenericCpuInfo;
fn _impl_checker() {
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::<Cpus<Cpu>, Vec<crate::persist::CpuJson>, limits_core::json_v2::GenericCpusLimit>();
impl_provider_builder::<
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>();
}

View file

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

View file

@ -4,10 +4,14 @@ use std::sync::Mutex;
use crate::persist::GpuJson;
use crate::settings::generic::Gpu as GenericGpu;
use crate::settings::MinMax;
use crate::settings::{TGpu, ProviderBuilder};
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;
match result {
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) {
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")]
if let Some(x) = ryzenadj.get_init_table_err() {
log::warn!("RyzenAdj table init error: {}", x);
}
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, "refresh", ryzenadj.refresh().map(|_| "success"));
msg_or_err(&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,
"refresh",
ryzenadj.refresh().map(|_| "success"),
);
msg_or_err(
&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_volt", ryzenadj.get_gfx_volt());
@ -41,7 +66,7 @@ fn ryzen_adj_or_log() -> Option<Mutex<RyzenAdj>> {
Ok(x) => {
log_capabilities(&x);
Some(Mutex::new(x))
},
}
Err(e) => {
log::error!("RyzenAdj init error: {}", e);
None
@ -90,7 +115,6 @@ impl ProviderBuilder<GpuJson, limits_core::json_v2::GenericGpuLimit> for Gpu {
}
impl Gpu {
fn set_all(&mut self) -> Result<(), Vec<SettingError>> {
let mutex = match &self.implementor {
Some(x) => x,

View file

@ -7,6 +7,10 @@ pub use gpu::Gpu;
fn _impl_checker() {
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>();
}

View file

@ -6,25 +6,37 @@ mod min_max;
mod traits;
mod util;
pub mod dev_mode;
pub mod generic;
pub mod generic_amd;
pub mod steam_deck;
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 general::{General, SettingVariant, Settings};
pub use min_max::{min_max_from_json, MinMax};
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)]
mod tests {
#[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);
}
}

View file

@ -1,16 +1,22 @@
use std::convert::Into;
use std::sync::{Arc, Mutex};
use sysfuss::{PowerSupplyAttribute, PowerSupplyPath, HwMonAttribute, HwMonAttributeItem, HwMonAttributeType, HwMonPath, SysEntity, SysEntityAttributesExt, SysAttribute};
use sysfuss::capability::attributes;
use sysfuss::{
HwMonAttribute, HwMonAttributeItem, HwMonAttributeType, HwMonPath, PowerSupplyAttribute,
PowerSupplyPath, SysAttribute, SysEntity, SysEntityAttributesExt,
};
use limits_core::json_v2::GenericBatteryLimit;
use smokepatio::ec::{ControllerSet, unnamed_power::{UnnamedPowerEC, ChargeMode}};
use crate::api::RangeLimit;
use crate::persist::{BatteryEventJson, BatteryJson};
use crate::settings::{TBattery, ProviderBuilder};
use crate::settings::{OnPowerEvent, OnResume, OnSet, PowerMode, SettingError};
use crate::settings::{ProviderBuilder, TBattery};
use smokepatio::ec::{
unnamed_power::{ChargeMode, UnnamedPowerEC},
ControllerSet,
};
#[derive(Debug, Clone)]
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 {
trigger: Self::str_to_trigger(&other.trigger).unwrap_or(EventTrigger::Ignored),
charge_rate: other.charge_rate,
@ -137,7 +148,10 @@ impl EventInstruction {
fn set_charge_mode(&self) -> Result<(), SettingError> {
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 {
msg: format!("Failed to set charge mode"),
setting: crate::settings::SettingVariant::Battery,
@ -149,12 +163,15 @@ impl EventInstruction {
fn set_charge_rate(&self) -> Result<(), SettingError> {
if let Some(charge_rate) = self.charge_rate {
self.sysfs_hwmon.set(MAX_BATTERY_CHARGE_RATE_ATTR, charge_rate).map_err(
|e| SettingError {
msg: format!("Failed to write to `{:?}`: {}", MAX_BATTERY_CHARGE_RATE_ATTR, e),
self.sysfs_hwmon
.set(MAX_BATTERY_CHARGE_RATE_ATTR, charge_rate)
.map_err(|e| SettingError {
msg: format!(
"Failed to write to `{:?}`: {}",
MAX_BATTERY_CHARGE_RATE_ATTR, e
),
setting: crate::settings::SettingVariant::Battery,
},
)
})
} else {
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_CURRENT_PATH: &str = "/sys/class/hwmon/hwmon5/curr1_input"; // read-only*/
const BATTERY_NEEDS: &[PowerSupplyAttribute] = &[
PowerSupplyAttribute::Type,
PowerSupplyAttribute::CurrentNow,
@ -213,8 +229,10 @@ const HWMON_NEEDS: &[HwMonAttribute] = &[
//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_LEVEL_ATTR: HwMonAttribute = HwMonAttribute::custom("max_battery_charge_level");
const MAX_BATTERY_CHARGE_RATE_ATTR: HwMonAttribute =
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 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");
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
},
}
Err(e) => {
log::error!("Failed to find SteamDeck battery power_supply in sysfs ({}), using naive fallback", e);
root.power_supply_by_name("BAT1")
@ -245,11 +266,15 @@ impl Battery {
Ok(hwmon) => {
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);
} else {
log::info!("Found SteamDeck battery hwmon {} in sysfs: {}", super::util::JUPITER_HWMON_NAME, hwmon.as_ref().display());
} else {
log::info!(
"Found SteamDeck battery hwmon {} in sysfs: {}",
super::util::JUPITER_HWMON_NAME,
hwmon.as_ref().display()
);
}
hwmon
},
}
Err(e) => {
log::warn!("Failed to find SteamDeck battery hwmon {} in sysfs ({}), trying alternate name",
super::util::JUPITER_HWMON_NAME, e);
@ -258,10 +283,14 @@ impl Battery {
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);
} 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
},
}
Err(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)
@ -295,21 +324,27 @@ impl Battery {
if let Some(charge_rate) = self.charge_rate {
self.state.charge_rate_set = true;
let path = MAX_BATTERY_CHARGE_RATE_ATTR.path(&*self.sysfs_hwmon);
self.sysfs_hwmon.set(MAX_BATTERY_CHARGE_RATE_ATTR, charge_rate).map_err(
|e| SettingError {
self.sysfs_hwmon
.set(MAX_BATTERY_CHARGE_RATE_ATTR, charge_rate)
.map_err(|e| SettingError {
msg: format!("Failed to write to `{}`: {}", path.display(), e),
setting: crate::settings::SettingVariant::Battery,
},
)
})
} else if self.state.charge_rate_set {
self.state.charge_rate_set = false;
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(
|e| SettingError {
self.sysfs_hwmon
.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),
setting: crate::settings::SettingVariant::Battery,
},
)
})
} else {
Ok(())
}
@ -318,14 +353,20 @@ impl Battery {
fn set_charge_mode(&mut self) -> Result<(), SettingError> {
if let Some(charge_mode) = self.charge_mode {
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 {
msg: format!("Failed to set charge mode"),
setting: crate::settings::SettingVariant::Battery,
})
} else if self.state.charge_mode_set {
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 {
msg: format!("Failed to set charge mode"),
setting: crate::settings::SettingVariant::Battery,
@ -337,23 +378,35 @@ impl Battery {
fn set_charge_limit(&mut self) -> Result<(), SettingError> {
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 {
self.state.charge_limit_set = true;
self.sysfs_hwmon.set(MAX_BATTERY_CHARGE_LEVEL_ATTR, (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,
}
self.sysfs_hwmon
.set(
MAX_BATTERY_CHARGE_LEVEL_ATTR,
(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 {
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 {
msg: format!("Failed to reset (write to) {:?}: {}", MAX_BATTERY_CHARGE_LEVEL_ATTR, e),
setting: crate::settings::SettingVariant::Battery,
}
)
msg: format!(
"Failed to reset (write to) {:?}: {}",
MAX_BATTERY_CHARGE_LEVEL_ATTR, e
),
setting: crate::settings::SettingVariant::Battery,
})
} else {
Ok(())
}
@ -373,8 +426,16 @@ impl Battery {
fn clamp_all(&mut self) {
if let Some(charge_rate) = &mut self.charge_rate {
*charge_rate =
(*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));
*charge_rate = (*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),
);
}
}
@ -558,13 +619,21 @@ impl Into<BatteryJson> for Battery {
charge_rate: self.charge_rate,
charge_mode: self.charge_mode.map(Self::charge_mode_to_str),
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 {
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 ec = Arc::new(Mutex::new(UnnamedPowerEC::new()));
match version {
@ -586,14 +655,15 @@ impl ProviderBuilder<BatteryJson, GenericBatteryLimit> for Battery {
sysfs_hwmon: hwmon_sys,
bat_ec: ec,
variant: super::Model::LCD,
}.remove_charge_limit_instructions(),
}
.remove_charge_limit_instructions(),
_ => Self {
charge_rate: persistent.charge_rate,
charge_mode: persistent
.charge_mode
.map(|x| Self::str_to_charge_mode(&x))
.flatten(),
charge_limit: None,
charge_limit: None,
events: persistent
.events
.into_iter()
@ -605,7 +675,8 @@ impl ProviderBuilder<BatteryJson, GenericBatteryLimit> for Battery {
sysfs_hwmon: hwmon_sys,
bat_ec: ec,
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>)),
bat_ec: Arc::new(Mutex::new(UnnamedPowerEC::new())),
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 {
crate::api::BatteryLimits {
charge_current: Some(RangeLimit {
min: self.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),
min: self
.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_modes: vec![

View file

@ -2,22 +2,20 @@ use std::convert::Into;
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::POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT;
use crate::api::RangeLimit;
use crate::persist::CpuJson;
use crate::settings::{min_max_from_json, MinMax};
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_SMT_PATH: &str = "/sys/devices/system/cpu/smt/control";
const CARD_EXTENSIONS: &[&'static str] = &[
super::DPM_FORCE_LIMITS_ATTRIBUTE
];
const CARD_EXTENSIONS: &[&'static str] = &[super::DPM_FORCE_LIMITS_ATTRIBUTE];
const MAX_CLOCK: u64 = 3500;
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 {
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();
let (_, can_smt) = Self::system_smt_capabilities();
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) {
Cpu::from_json_and_limits(
cpu,
version,
i,
cpu_limit.to_owned()
)
Cpu::from_json_and_limits(cpu, version, i, cpu_limit.to_owned())
} else {
Cpu::from_json(
cpu,
version,
i,
)
Cpu::from_json(cpu, version, i)
};
result.push(new_cpu);
}
@ -160,10 +153,7 @@ impl ProviderBuilder<Vec<CpuJson>, GenericCpusLimit> for Cpus {
let mut sys_cpus = Vec::with_capacity(max_cpu);
for i in 0..max_cpu {
let new_cpu = if let Some(cpu_limit) = limits.cpus.get(i) {
Cpu::from_limits(
i,
cpu_limit.to_owned()
)
Cpu::from_limits(i, cpu_limit.to_owned())
} else {
Cpu::system_default(i)
};
@ -255,7 +245,12 @@ enum ClockType {
impl Cpu {
#[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 {
0 => Self {
online: other.online,
@ -280,13 +275,21 @@ impl Cpu {
#[inline]
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)
}
fn find_card_sysfs(root: Option<impl AsRef<std::path::Path>>) -> BasicEntityPath {
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) => {
let card = iter
.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());
card
},
}
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"))
}
}
}
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);
self.sysfs.set(CPU_CLOCK_LIMITS_ATTRIBUTE.to_owned(), &payload).map_err(|e| {
SettingError {
self.sysfs
.set(CPU_CLOCK_LIMITS_ATTRIBUTE.to_owned(), &payload)
.map_err(|e| SettingError {
msg: format!(
"Failed to write `{}` to `{}`: {}",
&payload, CPU_CLOCK_LIMITS_ATTRIBUTE, e
),
setting: crate::settings::SettingVariant::Cpu,
}
})
})
}
fn reset_clock_limits(&self) -> Result<(), SettingError> {
self.sysfs.set(CPU_CLOCK_LIMITS_ATTRIBUTE.to_owned(), "r\n").map_err(|e| {
SettingError {
self.sysfs
.set(CPU_CLOCK_LIMITS_ATTRIBUTE.to_owned(), "r\n")
.map_err(|e| SettingError {
msg: format!(
"Failed to write `r` to `{}`: {}",
CPU_CLOCK_LIMITS_ATTRIBUTE, e
),
setting: crate::settings::SettingVariant::Cpu,
}
})
})
}
fn set_clock_limits(&mut self) -> Result<(), Vec<SettingError>> {
@ -350,11 +361,12 @@ impl Cpu {
}
// min clock
if let Some(min) = clock_limits.min {
let valid_min = if min < range_min_or_fallback(&self.limits.clock_min, MIN_MIN_CLOCK) {
range_min_or_fallback(&self.limits.clock_min, MIN_MIN_CLOCK)
} else {
min
};
let valid_min =
if min < range_min_or_fallback(&self.limits.clock_min, MIN_MIN_CLOCK) {
range_min_or_fallback(&self.limits.clock_min, MIN_MIN_CLOCK)
} else {
min
};
self.set_clock_limit(self.index, valid_min, ClockType::Min)
.unwrap_or_else(|e| errors.push(e));
}
@ -371,22 +383,30 @@ impl Cpu {
let mut errors = Vec::new();
self.state.clock_limits_set = false;
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_cpu(false, self.index);
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT
.enforce_level(&self.sysfs)?;
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level(&self.sysfs)?;
if POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.needs_manual() {
// always set clock speeds, since it doesn't reset correctly (kernel/hardware bug)
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level(&self.sysfs)?;
// disable manual clock limits
log::debug!("Setting CPU {} to default clockspeed", self.index);
// max clock
self.set_clock_limit(self.index, range_max_or_fallback(&self.limits.clock_max, MAX_CLOCK), ClockType::Max)
.unwrap_or_else(|e| errors.push(e));
self.set_clock_limit(
self.index,
range_max_or_fallback(&self.limits.clock_max, MAX_CLOCK),
ClockType::Max,
)
.unwrap_or_else(|e| errors.push(e));
// min clock
self.set_clock_limit(self.index, range_min_or_fallback(&self.limits.clock_min, MIN_MIN_CLOCK), ClockType::Min)
.unwrap_or_else(|e| errors.push(e));
self.set_clock_limit(
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
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() {
Ok(())
} else {
@ -407,11 +427,19 @@ impl Cpu {
// disable manual clock limits
log::debug!("Setting CPU {} to default clockspeed", self.index);
// max clock
self.set_clock_limit(self.index, range_max_or_fallback(&self.limits.clock_max, MAX_CLOCK), ClockType::Max)
.unwrap_or_else(|e| errors.push(e));
self.set_clock_limit(
self.index,
range_max_or_fallback(&self.limits.clock_max, MAX_CLOCK),
ClockType::Max,
)
.unwrap_or_else(|e| errors.push(e));
// min clock
self.set_clock_limit(self.index, range_min_or_fallback(&self.limits.clock_min, MIN_MIN_CLOCK), ClockType::Min)
.unwrap_or_else(|e| errors.push(e));
self.set_clock_limit(
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));
@ -430,12 +458,15 @@ impl Cpu {
}
fn set_confirm(&self) -> Result<(), SettingError> {
self.sysfs.set(CPU_CLOCK_LIMITS_ATTRIBUTE.to_owned(), "c\n").map_err(|e| {
SettingError {
msg: format!("Failed to write `c` to `{}`: {}", CPU_CLOCK_LIMITS_ATTRIBUTE, e),
self.sysfs
.set(CPU_CLOCK_LIMITS_ATTRIBUTE.to_owned(), "c\n")
.map_err(|e| SettingError {
msg: format!(
"Failed to write `c` to `{}`: {}",
CPU_CLOCK_LIMITS_ATTRIBUTE, e
),
setting: crate::settings::SettingVariant::Cpu,
}
})
})
}
fn set_force_performance_related(&mut self) -> Result<(), Vec<SettingError>> {
@ -504,12 +535,16 @@ impl Cpu {
fn clamp_all(&mut self) {
if let Some(clock_limits) = &mut self.clock_limits {
if let Some(min) = clock_limits.min {
clock_limits.min =
Some(min.clamp(range_min_or_fallback(&self.limits.clock_max, MIN_MAX_CLOCK), range_max_or_fallback(&self.limits.clock_min, MAX_CLOCK)));
clock_limits.min = Some(min.clamp(
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 {
clock_limits.max =
Some(max.clamp(range_min_or_fallback(&self.limits.clock_max, MIN_MAX_CLOCK), range_max_or_fallback(&self.limits.clock_max, MAX_CLOCK)));
clock_limits.max = Some(max.clamp(
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,
index: cpu_index,
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 {
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 {
@ -578,7 +616,10 @@ impl Into<CpuJson> for Cpu {
online: self.online,
clock_limits: self.clock_limits.map(|x| x.into()),
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 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 super::POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT;
use crate::api::RangeLimit;
use crate::persist::GpuJson;
use crate::settings::{TGpu, ProviderBuilder};
use crate::settings::{min_max_from_json, MinMax};
use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{ProviderBuilder, TGpu};
// usually in /sys/class/hwmon/hwmon4/<attribute>
const SLOW_PPT_ATTRIBUTE: sysfuss::HwMonAttribute = sysfuss::HwMonAttribute::custom("power1_cap");
@ -60,7 +63,14 @@ const PPT_DIVISOR: u64 = 1_000;
impl Gpu {
fn find_card_sysfs(root: Option<impl AsRef<std::path::Path>>) -> BasicEntityPath {
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) => {
let card = iter
.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");
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
},
}
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"))
}
}
@ -82,33 +98,47 @@ impl Gpu {
fn find_hwmon_sysfs(root: Option<impl AsRef<std::path::Path>>) -> HwMonPath {
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| {
log::error!("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());
let hwmon = root
.hwmon_by_name(super::util::GPU_HWMON_NAME)
.unwrap_or_else(|e| {
log::error!(
"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
}
fn set_clock_limit(&self, speed: u64, mode: ClockType) -> Result<(), SettingError> {
let payload = format!("s {} {}\n", mode as u8, speed);
let path = GPU_CLOCK_LIMITS_ATTRIBUTE.path(&self.sysfs_card);
self.sysfs_card.set(GPU_CLOCK_LIMITS_ATTRIBUTE.to_owned(), &payload).map_err(|e| {
SettingError {
msg: format!("Failed to write `{}` to `{}`: {}", &payload, path.display(), e),
self.sysfs_card
.set(GPU_CLOCK_LIMITS_ATTRIBUTE.to_owned(), &payload)
.map_err(|e| SettingError {
msg: format!(
"Failed to write `{}` to `{}`: {}",
&payload,
path.display(),
e
),
setting: crate::settings::SettingVariant::Gpu,
}
})
})
}
fn set_confirm(&self) -> Result<(), SettingError> {
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| {
SettingError {
self.sysfs_card
.set(GPU_CLOCK_LIMITS_ATTRIBUTE.to_owned(), "c\n")
.map_err(|e| SettingError {
msg: format!("Failed to write `c` to `{}`: {}", path.display(), e),
setting: crate::settings::SettingVariant::Gpu,
}
})
})
}
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) = &limit.max {
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);
} else {
log::debug!("chosen_clock: {}, limit_clock: {}", clock, limit);
@ -129,7 +164,10 @@ impl Gpu {
}
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));
// round (and find) nearest valid clock step
// roughly price is right strategy (clock step will always be lower or equal to chosen)
@ -142,7 +180,7 @@ impl Gpu {
if i == 0 {
return *current_val_opt as _;
} else {
return options[i-1].0 as _;
return options[i - 1].0 as _;
}
}
}
@ -160,9 +198,11 @@ impl Gpu {
use std::fmt::Write;
let mut payload = String::from("0");
for i in 1..max_val {
write!(payload, " {}", i).expect("Failed to write to memory payload (should be infallible!?)");
write!(payload, " {}", 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
}
}
@ -177,11 +217,13 @@ impl Gpu {
self.state.clock_limits_set = true;
// max clock
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
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));
@ -195,11 +237,23 @@ impl Gpu {
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level(&self.sysfs_card)?;
// disable manual clock limits
// max clock
self.set_clock_limit(self.limits.clock_max.and_then(|lim| lim.max).unwrap_or(MAX_CLOCK), ClockType::Max)
.unwrap_or_else(|e| errors.push(e));
self.set_clock_limit(
self.limits
.clock_max
.and_then(|lim| lim.max)
.unwrap_or(MAX_CLOCK),
ClockType::Max,
)
.unwrap_or_else(|e| errors.push(e));
// min clock
self.set_clock_limit(self.limits.clock_min.and_then(|lim| lim.min).unwrap_or(MIN_CLOCK), ClockType::Min)
.unwrap_or_else(|e| errors.push(e));
self.set_clock_limit(
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));
} else {
@ -218,28 +272,37 @@ impl Gpu {
fn set_memory_speed(&self, clock: u64) -> Result<(), SettingError> {
let path = GPU_MEMORY_DOWNCLOCK_ATTRIBUTE.path(&self.sysfs_card);
let payload = self.build_memory_clock_payload(clock);
log::debug!("Generated payload for gpu fclk (memory): `{}` (is maxed? {})", payload, self.is_memory_clock_maxed());
self.sysfs_card.set(GPU_MEMORY_DOWNCLOCK_ATTRIBUTE.to_owned(), payload).map_err(|e| {
SettingError {
log::debug!(
"Generated payload for gpu fclk (memory): `{}` (is maxed? {})",
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),
setting: crate::settings::SettingVariant::Gpu,
}
})
})
}
fn set_force_performance_related(&mut self) -> Result<(), Vec<SettingError>> {
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
.enforce_level(&self.sysfs_card)
.unwrap_or_else(|mut e| errors.append(&mut e));
.set_gpu(!self.is_memory_clock_maxed() || self.clock_limits.is_some());
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?)
self.set_memory_speed(
self.memory_clock
.or_else(|| self.limits.memory_clock
.map(|lim| lim.max.unwrap_or(MAX_MEMORY_CLOCK))
).unwrap_or(MAX_MEMORY_CLOCK)
).unwrap_or_else(|e| errors.push(e));
.or_else(|| {
self.limits
.memory_clock
.map(|lim| lim.max.unwrap_or(MAX_MEMORY_CLOCK))
})
.unwrap_or(MAX_MEMORY_CLOCK),
)
.unwrap_or_else(|e| errors.push(e));
self.set_clocks()
.unwrap_or_else(|mut e| errors.append(&mut e));
// commit changes (if no errors have already occured)
@ -262,7 +325,8 @@ impl Gpu {
// set fast PPT
if let Some(fast_ppt) = &self.fast_ppt {
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 {
msg: format!(
"Failed to write `{}` to `{:?}`: {}",
@ -276,7 +340,8 @@ impl Gpu {
} else if self.state.fast_ppt_set {
self.state.fast_ppt_set = false;
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 {
msg: format!(
"Failed to write `{}` to `{:?}`: {}",
@ -291,7 +356,8 @@ impl Gpu {
// set slow PPT
if let Some(slow_ppt) = &self.slow_ppt {
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 {
msg: format!(
"Failed to write `{}` to `{:?}`: {}",
@ -305,7 +371,8 @@ impl Gpu {
} else if self.state.slow_ppt_set {
self.state.slow_ppt_set = false;
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 {
msg: format!(
"Failed to write `{}` to `{:?}`: {}",
@ -328,23 +395,72 @@ impl Gpu {
fn clamp_all(&mut self) {
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 {
*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(min) = clock_limits.min {
clock_limits.min =
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)));
clock_limits.min = 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),
),
);
}
if let Some(max) = clock_limits.max {
clock_limits.max =
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)));
clock_limits.max = 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),
),
);
}
}
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,
clock_limits: self.clock_limits.map(|x| x.into()),
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 {
fast_ppt: persistent.fast_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,
limits: limits,
state: crate::state::steam_deck::Gpu::default(),
@ -386,7 +508,9 @@ impl ProviderBuilder<GpuJson, GenericGpuLimit> for Gpu {
_ => Self {
fast_ppt: persistent.fast_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,
limits: limits,
state: crate::state::steam_deck::Gpu::default(),
@ -433,12 +557,16 @@ impl TGpu for Gpu {
fn limits(&self) -> crate::api::GpuLimits {
crate::api::GpuLimits {
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),
max: super::util::range_max_or_fallback(&self.limits.fast_ppt, MAX_FAST_PPT) / self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR),
min: super::util::range_min_or_fallback(&self.limits.fast_ppt, MIN_FAST_PPT)
/ 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 {
min: super::util::range_min_or_fallback(&self.limits.slow_ppt, MIN_SLOW_PPT) / 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),
min: super::util::range_min_or_fallback(&self.limits.slow_ppt, MIN_SLOW_PPT)
/ 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),
tdp_limits: None,
@ -454,8 +582,14 @@ impl TGpu for Gpu {
}),
clock_step: self.limits.clock_step.unwrap_or(100),
memory_control: Some(RangeLimit {
min: super::util::range_min_or_fallback(&self.limits.memory_clock, MIN_MEMORY_CLOCK),
max: super::util::range_max_or_fallback(&self.limits.memory_clock, MAX_MEMORY_CLOCK),
min: super::util::range_min_or_fallback(
&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),
}
@ -472,8 +606,10 @@ impl TGpu for Gpu {
fn get_ppt(&self) -> (Option<u64>, Option<u64>) {
(
self.fast_ppt.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)),
self.fast_ppt
.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();
for line in s.split('\n') {
if !line.is_empty() {
if let Some((val, freq_mess)) = line.split_once(':') {
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>() {
result.push((val, freq));
}

View file

@ -7,7 +7,9 @@ mod util;
pub use battery::Battery;
pub use cpu::Cpus;
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)]
pub enum Model {
@ -20,7 +22,15 @@ pub use util::flash_led;
fn _impl_checker() {
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::<Cpus, Vec<crate::persist::CpuJson>, limits_core::json_v2::GenericCpusLimit>();
impl_provider_builder::<
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>();
}

View file

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

View file

@ -3,8 +3,8 @@ use std::convert::Into;
use limits_core::json_v2::GenericBatteryLimit;
use crate::persist::BatteryJson;
use crate::settings::{TBattery, ProviderBuilder};
use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{ProviderBuilder, TBattery};
#[derive(Debug, Clone)]
pub struct Battery;
@ -29,7 +29,11 @@ impl Into<BatteryJson> 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()
}

View file

@ -5,7 +5,7 @@ use limits_core::json_v2::GenericCpusLimit;
use crate::persist::CpuJson;
use crate::settings::MinMax;
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_SMT_PATH: &str = "/sys/devices/system/cpu/smt/control";
@ -146,7 +146,11 @@ impl 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 mut result = Vec::with_capacity(persistent.len());
let max_cpus = Self::cpu_count();
@ -284,7 +288,7 @@ impl Cpu {
.unwrap_or("schedutil".to_owned()),
index: cpu_index,
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::settings::MinMax;
use crate::settings::{TGpu, ProviderBuilder};
use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{ProviderBuilder, TGpu};
#[derive(Debug, Clone)]
pub struct Gpu {}
impl Gpu {
pub fn system_default() -> Self {
Self { }
Self {}
}
}

View file

@ -9,7 +9,15 @@ pub use gpu::Gpu;
fn _impl_checker() {
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::<Cpus, Vec<crate::persist::CpuJson>, limits_core::json_v2::GenericCpusLimit>();
impl_provider_builder::<
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>();
}

View file

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

View file

@ -120,51 +120,66 @@ mod generate {
let limits = limits_core::json_v2::Limits {
cpu: limits_core::json_v2::Limit {
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 {
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 {
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();
ron::ser::to_writer_pretty(output_file, &limits, crate::utility::ron_pretty_config()).unwrap();
let output_file =
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]
fn generate_default_minimal_save_file() {
let mut mini_variants = std::collections::HashMap::with_capacity(2);
mini_variants.insert(0, crate::persist::SettingsJson {
version: 0,
name: crate::consts::DEFAULT_SETTINGS_VARIANT_NAME.to_owned(),
variant: 0,
persistent: false,
cpus: vec![crate::persist::CpuJson::default(); 8],
gpu: crate::persist::GpuJson::default(),
battery: crate::persist::BatteryJson::default(),
provider: None,
});
mini_variants.insert(42, crate::persist::SettingsJson {
version: 0,
name: "FortySecondary".to_owned(),
variant: 42,
persistent: false,
cpus: vec![crate::persist::CpuJson::default(); 8],
gpu: crate::persist::GpuJson::default(),
battery: crate::persist::BatteryJson::default(),
provider: None,
});
mini_variants.insert(
0,
crate::persist::SettingsJson {
version: 0,
name: crate::consts::DEFAULT_SETTINGS_VARIANT_NAME.to_owned(),
variant: 0,
persistent: false,
cpus: vec![crate::persist::CpuJson::default(); 8],
gpu: crate::persist::GpuJson::default(),
battery: crate::persist::BatteryJson::default(),
provider: None,
},
);
mini_variants.insert(
42,
crate::persist::SettingsJson {
version: 0,
name: "FortySecondary".to_owned(),
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 {
version: 0,
name: crate::consts::DEFAULT_SETTINGS_NAME.to_owned(),
variants: mini_variants,
};
let output_file = 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();
let output_file =
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,
SingleDropdownOption,
Navigation,
Focusable,
Spinner,
//NotchLabel
//gamepadDialogClasses,
//joinClassNames,
@ -89,6 +91,7 @@ var startHook: any = null;
var endHook: any = null;
var userHook: any = null;
var usdplReady = false;
var isVariantLoading = false;
var tryNotifyProfileChange = function() {};
@ -343,6 +346,12 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
data: elem,
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 (
<PanelSection>
@ -383,83 +392,102 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
<Field
label={tr("Profile Variant")} // TODO translate
>
<Dropdown
{(!isVariantLoading && <Dropdown
menuLabel={tr("Profile Variant")}
rgOptions={variantOptions}
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;
})}
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) => {
let data = elem.data as backend.VariantInfo;
backend.log(backend.LogLevel.Debug, "Profile variant dropdown selected " + elem.data.toString());
backend.loadGeneralSettingsVariant(data.id, data.name);
set_value(CURRENT_VARIANT_GEN, elem.data as backend.VariantInfo);
reloadGUI("ProfileVariantGovernor");
if (elem.data.id != (get_value(CURRENT_VARIANT_GEN) as backend.VariantInfo).id) {
isVariantLoading = true;
let data = elem.data as backend.VariantInfo;
backend.log(backend.LogLevel.Debug, "Profile variant dropdown selected " + elem.data.id.toString());
//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>
</PanelSectionRow>
<PanelSectionRow style={{
alignItems: "center",
display: "flex",
justifyContent: "space-around",
}}>
<DialogButton
style={{
maxWidth: "30%",
minWidth: "auto",
}}
//layout="below"
onClick={(_: MouseEvent) => {
backend.log(backend.LogLevel.Debug, "Creating new PowerTools settings variant");
backend.resolve(
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),
(ok: boolean) => {
backend.log(backend.LogLevel.Debug, "New settings variant ok? " + ok);
reload();
backend.resolve(backend.waitForComplete(), (_) => {
backend.log(backend.LogLevel.Debug, "Trying to tell UI to re-render due to new settings variant");
tryNotifyProfileChange();
});
<PanelSectionRow>
<Focusable style={{
alignItems: "center",
display: "flex",
justifyContent: "space-around",
}}
flow-children="horizontal"
>
<DialogButton
style={{
maxWidth: "30%",
minWidth: "auto",
}}
//layout="below"
onClick={(_: MouseEvent) => {
backend.log(backend.LogLevel.Debug, "Creating new PowerTools settings variant");
backend.resolve(
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),
(ok: boolean) => {
backend.log(backend.LogLevel.Debug, "New settings variant ok? " + ok);
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 + ")");
}
);
}}
>
<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/>
</DialogButton>
<DialogButton
style={{
maxWidth: "30%",
minWidth: "auto",
}}
//layout="below"
onClick={(_: MouseEvent) => {
Navigation.Navigate(STORE_RESULTS_URI);
Navigation.CloseSideMenus();
}}
>
<TbWorldPlus />
</DialogButton>
}}
>
<HiUpload/>
</DialogButton>
<DialogButton
style={{
maxWidth: "30%",
minWidth: "auto",
}}
//layout="below"
onClick={(_: MouseEvent) => {
Navigation.Navigate(STORE_RESULTS_URI);
Navigation.CloseSideMenus();
}}
>
<TbWorldPlus />
</DialogButton>
</Focusable>
</PanelSectionRow>
<Debug idc={idc}/>