From 1466c4647b1ea719506e489f3a4959997ce280e9 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Mon, 21 Nov 2022 17:00:43 -0500 Subject: [PATCH] Add battery charge mode back-end support (untested) --- backend/src/api/api_types.rs | 5 +- backend/src/api/battery.rs | 48 ++++ backend/src/api/general.rs | 9 + backend/src/api/handler.rs | 4 + backend/src/main.rs | 17 +- backend/src/persist/battery.rs | 6 +- backend/src/settings/driver.rs | 34 ++- backend/src/settings/steam_deck/battery.rs | 64 +++++- backend/src/settings/steam_deck/mod.rs | 3 + backend/src/settings/steam_deck/util.rs | 93 ++++++++ .../src/settings/steam_deck_adv/battery.rs | 216 ------------------ backend/src/settings/steam_deck_adv/mod.rs | 4 +- backend/src/settings/traits.rs | 4 + backend/src/settings/unknown/battery.rs | 13 +- backend/src/state/steam_deck/battery.rs | 2 + main.py | 2 +- src/backend.ts | 21 +- src/index.tsx | 18 +- 18 files changed, 319 insertions(+), 244 deletions(-) create mode 100644 backend/src/settings/steam_deck/util.rs delete mode 100644 backend/src/settings/steam_deck_adv/battery.rs diff --git a/backend/src/api/api_types.rs b/backend/src/api/api_types.rs index 1210ece..0be7136 100644 --- a/backend/src/api/api_types.rs +++ b/backend/src/api/api_types.rs @@ -16,8 +16,9 @@ pub struct SettingsLimits { #[derive(Serialize, Deserialize)] pub struct BatteryLimits { - pub charge_rate: Option>, - pub charge_step: u64, + pub charge_current: Option>, + pub charge_current_step: u64, + pub charge_modes: Vec, } #[derive(Serialize, Deserialize)] diff --git a/backend/src/api/battery.rs b/backend/src/api/battery.rs index caa35d4..b2bbe87 100644 --- a/backend/src/api/battery.rs +++ b/backend/src/api/battery.rs @@ -71,3 +71,51 @@ pub fn unset_charge_rate( vec![true.into()] } } + +/// Generate set battery charge mode web method +pub fn set_charge_mode( + sender: Sender, +) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType { + let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety + let setter = move |mode: String| + sender.lock() + .unwrap() + .send(ApiMessage::Battery(BatteryMessage::SetChargeMode(Some(mode)))) + .expect("set_charge_mode send failed"); + move |params_in: super::ApiParameterType| { + if let Some(Primitive::String(new_val)) = params_in.get(0) { + setter(new_val.to_owned()); + vec![new_val.to_owned().into()] + } else { + vec!["set_charge_rate missing parameter".into()] + } + } +} + +/// Generate get battery charge mode web method +pub fn get_charge_mode( + sender: Sender, +) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType { + let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety + let getter = move || { + let (tx, rx) = mpsc::channel(); + let callback = move |mode: Option| tx.send(mode).expect("get_charge_mode callback send failed"); + sender.lock().unwrap().send(ApiMessage::Battery(BatteryMessage::GetChargeMode(Box::new(callback)))).expect("get_charge_mode send failed"); + rx.recv().expect("get_charge_mode callback recv failed") + }; + move |_: super::ApiParameterType| { + vec![getter().map(|x| x.into()).unwrap_or(Primitive::Empty)] + } +} + +/// Generate unset battery charge mode web method +pub fn unset_charge_mode( + sender: Sender, +) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType { + let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety + let setter = move || sender.lock().unwrap().send(ApiMessage::Battery(BatteryMessage::SetChargeMode(None))).expect("unset_charge_mode send failed"); + move |_params_in: super::ApiParameterType| { + setter(); + vec![true.into()] + } +} diff --git a/backend/src/api/general.rs b/backend/src/api/general.rs index 9dc765f..32e040b 100644 --- a/backend/src/api/general.rs +++ b/backend/src/api/general.rs @@ -177,3 +177,12 @@ pub fn get_limits( vec![Primitive::Json(serde_json::to_string(&getter()).unwrap())] } } + +pub fn gunter(_: super::ApiParameterType) -> super::ApiParameterType { + std::thread::spawn(|| { + log::info!("Zhu Li, do the thing!"); + crate::settings::driver::maybe_do_button(); + log::info!("Thing done.") + }); + vec![true.into()] +} diff --git a/backend/src/api/handler.rs b/backend/src/api/handler.rs index aa3e683..c930ec7 100644 --- a/backend/src/api/handler.rs +++ b/backend/src/api/handler.rs @@ -22,6 +22,8 @@ pub enum ApiMessage { pub enum BatteryMessage { SetChargeRate(Option), GetChargeRate(Callback>), + SetChargeMode(Option), + GetChargeMode(Callback>), } impl BatteryMessage { @@ -29,6 +31,8 @@ impl BatteryMessage { match self { Self::SetChargeRate(rate) => settings.charge_rate(rate), Self::GetChargeRate(cb) => cb(settings.get_charge_rate()), + Self::SetChargeMode(mode) => settings.charge_mode(mode), + Self::GetChargeMode(cb) => cb(settings.get_charge_mode()), } } } diff --git a/backend/src/main.rs b/backend/src/main.rs index 884d519..c3e07a8 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -82,6 +82,18 @@ fn main() -> Result<(), ()> { "BATTERY_unset_charge_rate", api::battery::unset_charge_rate(api_sender.clone()), ) + .register( + "BATTERY_set_charge_mode", + api::battery::set_charge_mode(api_sender.clone()), + ) + .register( + "BATTERY_get_charge_mode", + api::battery::get_charge_mode(api_sender.clone()), + ) + .register( + "BATTERY_unset_charge_mode", + api::battery::unset_charge_mode(api_sender.clone()), + ) // cpu API functions .register("CPU_count", api::cpu::max_cpus) .register( @@ -186,10 +198,11 @@ fn main() -> Result<(), ()> { "GENERAL_wait_for_unlocks", api::general::lock_unlock_all(api_sender.clone()) ) - .register( + .register_blocking( "GENERAL_get_limits", api::general::get_limits(api_sender.clone()) - ); + ) + .register("GENERAL_idk", api::general::gunter); api_worker::spawn(loaded_settings, api_handler); diff --git a/backend/src/persist/battery.rs b/backend/src/persist/battery.rs index 259e327..e5c08c7 100644 --- a/backend/src/persist/battery.rs +++ b/backend/src/persist/battery.rs @@ -6,10 +6,14 @@ use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] pub struct BatteryJson { pub charge_rate: Option, + pub charge_mode: Option, } impl Default for BatteryJson { fn default() -> Self { - Self { charge_rate: None } + Self { + charge_rate: None, + charge_mode: None, + } } } diff --git a/backend/src/settings/driver.rs b/backend/src/settings/driver.rs index 921c7a7..654d41f 100644 --- a/backend/src/settings/driver.rs +++ b/backend/src/settings/driver.rs @@ -15,6 +15,8 @@ fn auto_detect() -> DriverJson { log::debug!("Read from /etc/os-release:\n{}", os_info); if let Some(_) = lscpu.find("model name\t: AMD Custom APU 0405\n") { // definitely a Steam Deck, check if it's overclocked + // TODO: this auto-detect doesn't work + // look for a file instead? let max_freq: u64 = match usdpl_back::api::files::read_single("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq") { Ok(u) => u, Err(_) => return DriverJson::SteamDeck, @@ -84,7 +86,7 @@ impl Driver { }), cpus: Box::new(super::steam_deck_adv::Cpus::from_json(settings.cpus, settings.version)), gpu: Box::new(super::steam_deck_adv::Gpu::from_json(settings.gpu, settings.version)), - battery: Box::new(super::steam_deck_adv::Battery::from_json(settings.battery, settings.version)), + battery: Box::new(super::steam_deck::Battery::from_json(settings.battery, settings.version)), }), DriverJson::Unknown => Ok(Self { general: Box::new(General { @@ -123,7 +125,7 @@ impl Driver { }), cpus: Box::new(super::steam_deck_adv::Cpus::system_default()), gpu: Box::new(super::steam_deck_adv::Gpu::system_default()), - battery: Box::new(super::steam_deck_adv::Battery::system_default()), + battery: Box::new(super::steam_deck::Battery::system_default()), }, DriverJson::Unknown => Self { general: Box::new(General { @@ -146,7 +148,7 @@ impl Driver { pub fn read_current_now() -> Result, SettingError> { match auto_detect() { DriverJson::SteamDeck => super::steam_deck::Battery::read_current_now().map(|x| Some(x)), - DriverJson::SteamDeckAdvance => super::steam_deck_adv::Battery::read_current_now().map(|x| Some(x)), + DriverJson::SteamDeckAdvance => super::steam_deck::Battery::read_current_now().map(|x| Some(x)), DriverJson::Unknown => Ok(None), } } @@ -155,7 +157,7 @@ pub fn read_current_now() -> Result, SettingError> { pub fn read_charge_now() -> Result, SettingError> { match auto_detect() { DriverJson::SteamDeck => super::steam_deck::Battery::read_charge_now().map(|x| Some(x)), - DriverJson::SteamDeckAdvance => super::steam_deck_adv::Battery::read_charge_now().map(|x| Some(x)), + DriverJson::SteamDeckAdvance => super::steam_deck::Battery::read_charge_now().map(|x| Some(x)), DriverJson::Unknown => Ok(None), } } @@ -164,7 +166,7 @@ pub fn read_charge_now() -> Result, SettingError> { pub fn read_charge_full() -> Result, SettingError> { match auto_detect() { DriverJson::SteamDeck => super::steam_deck::Battery::read_charge_full().map(|x| Some(x)), - DriverJson::SteamDeckAdvance => super::steam_deck_adv::Battery::read_charge_full().map(|x| Some(x)), + DriverJson::SteamDeckAdvance => super::steam_deck::Battery::read_charge_full().map(|x| Some(x)), DriverJson::Unknown => Ok(None), } } @@ -173,7 +175,27 @@ pub fn read_charge_full() -> Result, SettingError> { pub fn read_charge_design() -> Result, SettingError> { match auto_detect() { DriverJson::SteamDeck => super::steam_deck::Battery::read_charge_design().map(|x| Some(x)), - DriverJson::SteamDeckAdvance => super::steam_deck_adv::Battery::read_charge_design().map(|x| Some(x)), + DriverJson::SteamDeckAdvance => super::steam_deck::Battery::read_charge_design().map(|x| Some(x)), DriverJson::Unknown => Ok(None), } } + +#[inline] +pub fn maybe_do_button() { + match auto_detect() { + DriverJson::SteamDeck | DriverJson::SteamDeckAdvance => { + let period = std::time::Duration::from_millis(500); + for _ in 0..10 { + if let Err(e) = crate::settings::steam_deck::set_led(false, true, false) { + log::error!("Thing err: {}", e); + } + std::thread::sleep(period); + if let Err(e) = crate::settings::steam_deck::set_led(false, false, false) { + log::error!("Thing err: {}", e); + }; + std::thread::sleep(period); + } + }, + DriverJson::Unknown => log::warn!("Can't do button activities on unknown platform"), + } +} diff --git a/backend/src/settings/steam_deck/battery.rs b/backend/src/settings/steam_deck/battery.rs index a002bca..ca93a2f 100644 --- a/backend/src/settings/steam_deck/battery.rs +++ b/backend/src/settings/steam_deck/battery.rs @@ -4,10 +4,12 @@ use crate::api::RangeLimit; use crate::settings::{OnResume, OnSet, SettingError, SettingsRange}; use crate::settings::TBattery; use crate::persist::BatteryJson; +use super::util::ChargeMode; #[derive(Debug, Clone)] pub struct Battery { pub charge_rate: Option, + pub charge_mode: Option, state: crate::state::steam_deck::Battery, } @@ -25,15 +27,36 @@ impl Battery { match version { 0 => Self { charge_rate: other.charge_rate, + charge_mode: other.charge_mode.map(|x| Self::str_to_charge_mode(&x)).flatten(), state: crate::state::steam_deck::Battery::default(), }, _ => Self { charge_rate: other.charge_rate, + charge_mode: other.charge_mode.map(|x| Self::str_to_charge_mode(&x)).flatten(), state: crate::state::steam_deck::Battery::default(), }, } } + #[inline] + fn charge_mode_to_str(mode: ChargeMode) -> String { + match mode { + ChargeMode::Normal => "normal", + ChargeMode::Idle => "idle", + ChargeMode::Discharge => "discharge", + }.to_owned() + } + + #[inline] + fn str_to_charge_mode(s: &str) -> Option { + match s { + "normal" => Some(ChargeMode::Normal), + "idle" => Some(ChargeMode::Idle), + "discharge" | "disacharge" => Some(ChargeMode::Discharge), + _ => None, + } + } + fn set_all(&mut self) -> Result<(), SettingError> { if let Some(charge_rate) = self.charge_rate { self.state.charge_rate_set = true; @@ -42,7 +65,7 @@ impl Battery { msg: format!("Failed to write to `{}`: {}", BATTERY_CHARGE_RATE_PATH, e), setting: crate::settings::SettingVariant::Battery, }, - ) + )?; } else if self.state.charge_rate_set { self.state.charge_rate_set = false; usdpl_back::api::files::write_single(BATTERY_CHARGE_RATE_PATH, Self::max().charge_rate.unwrap()).map_err( @@ -50,10 +73,26 @@ impl Battery { msg: format!("Failed to write to `{}`: {}", BATTERY_CHARGE_RATE_PATH, e), setting: crate::settings::SettingVariant::Battery, }, - ) - } else { - Ok(()) + )?; } + 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, + }, + )?; + } 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, + }, + )?; + } + Ok(()) } fn clamp_all(&mut self) { @@ -144,6 +183,7 @@ impl Battery { pub fn system_default() -> Self { Self { charge_rate: None, + charge_mode: None, state: crate::state::steam_deck::Battery::default(), } } @@ -154,6 +194,7 @@ impl Into for Battery { fn into(self) -> BatteryJson { BatteryJson { charge_rate: self.charge_rate, + charge_mode: self.charge_mode.map(Self::charge_mode_to_str), } } } @@ -176,6 +217,7 @@ impl SettingsRange for Battery { fn max() -> Self { Self { charge_rate: Some(2500), + charge_mode: None, state: crate::state::steam_deck::Battery::default(), } } @@ -184,6 +226,7 @@ impl SettingsRange for Battery { fn min() -> Self { Self { charge_rate: Some(250), + charge_mode: None, state: crate::state::steam_deck::Battery::default(), } } @@ -194,11 +237,12 @@ impl TBattery for Battery { let max = Self::max(); let min = Self::min(); crate::api::BatteryLimits { - charge_rate: Some(RangeLimit{ + charge_current: Some(RangeLimit{ min: min.charge_rate.unwrap(), max: max.charge_rate.unwrap(), }), - charge_step: 50, + charge_current_step: 50, + charge_modes: vec!["discharge".to_owned(), "idle".to_owned(), "normal".to_owned()], } } @@ -213,4 +257,12 @@ impl TBattery for Battery { fn get_charge_rate(&self) -> Option { self.charge_rate } + + fn charge_mode(&mut self, mode: Option) { + self.charge_mode = mode.map(|s| Self::str_to_charge_mode(&s)).flatten() + } + + fn get_charge_mode(&self) -> Option { + self.charge_mode.map(Self::charge_mode_to_str) + } } diff --git a/backend/src/settings/steam_deck/mod.rs b/backend/src/settings/steam_deck/mod.rs index 2039cae..a49088e 100644 --- a/backend/src/settings/steam_deck/mod.rs +++ b/backend/src/settings/steam_deck/mod.rs @@ -1,7 +1,10 @@ mod battery; mod cpu; mod gpu; +mod util; pub use battery::Battery; pub use cpu::{Cpu, Cpus}; pub use gpu::Gpu; + +pub use util::set_led; diff --git a/backend/src/settings/steam_deck/util.rs b/backend/src/settings/steam_deck/util.rs new file mode 100644 index 0000000..a8cd99e --- /dev/null +++ b/backend/src/settings/steam_deck/util.rs @@ -0,0 +1,93 @@ +//! Rough Rust port of some BatCtrl functionality +//! I do not have access to the source code, so this is my own interpretation of what it does. +//! +//! But also Quanta is based in a place with some questionable copyright practices, so... +#![allow(dead_code)] + +use std::fs::OpenOptions; +use std::io::{Error, Seek, SeekFrom, Read, Write}; + +#[inline] +fn write2(p0: u8, p1: u8) -> Result { + write_to(0x6c, 0x81)?; + wait_ready_for_write()?; + let count0 = write_to(0x68, p0)?; + wait_ready_for_write()?; + let count1 = write_to(0x68, p1)?; + Ok(count0 + count1) +} + +fn write_read(p0: u8) -> Result { + write_to(0x6c, 0x81)?; + wait_ready_for_write()?; + write_to(0x68, p0)?; + wait_ready_for_read()?; + read_from(0x68) +} + +fn write_to(location: u64, value: u8) -> Result { + let mut file = OpenOptions::new() + .write(true) + .open("/dev/port")?; + file.seek(SeekFrom::Start(location))?; + file.write(&[value]) +} + +fn read_from(location: u64) -> Result { + let mut file = OpenOptions::new() + .read(true) + .open("/dev/port")?; + file.seek(SeekFrom::Start(location))?; + let mut buffer = [0]; + file.read(&mut buffer)?; + Ok(buffer[0]) +} + +fn wait_ready_for_write() -> Result<(), Error> { + let mut count = 0; + while count < 0x1ffff && (read_from(0x6c)? & 2) != 0 { + count += 1; + } + Ok(()) +} + +fn wait_ready_for_read() -> Result<(), Error> { + let mut count = 0; + while count < 0x1ffff && (read_from(0x6c)? & 1) == 0 { + count += 1; + } + Ok(()) +} + +pub fn set_led(red_unused: bool, green_aka_white: bool, blue_unused: bool) -> Result { + let payload: u8 = 0x80 + (red_unused as u8 & 1) + ((green_aka_white as u8 & 1) << 1) + ((blue_unused as u8 & 1) << 2); + //log::info!("Payload: {:b}", payload); + write2(Setting::LEDStatus as _, payload) +} + +pub fn set(setting: Setting, mode: u8) -> Result { + write2(setting as u8, mode) +} + +#[derive(Copy, Clone)] +#[repr(u8)] +pub enum Setting { + Charge = 0xA6, + ChargeMode = 0x76, + LEDStatus = 199, +} + +#[derive(Copy, Clone, Debug)] +#[repr(u8)] +pub enum ChargeMode { + Normal = 0, + Discharge = 0x42, + Idle = 0x45, +} + +#[derive(Copy, Clone)] +#[repr(u8)] +pub enum Charge { + Enable = 0, + Disable = 4, +} diff --git a/backend/src/settings/steam_deck_adv/battery.rs b/backend/src/settings/steam_deck_adv/battery.rs deleted file mode 100644 index a002bca..0000000 --- a/backend/src/settings/steam_deck_adv/battery.rs +++ /dev/null @@ -1,216 +0,0 @@ -use std::convert::Into; - -use crate::api::RangeLimit; -use crate::settings::{OnResume, OnSet, SettingError, SettingsRange}; -use crate::settings::TBattery; -use crate::persist::BatteryJson; - -#[derive(Debug, Clone)] -pub struct Battery { - pub charge_rate: Option, - state: crate::state::steam_deck::Battery, -} - -const BATTERY_VOLTAGE: f64 = 7.7; - -const BATTERY_CHARGE_RATE_PATH: &str = "/sys/class/hwmon/hwmon5/maximum_battery_charge_rate"; // write-only -const BATTERY_CURRENT_NOW_PATH: &str = "/sys/class/power_supply/BAT1/current_now"; // read-only -const BATTERY_CHARGE_NOW_PATH: &str = "/sys/class/hwmon/hwmon2/device/charge_now"; // read-only -const BATTERY_CHARGE_FULL_PATH: &str = "/sys/class/hwmon/hwmon2/device/charge_full"; // read-only -const BATTERY_CHARGE_DESIGN_PATH: &str = "/sys/class/hwmon/hwmon2/device/charge_full_design"; // read-only - -impl Battery { - #[inline] - pub fn from_json(other: BatteryJson, version: u64) -> Self { - match version { - 0 => Self { - charge_rate: other.charge_rate, - state: crate::state::steam_deck::Battery::default(), - }, - _ => Self { - charge_rate: other.charge_rate, - state: crate::state::steam_deck::Battery::default(), - }, - } - } - - fn set_all(&mut self) -> Result<(), SettingError> { - if let Some(charge_rate) = self.charge_rate { - self.state.charge_rate_set = true; - 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, - }, - ) - } else if self.state.charge_rate_set { - self.state.charge_rate_set = false; - usdpl_back::api::files::write_single(BATTERY_CHARGE_RATE_PATH, Self::max().charge_rate.unwrap()).map_err( - |e| SettingError { - msg: format!("Failed to write to `{}`: {}", BATTERY_CHARGE_RATE_PATH, e), - setting: crate::settings::SettingVariant::Battery, - }, - ) - } else { - Ok(()) - } - } - - fn clamp_all(&mut self) { - let min = Self::min(); - let max = Self::max(); - if let Some(charge_rate) = &mut self.charge_rate { - *charge_rate = (*charge_rate).clamp(min.charge_rate.unwrap(), max.charge_rate.unwrap()); - } - } - - pub fn read_current_now() -> Result { - match usdpl_back::api::files::read_single::<_, u64, _>(BATTERY_CURRENT_NOW_PATH) { - Err((Some(e), None)) => Err(SettingError { - msg: format!("Failed to read from `{}`: {}", BATTERY_CURRENT_NOW_PATH, e), - setting: crate::settings::SettingVariant::Battery, - }), - Err((None, Some(e))) => Err(SettingError { - msg: format!("Failed to read from `{}`: {}", BATTERY_CURRENT_NOW_PATH, e), - setting: crate::settings::SettingVariant::Battery, - }), - Err(_) => panic!( - "Invalid error while reading from `{}`", - BATTERY_CURRENT_NOW_PATH - ), - // this value is in uA, while it's set in mA - // so convert this to mA for consistency - Ok(val) => Ok(val / 1000), - } - } - - pub fn read_charge_now() -> Result { - match usdpl_back::api::files::read_single::<_, u64, _>(BATTERY_CHARGE_NOW_PATH) { - Err((Some(e), None)) => Err(SettingError { - msg: format!("Failed to read from `{}`: {}", BATTERY_CHARGE_NOW_PATH, e), - setting: crate::settings::SettingVariant::Battery, - }), - Err((None, Some(e))) => Err(SettingError { - msg: format!("Failed to read from `{}`: {}", BATTERY_CHARGE_NOW_PATH, e), - setting: crate::settings::SettingVariant::Battery, - }), - Err(_) => panic!( - "Invalid error while reading from `{}`", - BATTERY_CHARGE_NOW_PATH - ), - // convert to Wh - Ok(val) => Ok((val as f64) / 1000000.0 * BATTERY_VOLTAGE), - } - } - - pub fn read_charge_full() -> Result { - match usdpl_back::api::files::read_single::<_, u64, _>(BATTERY_CHARGE_FULL_PATH) { - Err((Some(e), None)) => Err(SettingError { - msg: format!("Failed to read from `{}`: {}", BATTERY_CHARGE_FULL_PATH, e), - setting: crate::settings::SettingVariant::Battery, - }), - Err((None, Some(e))) => Err(SettingError { - msg: format!("Failed to read from `{}`: {}", BATTERY_CHARGE_FULL_PATH, e), - setting: crate::settings::SettingVariant::Battery, - }), - Err(_) => panic!( - "Invalid error while reading from `{}`", - BATTERY_CHARGE_NOW_PATH - ), - // convert to Wh - Ok(val) => Ok((val as f64) / 1000000.0 * BATTERY_VOLTAGE), - } - } - - pub fn read_charge_design() -> Result { - match usdpl_back::api::files::read_single::<_, u64, _>(BATTERY_CHARGE_DESIGN_PATH) { - Err((Some(e), None)) => Err(SettingError { - msg: format!("Failed to read from `{}`: {}", BATTERY_CHARGE_DESIGN_PATH, e), - setting: crate::settings::SettingVariant::Battery, - }), - Err((None, Some(e))) => Err(SettingError { - msg: format!("Failed to read from `{}`: {}", BATTERY_CHARGE_DESIGN_PATH, e), - setting: crate::settings::SettingVariant::Battery, - }), - Err(_) => panic!( - "Invalid error while reading from `{}`", - BATTERY_CHARGE_NOW_PATH - ), - // convert to Wh - Ok(val) => Ok((val as f64) / 1000000.0 * BATTERY_VOLTAGE), - } - } - - pub fn system_default() -> Self { - Self { - charge_rate: None, - state: crate::state::steam_deck::Battery::default(), - } - } -} - -impl Into for Battery { - #[inline] - fn into(self) -> BatteryJson { - BatteryJson { - charge_rate: self.charge_rate, - } - } -} - -impl OnSet for Battery { - fn on_set(&mut self) -> Result<(), SettingError> { - self.clamp_all(); - self.set_all() - } -} - -impl OnResume for Battery { - fn on_resume(&self) -> Result<(), SettingError> { - self.clone().set_all() - } -} - -impl SettingsRange for Battery { - #[inline] - fn max() -> Self { - Self { - charge_rate: Some(2500), - state: crate::state::steam_deck::Battery::default(), - } - } - - #[inline] - fn min() -> Self { - Self { - charge_rate: Some(250), - state: crate::state::steam_deck::Battery::default(), - } - } -} - -impl TBattery for Battery { - fn limits(&self) -> crate::api::BatteryLimits { - let max = Self::max(); - let min = Self::min(); - crate::api::BatteryLimits { - charge_rate: Some(RangeLimit{ - min: min.charge_rate.unwrap(), - max: max.charge_rate.unwrap(), - }), - charge_step: 50, - } - } - - fn json(&self) -> crate::persist::BatteryJson { - self.clone().into() - } - - fn charge_rate(&mut self, rate: Option) { - self.charge_rate = rate; - } - - fn get_charge_rate(&self) -> Option { - self.charge_rate - } -} diff --git a/backend/src/settings/steam_deck_adv/mod.rs b/backend/src/settings/steam_deck_adv/mod.rs index 2039cae..4a6bb90 100644 --- a/backend/src/settings/steam_deck_adv/mod.rs +++ b/backend/src/settings/steam_deck_adv/mod.rs @@ -1,7 +1,7 @@ -mod battery; +//mod battery; mod cpu; mod gpu; -pub use battery::Battery; +//pub use battery::Battery; pub use cpu::{Cpu, Cpus}; pub use gpu::Gpu; diff --git a/backend/src/settings/traits.rs b/backend/src/settings/traits.rs index 8c49385..b6087f7 100644 --- a/backend/src/settings/traits.rs +++ b/backend/src/settings/traits.rs @@ -79,4 +79,8 @@ pub trait TBattery: OnResume + OnSet + Debug + Send { fn charge_rate(&mut self, rate: Option); fn get_charge_rate(&self) -> Option; + + fn charge_mode(&mut self, mode: Option); + + fn get_charge_mode(&self) -> Option; } diff --git a/backend/src/settings/unknown/battery.rs b/backend/src/settings/unknown/battery.rs index e2cca2f..967a098 100644 --- a/backend/src/settings/unknown/battery.rs +++ b/backend/src/settings/unknown/battery.rs @@ -12,6 +12,7 @@ impl Into for Battery { fn into(self) -> BatteryJson { BatteryJson { charge_rate: None, + charge_mode: None, } } } @@ -31,8 +32,9 @@ impl OnResume for Battery { impl TBattery for Battery { fn limits(&self) -> crate::api::BatteryLimits { crate::api::BatteryLimits { - charge_rate: None, - charge_step: 50, + charge_current: None, + charge_current_step: 50, + charge_modes: vec![], } } @@ -46,4 +48,11 @@ impl TBattery for Battery { fn get_charge_rate(&self) -> Option { None } + + fn charge_mode(&mut self, _rate: Option) { + } + + fn get_charge_mode(&self) -> Option { + None + } } diff --git a/backend/src/state/steam_deck/battery.rs b/backend/src/state/steam_deck/battery.rs index ab4c9f0..83826a2 100644 --- a/backend/src/state/steam_deck/battery.rs +++ b/backend/src/state/steam_deck/battery.rs @@ -1,12 +1,14 @@ #[derive(Debug, Clone)] pub struct Battery { pub charge_rate_set: bool, + pub charge_mode_set: bool, } impl std::default::Default for Battery { fn default() -> Self { Self { charge_rate_set: false, + charge_mode_set: false, } } } diff --git a/main.py b/main.py index 3e7acb9..6c1ab39 100644 --- a/main.py +++ b/main.py @@ -11,6 +11,6 @@ class Plugin: # Asyncio-compatible long-running code, executed in a task when the plugin is loaded async def _main(self): # startup - self.backend_proc = subprocess.Popen([PARENT_DIR + "/bin/backend"]) + #self.backend_proc = subprocess.Popen([PARENT_DIR + "/bin/backend"]) while True: await asyncio.sleep(1) diff --git a/src/backend.ts b/src/backend.ts index d985380..1f626cb 100644 --- a/src/backend.ts +++ b/src/backend.ts @@ -39,8 +39,9 @@ export type SettingsLimits = { }; export type BatteryLimits = { - charge_rate: RangeLimit | null; - charge_step: number; + charge_current: RangeLimit | null; + charge_current_step: number; + charge_modes: number; }; export type CpuLimits = { @@ -104,6 +105,18 @@ export async function unsetBatteryChargeRate(): Promise { return await call_backend("BATTERY_unset_charge_rate", []); } +export async function getBatteryChargeMode(): Promise { + return (await call_backend("BATTERY_get_charge_mode", []))[0]; +} + +export async function setBatteryChargeMode(val: number): Promise { + return (await call_backend("BATTERY_set_charge_mode", [val]))[0]; +} + +export async function unsetBatteryChargeMode(): Promise { + return await call_backend("BATTERY_unset_charge_mode", []); +} + // CPU export async function setCpuSmt(status: boolean): Promise { @@ -213,3 +226,7 @@ export async function waitForComplete(): Promise { export async function getLimits(): Promise { return (await call_backend("GENERAL_get_limits", []))[0]; } + +export async function idk(): Promise { + return (await call_backend("GENERAL_idk", []))[0]; +} diff --git a/src/index.tsx b/src/index.tsx index 98352c4..88e0062 100755 --- a/src/index.tsx +++ b/src/index.tsx @@ -701,7 +701,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => { {get_value(CHARGE_FULL_BATT).toFixed(1)} Wh ({(100 * get_value(CHARGE_FULL_BATT) / get_value(CHARGE_DESIGN_BATT)).toFixed(1)}%) } - {(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_rate != null && + {(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_current != null && = ({}) => { { get_value(CHARGE_RATE_BATT) != null && { @@ -812,6 +812,16 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => { v{version_usdpl()} + {eggCount % 10 == 9 && + { + backend.idk(); + }} + > + ??? + + }