oxigdal_embedded/
power.rs1use crate::error::{EmbeddedError, Result};
6use core::sync::atomic::{AtomicU8, AtomicU16, Ordering};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
10#[repr(u8)]
11pub enum PowerMode {
12 HighPerformance = 0,
14 Balanced = 1,
16 LowPower = 2,
18 UltraLowPower = 3,
20 Sleep = 4,
22 DeepSleep = 5,
24}
25
26impl PowerMode {
27 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 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 pub const fn allows_execution(&self) -> bool {
54 !matches!(self, Self::Sleep | Self::DeepSleep)
55 }
56}
57
58pub struct PowerManager {
60 current_mode: AtomicU8,
61}
62
63impl PowerManager {
64 pub const fn new() -> Self {
66 Self {
67 current_mode: AtomicU8::new(PowerMode::HighPerformance as u8),
68 }
69 }
70
71 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 pub fn request_mode(&self, mode: PowerMode) -> Result<()> {
83 let current = self.current_mode();
84
85 if !self.is_transition_allowed(current, mode) {
87 return Err(EmbeddedError::PowerModeTransitionFailed);
88 }
89
90 self.current_mode.store(mode as u8, Ordering::Release);
92
93 self.apply_mode(mode)?;
95
96 Ok(())
97 }
98
99 fn is_transition_allowed(&self, from: PowerMode, to: PowerMode) -> bool {
101 let _ = from;
104 let _ = to;
105 true
106 }
107
108 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 Ok(())
125 }
126
127 fn apply_balanced(&self) -> Result<()> {
128 Ok(())
131 }
132
133 fn apply_low_power(&self) -> Result<()> {
134 Ok(())
138 }
139
140 fn apply_ultra_low_power(&self) -> Result<()> {
141 Ok(())
145 }
146
147 fn apply_sleep(&self) -> Result<()> {
148 #[cfg(feature = "esp32")]
150 {
151 }
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 Ok(())
168 }
169}
170
171impl Default for PowerManager {
172 fn default() -> Self {
173 Self::new()
174 }
175}
176
177pub struct PowerEstimator {
179 current_ma: u32,
180 voltage_mv: u32,
181}
182
183impl PowerEstimator {
184 pub const fn new(voltage_mv: u32) -> Self {
186 Self {
187 current_ma: 0,
188 voltage_mv,
189 }
190 }
191
192 pub fn set_current(&mut self, current_ma: u32) {
194 self.current_ma = current_ma;
195 }
196
197 pub const fn current_ma(&self) -> u32 {
199 self.current_ma
200 }
201
202 pub const fn power_mw(&self) -> u32 {
204 (self.current_ma as u64 * self.voltage_mv as u64 / 1000) as u32
205 }
206
207 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 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 }
222}
223
224#[derive(Debug, Clone, Copy, PartialEq, Eq)]
226pub enum WakeSource {
227 Timer,
229 Gpio,
231 Uart,
233 Touch,
235 Any,
237}
238
239pub struct SleepConfig {
241 pub wake_sources: heapless::Vec<WakeSource, 8>,
243 pub duration_us: Option<u64>,
245 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 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 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 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
286pub struct VoltageRegulator {
288 voltage_mv: AtomicU16, }
290
291impl VoltageRegulator {
292 pub const fn new(nominal_voltage_mv: u16) -> Self {
294 Self {
295 voltage_mv: AtomicU16::new(nominal_voltage_mv),
296 }
297 }
298
299 pub fn voltage_mv(&self) -> u16 {
301 self.voltage_mv.load(Ordering::Relaxed)
302 }
303
304 pub fn set_voltage(&self, voltage_mv: u16) -> Result<()> {
310 if !(500..=5000).contains(&voltage_mv) {
312 return Err(EmbeddedError::InvalidParameter);
313 }
314
315 self.voltage_mv.store(voltage_mv, Ordering::Release);
316
317 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); estimator.set_current(100); assert_eq!(estimator.power_mw(), 330); let battery_life = estimator.battery_life_hours(1000); assert_eq!(battery_life, 10.0); }
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 assert!(regulator.set_voltage(6000).is_err());
375 }
376}