1use crate::bindings;
17use crate::error::{Error, Result};
18
19#[repr(u32)]
35#[derive(Debug, Copy, Clone, PartialEq, Eq)]
36pub enum State {
37 Active = 0,
39 Idle = 1,
41 Standby = 2,
43 DeepSleep = 3,
45}
46
47#[repr(u32)]
49#[derive(Debug, Copy, Clone, PartialEq, Eq)]
50pub enum WakeType {
51 Gpio = 0,
53 Timer = 1,
55 Uart = 2,
57 Rtc = 3,
59}
60
61#[repr(u32)]
63#[derive(Debug, Copy, Clone, PartialEq, Eq)]
64pub enum Domain {
65 Radio = 0,
66 Sensor = 1,
67 Display = 2,
68 Audio = 3,
69 Storage = 4,
70 Comms = 5,
71 User0 = 6,
72 User1 = 7,
73}
74
75#[repr(u32)]
77#[derive(Debug, Copy, Clone, PartialEq, Eq)]
78pub enum Event {
79 PreSleep = 0,
81 PostWake = 1,
83}
84
85#[derive(Debug, Copy, Clone)]
89pub struct Cfg {
90 pub idle_threshold_ms: u32,
92 pub standby_threshold_ms: u32,
94 pub deep_sleep_threshold_ms: u32,
96}
97
98#[derive(Debug, Copy, Clone)]
100pub struct Stats {
101 pub time_in_state_us: [u64; 4],
103 pub transition_count: [u32; 4],
105 pub total_runtime_us: u64,
107 pub active_pct_x100: u32,
109}
110
111pub fn init(cfg: &Cfg) -> Result<()> {
118 let c_cfg = bindings::ove_pm_cfg {
119 idle_threshold_ms: cfg.idle_threshold_ms,
120 standby_threshold_ms: cfg.standby_threshold_ms,
121 deep_sleep_threshold_ms: cfg.deep_sleep_threshold_ms,
122 };
123 let rc = unsafe { bindings::ove_pm_init(&c_cfg) };
124 Error::from_code(rc)
125}
126
127pub fn deinit() {
129 unsafe { bindings::ove_pm_deinit() }
130}
131
132pub fn set_state(state: State) -> Result<()> {
139 let rc = unsafe { bindings::ove_pm_set_state(state as bindings::ove_pm_state_t) };
140 Error::from_code(rc)
141}
142
143pub fn get_state() -> State {
145 let raw = unsafe { bindings::ove_pm_get_state() };
146 match raw {
147 1 => State::Idle,
148 2 => State::Standby,
149 3 => State::DeepSleep,
150 _ => State::Active,
151 }
152}
153
154pub fn activity() {
156 unsafe { bindings::ove_pm_activity() }
157}
158
159pub fn wake_register_gpio(port: u32, pin: u32, edge: u32) -> Result<()> {
166 let mut src: bindings::ove_pm_wake_src = unsafe { core::mem::zeroed() };
167 src.type_ = WakeType::Gpio as bindings::ove_pm_wake_type_t;
168 src.__bindgen_anon_1.gpio.port = port;
169 src.__bindgen_anon_1.gpio.pin = pin;
170 src.__bindgen_anon_1.gpio.edge = edge as bindings::ove_gpio_irq_mode_t;
171 let rc = unsafe { bindings::ove_pm_wake_register(&src) };
172 Error::from_code(rc)
173}
174
175pub fn wake_register_timer(timeout_ms: u32) -> Result<()> {
180 let mut src: bindings::ove_pm_wake_src = unsafe { core::mem::zeroed() };
181 src.type_ = WakeType::Timer as bindings::ove_pm_wake_type_t;
182 src.__bindgen_anon_1.timer.timeout_ms = timeout_ms;
183 let rc = unsafe { bindings::ove_pm_wake_register(&src) };
184 Error::from_code(rc)
185}
186
187pub fn wake_register_uart(instance: u32) -> Result<()> {
192 let mut src: bindings::ove_pm_wake_src = unsafe { core::mem::zeroed() };
193 src.type_ = WakeType::Uart as bindings::ove_pm_wake_type_t;
194 src.__bindgen_anon_1.uart.instance = instance;
195 let rc = unsafe { bindings::ove_pm_wake_register(&src) };
196 Error::from_code(rc)
197}
198
199pub fn wake_unregister_gpio(port: u32, pin: u32) -> Result<()> {
204 let mut src: bindings::ove_pm_wake_src = unsafe { core::mem::zeroed() };
205 src.type_ = WakeType::Gpio as bindings::ove_pm_wake_type_t;
206 src.__bindgen_anon_1.gpio.port = port;
207 src.__bindgen_anon_1.gpio.pin = pin;
208 let rc = unsafe { bindings::ove_pm_wake_unregister(&src) };
209 Error::from_code(rc)
210}
211
212pub fn domain_request(domain: Domain) -> Result<()> {
221 let rc = unsafe { bindings::ove_pm_domain_request(domain as bindings::ove_pm_domain_t) };
222 Error::from_code(rc)
223}
224
225pub fn domain_release(domain: Domain) -> Result<()> {
232 let rc = unsafe { bindings::ove_pm_domain_release(domain as bindings::ove_pm_domain_t) };
233 Error::from_code(rc)
234}
235
236pub fn domain_get_refcount(domain: Domain) -> Result<i32> {
241 let rc = unsafe { bindings::ove_pm_domain_get_refcount(domain as bindings::ove_pm_domain_t) };
242 if rc < 0 {
243 Error::from_code(rc)?;
244 }
245 Ok(rc)
246}
247
248pub unsafe fn set_policy_raw(
256 policy: bindings::ove_pm_policy_fn,
257 user_data: *mut core::ffi::c_void,
258) -> Result<()> {
259 let rc = unsafe { bindings::ove_pm_set_policy(policy, user_data) };
260 Error::from_code(rc)
261}
262
263#[derive(Debug, Copy, Clone)]
265pub struct PolicyCtx {
266 pub current: State,
267 pub idle_ms: u32,
268 pub next_timeout_ms: u32,
269}
270
271pub struct PolicyHandler<T: Send + Sync + 'static> {
277 cell: &'static crate::InitCell<T>,
278 user: fn(&T, PolicyCtx) -> State,
279}
280
281impl<T: Send + Sync + 'static> PolicyHandler<T> {
282 pub const fn new(cell: &'static crate::InitCell<T>, user: fn(&T, PolicyCtx) -> State) -> Self {
285 Self { cell, user }
286 }
287}
288
289unsafe impl<T: Send + Sync + 'static> Sync for PolicyHandler<T> {}
294
295unsafe extern "C" fn policy_trampoline<T: Send + Sync + 'static>(
296 current: bindings::ove_pm_state_t,
297 idle_ms: u32,
298 next_timeout_ms: u32,
299 user_data: *mut core::ffi::c_void,
300) -> bindings::ove_pm_state_t {
301 if user_data.is_null() {
302 return current;
303 }
304 let h = unsafe { &*(user_data as *const PolicyHandler<T>) };
306 let Some(state) = h.cell.try_get() else {
307 return current;
308 };
309 let ctx = PolicyCtx {
310 current: match current {
311 1 => State::Idle,
312 2 => State::Standby,
313 3 => State::DeepSleep,
314 _ => State::Active,
315 },
316 idle_ms,
317 next_timeout_ms,
318 };
319 (h.user)(state, ctx) as bindings::ove_pm_state_t
320}
321
322pub fn set_policy<T: Send + Sync + 'static>(handler: &'static PolicyHandler<T>) -> Result<()> {
324 let rc = unsafe {
325 bindings::ove_pm_set_policy(
326 Some(policy_trampoline::<T>),
327 handler as *const _ as *mut core::ffi::c_void,
328 )
329 };
330 Error::from_code(rc)
331}
332
333pub fn clear_policy() -> Result<()> {
335 let rc = unsafe { bindings::ove_pm_set_policy(None, core::ptr::null_mut()) };
336 Error::from_code(rc)
337}
338
339pub unsafe fn notify_register_raw(
346 cb: bindings::ove_pm_notify_fn,
347 user_data: *mut core::ffi::c_void,
348) -> Result<()> {
349 let rc = unsafe { bindings::ove_pm_notify_register(cb, user_data) };
350 Error::from_code(rc)
351}
352
353pub unsafe fn notify_unregister_raw(
358 cb: bindings::ove_pm_notify_fn,
359 user_data: *mut core::ffi::c_void,
360) -> Result<()> {
361 let rc = unsafe { bindings::ove_pm_notify_unregister(cb, user_data) };
362 Error::from_code(rc)
363}
364
365pub struct NotifyHandler<T: Send + Sync + 'static> {
369 cell: &'static crate::InitCell<T>,
370 user: fn(&T, Event, State, State),
371}
372
373impl<T: Send + Sync + 'static> NotifyHandler<T> {
374 pub const fn new(cell: &'static crate::InitCell<T>, user: fn(&T, Event, State, State)) -> Self {
377 Self { cell, user }
378 }
379}
380
381unsafe impl<T: Send + Sync + 'static> Sync for NotifyHandler<T> {}
385
386unsafe extern "C" fn notify_trampoline<T: Send + Sync + 'static>(
387 event: bindings::ove_pm_event_t,
388 from_state: bindings::ove_pm_state_t,
389 to_state: bindings::ove_pm_state_t,
390 user_data: *mut core::ffi::c_void,
391) {
392 if user_data.is_null() {
393 return;
394 }
395 let h = unsafe { &*(user_data as *const NotifyHandler<T>) };
397 let Some(state) = h.cell.try_get() else {
398 return;
399 };
400 let ev = match event {
401 0 => Event::PreSleep,
402 1 => Event::PostWake,
403 _ => return,
404 };
405 let map = |s: bindings::ove_pm_state_t| match s {
406 1 => State::Idle,
407 2 => State::Standby,
408 3 => State::DeepSleep,
409 _ => State::Active,
410 };
411 (h.user)(state, ev, map(from_state), map(to_state));
412}
413
414pub fn notify_register<T: Send + Sync + 'static>(handler: &'static NotifyHandler<T>) -> Result<()> {
419 let rc = unsafe {
420 bindings::ove_pm_notify_register(
421 Some(notify_trampoline::<T>),
422 handler as *const _ as *mut core::ffi::c_void,
423 )
424 };
425 Error::from_code(rc)
426}
427
428pub fn notify_unregister<T: Send + Sync + 'static>(
433 handler: &'static NotifyHandler<T>,
434) -> Result<()> {
435 let rc = unsafe {
436 bindings::ove_pm_notify_unregister(
437 Some(notify_trampoline::<T>),
438 handler as *const _ as *mut core::ffi::c_void,
439 )
440 };
441 Error::from_code(rc)
442}
443
444pub fn get_stats() -> Result<Stats> {
451 let mut raw: bindings::ove_pm_stats = unsafe { core::mem::zeroed() };
452 let rc = unsafe { bindings::ove_pm_get_stats(&mut raw) };
453 Error::from_code(rc)?;
454 Ok(Stats {
455 time_in_state_us: raw.time_in_state_us,
456 transition_count: raw.transition_count,
457 total_runtime_us: raw.total_runtime_us,
458 active_pct_x100: raw.active_pct_x100,
459 })
460}
461
462pub fn reset_stats() {
464 unsafe { bindings::ove_pm_reset_stats() }
465}
466
467pub fn set_budget(target_low_power_pct_x100: u32) -> Result<()> {
474 let rc = unsafe { bindings::ove_pm_set_budget(target_low_power_pct_x100) };
475 Error::from_code(rc)
476}
477
478pub fn get_budget_status() -> Result<u32> {
485 let mut actual: u32 = 0;
486 let rc = unsafe { bindings::ove_pm_get_budget_status(&mut actual) };
487 Error::from_code(rc)?;
488 Ok(actual)
489}