Skip to main content

rdif_power/
lib.rs

1#![no_std]
2
3extern crate alloc;
4
5use rdif_base::def_driver;
6pub use rdif_base::{DriverGeneric, custom_type};
7
8custom_type!(
9    #[doc = "Power domain id"],
10    PowerDomainId, u64, "{:#x}");
11
12impl PowerDomainId {
13    pub const fn new(value: u64) -> Self {
14        Self(value)
15    }
16}
17
18impl From<u32> for PowerDomainId {
19    fn from(value: u32) -> Self {
20        Self(u64::from(value))
21    }
22}
23
24impl From<usize> for PowerDomainId {
25    fn from(value: usize) -> Self {
26        Self(value as u64)
27    }
28}
29
30#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq)]
31pub enum PowerError {
32    #[error("invalid power domain id")]
33    InvalidId,
34    #[error("unsupported power operation")]
35    Unsupported,
36    #[error("power controller is busy")]
37    Busy,
38    #[error("power controller error")]
39    Controller,
40}
41
42pub trait Interface: DriverGeneric {
43    fn power_on(&mut self, id: PowerDomainId) -> Result<(), PowerError>;
44
45    fn power_off(&mut self, id: PowerDomainId) -> Result<(), PowerError>;
46
47    fn is_powered(&self, _id: PowerDomainId) -> Result<bool, PowerError> {
48        Err(PowerError::Unsupported)
49    }
50}
51
52def_driver!(Power, Interface);
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    struct RecordingPower {
59        powered: bool,
60        calls: alloc::vec::Vec<(&'static str, PowerDomainId)>,
61    }
62
63    impl DriverGeneric for RecordingPower {
64        fn name(&self) -> &str {
65            "recording-power"
66        }
67    }
68
69    impl Interface for RecordingPower {
70        fn power_on(&mut self, id: PowerDomainId) -> Result<(), PowerError> {
71            self.powered = true;
72            self.calls.push(("on", id));
73            Ok(())
74        }
75
76        fn power_off(&mut self, id: PowerDomainId) -> Result<(), PowerError> {
77            self.powered = false;
78            self.calls.push(("off", id));
79            Ok(())
80        }
81
82        fn is_powered(&self, _id: PowerDomainId) -> Result<bool, PowerError> {
83            Ok(self.powered)
84        }
85    }
86
87    #[test]
88    fn power_domain_id_conversions_preserve_raw_value() {
89        assert_eq!(PowerDomainId::new(7).raw(), 7);
90        assert_eq!(PowerDomainId::from(8_u32).raw(), 8);
91        assert_eq!(PowerDomainId::from(9_usize).raw(), 9);
92        assert_eq!(PowerDomainId::from(10_u64).raw(), 10);
93    }
94
95    #[test]
96    fn power_domain_operations_are_dispatched_to_inner_driver() {
97        let mut power = Power::new(RecordingPower {
98            powered: false,
99            calls: alloc::vec::Vec::new(),
100        });
101
102        power.power_on(PowerDomainId::new(3)).unwrap();
103        assert_eq!(power.is_powered(PowerDomainId::new(3)), Ok(true));
104        power.power_off(PowerDomainId::new(3)).unwrap();
105        assert_eq!(power.is_powered(PowerDomainId::new(3)), Ok(false));
106
107        let inner = power.typed_ref::<RecordingPower>().unwrap();
108        assert_eq!(
109            inner.calls,
110            alloc::vec![
111                ("on", PowerDomainId::new(3)),
112                ("off", PowerDomainId::new(3))
113            ]
114        );
115    }
116
117    #[test]
118    fn default_is_powered_reports_unsupported() {
119        struct MinimalPower;
120
121        impl DriverGeneric for MinimalPower {
122            fn name(&self) -> &str {
123                "minimal-power"
124            }
125        }
126
127        impl Interface for MinimalPower {
128            fn power_on(&mut self, _id: PowerDomainId) -> Result<(), PowerError> {
129                Ok(())
130            }
131
132            fn power_off(&mut self, _id: PowerDomainId) -> Result<(), PowerError> {
133                Ok(())
134            }
135        }
136
137        let power = MinimalPower;
138        assert_eq!(
139            power.is_powered(PowerDomainId::new(1)),
140            Err(PowerError::Unsupported)
141        );
142    }
143}