Skip to main content

oxigdal_embedded/
power.rs

1//! Power management for embedded systems
2//!
3//! Provides utilities for managing power consumption in resource-constrained environments
4
5use crate::error::{EmbeddedError, Result};
6use core::sync::atomic::{AtomicU8, AtomicU16, Ordering};
7
8/// Power mode levels
9#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
10#[repr(u8)]
11pub enum PowerMode {
12    /// Full performance, maximum power consumption
13    HighPerformance = 0,
14    /// Balanced performance and power
15    Balanced = 1,
16    /// Low power, reduced performance
17    LowPower = 2,
18    /// Ultra low power, minimal functionality
19    UltraLowPower = 3,
20    /// Sleep mode, CPU halted
21    Sleep = 4,
22    /// Deep sleep, most peripherals off
23    DeepSleep = 5,
24}
25
26impl PowerMode {
27    /// Get power mode from u8
28    pub const fn from_u8(value: u8) -> Option<Self> {
29        match value {
30            0 => Some(Self::HighPerformance),
31            1 => Some(Self::Balanced),
32            2 => Some(Self::LowPower),
33            3 => Some(Self::UltraLowPower),
34            4 => Some(Self::Sleep),
35            5 => Some(Self::DeepSleep),
36            _ => None,
37        }
38    }
39
40    /// Get CPU frequency scaling factor (1.0 = full speed)
41    pub const fn cpu_freq_factor(&self) -> f32 {
42        match self {
43            Self::HighPerformance => 1.0,
44            Self::Balanced => 0.75,
45            Self::LowPower => 0.5,
46            Self::UltraLowPower => 0.25,
47            Self::Sleep => 0.0,
48            Self::DeepSleep => 0.0,
49        }
50    }
51
52    /// Check if mode allows CPU execution
53    pub const fn allows_execution(&self) -> bool {
54        !matches!(self, Self::Sleep | Self::DeepSleep)
55    }
56}
57
58/// Power manager for controlling system power state
59pub struct PowerManager {
60    current_mode: AtomicU8,
61}
62
63impl PowerManager {
64    /// Create a new power manager in high performance mode
65    pub const fn new() -> Self {
66        Self {
67            current_mode: AtomicU8::new(PowerMode::HighPerformance as u8),
68        }
69    }
70
71    /// Get current power mode
72    pub fn current_mode(&self) -> PowerMode {
73        let mode_u8 = self.current_mode.load(Ordering::Relaxed);
74        PowerMode::from_u8(mode_u8).unwrap_or(PowerMode::HighPerformance)
75    }
76
77    /// Request power mode transition
78    ///
79    /// # Errors
80    ///
81    /// Returns error if transition is not allowed or fails
82    pub fn request_mode(&self, mode: PowerMode) -> Result<()> {
83        let current = self.current_mode();
84
85        // Validate transition
86        if !self.is_transition_allowed(current, mode) {
87            return Err(EmbeddedError::PowerModeTransitionFailed);
88        }
89
90        // Store new mode
91        self.current_mode.store(mode as u8, Ordering::Release);
92
93        // Perform hardware transition (platform-specific)
94        self.apply_mode(mode)?;
95
96        Ok(())
97    }
98
99    /// Check if a power mode transition is allowed
100    fn is_transition_allowed(&self, from: PowerMode, to: PowerMode) -> bool {
101        // Allow any transition for now
102        // In real implementation, this would check hardware constraints
103        let _ = from;
104        let _ = to;
105        true
106    }
107
108    /// Apply the power mode to hardware
109    fn apply_mode(&self, mode: PowerMode) -> Result<()> {
110        match mode {
111            PowerMode::HighPerformance => self.apply_high_performance(),
112            PowerMode::Balanced => self.apply_balanced(),
113            PowerMode::LowPower => self.apply_low_power(),
114            PowerMode::UltraLowPower => self.apply_ultra_low_power(),
115            PowerMode::Sleep => self.apply_sleep(),
116            PowerMode::DeepSleep => self.apply_deep_sleep(),
117        }
118    }
119
120    fn apply_high_performance(&self) -> Result<()> {
121        // Set CPU to maximum frequency
122        // Enable all peripherals
123        // Disable power gating
124        Ok(())
125    }
126
127    fn apply_balanced(&self) -> Result<()> {
128        // Set CPU to moderate frequency
129        // Enable dynamic frequency scaling
130        Ok(())
131    }
132
133    fn apply_low_power(&self) -> Result<()> {
134        // Reduce CPU frequency
135        // Disable unused peripherals
136        // Enable aggressive power gating
137        Ok(())
138    }
139
140    fn apply_ultra_low_power(&self) -> Result<()> {
141        // Minimum CPU frequency
142        // Disable all non-essential peripherals
143        // Maximum power saving
144        Ok(())
145    }
146
147    fn apply_sleep(&self) -> Result<()> {
148        // Halt CPU, wait for interrupt
149        #[cfg(feature = "esp32")]
150        {
151            // Would call actual sleep implementation
152        }
153
154        #[cfg(feature = "riscv")]
155        {
156            use crate::target::riscv::power;
157            power::wait_for_interrupt()?;
158        }
159
160        Ok(())
161    }
162
163    fn apply_deep_sleep(&self) -> Result<()> {
164        // Enter deep sleep mode
165        // Most peripherals powered off
166        // Only wake on specific triggers
167        Ok(())
168    }
169}
170
171impl Default for PowerManager {
172    fn default() -> Self {
173        Self::new()
174    }
175}
176
177/// Power consumption estimator
178pub struct PowerEstimator {
179    current_ma: u32,
180    voltage_mv: u32,
181}
182
183impl PowerEstimator {
184    /// Create a new power estimator
185    pub const fn new(voltage_mv: u32) -> Self {
186        Self {
187            current_ma: 0,
188            voltage_mv,
189        }
190    }
191
192    /// Set current consumption in milliamps
193    pub fn set_current(&mut self, current_ma: u32) {
194        self.current_ma = current_ma;
195    }
196
197    /// Get current consumption in milliamps
198    pub const fn current_ma(&self) -> u32 {
199        self.current_ma
200    }
201
202    /// Calculate power consumption in milliwatts
203    pub const fn power_mw(&self) -> u32 {
204        (self.current_ma as u64 * self.voltage_mv as u64 / 1000) as u32
205    }
206
207    /// Estimate battery life in hours
208    pub fn battery_life_hours(&self, battery_mah: u32) -> f32 {
209        if self.current_ma == 0 {
210            return f32::INFINITY;
211        }
212
213        battery_mah as f32 / self.current_ma as f32
214    }
215
216    /// Estimate energy consumption in millijoules per operation
217    pub fn energy_per_op(&self, operation_time_us: u32) -> f32 {
218        let power_w = self.power_mw() as f32 / 1000.0;
219        let time_s = operation_time_us as f32 / 1_000_000.0;
220        power_w * time_s * 1000.0 // Convert to mJ
221    }
222}
223
224/// Wake source for sleep modes
225#[derive(Debug, Clone, Copy, PartialEq, Eq)]
226pub enum WakeSource {
227    /// Timer wake
228    Timer,
229    /// GPIO wake
230    Gpio,
231    /// UART wake
232    Uart,
233    /// Touch sensor wake
234    Touch,
235    /// Any wake source
236    Any,
237}
238
239/// Sleep configuration
240pub struct SleepConfig {
241    /// Wakeup sources
242    pub wake_sources: heapless::Vec<WakeSource, 8>,
243    /// Sleep duration in microseconds (for timer wake)
244    pub duration_us: Option<u64>,
245    /// Enable RTC during sleep
246    pub keep_rtc: bool,
247}
248
249impl Default for SleepConfig {
250    fn default() -> Self {
251        Self {
252            wake_sources: heapless::Vec::new(),
253            duration_us: None,
254            keep_rtc: true,
255        }
256    }
257}
258
259impl SleepConfig {
260    /// Create a new sleep configuration
261    pub const fn new() -> Self {
262        Self {
263            wake_sources: heapless::Vec::new(),
264            duration_us: None,
265            keep_rtc: true,
266        }
267    }
268
269    /// Add a wake source
270    pub fn add_wake_source(&mut self, source: WakeSource) -> Result<()> {
271        self.wake_sources
272            .push(source)
273            .map_err(|_| EmbeddedError::BufferTooSmall {
274                required: 1,
275                available: 0,
276            })
277    }
278
279    /// Set timer wake duration
280    pub fn set_timer_wake(&mut self, duration_us: u64) -> Result<()> {
281        self.duration_us = Some(duration_us);
282        self.add_wake_source(WakeSource::Timer)
283    }
284}
285
286/// Voltage regulator control
287pub struct VoltageRegulator {
288    voltage_mv: AtomicU16, // Actual voltage in millivolts
289}
290
291impl VoltageRegulator {
292    /// Create a new voltage regulator at nominal voltage
293    pub const fn new(nominal_voltage_mv: u16) -> Self {
294        Self {
295            voltage_mv: AtomicU16::new(nominal_voltage_mv),
296        }
297    }
298
299    /// Get current voltage in millivolts
300    pub fn voltage_mv(&self) -> u16 {
301        self.voltage_mv.load(Ordering::Relaxed)
302    }
303
304    /// Set voltage in millivolts
305    ///
306    /// # Errors
307    ///
308    /// Returns error if voltage is out of safe range
309    pub fn set_voltage(&self, voltage_mv: u16) -> Result<()> {
310        // Validate voltage range (0.5V to 5.0V)
311        if !(500..=5000).contains(&voltage_mv) {
312            return Err(EmbeddedError::InvalidParameter);
313        }
314
315        self.voltage_mv.store(voltage_mv, Ordering::Release);
316
317        // Apply voltage change to hardware
318        // This would interface with voltage regulator hardware
319        Ok(())
320    }
321}
322
323#[cfg(test)]
324mod tests {
325    use super::*;
326
327    #[test]
328    fn test_power_mode_ordering() {
329        assert!(PowerMode::HighPerformance < PowerMode::LowPower);
330        assert!(PowerMode::LowPower < PowerMode::Sleep);
331    }
332
333    #[test]
334    fn test_power_manager() {
335        let pm = PowerManager::new();
336        assert_eq!(pm.current_mode(), PowerMode::HighPerformance);
337
338        pm.request_mode(PowerMode::LowPower)
339            .expect("mode change failed");
340        assert_eq!(pm.current_mode(), PowerMode::LowPower);
341    }
342
343    #[test]
344    fn test_power_estimator() {
345        let mut estimator = PowerEstimator::new(3300); // 3.3V
346        estimator.set_current(100); // 100mA
347
348        assert_eq!(estimator.power_mw(), 330); // 330mW
349
350        let battery_life = estimator.battery_life_hours(1000); // 1000mAh battery
351        assert_eq!(battery_life, 10.0); // 10 hours
352    }
353
354    #[test]
355    fn test_sleep_config() {
356        let mut config = SleepConfig::new();
357        config
358            .add_wake_source(WakeSource::Gpio)
359            .expect("add failed");
360        config.set_timer_wake(1_000_000).expect("set timer failed");
361
362        assert_eq!(config.wake_sources.len(), 2);
363    }
364
365    #[test]
366    fn test_voltage_regulator() {
367        let regulator = VoltageRegulator::new(3300);
368        assert_eq!(regulator.voltage_mv(), 3300);
369
370        regulator.set_voltage(1800).expect("voltage change failed");
371        assert_eq!(regulator.voltage_mv(), 1800);
372
373        // Test invalid voltage
374        assert!(regulator.set_voltage(6000).is_err());
375    }
376}