Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] First iteration of OOing Battery #393

Merged
merged 2 commits into from
Aug 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions src/daemon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,15 @@ use super::graph::{Graph, Grapher};
use super::logger;
use super::logger::Interface;
use super::network::{hook, listen};
use super::power::{
get_battery_status, has_battery, read_battery_charge, read_lid_state, read_power_source,
LidState,
};
use super::power::{has_battery, read_lid_state, read_power_source, Battery, LidState};
use super::settings::{GraphType, Settings};
use super::system::{
check_available_governors, check_cpu_freq, check_cpu_temperature, check_cpu_usage,
get_battery_condition, get_highest_temp, list_cpus, parse_proc_file, read_proc_stat_file,
ProcStat,
get_highest_temp, list_cpus, parse_proc_file, read_proc_stat_file, ProcStat,
};
use super::terminal::terminal_width;
use super::Error;
use crate::display::print_turbo_status;
use crate::system::check_bat_cond;
use crate::warn_user;

#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
Expand Down Expand Up @@ -81,6 +76,7 @@ pub trait Checker {
}

pub struct Daemon {
pub battery: Battery,
pub cpus: Vec<CPU>,
pub last_proc: Vec<ProcStat>,
pub message: String,
Expand Down Expand Up @@ -200,7 +196,7 @@ impl Checker for Daemon {

// Update current states
self.charging = read_power_source()?;
self.charge = read_battery_charge()?;
self.charge = self.battery.read_charge()?;
self.lid_state = read_lid_state()?;
self.usage = calculate_average_usage(&self.cpus) * 100.0;

Expand Down Expand Up @@ -282,13 +278,14 @@ impl Checker for Daemon {
let cpus = &self.cpus.iter().map(|c| c.render()).collect::<String>();

// Prints battery percent or N/A if not
let battery_status = get_battery_status(self.charging);
let battery_status = self.battery.print_status(self.charging);

let mut battery_condition: String = "N/A".to_string();
if let Ok(check_bat_cond) = check_bat_cond() {
battery_condition = format!("Condition: {}%", get_battery_condition(check_bat_cond));
} else {
println!("Failed to get battery condition");
let battery_condition: String;
match self.battery.get_condition() {
Ok(condition) => {
battery_condition = format!("Condition: {}%", condition);
}
Err(_) => battery_condition = "Condition: N/A".to_string(),
}

format!(
Expand Down Expand Up @@ -478,6 +475,7 @@ pub fn daemon_init(settings: Settings, config: Config) -> Result<Arc<Mutex<Daemo

// Create a new Daemon
let mut daemon: Daemon = Daemon {
battery: Battery::new(),
cpus: Vec::<CPU>::new(),
last_proc: Vec::<ProcStat>::new(),
message,
Expand Down
10 changes: 6 additions & 4 deletions src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use super::display::{
print_available_governors, print_bat_cond, print_cpu_governors, print_cpu_speeds,
print_cpu_temp, print_cpus, print_freq, print_power, print_turbo,
};
use super::power::{read_battery_charge, read_lid_state, read_power_source};
use super::power::{read_lid_state, read_power_source, Battery};
use super::settings::Settings;
use super::system::{
check_available_governors, check_bat_cond, check_cpu_freq, check_cpu_name, check_turbo_enabled,
check_available_governors, check_cpu_freq, check_cpu_name, check_turbo_enabled,
get_cpu_percent, list_cpu_governors, list_cpu_speeds, list_cpu_temp, list_cpus,
};
use super::thermal::read_thermal_zones;
Expand Down Expand Up @@ -35,6 +35,7 @@ impl Getter for Get {
}

fn power(&self, raw: bool) {
let mut battery = Battery::new();
let plugged = match read_power_source() {
Ok(plugged) => plugged,
Err(_) => {
Expand All @@ -43,7 +44,7 @@ impl Getter for Get {
}
};

let bat = match read_battery_charge() {
let bat = match battery.read_charge() {
Ok(bat) => bat,
Err(_) => {
eprintln!("Failed to get read battery charger");
Expand Down Expand Up @@ -124,7 +125,8 @@ impl Getter for Get {
}

fn bat_cond(&self, raw: bool) {
match check_bat_cond() {
let mut battery = Battery::new();
match battery.get_condition() {
Ok(bat_cond) => print_bat_cond(bat_cond, raw),
Err(_) => println!("Failed to get battery condition"),
}
Expand Down
186 changes: 143 additions & 43 deletions src/power.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,49 +91,6 @@ pub fn read_lid_state() -> Result<LidState, Error> {
Ok(state)
}

pub fn get_battery_status(charging: bool) -> String {
if has_battery() {
match read_battery_charge() {
Ok(bat) => {
format!(
"Battery: {}",
if charging {
format!("{}%", bat).green()
} else {
format!("{}%", bat).red()
},
)
}
Err(e) => format!("Battery charge could not be read\n{:?}", e),
}
} else {
format!("Battery: {}", "N/A".bold())
}
}

pub fn read_battery_charge() -> Result<i8, Error> {
let path: &str = match get_best_path(BATTERY_CHARGE_PATH) {
Ok(path) => path,
Err(error) => {
if error.type_id() == Error::IO.type_id() {
// Make sure to return IO error if one occurs
return Err(error);
}
// If it doesn't exist then it is plugged in so make it 100% percent capacity
eprintln!("We could not detect your battery.");
create_issue!("If you are on a laptop");
return Ok(100);
}
};

let mut cap_str = fs::read_to_string(path)?;

// Remove the \n char
cap_str.pop();

Ok(cap_str.parse::<i8>().unwrap())
}

pub fn read_power_source() -> Result<bool, Error> {
let path: &str = match get_best_path(POWER_SOURCE_PATH) {
Ok(path) => path,
Expand All @@ -155,3 +112,146 @@ pub fn read_power_source() -> Result<bool, Error> {

Ok(pwr_str == "1")
}

enum BatteryConditionType {
Energy,
Charge,
None,
}
pub struct Battery {
sys_parent_path: String,
capacity: i8,
condition_type: BatteryConditionType,
condition: f32,
charge_full: i32,
charge_full_design: i32,
energy_full: i32,
energy_full_design: i32,
}

impl Battery {
pub fn new() -> Battery {
let mut obj = Battery {
sys_parent_path: "/sys/class/power_supply/BAT0/".to_string(),
capacity: 0 as i8,
condition_type: BatteryConditionType::None,
condition: 0 as f32,
charge_full: 0 as i32,
charge_full_design: 0 as i32,
energy_full: 0 as i32,
energy_full_design: 0 as i32,
};
obj.check_condition_type();
obj
}

pub fn read_charge(&mut self) -> Result<i8, Error> {
let path: &str = match get_best_path(BATTERY_CHARGE_PATH) {
Ok(path) => path,
Err(error) => {
if error.type_id() == Error::IO.type_id() {
// Make sure to return IO error if one occurs
return Err(error);
}
// If it doesn't exist then it is plugged in so make it 100% percent capacity
eprintln!("We could not detect your battery.");
create_issue!("If you are on a laptop");
return Ok(100);
}
};

let mut cap_str = fs::read_to_string(path)?;

// Remove the \n char
cap_str.pop();

Ok(cap_str.parse::<i8>().unwrap())
}

pub fn print_status(&mut self, charging: bool) -> String {
if has_battery() {
match self.read_charge() {
Ok(bat) => {
format!(
"Battery: {}",
if charging {
format!("{}%", bat).green()
} else {
format!("{}%", bat).red()
},
)
}
Err(e) => format!("Battery charge could not be read\n{:?}", e),
}
} else {
format!("Battery: {}", "N/A".bold())
}
}

fn check_condition_type(&mut self) {
let path = self.sys_parent_path.to_string() + "charge_full";
if Path::new(&path).is_file() {
self.condition_type = BatteryConditionType::Charge
}
let path = self.sys_parent_path.to_string() + "energy_full";
if Path::new(&path).is_file() {
self.condition_type = BatteryConditionType::Energy
}
}

pub fn get_condition(&mut self) -> Result<f32, Error> {
match self.condition_type {
BatteryConditionType::Energy => {
self.read_energy_full()?;
self.condition = self.energy_full as f32 / self.energy_full_design as f32
}
BatteryConditionType::Charge => {
self.read_charge_full()?;
self.condition = self.charge_full as f32 / self.charge_full_design as f32
}
BatteryConditionType::None => {
return Err(Error::Unknown);
}
}
let mut bat_cond = self.condition * 100.0;
if bat_cond >= 100.0 {
bat_cond = 100.00;
} else if bat_cond <= 0.0 {
bat_cond = 0.0;
}

Ok(bat_cond.round())
}

fn read_energy_full(&mut self) -> Result<(), Error> {
let mut energy_path: String;
let mut value: String;

energy_path = self.sys_parent_path.to_string() + "energy_full_design";
value = fs::read_to_string(energy_path)?;
value.pop();
self.energy_full_design = value.parse::<i32>().unwrap();

energy_path = self.sys_parent_path.to_string() + "energy_full";
value = fs::read_to_string(energy_path)?;
value.pop();
self.energy_full = value.parse::<i32>().unwrap();
Ok(())
}

fn read_charge_full(&mut self) -> Result<(), Error> {
let mut charge_path: String;
let mut value: String;

charge_path = self.sys_parent_path.to_string() + "charge_full_design";
value = fs::read_to_string(charge_path)?;
value.pop();
self.charge_full_design = value.parse::<i32>().unwrap();

charge_path = self.sys_parent_path.to_string() + "charge_full";
value = fs::read_to_string(charge_path)?;
value.pop();
self.charge_full = value.parse::<i32>().unwrap();
Ok(())
}
}
30 changes: 0 additions & 30 deletions src/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,43 +171,13 @@ fn interpret_turbo(is_turbo: &mut String) -> Result<bool, Error> {
}
}

fn read_bat_energy_full(design: bool) -> Result<i32, Error> {
let bat_energy_parent_path: &str = "/sys/class/power_supply/BAT0/";
let bat_energy_path: String;
if design {
bat_energy_path = bat_energy_parent_path.to_string() + "energy_full_design";
} else {
bat_energy_path = bat_energy_parent_path.to_string() + "energy_full";
};
let mut capacity_readings = fs::read_to_string(bat_energy_path)?;
capacity_readings.pop();
Ok(capacity_readings.parse::<i32>().unwrap())
}

/// Check if turbo is enabled for the machine, (enabled in bios)
pub fn check_turbo_enabled() -> Result<bool, Error> {
let mut turbo_string = read_turbo_file()?;
let is_turbo = interpret_turbo(&mut turbo_string)?;
Ok(is_turbo)
}

pub fn check_bat_cond() -> Result<f32, Error> {
let bat_cond_calc: f32 = read_bat_energy_full(false).unwrap_or(0) as f32
/ read_bat_energy_full(true).unwrap_or(0) as f32;
Ok(bat_cond_calc)
}

pub fn get_battery_condition(check_bat_cond: f32) -> f32 {
let mut bat_cond = check_bat_cond * 100.0;
if bat_cond >= 100.0 {
bat_cond = 100.00;
} else if bat_cond <= 0.0 {
bat_cond = 0.0;
}

bat_cond.round()
}

fn read_govs_file() -> Result<String, Error> {
let governors_path: &str = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors";
let governors_string = fs::read_to_string(governors_path)?;
Expand Down