forked from NG-SD-Plugins/PowerTools
Add battery charge limit functionality
This commit is contained in:
parent
32ae1a7eeb
commit
f42efab0b0
33 changed files with 799 additions and 63 deletions
2
backend/Cargo.lock
generated
2
backend/Cargo.lock
generated
|
@ -1095,7 +1095,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "powertools"
|
name = "powertools"
|
||||||
version = "1.3.0-alpha"
|
version = "1.3.0-beta1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"libryzenadj",
|
"libryzenadj",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "powertools"
|
name = "powertools"
|
||||||
version = "1.3.0-alpha"
|
version = "1.3.0-beta1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["NGnius (Graham) <ngniusness@gmail.com>"]
|
authors = ["NGnius (Graham) <ngniusness@gmail.com>"]
|
||||||
description = "Backend (superuser) functionality for PowerTools"
|
description = "Backend (superuser) functionality for PowerTools"
|
||||||
|
|
|
@ -26,6 +26,8 @@ pub struct BatteryLimits {
|
||||||
pub charge_current: Option<RangeLimit<u64>>,
|
pub charge_current: Option<RangeLimit<u64>>,
|
||||||
pub charge_current_step: u64,
|
pub charge_current_step: u64,
|
||||||
pub charge_modes: Vec<String>,
|
pub charge_modes: Vec<String>,
|
||||||
|
pub charge_limit: Option<RangeLimit<f64>>,
|
||||||
|
pub charge_limit_step: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
|
|
@ -193,3 +193,83 @@ pub fn unset_charge_mode(
|
||||||
vec![true.into()]
|
vec![true.into()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate unplugged event receiver web method
|
||||||
|
pub fn on_unplugged(
|
||||||
|
sender: Sender<ApiMessage>,
|
||||||
|
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
|
||||||
|
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
|
||||||
|
move |_| {
|
||||||
|
sender.lock().unwrap().send(ApiMessage::OnUnplugged).expect("on_unplugged send failed");
|
||||||
|
vec![true.into()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate plugged in event receiver web method
|
||||||
|
pub fn on_plugged(
|
||||||
|
sender: Sender<ApiMessage>,
|
||||||
|
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
|
||||||
|
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
|
||||||
|
move |_| {
|
||||||
|
sender.lock().unwrap().send(ApiMessage::OnPluggedIn).expect("on_plugged send failed");
|
||||||
|
vec![true.into()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate set battery charge limit web method
|
||||||
|
pub fn set_charge_limit(
|
||||||
|
sender: Sender<ApiMessage>,
|
||||||
|
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
|
||||||
|
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
|
||||||
|
let setter = move |limit: f64|
|
||||||
|
sender.lock()
|
||||||
|
.unwrap()
|
||||||
|
.send(ApiMessage::Battery(BatteryMessage::SetChargeLimit(Some(limit))))
|
||||||
|
.expect("set_charge_limit send failed");
|
||||||
|
move |params_in: super::ApiParameterType| {
|
||||||
|
if let Some(&Primitive::F64(new_val)) = params_in.get(0) {
|
||||||
|
setter(new_val);
|
||||||
|
vec![new_val.into()]
|
||||||
|
} else {
|
||||||
|
vec!["set_charge_limit missing parameter".into()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate unset battery charge limit web method
|
||||||
|
pub fn unset_charge_limit(
|
||||||
|
sender: Sender<ApiMessage>,
|
||||||
|
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
|
||||||
|
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
|
||||||
|
let unsetter = move ||
|
||||||
|
sender.lock()
|
||||||
|
.unwrap()
|
||||||
|
.send(ApiMessage::Battery(BatteryMessage::SetChargeLimit(None)))
|
||||||
|
.expect("unset_charge_limit send failed");
|
||||||
|
move |_: super::ApiParameterType| {
|
||||||
|
unsetter();
|
||||||
|
vec![true.into()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Charge design web method
|
||||||
|
pub fn get_charge_limit(
|
||||||
|
sender: Sender<ApiMessage>,
|
||||||
|
) -> impl AsyncCallable {
|
||||||
|
let sender = Arc::new(Mutex::new(sender)); // Sender is not Sync; this is required for safety
|
||||||
|
let getter = move || {
|
||||||
|
let sender2 = sender.clone();
|
||||||
|
move || {
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
let callback = move |val: Option<f64>| tx.send(val).expect("get_charge_limit callback send failed");
|
||||||
|
sender2.lock().unwrap().send(ApiMessage::Battery(BatteryMessage::GetChargeLimit(Box::new(callback)))).expect("get_charge_limit send failed");
|
||||||
|
rx.recv().expect("get_charge_limit callback recv failed")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
super::async_utils::AsyncIshGetter {
|
||||||
|
set_get: getter,
|
||||||
|
trans_getter: |result| {
|
||||||
|
super::utility::map_optional_result(Ok(result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -47,14 +47,14 @@ pub fn load_settings(
|
||||||
sender: Sender<ApiMessage>,
|
sender: Sender<ApiMessage>,
|
||||||
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
|
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
|
||||||
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
|
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
|
||||||
let setter = move |path: String, name: String|
|
let setter = move |path: i64, name: String|
|
||||||
sender.lock()
|
sender.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.send(ApiMessage::LoadSettings(path, name)).expect("load_settings send failed");
|
.send(ApiMessage::LoadSettings(path, name)).expect("load_settings send failed");
|
||||||
move |params_in: super::ApiParameterType| {
|
move |params_in: super::ApiParameterType| {
|
||||||
if let Some(Primitive::String(path)) = params_in.get(0) {
|
if let Some(Primitive::F64(id)) = params_in.get(0) {
|
||||||
if let Some(Primitive::String(name)) = params_in.get(1) {
|
if let Some(Primitive::String(name)) = params_in.get(1) {
|
||||||
setter(path.to_owned(), name.to_owned());
|
setter(*id as i64, name.to_owned());
|
||||||
vec![true.into()]
|
vec![true.into()]
|
||||||
} else {
|
} else {
|
||||||
vec!["load_settings missing name parameter".into()]
|
vec!["load_settings missing name parameter".into()]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::sync::mpsc::{self, Receiver, Sender};
|
use std::sync::mpsc::{self, Receiver, Sender};
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use crate::settings::{Settings, TCpus, TGpu, TBattery, TGeneral, OnSet, OnResume, MinMax};
|
use crate::settings::{Settings, TCpus, TGpu, TBattery, TGeneral, OnSet, OnResume, MinMax, OnPowerEvent, PowerMode};
|
||||||
use crate::persist::SettingsJson;
|
use crate::persist::SettingsJson;
|
||||||
use crate::utility::unwrap_maybe_fatal;
|
use crate::utility::unwrap_maybe_fatal;
|
||||||
|
|
||||||
|
@ -13,8 +13,15 @@ pub enum ApiMessage {
|
||||||
Gpu(GpuMessage),
|
Gpu(GpuMessage),
|
||||||
General(GeneralMessage),
|
General(GeneralMessage),
|
||||||
OnResume,
|
OnResume,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
OnPluggedIn,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
OnUnplugged,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
OnChargeChange(f64), // battery fill amount: 0 = empty, 1 = full
|
||||||
|
PowerVibeCheck,
|
||||||
WaitForEmptyQueue(Callback<()>),
|
WaitForEmptyQueue(Callback<()>),
|
||||||
LoadSettings(String, String), // (path, name)
|
LoadSettings(i64, String), // (path, name)
|
||||||
LoadMainSettings,
|
LoadMainSettings,
|
||||||
LoadSystemSettings,
|
LoadSystemSettings,
|
||||||
GetLimits(Callback<super::SettingsLimits>),
|
GetLimits(Callback<super::SettingsLimits>),
|
||||||
|
@ -30,6 +37,8 @@ pub enum BatteryMessage {
|
||||||
ReadChargeNow(Callback<Option<f64>>),
|
ReadChargeNow(Callback<Option<f64>>),
|
||||||
ReadChargeDesign(Callback<Option<f64>>),
|
ReadChargeDesign(Callback<Option<f64>>),
|
||||||
ReadCurrentNow(Callback<Option<f64>>),
|
ReadCurrentNow(Callback<Option<f64>>),
|
||||||
|
SetChargeLimit(Option<f64>),
|
||||||
|
GetChargeLimit(Callback<Option<f64>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BatteryMessage {
|
impl BatteryMessage {
|
||||||
|
@ -44,6 +53,8 @@ impl BatteryMessage {
|
||||||
Self::ReadChargeNow(cb) => cb(settings.read_charge_now()),
|
Self::ReadChargeNow(cb) => cb(settings.read_charge_now()),
|
||||||
Self::ReadChargeDesign(cb) => cb(settings.read_charge_design()),
|
Self::ReadChargeDesign(cb) => cb(settings.read_charge_design()),
|
||||||
Self::ReadCurrentNow(cb) => cb(settings.read_current_now()),
|
Self::ReadCurrentNow(cb) => cb(settings.read_current_now()),
|
||||||
|
Self::SetChargeLimit(limit) => settings.charge_limit(limit),
|
||||||
|
Self::GetChargeLimit(cb) => cb(settings.get_charge_limit()),
|
||||||
}
|
}
|
||||||
dirty
|
dirty
|
||||||
}
|
}
|
||||||
|
@ -287,11 +298,44 @@ impl ApiMessageHandler {
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
ApiMessage::OnPluggedIn => {
|
||||||
|
if let Err(e) = settings.on_power_event(PowerMode::PluggedIn) {
|
||||||
|
print_errors("on_power_event(PluggedIn)", e);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
ApiMessage::OnUnplugged => {
|
||||||
|
if let Err(e) = settings.on_power_event(PowerMode::PluggedOut) {
|
||||||
|
print_errors("on_power_event(PluggedOut)", e);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
ApiMessage::OnChargeChange(charge) => {
|
||||||
|
if let Err(e) = settings.on_power_event(PowerMode::BatteryCharge(charge)) {
|
||||||
|
print_errors(&format!("on_power_event(BatteryCharge={:#0.5})", charge), e);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
ApiMessage::PowerVibeCheck => {
|
||||||
|
match settings.battery.check_power() {
|
||||||
|
Err(e) => print_errors("check_power()", e),
|
||||||
|
Ok(events) => {
|
||||||
|
for ev in events {
|
||||||
|
let name = format!("on_power_event([vibe]{:?})", ev);
|
||||||
|
if let Err(e) = settings.on_power_event(ev) {
|
||||||
|
print_errors(&name, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
ApiMessage::WaitForEmptyQueue(callback) => {
|
ApiMessage::WaitForEmptyQueue(callback) => {
|
||||||
self.on_empty.push(callback);
|
self.on_empty.push(callback);
|
||||||
false
|
false
|
||||||
},
|
},
|
||||||
ApiMessage::LoadSettings(path, name) => {
|
ApiMessage::LoadSettings(id, name) => {
|
||||||
|
let path = format!("{}.json", id);
|
||||||
match settings.load_file(path.into(), name, false) {
|
match settings.load_file(path.into(), name, false) {
|
||||||
Ok(success) => log::info!("Loaded settings file? {}", success),
|
Ok(success) => log::info!("Loaded settings file? {}", success),
|
||||||
Err(e) => log::warn!("Load file err: {}", e),
|
Err(e) => log::warn!("Load file err: {}", e),
|
||||||
|
|
|
@ -5,6 +5,7 @@ mod state;
|
||||||
|
|
||||||
mod consts;
|
mod consts;
|
||||||
use consts::*;
|
use consts::*;
|
||||||
|
mod power_worker;
|
||||||
mod resume_worker;
|
mod resume_worker;
|
||||||
//mod save_worker;
|
//mod save_worker;
|
||||||
mod api_worker;
|
mod api_worker;
|
||||||
|
@ -70,6 +71,7 @@ fn main() -> Result<(), ()> {
|
||||||
|
|
||||||
//let (_save_handle, save_sender) = save_worker::spawn(loaded_settings.clone());
|
//let (_save_handle, save_sender) = save_worker::spawn(loaded_settings.clone());
|
||||||
let _resume_handle = resume_worker::spawn(api_sender.clone());
|
let _resume_handle = resume_worker::spawn(api_sender.clone());
|
||||||
|
let _power_handle = power_worker::spawn(api_sender.clone());
|
||||||
|
|
||||||
let instance = Instance::new(PORT)
|
let instance = Instance::new(PORT)
|
||||||
.register("V_INFO", |_: Vec<Primitive>| {
|
.register("V_INFO", |_: Vec<Primitive>| {
|
||||||
|
@ -111,6 +113,18 @@ fn main() -> Result<(), ()> {
|
||||||
"BATTERY_unset_charge_mode",
|
"BATTERY_unset_charge_mode",
|
||||||
api::battery::unset_charge_mode(api_sender.clone()),
|
api::battery::unset_charge_mode(api_sender.clone()),
|
||||||
)
|
)
|
||||||
|
.register(
|
||||||
|
"BATTERY_set_charge_limit",
|
||||||
|
api::battery::set_charge_limit(api_sender.clone()),
|
||||||
|
)
|
||||||
|
.register(
|
||||||
|
"BATTERY_unset_charge_limit",
|
||||||
|
api::battery::unset_charge_limit(api_sender.clone()),
|
||||||
|
)
|
||||||
|
.register_async(
|
||||||
|
"BATTERY_get_charge_limit",
|
||||||
|
api::battery::get_charge_limit(api_sender.clone()),
|
||||||
|
)
|
||||||
// cpu API functions
|
// cpu API functions
|
||||||
.register("CPU_count", api::cpu::max_cpus)
|
.register("CPU_count", api::cpu::max_cpus)
|
||||||
.register(
|
.register(
|
||||||
|
@ -232,10 +246,17 @@ fn main() -> Result<(), ()> {
|
||||||
api::general::get_provider(api_sender.clone())
|
api::general::get_provider(api_sender.clone())
|
||||||
)
|
)
|
||||||
.register("GENERAL_idk", api::general::gunter)
|
.register("GENERAL_idk", api::general::gunter)
|
||||||
// general API functions
|
|
||||||
.register(
|
.register(
|
||||||
"GENERAL_apply_now",
|
"GENERAL_apply_now",
|
||||||
api::general::force_apply(api_sender.clone())
|
api::general::force_apply(api_sender.clone())
|
||||||
|
)
|
||||||
|
.register(
|
||||||
|
"GENERAL_on_pluggedin",
|
||||||
|
api::battery::on_plugged(api_sender.clone())
|
||||||
|
)
|
||||||
|
.register(
|
||||||
|
"GENERAL_on_unplugged",
|
||||||
|
api::battery::on_unplugged(api_sender.clone())
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Err(e) = loaded_settings.on_set() {
|
if let Err(e) = loaded_settings.on_set() {
|
||||||
|
|
|
@ -7,6 +7,15 @@ use serde::{Deserialize, Serialize};
|
||||||
pub struct BatteryJson {
|
pub struct BatteryJson {
|
||||||
pub charge_rate: Option<u64>,
|
pub charge_rate: Option<u64>,
|
||||||
pub charge_mode: Option<String>,
|
pub charge_mode: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub events: Vec<BatteryEventJson>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub struct BatteryEventJson {
|
||||||
|
pub trigger: String,
|
||||||
|
pub charge_rate: Option<u64>,
|
||||||
|
pub charge_mode: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for BatteryJson {
|
impl Default for BatteryJson {
|
||||||
|
@ -14,6 +23,7 @@ impl Default for BatteryJson {
|
||||||
Self {
|
Self {
|
||||||
charge_rate: None,
|
charge_rate: None,
|
||||||
charge_mode: None,
|
charge_mode: None,
|
||||||
|
events: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ mod error;
|
||||||
mod general;
|
mod general;
|
||||||
mod gpu;
|
mod gpu;
|
||||||
|
|
||||||
pub use battery::BatteryJson;
|
pub use battery::{BatteryJson, BatteryEventJson};
|
||||||
pub use cpu::CpuJson;
|
pub use cpu::CpuJson;
|
||||||
pub use driver::DriverJson;
|
pub use driver::DriverJson;
|
||||||
pub use general::{MinMaxJson, SettingsJson};
|
pub use general::{MinMaxJson, SettingsJson};
|
||||||
|
|
19
backend/src/power_worker.rs
Normal file
19
backend/src/power_worker.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
use std::thread::{self, JoinHandle};
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::sync::mpsc::Sender;
|
||||||
|
|
||||||
|
use crate::api::handler::ApiMessage;
|
||||||
|
//use crate::utility::unwrap_maybe_fatal;
|
||||||
|
|
||||||
|
const PERIOD: Duration = Duration::from_secs(5);
|
||||||
|
|
||||||
|
pub fn spawn(sender: Sender<ApiMessage>) -> JoinHandle<()> {
|
||||||
|
thread::spawn(move || {
|
||||||
|
log::info!("power_worker starting...");
|
||||||
|
loop {
|
||||||
|
sender.send(ApiMessage::PowerVibeCheck).expect("power_worker send failed");
|
||||||
|
thread::sleep(PERIOD);
|
||||||
|
}
|
||||||
|
//log::warn!("resume_worker completed!");
|
||||||
|
})
|
||||||
|
}
|
|
@ -48,6 +48,8 @@ impl OnResume for General {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::settings::OnPowerEvent for General {}
|
||||||
|
|
||||||
impl TGeneral for General {
|
impl TGeneral for General {
|
||||||
fn limits(&self) -> crate::api::GeneralLimits {
|
fn limits(&self) -> crate::api::GeneralLimits {
|
||||||
crate::api::GeneralLimits { }
|
crate::api::GeneralLimits { }
|
||||||
|
@ -92,11 +94,23 @@ pub struct Settings {
|
||||||
|
|
||||||
impl OnSet for Settings {
|
impl OnSet for Settings {
|
||||||
fn on_set(&mut self) -> Result<(), Vec<SettingError>> {
|
fn on_set(&mut self) -> Result<(), Vec<SettingError>> {
|
||||||
self.battery.on_set()?;
|
let mut errors = Vec::new();
|
||||||
self.cpus.on_set()?;
|
|
||||||
self.gpu.on_set()?;
|
log::debug!("Applying settings for on_resume");
|
||||||
self.general.on_set()?;
|
self.general.on_set().unwrap_or_else(|mut e| errors.append(&mut e));
|
||||||
Ok(())
|
log::debug!("Resumed general");
|
||||||
|
self.battery.on_set().unwrap_or_else(|mut e| errors.append(&mut e));
|
||||||
|
log::debug!("Resumed battery");
|
||||||
|
self.cpus.on_set().unwrap_or_else(|mut e| errors.append(&mut e));
|
||||||
|
log::debug!("Resumed CPUs");
|
||||||
|
self.gpu.on_set().unwrap_or_else(|mut e| errors.append(&mut e));
|
||||||
|
log::debug!("Resumed GPU");
|
||||||
|
|
||||||
|
if errors.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(errors)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,14 +240,40 @@ impl Settings {
|
||||||
|
|
||||||
impl OnResume for Settings {
|
impl OnResume for Settings {
|
||||||
fn on_resume(&self) -> Result<(), Vec<SettingError>> {
|
fn on_resume(&self) -> Result<(), Vec<SettingError>> {
|
||||||
|
let mut errors = Vec::new();
|
||||||
|
|
||||||
log::debug!("Applying settings for on_resume");
|
log::debug!("Applying settings for on_resume");
|
||||||
self.battery.on_resume()?;
|
self.general.on_resume().unwrap_or_else(|mut e| errors.append(&mut e));
|
||||||
|
log::debug!("Resumed general");
|
||||||
|
self.battery.on_resume().unwrap_or_else(|mut e| errors.append(&mut e));
|
||||||
log::debug!("Resumed battery");
|
log::debug!("Resumed battery");
|
||||||
self.cpus.on_resume()?;
|
self.cpus.on_resume().unwrap_or_else(|mut e| errors.append(&mut e));
|
||||||
log::debug!("Resumed CPUs");
|
log::debug!("Resumed CPUs");
|
||||||
self.gpu.on_resume()?;
|
self.gpu.on_resume().unwrap_or_else(|mut e| errors.append(&mut e));
|
||||||
log::debug!("Resumed GPU");
|
log::debug!("Resumed GPU");
|
||||||
Ok(())
|
|
||||||
|
if errors.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(errors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::settings::OnPowerEvent for Settings {
|
||||||
|
fn on_power_event(&mut self, new_mode: super::PowerMode) -> Result<(), Vec<SettingError>> {
|
||||||
|
let mut errors = Vec::new();
|
||||||
|
|
||||||
|
self.general.on_power_event(new_mode).unwrap_or_else(|mut e| errors.append(&mut e));
|
||||||
|
self.battery.on_power_event(new_mode).unwrap_or_else(|mut e| errors.append(&mut e));
|
||||||
|
self.cpus.on_power_event(new_mode).unwrap_or_else(|mut e| errors.append(&mut e));
|
||||||
|
self.gpu.on_power_event(new_mode).unwrap_or_else(|mut e| errors.append(&mut e));
|
||||||
|
|
||||||
|
if errors.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(errors)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ impl Into<BatteryJson> for Battery {
|
||||||
BatteryJson {
|
BatteryJson {
|
||||||
charge_rate: None,
|
charge_rate: None,
|
||||||
charge_mode: None,
|
charge_mode: None,
|
||||||
|
events: Vec::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,12 +66,16 @@ impl OnResume for Battery {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::settings::OnPowerEvent for Battery {}
|
||||||
|
|
||||||
impl TBattery for Battery {
|
impl TBattery for Battery {
|
||||||
fn limits(&self) -> crate::api::BatteryLimits {
|
fn limits(&self) -> crate::api::BatteryLimits {
|
||||||
crate::api::BatteryLimits {
|
crate::api::BatteryLimits {
|
||||||
charge_current: None,
|
charge_current: None,
|
||||||
charge_current_step: 50,
|
charge_current_step: 50,
|
||||||
charge_modes: vec![],
|
charge_modes: vec![],
|
||||||
|
charge_limit: None,
|
||||||
|
charge_limit_step: 1.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,6 +131,10 @@ impl TBattery for Battery {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn charge_limit(&mut self, _limit: Option<f64>) {}
|
||||||
|
|
||||||
|
fn get_charge_limit(&self) -> Option<f64> { None }
|
||||||
|
|
||||||
fn provider(&self) -> crate::persist::DriverJson {
|
fn provider(&self) -> crate::persist::DriverJson {
|
||||||
crate::persist::DriverJson::Generic
|
crate::persist::DriverJson::Generic
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,7 +138,21 @@ impl<C: AsMut<Cpu> + AsRef<Cpu> + TCpu + FromGenericCpuInfo> Cpus<C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: AsMut<Cpu> + AsRef<Cpu> + TCpu + OnResume + OnSet> TCpus for Cpus<C> {
|
impl<C: AsMut<Cpu> + AsRef<Cpu> + TCpu + crate::settings::OnPowerEvent> crate::settings::OnPowerEvent for Cpus<C> {
|
||||||
|
fn on_power_event(&mut self, new_mode: crate::settings::PowerMode) -> Result<(), Vec<SettingError>> {
|
||||||
|
let mut errors = Vec::new();
|
||||||
|
for cpu in &mut self.cpus {
|
||||||
|
cpu.on_power_event(new_mode).unwrap_or_else(|mut e| errors.append(&mut e));
|
||||||
|
}
|
||||||
|
if errors.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(errors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: AsMut<Cpu> + AsRef<Cpu> + TCpu + OnResume + OnSet + crate::settings::OnPowerEvent> TCpus for Cpus<C> {
|
||||||
fn limits(&self) -> crate::api::CpusLimits {
|
fn limits(&self) -> crate::api::CpusLimits {
|
||||||
crate::api::CpusLimits {
|
crate::api::CpusLimits {
|
||||||
cpus: self.cpus.iter().map(|x| x.as_ref().limits()).collect(),
|
cpus: self.cpus.iter().map(|x| x.as_ref().limits()).collect(),
|
||||||
|
@ -333,6 +347,8 @@ impl OnResume for Cpu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::settings::OnPowerEvent for Cpu {}
|
||||||
|
|
||||||
impl TCpu for Cpu {
|
impl TCpu for Cpu {
|
||||||
fn online(&mut self) -> &mut bool {
|
fn online(&mut self) -> &mut bool {
|
||||||
&mut self.online
|
&mut self.online
|
||||||
|
|
|
@ -80,6 +80,8 @@ impl OnResume for Gpu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::settings::OnPowerEvent for Gpu {}
|
||||||
|
|
||||||
impl TGpu for Gpu {
|
impl TGpu for Gpu {
|
||||||
fn limits(&self) -> crate::api::GpuLimits {
|
fn limits(&self) -> crate::api::GpuLimits {
|
||||||
crate::api::GpuLimits {
|
crate::api::GpuLimits {
|
||||||
|
|
|
@ -37,6 +37,8 @@ impl OnSet for Cpus {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::settings::OnPowerEvent for Cpus {}
|
||||||
|
|
||||||
impl TCpus for Cpus {
|
impl TCpus for Cpus {
|
||||||
fn limits(&self) -> crate::api::CpusLimits {
|
fn limits(&self) -> crate::api::CpusLimits {
|
||||||
self.generic.limits()
|
self.generic.limits()
|
||||||
|
@ -110,6 +112,8 @@ impl OnSet for Cpu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::settings::OnPowerEvent for Cpu {}
|
||||||
|
|
||||||
impl TCpu for Cpu {
|
impl TCpu for Cpu {
|
||||||
fn online(&mut self) -> &mut bool {
|
fn online(&mut self) -> &mut bool {
|
||||||
self.generic.online()
|
self.generic.online()
|
||||||
|
|
|
@ -213,6 +213,8 @@ impl OnSet for Gpu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::settings::OnPowerEvent for Gpu {}
|
||||||
|
|
||||||
impl TGpu for Gpu {
|
impl TGpu for Gpu {
|
||||||
fn limits(&self) -> crate::api::GpuLimits {
|
fn limits(&self) -> crate::api::GpuLimits {
|
||||||
self.generic.limits()
|
self.generic.limits()
|
||||||
|
|
|
@ -17,7 +17,7 @@ pub use general::{SettingVariant, Settings, General};
|
||||||
pub use min_max::{MinMax, min_max_from_json};
|
pub use min_max::{MinMax, min_max_from_json};
|
||||||
|
|
||||||
pub use error::SettingError;
|
pub use error::SettingError;
|
||||||
pub use traits::{OnResume, OnSet, SettingsRange, TGeneral, TGpu, TCpus, TBattery, TCpu};
|
pub use traits::{OnResume, OnSet, TGeneral, TGpu, TCpus, TBattery, TCpu, OnPowerEvent, PowerMode};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use std::convert::Into;
|
use std::convert::Into;
|
||||||
|
|
||||||
use crate::api::RangeLimit;
|
use crate::api::RangeLimit;
|
||||||
use crate::settings::{OnResume, OnSet, SettingError};
|
use crate::settings::{OnResume, OnSet, SettingError, OnPowerEvent, PowerMode};
|
||||||
use crate::settings::TBattery;
|
use crate::settings::TBattery;
|
||||||
use crate::persist::BatteryJson;
|
use crate::persist::{BatteryJson, BatteryEventJson};
|
||||||
use super::util::ChargeMode;
|
use super::util::ChargeMode;
|
||||||
use super::oc_limits::{BatteryLimits, OverclockLimits};
|
use super::oc_limits::{BatteryLimits, OverclockLimits};
|
||||||
|
|
||||||
|
@ -11,11 +11,155 @@ use super::oc_limits::{BatteryLimits, OverclockLimits};
|
||||||
pub struct Battery {
|
pub struct Battery {
|
||||||
pub charge_rate: Option<u64>,
|
pub charge_rate: Option<u64>,
|
||||||
pub charge_mode: Option<ChargeMode>,
|
pub charge_mode: Option<ChargeMode>,
|
||||||
|
events: Vec<EventInstruction>,
|
||||||
limits: BatteryLimits,
|
limits: BatteryLimits,
|
||||||
state: crate::state::steam_deck::Battery,
|
state: crate::state::steam_deck::Battery,
|
||||||
driver_mode: crate::persist::DriverJson,
|
driver_mode: crate::persist::DriverJson,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum EventTrigger {
|
||||||
|
PluggedIn,
|
||||||
|
PluggedOut,
|
||||||
|
BatteryAbove(f64),
|
||||||
|
BatteryBelow(f64),
|
||||||
|
Ignored,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct EventInstruction {
|
||||||
|
trigger: EventTrigger,
|
||||||
|
charge_rate: Option<u64>,
|
||||||
|
charge_mode: Option<ChargeMode>,
|
||||||
|
is_triggered: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OnPowerEvent for EventInstruction {
|
||||||
|
fn on_power_event(&mut self, new_mode: PowerMode) -> Result<(), Vec<SettingError>> {
|
||||||
|
match (&self.trigger, new_mode) {
|
||||||
|
(EventTrigger::PluggedIn, PowerMode::PluggedIn) => {
|
||||||
|
log::info!("Steam Deck plugged in event handled");
|
||||||
|
self.set_all()
|
||||||
|
},
|
||||||
|
(EventTrigger::PluggedOut, PowerMode::PluggedOut) => {
|
||||||
|
log::info!("Steam Deck plugged out event handled");
|
||||||
|
self.set_all()
|
||||||
|
},
|
||||||
|
(EventTrigger::BatteryAbove(exp), PowerMode::BatteryCharge(act)) => {
|
||||||
|
if act > *exp {
|
||||||
|
if self.is_triggered {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
self.is_triggered = true;
|
||||||
|
log::info!("Steam Deck battery above {} event handled", exp);
|
||||||
|
self.set_all()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.is_triggered = false;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(EventTrigger::BatteryBelow(exp), PowerMode::BatteryCharge(act)) => {
|
||||||
|
if act < *exp {
|
||||||
|
if self.is_triggered {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
self.is_triggered = true;
|
||||||
|
log::info!("Steam Deck battery below {} event handled", exp);
|
||||||
|
self.set_all()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.is_triggered = false;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventInstruction {
|
||||||
|
#[inline]
|
||||||
|
fn trigger_to_str(mode: EventTrigger) -> String {
|
||||||
|
match mode {
|
||||||
|
EventTrigger::PluggedIn => "plug-in".to_owned(),
|
||||||
|
EventTrigger::PluggedOut => "plug-out".to_owned(),
|
||||||
|
EventTrigger::BatteryAbove(x) => format!(">{:#0.2}", x * 100.0),
|
||||||
|
EventTrigger::BatteryBelow(x) => format!("<{:#0.2}", x * 100.0),
|
||||||
|
EventTrigger::Ignored => "/shrug".to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn str_to_trigger(s: &str) -> Option<EventTrigger> {
|
||||||
|
match s {
|
||||||
|
"normal" => Some(EventTrigger::PluggedIn),
|
||||||
|
"idle" => Some(EventTrigger::PluggedOut),
|
||||||
|
s if s.starts_with('>') => s.trim_start_matches('>').parse::<f64>().ok().map(|x| EventTrigger::BatteryAbove(x)),
|
||||||
|
s if s.starts_with('<') => s.trim_start_matches('<').parse::<f64>().ok().map(|x| EventTrigger::BatteryBelow(x)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_json(other: BatteryEventJson, _version: u64) -> Self {
|
||||||
|
Self {
|
||||||
|
trigger: Self::str_to_trigger(&other.trigger).unwrap_or(EventTrigger::Ignored),
|
||||||
|
charge_rate: other.charge_rate,
|
||||||
|
charge_mode: other.charge_mode.map(|x| Battery::str_to_charge_mode(&x)).flatten(),
|
||||||
|
is_triggered: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_charge_mode(&self) -> Result<(), SettingError> {
|
||||||
|
if let Some(charge_mode) = self.charge_mode {
|
||||||
|
super::util::set(super::util::Setting::ChargeMode, charge_mode as _).map_err(
|
||||||
|
|e| SettingError {
|
||||||
|
msg: format!("Failed to set charge mode: {}", e),
|
||||||
|
setting: crate::settings::SettingVariant::Battery,
|
||||||
|
},
|
||||||
|
).map(|_| ())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_charge_rate(&self) -> Result<(), SettingError> {
|
||||||
|
if let Some(charge_rate) = self.charge_rate {
|
||||||
|
usdpl_back::api::files::write_single(BATTERY_CHARGE_RATE_PATH, charge_rate).map_err(
|
||||||
|
|e| SettingError {
|
||||||
|
msg: format!("Failed to write to `{}`: {}", BATTERY_CHARGE_RATE_PATH, e),
|
||||||
|
setting: crate::settings::SettingVariant::Battery,
|
||||||
|
},
|
||||||
|
).map(|_| ())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_all(&self) -> Result<(), Vec<SettingError>> {
|
||||||
|
let mut errors = Vec::new();
|
||||||
|
|
||||||
|
self.set_charge_rate().unwrap_or_else(|e| errors.push(e));
|
||||||
|
self.set_charge_mode().unwrap_or_else(|e| errors.push(e));
|
||||||
|
|
||||||
|
if errors.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(errors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<BatteryEventJson> for EventInstruction {
|
||||||
|
fn into(self) -> BatteryEventJson {
|
||||||
|
BatteryEventJson {
|
||||||
|
trigger: Self::trigger_to_str(self.trigger),
|
||||||
|
charge_rate: self.charge_rate,
|
||||||
|
charge_mode: self.charge_mode.map(|c| Battery::charge_mode_to_str(c)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const BATTERY_VOLTAGE: f64 = 7.7;
|
const BATTERY_VOLTAGE: f64 = 7.7;
|
||||||
|
|
||||||
const BATTERY_CHARGE_RATE_PATH: &str = "/sys/class/hwmon/hwmon5/maximum_battery_charge_rate"; // write-only
|
const BATTERY_CHARGE_RATE_PATH: &str = "/sys/class/hwmon/hwmon5/maximum_battery_charge_rate"; // write-only
|
||||||
|
@ -23,6 +167,7 @@ const BATTERY_CURRENT_NOW_PATH: &str = "/sys/class/power_supply/BAT1/current_now
|
||||||
const BATTERY_CHARGE_NOW_PATH: &str = "/sys/class/power_supply/BAT1/charge_now"; // read-only
|
const BATTERY_CHARGE_NOW_PATH: &str = "/sys/class/power_supply/BAT1/charge_now"; // read-only
|
||||||
const BATTERY_CHARGE_FULL_PATH: &str = "/sys/class/power_supply/BAT1/charge_full"; // read-only
|
const BATTERY_CHARGE_FULL_PATH: &str = "/sys/class/power_supply/BAT1/charge_full"; // read-only
|
||||||
const BATTERY_CHARGE_DESIGN_PATH: &str = "/sys/class/power_supply/BAT1/charge_full_design"; // read-only
|
const BATTERY_CHARGE_DESIGN_PATH: &str = "/sys/class/power_supply/BAT1/charge_full_design"; // read-only
|
||||||
|
const USB_PD_IN_MVOLTAGE_PATH: &str = "/sys/class/hwmon/hwmon5/in0_input"; // read-only
|
||||||
|
|
||||||
impl Battery {
|
impl Battery {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -34,6 +179,7 @@ impl Battery {
|
||||||
0 => Self {
|
0 => Self {
|
||||||
charge_rate: other.charge_rate,
|
charge_rate: other.charge_rate,
|
||||||
charge_mode: other.charge_mode.map(|x| Self::str_to_charge_mode(&x)).flatten(),
|
charge_mode: other.charge_mode.map(|x| Self::str_to_charge_mode(&x)).flatten(),
|
||||||
|
events: other.events.into_iter().map(|x| EventInstruction::from_json(x, version)).collect(),
|
||||||
limits: oc_limits,
|
limits: oc_limits,
|
||||||
state: crate::state::steam_deck::Battery::default(),
|
state: crate::state::steam_deck::Battery::default(),
|
||||||
driver_mode: driver,
|
driver_mode: driver,
|
||||||
|
@ -41,6 +187,7 @@ impl Battery {
|
||||||
_ => Self {
|
_ => Self {
|
||||||
charge_rate: other.charge_rate,
|
charge_rate: other.charge_rate,
|
||||||
charge_mode: other.charge_mode.map(|x| Self::str_to_charge_mode(&x)).flatten(),
|
charge_mode: other.charge_mode.map(|x| Self::str_to_charge_mode(&x)).flatten(),
|
||||||
|
events: other.events.into_iter().map(|x| EventInstruction::from_json(x, version)).collect(),
|
||||||
limits: oc_limits,
|
limits: oc_limits,
|
||||||
state: crate::state::steam_deck::Battery::default(),
|
state: crate::state::steam_deck::Battery::default(),
|
||||||
driver_mode: driver,
|
driver_mode: driver,
|
||||||
|
@ -62,11 +209,33 @@ impl Battery {
|
||||||
match s {
|
match s {
|
||||||
"normal" => Some(ChargeMode::Normal),
|
"normal" => Some(ChargeMode::Normal),
|
||||||
"idle" => Some(ChargeMode::Idle),
|
"idle" => Some(ChargeMode::Idle),
|
||||||
"discharge" | "disacharge" => Some(ChargeMode::Discharge),
|
"discharge" => Some(ChargeMode::Discharge),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_charge_mode(&mut self) -> Result<(), SettingError> {
|
||||||
|
if let Some(charge_mode) = self.charge_mode {
|
||||||
|
self.state.charge_mode_set = true;
|
||||||
|
super::util::set(super::util::Setting::ChargeMode, charge_mode as _).map_err(
|
||||||
|
|e| SettingError {
|
||||||
|
msg: format!("Failed to set charge mode: {}", e),
|
||||||
|
setting: crate::settings::SettingVariant::Battery,
|
||||||
|
},
|
||||||
|
).map(|_| ())
|
||||||
|
} else if self.state.charge_mode_set {
|
||||||
|
self.state.charge_mode_set = false;
|
||||||
|
super::util::set(super::util::Setting::ChargeMode, ChargeMode::Normal as _).map_err(
|
||||||
|
|e| SettingError {
|
||||||
|
msg: format!("Failed to set charge mode: {}", e),
|
||||||
|
setting: crate::settings::SettingVariant::Battery,
|
||||||
|
},
|
||||||
|
).map(|_| ())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn set_all(&mut self) -> Result<(), Vec<SettingError>> {
|
fn set_all(&mut self) -> Result<(), Vec<SettingError>> {
|
||||||
let mut errors = Vec::new();
|
let mut errors = Vec::new();
|
||||||
if let Some(charge_rate) = self.charge_rate {
|
if let Some(charge_rate) = self.charge_rate {
|
||||||
|
@ -86,23 +255,7 @@ impl Battery {
|
||||||
},
|
},
|
||||||
).unwrap_or_else(|e| errors.push(e));
|
).unwrap_or_else(|e| errors.push(e));
|
||||||
}
|
}
|
||||||
if let Some(charge_mode) = self.charge_mode {
|
self.set_charge_mode().unwrap_or_else(|e| errors.push(e));
|
||||||
self.state.charge_mode_set = true;
|
|
||||||
super::util::set(super::util::Setting::ChargeMode, charge_mode as _).map_err(
|
|
||||||
|e| SettingError {
|
|
||||||
msg: format!("Failed to set charge mode: {}", e),
|
|
||||||
setting: crate::settings::SettingVariant::Battery,
|
|
||||||
},
|
|
||||||
).unwrap_or_else(|e| {errors.push(e); 0});
|
|
||||||
} else if self.state.charge_mode_set {
|
|
||||||
self.state.charge_mode_set = false;
|
|
||||||
super::util::set(super::util::Setting::ChargeMode, ChargeMode::Normal as _).map_err(
|
|
||||||
|e| SettingError {
|
|
||||||
msg: format!("Failed to set charge mode: {}", e),
|
|
||||||
setting: crate::settings::SettingVariant::Battery,
|
|
||||||
},
|
|
||||||
).unwrap_or_else(|e| {errors.push(e); 0});
|
|
||||||
}
|
|
||||||
if errors.is_empty() {
|
if errors.is_empty() {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
|
@ -161,6 +314,17 @@ impl Battery {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_usb_voltage() -> Result<f64, SettingError> {
|
||||||
|
match usdpl_back::api::files::read_single::<_, u64, _>(USB_PD_IN_MVOLTAGE_PATH) {
|
||||||
|
Err(e) => Err(SettingError {
|
||||||
|
msg: format!("Failed to read from `{}`: {}", USB_PD_IN_MVOLTAGE_PATH, e),
|
||||||
|
setting: crate::settings::SettingVariant::Battery,
|
||||||
|
}),
|
||||||
|
// convert to V (from mV)
|
||||||
|
Ok(val) => Ok((val as f64)/1000.0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn system_default() -> Self {
|
pub fn system_default() -> Self {
|
||||||
let (oc_limits, is_default) = OverclockLimits::load_or_default();
|
let (oc_limits, is_default) = OverclockLimits::load_or_default();
|
||||||
let oc_limits = oc_limits.battery;
|
let oc_limits = oc_limits.battery;
|
||||||
|
@ -168,11 +332,40 @@ impl Battery {
|
||||||
Self {
|
Self {
|
||||||
charge_rate: None,
|
charge_rate: None,
|
||||||
charge_mode: None,
|
charge_mode: None,
|
||||||
|
events: Vec::new(),
|
||||||
limits: oc_limits,
|
limits: oc_limits,
|
||||||
state: crate::state::steam_deck::Battery::default(),
|
state: crate::state::steam_deck::Battery::default(),
|
||||||
driver_mode: driver,
|
driver_mode: driver,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_limit_event(&self) -> Option<usize> {
|
||||||
|
for (i, event) in self.events.iter().enumerate() {
|
||||||
|
match event.trigger {
|
||||||
|
EventTrigger::BatteryAbove(_) => {
|
||||||
|
if event.charge_mode.is_some() {
|
||||||
|
return Some(i);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_unlimit_event(&self) -> Option<usize> {
|
||||||
|
for (i, event) in self.events.iter().enumerate() {
|
||||||
|
match event.trigger {
|
||||||
|
EventTrigger::BatteryBelow(_) => {
|
||||||
|
if event.charge_mode.is_some() {
|
||||||
|
return Some(i);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<BatteryJson> for Battery {
|
impl Into<BatteryJson> for Battery {
|
||||||
|
@ -181,6 +374,7 @@ impl Into<BatteryJson> for Battery {
|
||||||
BatteryJson {
|
BatteryJson {
|
||||||
charge_rate: self.charge_rate,
|
charge_rate: self.charge_rate,
|
||||||
charge_mode: self.charge_mode.map(Self::charge_mode_to_str),
|
charge_mode: self.charge_mode.map(Self::charge_mode_to_str),
|
||||||
|
events: self.events.into_iter().map(|x| x.into()).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,6 +392,35 @@ impl OnResume for Battery {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl OnPowerEvent for Battery {
|
||||||
|
fn on_power_event(&mut self, new_mode: PowerMode) -> Result<(), Vec<SettingError>> {
|
||||||
|
let mut errors = Vec::new();
|
||||||
|
match new_mode {
|
||||||
|
PowerMode::PluggedIn => {
|
||||||
|
// plug event resets battery settings
|
||||||
|
self.events.iter_mut().for_each(|ev| ev.is_triggered = false);
|
||||||
|
self.set_charge_mode()
|
||||||
|
.map_err(|e| vec![e])
|
||||||
|
},
|
||||||
|
PowerMode::PluggedOut => {
|
||||||
|
// plug event resets battery settings
|
||||||
|
self.events.iter_mut().for_each(|ev| ev.is_triggered = false);
|
||||||
|
self.set_charge_mode()
|
||||||
|
.map_err(|e| vec![e])
|
||||||
|
},
|
||||||
|
PowerMode::BatteryCharge(_) => Ok(())
|
||||||
|
}.unwrap_or_else(|mut e| errors.append(&mut e));
|
||||||
|
for ev in &mut self.events {
|
||||||
|
ev.on_power_event(new_mode).unwrap_or_else(|mut e| errors.append(&mut e));
|
||||||
|
}
|
||||||
|
if errors.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(errors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TBattery for Battery {
|
impl TBattery for Battery {
|
||||||
fn limits(&self) -> crate::api::BatteryLimits {
|
fn limits(&self) -> crate::api::BatteryLimits {
|
||||||
crate::api::BatteryLimits {
|
crate::api::BatteryLimits {
|
||||||
|
@ -207,6 +430,11 @@ impl TBattery for Battery {
|
||||||
}),
|
}),
|
||||||
charge_current_step: 50,
|
charge_current_step: 50,
|
||||||
charge_modes: vec!["normal".to_owned(), "discharge".to_owned(), "idle".to_owned()],
|
charge_modes: vec!["normal".to_owned(), "discharge".to_owned(), "idle".to_owned()],
|
||||||
|
charge_limit: Some(RangeLimit {
|
||||||
|
min: 10.0,
|
||||||
|
max: 90.0,
|
||||||
|
}),
|
||||||
|
charge_limit_step: 1.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,6 +498,107 @@ impl TBattery for Battery {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn charge_limit(&mut self, limit: Option<f64>) {
|
||||||
|
// upper limit
|
||||||
|
let index = self.find_limit_event();
|
||||||
|
if let Some(index) = index {
|
||||||
|
if let Some(limit) = limit {
|
||||||
|
log::info!("Updating Steam Deck charge limit event instruction to >{}", limit);
|
||||||
|
self.events[index] = EventInstruction {
|
||||||
|
trigger: EventTrigger::BatteryAbove(limit/100.0),
|
||||||
|
charge_rate: None,
|
||||||
|
charge_mode: Some(ChargeMode::Idle),
|
||||||
|
is_triggered: false,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
self.events.remove(index);
|
||||||
|
}
|
||||||
|
} else if let Some(limit) = limit {
|
||||||
|
log::info!("Creating Steam Deck charge limit event instruction of >{}", limit);
|
||||||
|
self.events.push(
|
||||||
|
EventInstruction {
|
||||||
|
trigger: EventTrigger::BatteryAbove(limit/100.0),
|
||||||
|
charge_rate: None,
|
||||||
|
charge_mode: Some(ChargeMode::Idle),
|
||||||
|
is_triggered: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// lower limit
|
||||||
|
let index = self.find_unlimit_event();
|
||||||
|
if let Some(index) = index {
|
||||||
|
if let Some(limit) = limit {
|
||||||
|
let limit = (limit - 10.0).clamp(0.0, 100.0);
|
||||||
|
log::info!("Updating Steam Deck charge limit event instruction to <{}", limit);
|
||||||
|
self.events[index] = EventInstruction {
|
||||||
|
trigger: EventTrigger::BatteryBelow(limit/100.0),
|
||||||
|
charge_rate: None,
|
||||||
|
charge_mode: Some(ChargeMode::Normal),
|
||||||
|
is_triggered: false,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
self.events.remove(index);
|
||||||
|
}
|
||||||
|
} else if let Some(limit) = limit {
|
||||||
|
let limit = (limit - 10.0).clamp(0.0, 100.0);
|
||||||
|
log::info!("Creating Steam Deck charge limit event instruction of <{}", limit);
|
||||||
|
self.events.push(
|
||||||
|
EventInstruction {
|
||||||
|
trigger: EventTrigger::BatteryBelow(limit/100.0),
|
||||||
|
charge_rate: None,
|
||||||
|
charge_mode: Some(ChargeMode::Normal),
|
||||||
|
is_triggered: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_charge_limit(&self) -> Option<f64> {
|
||||||
|
let index = self.find_limit_event();
|
||||||
|
if let Some(index) = index {
|
||||||
|
if let EventTrigger::BatteryAbove(limit) = self.events[index].trigger {
|
||||||
|
Some(limit * 100.0)
|
||||||
|
} else {
|
||||||
|
log::error!("Got index {} for battery charge limit which does not have expected event trigger: {:?}", index, &self.events);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_power(&mut self) -> Result<Vec<PowerMode>, Vec<SettingError>> {
|
||||||
|
log::debug!("Steam Deck power vibe check");
|
||||||
|
let mut errors = Vec::new();
|
||||||
|
let mut events = Vec::new();
|
||||||
|
match (Self::read_charge_full(), Self::read_charge_now()) {
|
||||||
|
(Ok(full), Ok(now)) => events.push(PowerMode::BatteryCharge(now/full)),
|
||||||
|
(Err(e1), Err(e2)) => {
|
||||||
|
errors.push(e1);
|
||||||
|
errors.push(e2);
|
||||||
|
},
|
||||||
|
(Err(e), _) => errors.push(e),
|
||||||
|
(_, Err(e)) => errors.push(e),
|
||||||
|
}
|
||||||
|
match Self::read_usb_voltage() {
|
||||||
|
Ok(voltage) => {
|
||||||
|
if voltage > 0.0 && self.state.charger_state != crate::state::steam_deck::ChargeState::PluggedIn {
|
||||||
|
events.push(PowerMode::PluggedIn);
|
||||||
|
self.state.charger_state = crate::state::steam_deck::ChargeState::PluggedIn;
|
||||||
|
} else if voltage == 0.0 && self.state.charger_state != crate::state::steam_deck::ChargeState::Unplugged {
|
||||||
|
events.push(PowerMode::PluggedOut);
|
||||||
|
self.state.charger_state = crate::state::steam_deck::ChargeState::Unplugged;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => errors.push(e),
|
||||||
|
}
|
||||||
|
if errors.is_empty() {
|
||||||
|
Ok(events)
|
||||||
|
} else {
|
||||||
|
Err(errors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn provider(&self) -> crate::persist::DriverJson {
|
fn provider(&self) -> crate::persist::DriverJson {
|
||||||
self.driver_mode.clone()
|
self.driver_mode.clone()
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,6 +158,8 @@ impl Cpus {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::settings::OnPowerEvent for Cpus {}
|
||||||
|
|
||||||
impl TCpus for Cpus {
|
impl TCpus for Cpus {
|
||||||
fn limits(&self) -> crate::api::CpusLimits {
|
fn limits(&self) -> crate::api::CpusLimits {
|
||||||
crate::api::CpusLimits {
|
crate::api::CpusLimits {
|
||||||
|
|
|
@ -249,6 +249,8 @@ impl OnResume for Gpu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::settings::OnPowerEvent for Gpu {}
|
||||||
|
|
||||||
impl TGpu for Gpu {
|
impl TGpu for Gpu {
|
||||||
fn limits(&self) -> crate::api::GpuLimits {
|
fn limits(&self) -> crate::api::GpuLimits {
|
||||||
crate::api::GpuLimits {
|
crate::api::GpuLimits {
|
||||||
|
|
|
@ -10,12 +10,37 @@ pub trait OnResume {
|
||||||
fn on_resume(&self) -> Result<(), Vec<SettingError>>;
|
fn on_resume(&self) -> Result<(), Vec<SettingError>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SettingsRange {
|
#[repr(u8)]
|
||||||
fn max() -> Self;
|
#[derive(Clone, Copy, Debug)]
|
||||||
fn min() -> Self;
|
pub enum PowerMode {
|
||||||
|
PluggedIn,
|
||||||
|
PluggedOut, // unplugged
|
||||||
|
BatteryCharge(f64), // battery fill amount: 0 = empty, 1 = full
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TGpu: OnResume + OnSet + Debug + Send {
|
pub trait OnPowerEvent {
|
||||||
|
fn on_plugged_in(&mut self) -> Result<(), Vec<SettingError>> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_plugged_out(&mut self) -> Result<(), Vec<SettingError>> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_charge_amount(&mut self, _amount: f64) -> Result<(), Vec<SettingError>> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_power_event(&mut self, new_mode: PowerMode) -> Result<(), Vec<SettingError>> {
|
||||||
|
match new_mode {
|
||||||
|
PowerMode::PluggedIn => self.on_plugged_in(),
|
||||||
|
PowerMode::PluggedOut => self.on_plugged_out(),
|
||||||
|
PowerMode::BatteryCharge(now) => self.on_charge_amount(now),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait TGpu: OnSet + OnResume + OnPowerEvent + Debug + Send {
|
||||||
fn limits(&self) -> crate::api::GpuLimits;
|
fn limits(&self) -> crate::api::GpuLimits;
|
||||||
|
|
||||||
fn json(&self) -> crate::persist::GpuJson;
|
fn json(&self) -> crate::persist::GpuJson;
|
||||||
|
@ -35,7 +60,7 @@ pub trait TGpu: OnResume + OnSet + Debug + Send {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TCpus: OnResume + OnSet + Debug + Send {
|
pub trait TCpus: OnSet + OnResume + OnPowerEvent + Debug + Send {
|
||||||
fn limits(&self) -> crate::api::CpusLimits;
|
fn limits(&self) -> crate::api::CpusLimits;
|
||||||
|
|
||||||
fn json(&self) -> Vec<crate::persist::CpuJson>;
|
fn json(&self) -> Vec<crate::persist::CpuJson>;
|
||||||
|
@ -63,7 +88,7 @@ pub trait TCpu: Debug + Send {
|
||||||
fn get_clock_limits(&self) -> Option<&MinMax<u64>>;
|
fn get_clock_limits(&self) -> Option<&MinMax<u64>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TGeneral: OnResume + OnSet + Debug + Send {
|
pub trait TGeneral: OnSet + OnResume + OnPowerEvent + Debug + Send {
|
||||||
fn limits(&self) -> crate::api::GeneralLimits;
|
fn limits(&self) -> crate::api::GeneralLimits;
|
||||||
|
|
||||||
fn get_persistent(&self) -> bool;
|
fn get_persistent(&self) -> bool;
|
||||||
|
@ -81,7 +106,7 @@ pub trait TGeneral: OnResume + OnSet + Debug + Send {
|
||||||
fn provider(&self) -> crate::persist::DriverJson;
|
fn provider(&self) -> crate::persist::DriverJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TBattery: OnResume + OnSet + Debug + Send {
|
pub trait TBattery: OnSet + OnResume + OnPowerEvent + Debug + Send {
|
||||||
fn limits(&self) -> crate::api::BatteryLimits;
|
fn limits(&self) -> crate::api::BatteryLimits;
|
||||||
|
|
||||||
fn json(&self) -> crate::persist::BatteryJson;
|
fn json(&self) -> crate::persist::BatteryJson;
|
||||||
|
@ -102,6 +127,19 @@ pub trait TBattery: OnResume + OnSet + Debug + Send {
|
||||||
|
|
||||||
fn read_current_now(&self) -> Option<f64>;
|
fn read_current_now(&self) -> Option<f64>;
|
||||||
|
|
||||||
|
fn charge_limit(&mut self, limit: Option<f64>);
|
||||||
|
|
||||||
|
fn get_charge_limit(&self) -> Option<f64>;
|
||||||
|
|
||||||
|
fn check_power(&mut self) -> Result<Vec<PowerMode>, Vec<SettingError>> {
|
||||||
|
log::warn!("Power event check using default trait implementation");
|
||||||
|
let mut events = Vec::new();
|
||||||
|
if let (Some(full), Some(now)) = (self.read_charge_full(), self.read_charge_now()) {
|
||||||
|
events.push(PowerMode::BatteryCharge(now/full));
|
||||||
|
}
|
||||||
|
Ok(events)
|
||||||
|
}
|
||||||
|
|
||||||
fn provider(&self) -> crate::persist::DriverJson {
|
fn provider(&self) -> crate::persist::DriverJson {
|
||||||
crate::persist::DriverJson::AutoDetect
|
crate::persist::DriverJson::AutoDetect
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ impl Into<BatteryJson> for Battery {
|
||||||
BatteryJson {
|
BatteryJson {
|
||||||
charge_rate: None,
|
charge_rate: None,
|
||||||
charge_mode: None,
|
charge_mode: None,
|
||||||
|
events: Vec::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,12 +30,16 @@ impl OnResume for Battery {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::settings::OnPowerEvent for Battery {}
|
||||||
|
|
||||||
impl TBattery for Battery {
|
impl TBattery for Battery {
|
||||||
fn limits(&self) -> crate::api::BatteryLimits {
|
fn limits(&self) -> crate::api::BatteryLimits {
|
||||||
crate::api::BatteryLimits {
|
crate::api::BatteryLimits {
|
||||||
charge_current: None,
|
charge_current: None,
|
||||||
charge_current_step: 50,
|
charge_current_step: 50,
|
||||||
charge_modes: vec![],
|
charge_modes: vec![],
|
||||||
|
charge_limit: None,
|
||||||
|
charge_limit_step: 1.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +69,10 @@ impl TBattery for Battery {
|
||||||
|
|
||||||
fn read_current_now(&self) -> Option<f64> { None }
|
fn read_current_now(&self) -> Option<f64> { None }
|
||||||
|
|
||||||
|
fn charge_limit(&mut self, _limit: Option<f64>) {}
|
||||||
|
|
||||||
|
fn get_charge_limit(&self) -> Option<f64> { None }
|
||||||
|
|
||||||
fn provider(&self) -> crate::persist::DriverJson {
|
fn provider(&self) -> crate::persist::DriverJson {
|
||||||
crate::persist::DriverJson::Unknown
|
crate::persist::DriverJson::Unknown
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,8 @@ impl OnResume for Cpus {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::settings::OnPowerEvent for Cpus {}
|
||||||
|
|
||||||
impl Cpus {
|
impl Cpus {
|
||||||
pub fn cpu_count() -> Option<usize> {
|
pub fn cpu_count() -> Option<usize> {
|
||||||
let mut data: String = usdpl_back::api::files::read_single(CPU_PRESENT_PATH)
|
let mut data: String = usdpl_back::api::files::read_single(CPU_PRESENT_PATH)
|
||||||
|
|
|
@ -49,6 +49,8 @@ impl OnResume for Gpu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::settings::OnPowerEvent for Gpu {}
|
||||||
|
|
||||||
impl TGpu for Gpu {
|
impl TGpu for Gpu {
|
||||||
fn limits(&self) -> crate::api::GpuLimits {
|
fn limits(&self) -> crate::api::GpuLimits {
|
||||||
crate::api::GpuLimits {
|
crate::api::GpuLimits {
|
||||||
|
|
|
@ -2,13 +2,22 @@
|
||||||
pub struct Battery {
|
pub struct Battery {
|
||||||
pub charge_rate_set: bool,
|
pub charge_rate_set: bool,
|
||||||
pub charge_mode_set: bool,
|
pub charge_mode_set: bool,
|
||||||
|
pub charger_state: ChargeState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::default::Default for Battery {
|
impl std::default::Default for Battery {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
charge_rate_set: false,
|
charge_rate_set: true,
|
||||||
charge_mode_set: false,
|
charge_mode_set: true,
|
||||||
|
charger_state: ChargeState::Unknown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum ChargeState {
|
||||||
|
PluggedIn,
|
||||||
|
Unplugged,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,6 @@ mod battery;
|
||||||
mod cpu;
|
mod cpu;
|
||||||
mod gpu;
|
mod gpu;
|
||||||
|
|
||||||
pub use battery::Battery;
|
pub use battery::{Battery, ChargeState};
|
||||||
pub use cpu::Cpu;
|
pub use cpu::Cpu;
|
||||||
pub use gpu::Gpu;
|
pub use gpu::Gpu;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "PowerTools",
|
"name": "PowerTools",
|
||||||
"version": "1.3.0-alpha",
|
"version": "1.3.0-beta1",
|
||||||
"description": "Power tweaks for power users",
|
"description": "Power tweaks for power users",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "shx rm -rf dist && rollup -c",
|
"build": "shx rm -rf dist && rollup -c",
|
||||||
|
|
|
@ -63,6 +63,8 @@ export type BatteryLimits = {
|
||||||
charge_current: RangeLimit | null;
|
charge_current: RangeLimit | null;
|
||||||
charge_current_step: number;
|
charge_current_step: number;
|
||||||
charge_modes: string[];
|
charge_modes: string[];
|
||||||
|
charge_limit: RangeLimit | null;
|
||||||
|
charge_limit_step: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CpuLimits = {
|
export type CpuLimits = {
|
||||||
|
@ -139,6 +141,18 @@ export async function unsetBatteryChargeMode(): Promise<any[]> {
|
||||||
return await call_backend("BATTERY_unset_charge_mode", []);
|
return await call_backend("BATTERY_unset_charge_mode", []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getBatteryChargeLimit(): Promise<number | null> {
|
||||||
|
return (await call_backend("BATTERY_get_charge_limit", []))[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setBatteryChargeLimit(val: number): Promise<number> {
|
||||||
|
return (await call_backend("BATTERY_set_charge_limit", [val]))[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function unsetBatteryChargeLimit(): Promise<any[]> {
|
||||||
|
return await call_backend("BATTERY_unset_charge_limit", []);
|
||||||
|
}
|
||||||
|
|
||||||
// CPU
|
// CPU
|
||||||
|
|
||||||
export async function setCpuSmt(status: boolean): Promise<boolean[]> {
|
export async function setCpuSmt(status: boolean): Promise<boolean[]> {
|
||||||
|
@ -229,8 +243,8 @@ export async function getGeneralPersistent(): Promise<boolean> {
|
||||||
return (await call_backend("GENERAL_get_persistent", []))[0];
|
return (await call_backend("GENERAL_get_persistent", []))[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadGeneralSettings(path: string, name: string): Promise<boolean> {
|
export async function loadGeneralSettings(id: number, name: string): Promise<boolean> {
|
||||||
return (await call_backend("GENERAL_load_settings", [path, name]))[0];
|
return (await call_backend("GENERAL_load_settings", [id, name]))[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadGeneralDefaultSettings(): Promise<boolean> {
|
export async function loadGeneralDefaultSettings(): Promise<boolean> {
|
||||||
|
@ -280,3 +294,11 @@ export async function idk(): Promise<boolean> {
|
||||||
export async function forceApplySettings(): Promise<boolean> {
|
export async function forceApplySettings(): Promise<boolean> {
|
||||||
return (await call_backend("GENERAL_apply_now", []))[0];
|
return (await call_backend("GENERAL_apply_now", []))[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function onPluggedIn(): Promise<boolean> {
|
||||||
|
return (await call_backend("GENERAL_on_pluggedin", []))[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function onUnplugged(): Promise<boolean> {
|
||||||
|
return (await call_backend("GENERAL_on_unplugged", []))[0];
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import {
|
||||||
CHARGE_RATE_BATT,
|
CHARGE_RATE_BATT,
|
||||||
CHARGE_MODE_BATT,
|
CHARGE_MODE_BATT,
|
||||||
CURRENT_BATT,
|
CURRENT_BATT,
|
||||||
|
CHARGE_LIMIT_BATT,
|
||||||
} from "../consts";
|
} from "../consts";
|
||||||
import { set_value, get_value} from "usdpl-front";
|
import { set_value, get_value} from "usdpl-front";
|
||||||
|
|
||||||
|
@ -53,6 +54,12 @@ export class Battery extends Component<backend.IdcProps> {
|
||||||
{get_value(CHARGE_FULL_BATT).toFixed(1)} Wh ({(100 * get_value(CHARGE_FULL_BATT) / get_value(CHARGE_DESIGN_BATT)).toFixed(1)}%)
|
{get_value(CHARGE_FULL_BATT).toFixed(1)} Wh ({(100 * get_value(CHARGE_FULL_BATT) / get_value(CHARGE_DESIGN_BATT)).toFixed(1)}%)
|
||||||
</Field>
|
</Field>
|
||||||
</PanelSectionRow>}
|
</PanelSectionRow>}
|
||||||
|
<PanelSectionRow>
|
||||||
|
<Field
|
||||||
|
label={tr("Current")}>
|
||||||
|
{get_value(CURRENT_BATT)} mA
|
||||||
|
</Field>
|
||||||
|
</PanelSectionRow>
|
||||||
{(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_current != null && <PanelSectionRow>
|
{(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_current != null && <PanelSectionRow>
|
||||||
<ToggleField
|
<ToggleField
|
||||||
checked={get_value(CHARGE_RATE_BATT) != null}
|
checked={get_value(CHARGE_RATE_BATT) != null}
|
||||||
|
@ -60,7 +67,7 @@ export class Battery extends Component<backend.IdcProps> {
|
||||||
description={tr("Control battery charge rate when awake")}
|
description={tr("Control battery charge rate when awake")}
|
||||||
onChange={(value: boolean) => {
|
onChange={(value: boolean) => {
|
||||||
if (value) {
|
if (value) {
|
||||||
set_value(CHARGE_RATE_BATT, 2500);
|
set_value(CHARGE_RATE_BATT, (get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_current!.max);
|
||||||
reloadGUI("BATTChargeRateToggle");
|
reloadGUI("BATTChargeRateToggle");
|
||||||
} else {
|
} else {
|
||||||
set_value(CHARGE_RATE_BATT, null);
|
set_value(CHARGE_RATE_BATT, null);
|
||||||
|
@ -128,12 +135,44 @@ export class Battery extends Component<backend.IdcProps> {
|
||||||
/>
|
/>
|
||||||
</Field>}
|
</Field>}
|
||||||
</PanelSectionRow>}
|
</PanelSectionRow>}
|
||||||
<PanelSectionRow>
|
{(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_limit != null && <PanelSectionRow>
|
||||||
<Field
|
<ToggleField
|
||||||
label={tr("Current")}>
|
checked={get_value(CHARGE_LIMIT_BATT) != null}
|
||||||
{get_value(CURRENT_BATT)} mA
|
label={tr("Charge Limit")}
|
||||||
</Field>
|
description={tr("Limit battery charge when awake")}
|
||||||
</PanelSectionRow>
|
onChange={(value: boolean) => {
|
||||||
|
if (value) {
|
||||||
|
set_value(CHARGE_LIMIT_BATT, (get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_limit!.max);
|
||||||
|
reloadGUI("BATTChargeLimitToggle");
|
||||||
|
} else {
|
||||||
|
set_value(CHARGE_LIMIT_BATT, null);
|
||||||
|
backend.resolve(backend.unsetBatteryChargeLimit(), (_: any[]) => {
|
||||||
|
reloadGUI("BATTUnsetChargeRate");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{ get_value(CHARGE_LIMIT_BATT) != null && <SliderField
|
||||||
|
label={tr("Maximum (%)")}
|
||||||
|
value={get_value(CHARGE_LIMIT_BATT)}
|
||||||
|
max={(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_limit!.max}
|
||||||
|
min={(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_limit!.min}
|
||||||
|
step={(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_limit_step}
|
||||||
|
showValue={true}
|
||||||
|
disabled={get_value(CHARGE_LIMIT_BATT) == null}
|
||||||
|
onChange={(val: number) => {
|
||||||
|
backend.log(backend.LogLevel.Debug, "Charge limit is now " + val.toString());
|
||||||
|
const rateNow = get_value(CHARGE_LIMIT_BATT);
|
||||||
|
if (val != rateNow) {
|
||||||
|
backend.resolve(backend.setBatteryChargeLimit(val),
|
||||||
|
(rate: number) => {
|
||||||
|
set_value(CHARGE_LIMIT_BATT, rate);
|
||||||
|
reloadGUI("BATTChargeLimit");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>}
|
||||||
|
</PanelSectionRow>}
|
||||||
</Fragment>);
|
</Fragment>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ export const LIMITS_INFO = "LIMITS_all";
|
||||||
export const CURRENT_BATT = "BATTERY_current_now";
|
export const CURRENT_BATT = "BATTERY_current_now";
|
||||||
export const CHARGE_RATE_BATT = "BATTERY_charge_rate";
|
export const CHARGE_RATE_BATT = "BATTERY_charge_rate";
|
||||||
export const CHARGE_MODE_BATT = "BATTERY_charge_mode";
|
export const CHARGE_MODE_BATT = "BATTERY_charge_mode";
|
||||||
|
export const CHARGE_LIMIT_BATT = "BATTERY_charge_limit";
|
||||||
export const CHARGE_NOW_BATT = "BATTERY_charge_now";
|
export const CHARGE_NOW_BATT = "BATTERY_charge_now";
|
||||||
export const CHARGE_FULL_BATT = "BATTERY_charge_full";
|
export const CHARGE_FULL_BATT = "BATTERY_charge_full";
|
||||||
export const CHARGE_DESIGN_BATT = "BATTERY_charge_design";
|
export const CHARGE_DESIGN_BATT = "BATTERY_charge_design";
|
||||||
|
|
|
@ -35,6 +35,7 @@ import {
|
||||||
CURRENT_BATT,
|
CURRENT_BATT,
|
||||||
CHARGE_RATE_BATT,
|
CHARGE_RATE_BATT,
|
||||||
CHARGE_MODE_BATT,
|
CHARGE_MODE_BATT,
|
||||||
|
CHARGE_LIMIT_BATT,
|
||||||
CHARGE_NOW_BATT,
|
CHARGE_NOW_BATT,
|
||||||
CHARGE_FULL_BATT,
|
CHARGE_FULL_BATT,
|
||||||
CHARGE_DESIGN_BATT,
|
CHARGE_DESIGN_BATT,
|
||||||
|
@ -108,6 +109,7 @@ const reload = function() {
|
||||||
backend.resolve(backend.getBatteryCurrent(), (rate: number) => { set_value(CURRENT_BATT, rate) });
|
backend.resolve(backend.getBatteryCurrent(), (rate: number) => { set_value(CURRENT_BATT, rate) });
|
||||||
backend.resolve_nullable(backend.getBatteryChargeRate(), (rate: number | null) => { set_value(CHARGE_RATE_BATT, rate) });
|
backend.resolve_nullable(backend.getBatteryChargeRate(), (rate: number | null) => { set_value(CHARGE_RATE_BATT, rate) });
|
||||||
backend.resolve_nullable(backend.getBatteryChargeMode(), (mode: string | null) => { set_value(CHARGE_MODE_BATT, mode) });
|
backend.resolve_nullable(backend.getBatteryChargeMode(), (mode: string | null) => { set_value(CHARGE_MODE_BATT, mode) });
|
||||||
|
backend.resolve_nullable(backend.getBatteryChargeLimit(), (limit: number | null) => { set_value(CHARGE_LIMIT_BATT, limit) });
|
||||||
backend.resolve(backend.getBatteryChargeNow(), (rate: number) => { set_value(CHARGE_NOW_BATT, rate) });
|
backend.resolve(backend.getBatteryChargeNow(), (rate: number) => { set_value(CHARGE_NOW_BATT, rate) });
|
||||||
backend.resolve(backend.getBatteryChargeFull(), (rate: number) => { set_value(CHARGE_FULL_BATT, rate) });
|
backend.resolve(backend.getBatteryChargeFull(), (rate: number) => { set_value(CHARGE_FULL_BATT, rate) });
|
||||||
backend.resolve(backend.getBatteryChargeDesign(), (rate: number) => { set_value(CHARGE_DESIGN_BATT, rate) });
|
backend.resolve(backend.getBatteryChargeDesign(), (rate: number) => { set_value(CHARGE_DESIGN_BATT, rate) });
|
||||||
|
@ -175,7 +177,7 @@ const reload = function() {
|
||||||
let gameInfo: any = appStore.GetAppOverviewByGameID(id);
|
let gameInfo: any = appStore.GetAppOverviewByGameID(id);
|
||||||
// don't use gameInfo.appid, haha
|
// don't use gameInfo.appid, haha
|
||||||
backend.resolve(
|
backend.resolve(
|
||||||
backend.loadGeneralSettings(id.toString() + ".json", gameInfo.display_name),
|
backend.loadGeneralSettings(id, gameInfo.display_name),
|
||||||
(ok: boolean) => {backend.log(backend.LogLevel.Debug, "Loading settings ok? " + ok)}
|
(ok: boolean) => {backend.log(backend.LogLevel.Debug, "Loading settings ok? " + ok)}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -83,7 +83,7 @@ msgstr "Maximum (mA)"
|
||||||
# (Battery charge mode override toggle)
|
# (Battery charge mode override toggle)
|
||||||
#: components/battery.tsx:97,115
|
#: components/battery.tsx:97,115
|
||||||
msgid "Charge Mode"
|
msgid "Charge Mode"
|
||||||
msgstr "Mode de Charge"
|
msgstr "Mode de charge"
|
||||||
|
|
||||||
# (Battery charge mode override toggle description)
|
# (Battery charge mode override toggle description)
|
||||||
#: components/battery.tsx:98
|
#: components/battery.tsx:98
|
||||||
|
@ -100,6 +100,21 @@ msgstr "Mode"
|
||||||
msgid "Current"
|
msgid "Current"
|
||||||
msgstr "Courant"
|
msgstr "Courant"
|
||||||
|
|
||||||
|
#: components/battery.tsx:141
|
||||||
|
# (Battery charging maximum)
|
||||||
|
msgid "Charge Limit"
|
||||||
|
msgstr "Limite de charge"
|
||||||
|
|
||||||
|
#: components/battery.tsx:142
|
||||||
|
# (Battery charging maximum description)
|
||||||
|
msgid "Limit battery charge when awake"
|
||||||
|
msgstr "Limiter la charge de la batterie quand éveillé"
|
||||||
|
|
||||||
|
#: components/battery.tsx:156
|
||||||
|
# (Battery charging maximum slider)
|
||||||
|
msgid "Maximum (%)"
|
||||||
|
msgstr "Maximum (%)"
|
||||||
|
|
||||||
# -- components/cpus.tsx --
|
# -- components/cpus.tsx --
|
||||||
# (CPU section title)
|
# (CPU section title)
|
||||||
#: components/cpus.tsx:64
|
#: components/cpus.tsx:64
|
||||||
|
|
|
@ -99,6 +99,21 @@ msgstr ""
|
||||||
msgid "Current"
|
msgid "Current"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: components/battery.tsx:141
|
||||||
|
# (Battery charging maximum)
|
||||||
|
msgid "Charge Limit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: components/battery.tsx:142
|
||||||
|
# (Battery charging maximum description)
|
||||||
|
msgid "Limit battery charge when awake"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: components/battery.tsx:156
|
||||||
|
# (Battery charging maximum slider)
|
||||||
|
msgid "Maximum (%)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
# -- components/cpus.tsx --
|
# -- components/cpus.tsx --
|
||||||
|
|
||||||
#: components/cpus.tsx:64
|
#: components/cpus.tsx:64
|
||||||
|
|
Loading…
Reference in a new issue