Skip to main content

auto_cpufreq/battery/
mod.rs

1// src/battery/mod.rs
2use anyhow::Result;
3use std::fs;
4use std::path::Path;
5use std::process::Command;
6
7pub mod asus;
8pub mod ideapad_acpi;
9pub mod ideapad_laptop;
10pub mod thinkpad;
11
12use crate::config::Config;
13
14const POWER_SUPPLY_DIR: &str = "/sys/class/power_supply/";
15
16/// Detect which laptop module is loaded
17#[derive(Debug, Clone, Copy, PartialEq)]
18pub enum LaptopModule {
19    IdeapadAcpi,
20    IdeapadLaptop,
21    ThinkpadAcpi,
22    AsusWmi,
23    None,
24}
25
26impl LaptopModule {
27    pub fn detect() -> Self {
28        if is_module_loaded("ideapad_acpi") {
29            Self::IdeapadAcpi
30        } else if is_module_loaded("ideapad_laptop") {
31            Self::IdeapadLaptop
32        } else if is_module_loaded("thinkpad_acpi") {
33            Self::ThinkpadAcpi
34        } else if is_module_loaded("asus_wmi") {
35            Self::AsusWmi
36        } else {
37            Self::None
38        }
39    }
40
41    pub fn name(&self) -> &str {
42        match self {
43            Self::IdeapadAcpi => "ideapad_acpi",
44            Self::IdeapadLaptop => "ideapad_laptop",
45            Self::ThinkpadAcpi => "thinkpad_acpi",
46            Self::AsusWmi => "asus_wmi",
47            Self::None => "none",
48        }
49    }
50}
51
52fn is_module_loaded(module: &str) -> bool {
53    Command::new("lsmod")
54        .output()
55        .ok()
56        .and_then(|output| String::from_utf8(output.stdout).ok())
57        .map(|stdout| stdout.contains(module))
58        .unwrap_or(false)
59}
60
61/// Get list of batteries in the system
62pub fn get_batteries() -> Result<Vec<String>> {
63    let power_dir = Path::new(POWER_SUPPLY_DIR);
64
65    if !power_dir.exists() {
66        return Ok(Vec::new());
67    }
68
69    let mut batteries = Vec::new();
70
71    for entry in fs::read_dir(power_dir)? {
72        let entry = entry?;
73        let name = entry.file_name();
74        let name_str = name.to_string_lossy();
75
76        if name_str.starts_with("BAT") {
77            batteries.push(name_str.to_string());
78        }
79    }
80
81    batteries.sort();
82    Ok(batteries)
83}
84
85/// Common trait for battery threshold management
86pub trait BatteryManager {
87    fn setup(&self, config: &Config) -> Result<()>;
88    fn print_thresholds(&self) -> Result<()>;
89}
90
91/// Main battery setup function - delegates to appropriate module
92pub fn battery_setup(config: &Config) -> Result<()> {
93    let module = LaptopModule::detect();
94
95    match module {
96        LaptopModule::IdeapadAcpi => ideapad_acpi::IdeapadAcpiManager.setup(config),
97        LaptopModule::IdeapadLaptop => ideapad_laptop::IdeapadLaptopManager.setup(config),
98        LaptopModule::ThinkpadAcpi => thinkpad::ThinkpadManager.setup(config),
99        LaptopModule::AsusWmi => asus::AsusManager.setup(config),
100        LaptopModule::None => {
101            Ok(()) // No battery management needed
102        }
103    }
104}
105
106/// Print battery thresholds
107pub fn battery_get_thresholds() -> Result<()> {
108    let module = LaptopModule::detect();
109
110    match module {
111        LaptopModule::IdeapadAcpi => ideapad_acpi::IdeapadAcpiManager.print_thresholds(),
112        LaptopModule::IdeapadLaptop => ideapad_laptop::IdeapadLaptopManager.print_thresholds(),
113        LaptopModule::ThinkpadAcpi => thinkpad::ThinkpadManager.print_thresholds(),
114        LaptopModule::AsusWmi => asus::AsusManager.print_thresholds(),
115        LaptopModule::None => {
116            Ok(()) // Nothing to print
117        }
118    }
119}