From 2b2a6eaf9df41f4000606200d9410d7e58d2e5b4 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Mon, 21 Nov 2022 20:58:35 -0500 Subject: [PATCH] Add charge mode setting for SD, move static battery readings into driver --- backend/src/api/battery.rs | 92 +++++++++++++++++++--- backend/src/api/handler.rs | 8 ++ backend/src/main.rs | 8 +- backend/src/settings/driver.rs | 39 +-------- backend/src/settings/steam_deck/battery.rs | 42 +++++++++- backend/src/settings/traits.rs | 8 ++ backend/src/settings/unknown/battery.rs | 8 ++ src/backend.ts | 6 +- src/index.tsx | 46 ++++++++++- 9 files changed, 201 insertions(+), 56 deletions(-) diff --git a/backend/src/api/battery.rs b/backend/src/api/battery.rs index b2bbe87..e7c4638 100644 --- a/backend/src/api/battery.rs +++ b/backend/src/api/battery.rs @@ -1,27 +1,101 @@ use std::sync::mpsc::{Sender, self}; -use std::sync::Mutex; +use std::sync::{Arc, Mutex}; use usdpl_back::core::serdes::Primitive; +use usdpl_back::AsyncCallable; use super::handler::{ApiMessage, BatteryMessage}; /// Current current (ha!) web method -pub fn current_now(_: super::ApiParameterType) -> super::ApiParameterType { - super::utility::map_optional_result(crate::settings::driver::read_current_now()) +pub fn current_now( + sender: Sender, +) -> 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| tx.send(val).expect("current_now callback send failed"); + sender2.lock().unwrap().send(ApiMessage::Battery(BatteryMessage::ReadCurrentNow(Box::new(callback)))).expect("current_now send failed"); + rx.recv().expect("current_now callback recv failed") + } + }; + super::async_utils::AsyncIshGetter { + set_get: getter, + trans_getter: |result| { + super::utility::map_optional_result(Ok(result)) + } + } } +/// Current current (ha!) web method +/*pub fn current_now(_: super::ApiParameterType) -> super::ApiParameterType { + super::utility::map_optional_result(crate::settings::driver::read_current_now()) +}*/ + /// Charge now web method -pub fn charge_now(_: super::ApiParameterType) -> super::ApiParameterType { - super::utility::map_optional_result(crate::settings::driver::read_charge_now()) +pub fn charge_now( + sender: Sender, +) -> 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| tx.send(val).expect("charge_now callback send failed"); + sender2.lock().unwrap().send(ApiMessage::Battery(BatteryMessage::ReadChargeNow(Box::new(callback)))).expect("charge_now send failed"); + rx.recv().expect("charge_now callback recv failed") + } + }; + super::async_utils::AsyncIshGetter { + set_get: getter, + trans_getter: |result| { + super::utility::map_optional_result(Ok(result)) + } + } } /// Charge full web method -pub fn charge_full(_: super::ApiParameterType) -> super::ApiParameterType { - super::utility::map_optional_result(crate::settings::driver::read_charge_full()) +pub fn charge_full( + sender: Sender, +) -> 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| tx.send(val).expect("charge_full callback send failed"); + sender2.lock().unwrap().send(ApiMessage::Battery(BatteryMessage::ReadChargeFull(Box::new(callback)))).expect("charge_full send failed"); + rx.recv().expect("charge_full callback recv failed") + } + }; + super::async_utils::AsyncIshGetter { + set_get: getter, + trans_getter: |result| { + super::utility::map_optional_result(Ok(result)) + } + } } /// Charge design web method -pub fn charge_design(_: super::ApiParameterType) -> super::ApiParameterType { - super::utility::map_optional_result(crate::settings::driver::read_charge_design()) +pub fn charge_design( + sender: Sender, +) -> 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| tx.send(val).expect("charge_design callback send failed"); + sender2.lock().unwrap().send(ApiMessage::Battery(BatteryMessage::ReadChargeDesign(Box::new(callback)))).expect("charge_design send failed"); + rx.recv().expect("charge_design callback recv failed") + } + }; + super::async_utils::AsyncIshGetter { + set_get: getter, + trans_getter: |result| { + super::utility::map_optional_result(Ok(result)) + } + } } /// Generate set battery charge rate web method diff --git a/backend/src/api/handler.rs b/backend/src/api/handler.rs index c930ec7..49067ba 100644 --- a/backend/src/api/handler.rs +++ b/backend/src/api/handler.rs @@ -24,6 +24,10 @@ pub enum BatteryMessage { GetChargeRate(Callback>), SetChargeMode(Option), GetChargeMode(Callback>), + ReadChargeFull(Callback>), + ReadChargeNow(Callback>), + ReadChargeDesign(Callback>), + ReadCurrentNow(Callback>), } impl BatteryMessage { @@ -33,6 +37,10 @@ impl BatteryMessage { Self::GetChargeRate(cb) => cb(settings.get_charge_rate()), Self::SetChargeMode(mode) => settings.charge_mode(mode), Self::GetChargeMode(cb) => cb(settings.get_charge_mode()), + Self::ReadChargeFull(cb) => cb(settings.read_charge_full()), + Self::ReadChargeNow(cb) => cb(settings.read_charge_now()), + Self::ReadChargeDesign(cb) => cb(settings.read_charge_design()), + Self::ReadCurrentNow(cb) => cb(settings.read_current_now()), } } } diff --git a/backend/src/main.rs b/backend/src/main.rs index c3e07a8..b0fed4b 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -66,10 +66,10 @@ fn main() -> Result<(), ()> { vec![format!("{} v{}", PACKAGE_NAME, PACKAGE_VERSION).into()] }) // battery API functions - .register("BATTERY_current_now", api::battery::current_now) - .register("BATTERY_charge_now", api::battery::charge_now) - .register("BATTERY_charge_full", api::battery::charge_full) - .register("BATTERY_charge_design", api::battery::charge_design) + .register_async("BATTERY_current_now", api::battery::current_now(api_sender.clone())) + .register_async("BATTERY_charge_now", api::battery::charge_now(api_sender.clone())) + .register_async("BATTERY_charge_full", api::battery::charge_full(api_sender.clone())) + .register_async("BATTERY_charge_design", api::battery::charge_design(api_sender.clone())) .register( "BATTERY_set_charge_rate", api::battery::set_charge_rate(api_sender.clone()), diff --git a/backend/src/settings/driver.rs b/backend/src/settings/driver.rs index 654d41f..7f8b160 100644 --- a/backend/src/settings/driver.rs +++ b/backend/src/settings/driver.rs @@ -142,44 +142,7 @@ impl Driver { } } -// static battery calls - -#[inline] -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::Battery::read_current_now().map(|x| Some(x)), - DriverJson::Unknown => Ok(None), - } -} - -#[inline] -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::Battery::read_charge_now().map(|x| Some(x)), - DriverJson::Unknown => Ok(None), - } -} - -#[inline] -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::Battery::read_charge_full().map(|x| Some(x)), - DriverJson::Unknown => Ok(None), - } -} - -#[inline] -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::Battery::read_charge_design().map(|x| Some(x)), - DriverJson::Unknown => Ok(None), - } -} - +// sshhhh, this function isn't here ;) #[inline] pub fn maybe_do_button() { match auto_detect() { diff --git a/backend/src/settings/steam_deck/battery.rs b/backend/src/settings/steam_deck/battery.rs index ca93a2f..8cee15e 100644 --- a/backend/src/settings/steam_deck/battery.rs +++ b/backend/src/settings/steam_deck/battery.rs @@ -242,7 +242,7 @@ impl TBattery for Battery { max: max.charge_rate.unwrap(), }), charge_current_step: 50, - charge_modes: vec!["discharge".to_owned(), "idle".to_owned(), "normal".to_owned()], + charge_modes: vec!["normal".to_owned(), "discharge".to_owned(), "idle".to_owned()], } } @@ -265,4 +265,44 @@ impl TBattery for Battery { fn get_charge_mode(&self) -> Option { self.charge_mode.map(Self::charge_mode_to_str) } + + fn read_charge_full(&self) -> Option { + match Self::read_charge_full() { + Ok(x) => Some(x), + Err(e) => { + log::warn!("read_charge_full err: {}", e.msg); + None + } + } + } + + fn read_charge_now(&self) -> Option { + match Self::read_charge_now() { + Ok(x) => Some(x), + Err(e) => { + log::warn!("read_charge_now err: {}", e.msg); + None + } + } + } + + fn read_charge_design(&self) -> Option { + match Self::read_charge_design() { + Ok(x) => Some(x), + Err(e) => { + log::warn!("read_charge_design err: {}", e.msg); + None + } + } + } + + fn read_current_now(&self) -> Option { + match Self::read_current_now() { + Ok(x) => Some(x as f64), + Err(e) => { + log::warn!("read_current_now err: {}", e.msg); + None + } + } + } } diff --git a/backend/src/settings/traits.rs b/backend/src/settings/traits.rs index b6087f7..dd0b433 100644 --- a/backend/src/settings/traits.rs +++ b/backend/src/settings/traits.rs @@ -83,4 +83,12 @@ pub trait TBattery: OnResume + OnSet + Debug + Send { fn charge_mode(&mut self, mode: Option); fn get_charge_mode(&self) -> Option; + + fn read_charge_full(&self) -> Option; + + fn read_charge_now(&self) -> Option; + + fn read_charge_design(&self) -> Option; + + fn read_current_now(&self) -> Option; } diff --git a/backend/src/settings/unknown/battery.rs b/backend/src/settings/unknown/battery.rs index 967a098..e7edb11 100644 --- a/backend/src/settings/unknown/battery.rs +++ b/backend/src/settings/unknown/battery.rs @@ -55,4 +55,12 @@ impl TBattery for Battery { fn get_charge_mode(&self) -> Option { None } + + fn read_charge_full(&self) -> Option { None } + + fn read_charge_now(&self) -> Option { None } + + fn read_charge_design(&self) -> Option { None } + + fn read_current_now(&self) -> Option { None } } diff --git a/src/backend.ts b/src/backend.ts index 1f626cb..d736630 100644 --- a/src/backend.ts +++ b/src/backend.ts @@ -41,7 +41,7 @@ export type SettingsLimits = { export type BatteryLimits = { charge_current: RangeLimit | null; charge_current_step: number; - charge_modes: number; + charge_modes: string[]; }; export type CpuLimits = { @@ -105,11 +105,11 @@ export async function unsetBatteryChargeRate(): Promise { return await call_backend("BATTERY_unset_charge_rate", []); } -export async function getBatteryChargeMode(): Promise { +export async function getBatteryChargeMode(): Promise { return (await call_backend("BATTERY_get_charge_mode", []))[0]; } -export async function setBatteryChargeMode(val: number): Promise { +export async function setBatteryChargeMode(val: string): Promise { return (await call_backend("BATTERY_set_charge_mode", [val]))[0]; } diff --git a/src/index.tsx b/src/index.tsx index 88e0062..0391718 100755 --- a/src/index.tsx +++ b/src/index.tsx @@ -51,6 +51,7 @@ const LIMITS_INFO = "LIMITS_all"; const CURRENT_BATT = "BATTERY_current_now"; const CHARGE_RATE_BATT = "BATTERY_charge_rate"; +const CHARGE_MODE_BATT = "BATTERY_charge_mode"; const CHARGE_NOW_BATT = "BATTERY_charge_now"; const CHARGE_FULL_BATT = "BATTERY_charge_full"; const CHARGE_DESIGN_BATT = "BATTERY_charge_design" @@ -107,6 +108,7 @@ const reload = function() { backend.resolve(backend.getBatteryCurrent(), (rate: number) => { set_value(CURRENT_BATT, rate) }); backend.resolve(backend.getBatteryChargeRate(), (rate: number) => { set_value(CHARGE_RATE_BATT, rate) }); + backend.resolve(backend.getBatteryChargeMode(), (mode: string) => { set_value(CHARGE_MODE_BATT, mode) }); 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.getBatteryChargeDesign(), (rate: number) => { set_value(CHARGE_DESIGN_BATT, rate) }); @@ -218,6 +220,11 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => { label: {elem}, };}); + const chargeModeOptions: SingleDropdownOption[] = (get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_modes.map((elem) => {return { + data: elem, + label: {elem}, + };}); + return ( {/* CPU */} @@ -494,7 +501,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => { }} />} } - {advancedMode && (get_value(LIMITS_INFO) as backend.SettingsLimits).cpu.cpus[advancedCpuIndex].governors.length != 0 && + {advancedMode && governorOptions.length != 0 && @@ -739,6 +746,43 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => { }} />} } + {chargeModeOptions.length != 0 && + { + if (value) { + set_value(CHARGE_MODE_BATT, chargeModeOptions[0].data as string); + reloadGUI("BATTChargeModeToggle"); + } else { + set_value(CHARGE_MODE_BATT, null); + backend.resolve(backend.unsetBatteryChargeMode(), (_: any[]) => { + reloadGUI("BATTUnsetChargeMode"); + }); + } + }} + /> + {get_value(CHARGE_MODE_BATT) != null && + { + return val.data == get_value(CHARGE_MODE_BATT); + })} + strDefaultLabel={get_value(CHARGE_MODE_BATT)} + onChange={(elem: SingleDropdownOption) => { + console.debug("Charge mode dropdown selected", elem); + backend.resolve(backend.setBatteryChargeMode(elem.data as string), (mode: string) => { + set_value(CHARGE_MODE_BATT, mode); + reloadGUI("BATTChargeMode"); + }); + }} + /> + } + }