forked from NG-SD-Plugins/PowerTools
Add battery charge mode back-end support (untested)
This commit is contained in:
parent
31c72de11e
commit
1466c4647b
18 changed files with 319 additions and 244 deletions
|
@ -16,8 +16,9 @@ pub struct SettingsLimits {
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct BatteryLimits {
|
pub struct BatteryLimits {
|
||||||
pub charge_rate: Option<RangeLimit<u64>>,
|
pub charge_current: Option<RangeLimit<u64>>,
|
||||||
pub charge_step: u64,
|
pub charge_current_step: u64,
|
||||||
|
pub charge_modes: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
|
|
@ -71,3 +71,51 @@ pub fn unset_charge_rate(
|
||||||
vec![true.into()]
|
vec![true.into()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate set battery charge mode web method
|
||||||
|
pub fn set_charge_mode(
|
||||||
|
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 |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<ApiMessage>,
|
||||||
|
) -> 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<String>| 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<ApiMessage>,
|
||||||
|
) -> 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()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -177,3 +177,12 @@ pub fn get_limits(
|
||||||
vec![Primitive::Json(serde_json::to_string(&getter()).unwrap())]
|
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()]
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ pub enum ApiMessage {
|
||||||
pub enum BatteryMessage {
|
pub enum BatteryMessage {
|
||||||
SetChargeRate(Option<u64>),
|
SetChargeRate(Option<u64>),
|
||||||
GetChargeRate(Callback<Option<u64>>),
|
GetChargeRate(Callback<Option<u64>>),
|
||||||
|
SetChargeMode(Option<String>),
|
||||||
|
GetChargeMode(Callback<Option<String>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BatteryMessage {
|
impl BatteryMessage {
|
||||||
|
@ -29,6 +31,8 @@ impl BatteryMessage {
|
||||||
match self {
|
match self {
|
||||||
Self::SetChargeRate(rate) => settings.charge_rate(rate),
|
Self::SetChargeRate(rate) => settings.charge_rate(rate),
|
||||||
Self::GetChargeRate(cb) => cb(settings.get_charge_rate()),
|
Self::GetChargeRate(cb) => cb(settings.get_charge_rate()),
|
||||||
|
Self::SetChargeMode(mode) => settings.charge_mode(mode),
|
||||||
|
Self::GetChargeMode(cb) => cb(settings.get_charge_mode()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,18 @@ fn main() -> Result<(), ()> {
|
||||||
"BATTERY_unset_charge_rate",
|
"BATTERY_unset_charge_rate",
|
||||||
api::battery::unset_charge_rate(api_sender.clone()),
|
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
|
// cpu API functions
|
||||||
.register("CPU_count", api::cpu::max_cpus)
|
.register("CPU_count", api::cpu::max_cpus)
|
||||||
.register(
|
.register(
|
||||||
|
@ -186,10 +198,11 @@ fn main() -> Result<(), ()> {
|
||||||
"GENERAL_wait_for_unlocks",
|
"GENERAL_wait_for_unlocks",
|
||||||
api::general::lock_unlock_all(api_sender.clone())
|
api::general::lock_unlock_all(api_sender.clone())
|
||||||
)
|
)
|
||||||
.register(
|
.register_blocking(
|
||||||
"GENERAL_get_limits",
|
"GENERAL_get_limits",
|
||||||
api::general::get_limits(api_sender.clone())
|
api::general::get_limits(api_sender.clone())
|
||||||
);
|
)
|
||||||
|
.register("GENERAL_idk", api::general::gunter);
|
||||||
|
|
||||||
api_worker::spawn(loaded_settings, api_handler);
|
api_worker::spawn(loaded_settings, api_handler);
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,14 @@ use serde::{Deserialize, Serialize};
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct BatteryJson {
|
pub struct BatteryJson {
|
||||||
pub charge_rate: Option<u64>,
|
pub charge_rate: Option<u64>,
|
||||||
|
pub charge_mode: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for BatteryJson {
|
impl Default for BatteryJson {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self { charge_rate: None }
|
Self {
|
||||||
|
charge_rate: None,
|
||||||
|
charge_mode: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@ fn auto_detect() -> DriverJson {
|
||||||
log::debug!("Read from /etc/os-release:\n{}", os_info);
|
log::debug!("Read from /etc/os-release:\n{}", os_info);
|
||||||
if let Some(_) = lscpu.find("model name\t: AMD Custom APU 0405\n") {
|
if let Some(_) = lscpu.find("model name\t: AMD Custom APU 0405\n") {
|
||||||
// definitely a Steam Deck, check if it's overclocked
|
// 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") {
|
let max_freq: u64 = match usdpl_back::api::files::read_single("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq") {
|
||||||
Ok(u) => u,
|
Ok(u) => u,
|
||||||
Err(_) => return DriverJson::SteamDeck,
|
Err(_) => return DriverJson::SteamDeck,
|
||||||
|
@ -84,7 +86,7 @@ impl Driver {
|
||||||
}),
|
}),
|
||||||
cpus: Box::new(super::steam_deck_adv::Cpus::from_json(settings.cpus, settings.version)),
|
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)),
|
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 {
|
DriverJson::Unknown => Ok(Self {
|
||||||
general: Box::new(General {
|
general: Box::new(General {
|
||||||
|
@ -123,7 +125,7 @@ impl Driver {
|
||||||
}),
|
}),
|
||||||
cpus: Box::new(super::steam_deck_adv::Cpus::system_default()),
|
cpus: Box::new(super::steam_deck_adv::Cpus::system_default()),
|
||||||
gpu: Box::new(super::steam_deck_adv::Gpu::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 {
|
DriverJson::Unknown => Self {
|
||||||
general: Box::new(General {
|
general: Box::new(General {
|
||||||
|
@ -146,7 +148,7 @@ impl Driver {
|
||||||
pub fn read_current_now() -> Result<Option<u64>, SettingError> {
|
pub fn read_current_now() -> Result<Option<u64>, SettingError> {
|
||||||
match auto_detect() {
|
match auto_detect() {
|
||||||
DriverJson::SteamDeck => super::steam_deck::Battery::read_current_now().map(|x| Some(x)),
|
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),
|
DriverJson::Unknown => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,7 +157,7 @@ pub fn read_current_now() -> Result<Option<u64>, SettingError> {
|
||||||
pub fn read_charge_now() -> Result<Option<f64>, SettingError> {
|
pub fn read_charge_now() -> Result<Option<f64>, SettingError> {
|
||||||
match auto_detect() {
|
match auto_detect() {
|
||||||
DriverJson::SteamDeck => super::steam_deck::Battery::read_charge_now().map(|x| Some(x)),
|
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),
|
DriverJson::Unknown => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,7 +166,7 @@ pub fn read_charge_now() -> Result<Option<f64>, SettingError> {
|
||||||
pub fn read_charge_full() -> Result<Option<f64>, SettingError> {
|
pub fn read_charge_full() -> Result<Option<f64>, SettingError> {
|
||||||
match auto_detect() {
|
match auto_detect() {
|
||||||
DriverJson::SteamDeck => super::steam_deck::Battery::read_charge_full().map(|x| Some(x)),
|
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),
|
DriverJson::Unknown => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,7 +175,27 @@ pub fn read_charge_full() -> Result<Option<f64>, SettingError> {
|
||||||
pub fn read_charge_design() -> Result<Option<f64>, SettingError> {
|
pub fn read_charge_design() -> Result<Option<f64>, SettingError> {
|
||||||
match auto_detect() {
|
match auto_detect() {
|
||||||
DriverJson::SteamDeck => super::steam_deck::Battery::read_charge_design().map(|x| Some(x)),
|
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),
|
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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,10 +4,12 @@ use crate::api::RangeLimit;
|
||||||
use crate::settings::{OnResume, OnSet, SettingError, SettingsRange};
|
use crate::settings::{OnResume, OnSet, SettingError, SettingsRange};
|
||||||
use crate::settings::TBattery;
|
use crate::settings::TBattery;
|
||||||
use crate::persist::BatteryJson;
|
use crate::persist::BatteryJson;
|
||||||
|
use super::util::ChargeMode;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Battery {
|
pub struct Battery {
|
||||||
pub charge_rate: Option<u64>,
|
pub charge_rate: Option<u64>,
|
||||||
|
pub charge_mode: Option<ChargeMode>,
|
||||||
state: crate::state::steam_deck::Battery,
|
state: crate::state::steam_deck::Battery,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,15 +27,36 @@ impl Battery {
|
||||||
match version {
|
match version {
|
||||||
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(),
|
||||||
state: crate::state::steam_deck::Battery::default(),
|
state: crate::state::steam_deck::Battery::default(),
|
||||||
},
|
},
|
||||||
_ => 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(),
|
||||||
state: crate::state::steam_deck::Battery::default(),
|
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<ChargeMode> {
|
||||||
|
match s {
|
||||||
|
"normal" => Some(ChargeMode::Normal),
|
||||||
|
"idle" => Some(ChargeMode::Idle),
|
||||||
|
"discharge" | "disacharge" => Some(ChargeMode::Discharge),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn set_all(&mut self) -> Result<(), SettingError> {
|
fn set_all(&mut self) -> Result<(), SettingError> {
|
||||||
if let Some(charge_rate) = self.charge_rate {
|
if let Some(charge_rate) = self.charge_rate {
|
||||||
self.state.charge_rate_set = true;
|
self.state.charge_rate_set = true;
|
||||||
|
@ -42,7 +65,7 @@ impl Battery {
|
||||||
msg: format!("Failed to write to `{}`: {}", BATTERY_CHARGE_RATE_PATH, e),
|
msg: format!("Failed to write to `{}`: {}", BATTERY_CHARGE_RATE_PATH, e),
|
||||||
setting: crate::settings::SettingVariant::Battery,
|
setting: crate::settings::SettingVariant::Battery,
|
||||||
},
|
},
|
||||||
)
|
)?;
|
||||||
} else if self.state.charge_rate_set {
|
} else if self.state.charge_rate_set {
|
||||||
self.state.charge_rate_set = false;
|
self.state.charge_rate_set = false;
|
||||||
usdpl_back::api::files::write_single(BATTERY_CHARGE_RATE_PATH, Self::max().charge_rate.unwrap()).map_err(
|
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),
|
msg: format!("Failed to write to `{}`: {}", BATTERY_CHARGE_RATE_PATH, e),
|
||||||
setting: crate::settings::SettingVariant::Battery,
|
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) {
|
fn clamp_all(&mut self) {
|
||||||
|
@ -144,6 +183,7 @@ impl Battery {
|
||||||
pub fn system_default() -> Self {
|
pub fn system_default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
charge_rate: None,
|
charge_rate: None,
|
||||||
|
charge_mode: None,
|
||||||
state: crate::state::steam_deck::Battery::default(),
|
state: crate::state::steam_deck::Battery::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,6 +194,7 @@ impl Into<BatteryJson> for Battery {
|
||||||
fn into(self) -> BatteryJson {
|
fn into(self) -> BatteryJson {
|
||||||
BatteryJson {
|
BatteryJson {
|
||||||
charge_rate: self.charge_rate,
|
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 {
|
fn max() -> Self {
|
||||||
Self {
|
Self {
|
||||||
charge_rate: Some(2500),
|
charge_rate: Some(2500),
|
||||||
|
charge_mode: None,
|
||||||
state: crate::state::steam_deck::Battery::default(),
|
state: crate::state::steam_deck::Battery::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,6 +226,7 @@ impl SettingsRange for Battery {
|
||||||
fn min() -> Self {
|
fn min() -> Self {
|
||||||
Self {
|
Self {
|
||||||
charge_rate: Some(250),
|
charge_rate: Some(250),
|
||||||
|
charge_mode: None,
|
||||||
state: crate::state::steam_deck::Battery::default(),
|
state: crate::state::steam_deck::Battery::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,11 +237,12 @@ impl TBattery for Battery {
|
||||||
let max = Self::max();
|
let max = Self::max();
|
||||||
let min = Self::min();
|
let min = Self::min();
|
||||||
crate::api::BatteryLimits {
|
crate::api::BatteryLimits {
|
||||||
charge_rate: Some(RangeLimit{
|
charge_current: Some(RangeLimit{
|
||||||
min: min.charge_rate.unwrap(),
|
min: min.charge_rate.unwrap(),
|
||||||
max: max.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<u64> {
|
fn get_charge_rate(&self) -> Option<u64> {
|
||||||
self.charge_rate
|
self.charge_rate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn charge_mode(&mut self, mode: Option<String>) {
|
||||||
|
self.charge_mode = mode.map(|s| Self::str_to_charge_mode(&s)).flatten()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_charge_mode(&self) -> Option<String> {
|
||||||
|
self.charge_mode.map(Self::charge_mode_to_str)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
mod battery;
|
mod battery;
|
||||||
mod cpu;
|
mod cpu;
|
||||||
mod gpu;
|
mod gpu;
|
||||||
|
mod util;
|
||||||
|
|
||||||
pub use battery::Battery;
|
pub use battery::Battery;
|
||||||
pub use cpu::{Cpu, Cpus};
|
pub use cpu::{Cpu, Cpus};
|
||||||
pub use gpu::Gpu;
|
pub use gpu::Gpu;
|
||||||
|
|
||||||
|
pub use util::set_led;
|
||||||
|
|
93
backend/src/settings/steam_deck/util.rs
Normal file
93
backend/src/settings/steam_deck/util.rs
Normal file
|
@ -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<usize, Error> {
|
||||||
|
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<u8, Error> {
|
||||||
|
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<usize, Error> {
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.open("/dev/port")?;
|
||||||
|
file.seek(SeekFrom::Start(location))?;
|
||||||
|
file.write(&[value])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_from(location: u64) -> Result<u8, Error> {
|
||||||
|
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<usize, Error> {
|
||||||
|
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<usize, Error> {
|
||||||
|
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,
|
||||||
|
}
|
|
@ -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<u64>,
|
|
||||||
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<u64, SettingError> {
|
|
||||||
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<f64, SettingError> {
|
|
||||||
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<f64, SettingError> {
|
|
||||||
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<f64, SettingError> {
|
|
||||||
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<BatteryJson> 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<u64>) {
|
|
||||||
self.charge_rate = rate;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_charge_rate(&self) -> Option<u64> {
|
|
||||||
self.charge_rate
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
mod battery;
|
//mod battery;
|
||||||
mod cpu;
|
mod cpu;
|
||||||
mod gpu;
|
mod gpu;
|
||||||
|
|
||||||
pub use battery::Battery;
|
//pub use battery::Battery;
|
||||||
pub use cpu::{Cpu, Cpus};
|
pub use cpu::{Cpu, Cpus};
|
||||||
pub use gpu::Gpu;
|
pub use gpu::Gpu;
|
||||||
|
|
|
@ -79,4 +79,8 @@ pub trait TBattery: OnResume + OnSet + Debug + Send {
|
||||||
fn charge_rate(&mut self, rate: Option<u64>);
|
fn charge_rate(&mut self, rate: Option<u64>);
|
||||||
|
|
||||||
fn get_charge_rate(&self) -> Option<u64>;
|
fn get_charge_rate(&self) -> Option<u64>;
|
||||||
|
|
||||||
|
fn charge_mode(&mut self, mode: Option<String>);
|
||||||
|
|
||||||
|
fn get_charge_mode(&self) -> Option<String>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ impl Into<BatteryJson> for Battery {
|
||||||
fn into(self) -> BatteryJson {
|
fn into(self) -> BatteryJson {
|
||||||
BatteryJson {
|
BatteryJson {
|
||||||
charge_rate: None,
|
charge_rate: None,
|
||||||
|
charge_mode: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,8 +32,9 @@ impl OnResume 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_rate: None,
|
charge_current: None,
|
||||||
charge_step: 50,
|
charge_current_step: 50,
|
||||||
|
charge_modes: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,4 +48,11 @@ impl TBattery for Battery {
|
||||||
fn get_charge_rate(&self) -> Option<u64> {
|
fn get_charge_rate(&self) -> Option<u64> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn charge_mode(&mut self, _rate: Option<String>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_charge_mode(&self) -> Option<String> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Battery {
|
pub struct Battery {
|
||||||
pub charge_rate_set: bool,
|
pub charge_rate_set: bool,
|
||||||
|
pub charge_mode_set: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
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: false,
|
||||||
|
charge_mode_set: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2
main.py
2
main.py
|
@ -11,6 +11,6 @@ class Plugin:
|
||||||
# Asyncio-compatible long-running code, executed in a task when the plugin is loaded
|
# Asyncio-compatible long-running code, executed in a task when the plugin is loaded
|
||||||
async def _main(self):
|
async def _main(self):
|
||||||
# startup
|
# startup
|
||||||
self.backend_proc = subprocess.Popen([PARENT_DIR + "/bin/backend"])
|
#self.backend_proc = subprocess.Popen([PARENT_DIR + "/bin/backend"])
|
||||||
while True:
|
while True:
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
|
@ -39,8 +39,9 @@ export type SettingsLimits = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type BatteryLimits = {
|
export type BatteryLimits = {
|
||||||
charge_rate: RangeLimit | null;
|
charge_current: RangeLimit | null;
|
||||||
charge_step: number;
|
charge_current_step: number;
|
||||||
|
charge_modes: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CpuLimits = {
|
export type CpuLimits = {
|
||||||
|
@ -104,6 +105,18 @@ export async function unsetBatteryChargeRate(): Promise<any[]> {
|
||||||
return await call_backend("BATTERY_unset_charge_rate", []);
|
return await call_backend("BATTERY_unset_charge_rate", []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getBatteryChargeMode(): Promise<number> {
|
||||||
|
return (await call_backend("BATTERY_get_charge_mode", []))[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setBatteryChargeMode(val: number): Promise<number> {
|
||||||
|
return (await call_backend("BATTERY_set_charge_mode", [val]))[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function unsetBatteryChargeMode(): Promise<any[]> {
|
||||||
|
return await call_backend("BATTERY_unset_charge_mode", []);
|
||||||
|
}
|
||||||
|
|
||||||
// CPU
|
// CPU
|
||||||
|
|
||||||
export async function setCpuSmt(status: boolean): Promise<boolean> {
|
export async function setCpuSmt(status: boolean): Promise<boolean> {
|
||||||
|
@ -213,3 +226,7 @@ export async function waitForComplete(): Promise<boolean> {
|
||||||
export async function getLimits(): Promise<SettingsLimits> {
|
export async function getLimits(): Promise<SettingsLimits> {
|
||||||
return (await call_backend("GENERAL_get_limits", []))[0];
|
return (await call_backend("GENERAL_get_limits", []))[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function idk(): Promise<boolean> {
|
||||||
|
return (await call_backend("GENERAL_idk", []))[0];
|
||||||
|
}
|
||||||
|
|
|
@ -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(CHARGE_FULL_BATT).toFixed(1)} Wh ({(100 * get_value(CHARGE_FULL_BATT) / get_value(CHARGE_DESIGN_BATT)).toFixed(1)}%)
|
||||||
</Field>
|
</Field>
|
||||||
</PanelSectionRow>}
|
</PanelSectionRow>}
|
||||||
{(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_rate != 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}
|
||||||
label="Charge Current Limits"
|
label="Charge Current Limits"
|
||||||
|
@ -721,9 +721,9 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
|
||||||
{ get_value(CHARGE_RATE_BATT) != null && <SliderField
|
{ get_value(CHARGE_RATE_BATT) != null && <SliderField
|
||||||
label="Maximum (mA)"
|
label="Maximum (mA)"
|
||||||
value={get_value(CHARGE_RATE_BATT)}
|
value={get_value(CHARGE_RATE_BATT)}
|
||||||
max={(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_rate!.max}
|
max={(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_current!.max}
|
||||||
min={(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_rate!.min}
|
min={(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_current!.min}
|
||||||
step={(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_step}
|
step={(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_current_step}
|
||||||
showValue={true}
|
showValue={true}
|
||||||
disabled={get_value(CHARGE_RATE_BATT) == null}
|
disabled={get_value(CHARGE_RATE_BATT) == null}
|
||||||
onChange={(val: number) => {
|
onChange={(val: number) => {
|
||||||
|
@ -812,6 +812,16 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
|
||||||
v{version_usdpl()}
|
v{version_usdpl()}
|
||||||
</Field>
|
</Field>
|
||||||
</PanelSectionRow>
|
</PanelSectionRow>
|
||||||
|
{eggCount % 10 == 9 && <PanelSectionRow>
|
||||||
|
<ButtonItem
|
||||||
|
layout="below"
|
||||||
|
onClick={(_: MouseEvent) => {
|
||||||
|
backend.idk();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
???
|
||||||
|
</ButtonItem>
|
||||||
|
</PanelSectionRow>}
|
||||||
<PanelSectionRow>
|
<PanelSectionRow>
|
||||||
<ButtonItem
|
<ButtonItem
|
||||||
layout="below"
|
layout="below"
|
||||||
|
|
Loading…
Reference in a new issue