uconsole_sleep/
power_mode.rs1use crate::hardware::{backlight, drm_panel, framebuffer};
4use crate::{BTConfig, CpuFreqConfig, WifiConfig};
5use log::{debug, info, warn};
6use std::fs;
7
8fn toggle_display(dry_run: bool) -> Result<(), String> {
9 let backlight_path = match backlight::find_backlight() {
10 Ok(Some(p)) => p,
11 Ok(None) => return Err("backlight not found".to_string()),
12 Err(e) => return Err(format!("failed to find backlight: {}", e)),
13 };
14
15 let framebuffer_path = framebuffer::find_framebuffer().ok().flatten();
16 let drm_path = drm_panel::find_drm_panel().ok().flatten();
17
18 let bl_state =
19 fs::read_to_string(backlight_path.join("bl_power")).unwrap_or_else(|_| "4".to_string());
20 let bl_state_trim = bl_state.trim();
21
22 if bl_state_trim == "4" {
23 info!("Turning display ON");
25 if !dry_run {
26 if let Some(fb) = framebuffer_path {
27 let _ = fs::write(fb.join("blank"), "0");
28 }
29 let _ = fs::write(backlight_path.join("bl_power"), "0");
30 if let Some(drm) = drm_path {
31 let _ = fs::write(drm.join("status"), "detect");
32 }
33 } else {
34 debug!("DRY-RUN: toggle_display ON skipped");
35 }
36 } else {
37 info!("Turning display OFF");
39 if !dry_run {
40 if let Some(drm) = drm_path {
41 let _ = fs::write(drm.join("status"), "off");
42 }
43 if let Some(fb) = framebuffer_path {
44 let _ = fs::write(fb.join("blank"), "1");
45 }
46 let _ = fs::write(backlight_path.join("bl_power"), "4");
47 } else {
48 debug!("DRY-RUN: toggle_display OFF skipped");
49 }
50 }
51 Ok(())
52}
53
54#[derive(Clone, Debug, PartialEq)]
56pub enum PowerMode {
57 Normal,
58 Saving,
59}
60
61pub fn enter_saving_mode(
62 cpu_config: &CpuFreqConfig,
63 dry_run: bool,
64 wifi: Option<&WifiConfig>,
65 bt: Option<&BTConfig>,
66) {
67 info!("Entering power-saving mode");
68 if let Err(e) = toggle_display(dry_run) {
69 warn!("toggle_display failed: {}", e);
70 }
71 cpu_config.apply_saving_mode(dry_run);
72 if let Some(w) = wifi {
73 w.block(dry_run);
74 }
75 if let Some(b) = bt {
76 b.block(dry_run);
77 }
78}
79
80pub fn exit_saving_mode(
82 cpu_config: &CpuFreqConfig,
83 dry_run: bool,
84 wifi: Option<&WifiConfig>,
85 bt: Option<&BTConfig>,
86) {
87 info!("Exiting power-saving mode");
88 cpu_config.apply_normal_mode(dry_run);
89 if let Err(e) = toggle_display(dry_run) {
90 warn!("toggle_display failed: {}", e);
91 }
92 if let Some(w) = wifi {
93 w.unblock(dry_run);
94 }
95 if let Some(b) = bt {
96 b.unblock(dry_run);
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103 use std::env;
104 use std::fs;
105
106 #[test]
107 fn test_enter_exit_saving_mode_dryrun() {
108 let tmp = env::temp_dir().join(format!(
109 "uconsole_pm_test_{}",
110 std::time::SystemTime::now()
111 .duration_since(std::time::UNIX_EPOCH)
112 .unwrap()
113 .as_millis()
114 ));
115 let _ = fs::create_dir_all(&tmp);
116 let cpu = CpuFreqConfig::with_policy_path(tmp.clone(), Some(String::from("100,200")));
117 enter_saving_mode(&cpu, true, None, None);
119 assert!(!tmp.join("scaling_min_freq").exists());
120 assert!(!tmp.join("scaling_max_freq").exists());
121
122 enter_saving_mode(&cpu, false, None, None);
124 assert!(tmp.join("scaling_min_freq").exists());
125 assert!(tmp.join("scaling_max_freq").exists());
126
127 exit_saving_mode(&cpu, false, None, None);
129 }
130}