Add battery charge mode back-end support (untested)

This commit is contained in:
NGnius (Graham) 2022-11-21 17:00:43 -05:00
parent 31c72de11e
commit 1466c4647b
18 changed files with 319 additions and 244 deletions

View file

@ -16,8 +16,9 @@ pub struct SettingsLimits {
#[derive(Serialize, Deserialize)]
pub struct BatteryLimits {
pub charge_rate: Option<RangeLimit<u64>>,
pub charge_step: u64,
pub charge_current: Option<RangeLimit<u64>>,
pub charge_current_step: u64,
pub charge_modes: Vec<String>,
}
#[derive(Serialize, Deserialize)]

View file

@ -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<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()]
}
}

View file

@ -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()]
}

View file

@ -22,6 +22,8 @@ pub enum ApiMessage {
pub enum BatteryMessage {
SetChargeRate(Option<u64>),
GetChargeRate(Callback<Option<u64>>),
SetChargeMode(Option<String>),
GetChargeMode(Callback<Option<String>>),
}
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()),
}
}
}

View file

@ -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);

View file

@ -6,10 +6,14 @@ use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct BatteryJson {
pub charge_rate: Option<u64>,
pub charge_mode: Option<String>,
}
impl Default for BatteryJson {
fn default() -> Self {
Self { charge_rate: None }
Self {
charge_rate: None,
charge_mode: None,
}
}
}

View file

@ -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<Option<u64>, 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<Option<u64>, SettingError> {
pub fn read_charge_now() -> Result<Option<f64>, 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<Option<f64>, SettingError> {
pub fn read_charge_full() -> Result<Option<f64>, 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<Option<f64>, SettingError> {
pub fn read_charge_design() -> Result<Option<f64>, 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"),
}
}

View file

@ -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<u64>,
pub charge_mode: Option<ChargeMode>,
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<ChargeMode> {
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<BatteryJson> 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<u64> {
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)
}
}

View file

@ -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;

View 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,
}

View file

@ -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
}
}

View file

@ -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;

View file

@ -79,4 +79,8 @@ pub trait TBattery: OnResume + OnSet + Debug + Send {
fn charge_rate(&mut self, rate: Option<u64>);
fn get_charge_rate(&self) -> Option<u64>;
fn charge_mode(&mut self, mode: Option<String>);
fn get_charge_mode(&self) -> Option<String>;
}

View file

@ -12,6 +12,7 @@ impl Into<BatteryJson> 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<u64> {
None
}
fn charge_mode(&mut self, _rate: Option<String>) {
}
fn get_charge_mode(&self) -> Option<String> {
None
}
}

View file

@ -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,
}
}
}

View file

@ -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)

View file

@ -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<any[]> {
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
export async function setCpuSmt(status: boolean): Promise<boolean> {
@ -213,3 +226,7 @@ export async function waitForComplete(): Promise<boolean> {
export async function getLimits(): Promise<SettingsLimits> {
return (await call_backend("GENERAL_get_limits", []))[0];
}
export async function idk(): Promise<boolean> {
return (await call_backend("GENERAL_idk", []))[0];
}

View file

@ -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)}%)
</Field>
</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
checked={get_value(CHARGE_RATE_BATT) != null}
label="Charge Current Limits"
@ -721,9 +721,9 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
{ get_value(CHARGE_RATE_BATT) != null && <SliderField
label="Maximum (mA)"
value={get_value(CHARGE_RATE_BATT)}
max={(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_rate!.max}
min={(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_rate!.min}
step={(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_step}
max={(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_current!.max}
min={(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_current!.min}
step={(get_value(LIMITS_INFO) as backend.SettingsLimits).battery.charge_current_step}
showValue={true}
disabled={get_value(CHARGE_RATE_BATT) == null}
onChange={(val: number) => {
@ -812,6 +812,16 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
v{version_usdpl()}
</Field>
</PanelSectionRow>
{eggCount % 10 == 9 && <PanelSectionRow>
<ButtonItem
layout="below"
onClick={(_: MouseEvent) => {
backend.idk();
}}
>
???
</ButtonItem>
</PanelSectionRow>}
<PanelSectionRow>
<ButtonItem
layout="below"