1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/// Power-supply current limit.
///
/// Argument of [`PwrCtrl::set_current_lim`].
#[derive(Debug, Default, PartialEq, Eq, Ord, PartialOrd, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
pub enum CurrentLim {
    /// 25 mA
    Milli25 = 0x0,
    /// 50 mA (default)
    #[default]
    Milli50 = 0x1,
    /// 100 mA
    Milli100 = 0x2,
    /// 200 mA
    Milli200 = 0x3,
}

impl CurrentLim {
    /// Get the SMPS drive value as milliamps.
    ///
    /// # Example
    ///
    /// ```
    /// use stm32wlxx_hal::subghz::CurrentLim;
    ///
    /// assert_eq!(CurrentLim::Milli25.as_milliamps(), 25);
    /// assert_eq!(CurrentLim::Milli50.as_milliamps(), 50);
    /// assert_eq!(CurrentLim::Milli100.as_milliamps(), 100);
    /// assert_eq!(CurrentLim::Milli200.as_milliamps(), 200);
    /// ```
    pub const fn as_milliamps(&self) -> u8 {
        match self {
            CurrentLim::Milli25 => 25,
            CurrentLim::Milli50 => 50,
            CurrentLim::Milli100 => 100,
            CurrentLim::Milli200 => 200,
        }
    }
}

/// Power control.
///
/// Argument of [`set_bit_sync`](super::SubGhz::set_bit_sync).
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PwrCtrl {
    val: u8,
}

impl PwrCtrl {
    /// Power control register reset value.
    pub const RESET: PwrCtrl = PwrCtrl { val: 0x50 };

    /// Create a new [`PwrCtrl`] structure from a raw value.
    ///
    /// Reserved bits will be masked.
    pub const fn from_raw(raw: u8) -> Self {
        Self { val: raw & 0x70 }
    }

    /// Get the raw value of the [`PwrCtrl`] register.
    pub const fn as_bits(&self) -> u8 {
        self.val
    }

    /// Set the current limiter enable.
    ///
    /// # Example
    ///
    /// ```
    /// use stm32wlxx_hal::subghz::PwrCtrl;
    ///
    /// const PWR_CTRL: PwrCtrl = PwrCtrl::RESET.set_current_lim_en(true);
    /// # assert_eq!(u8::from(PWR_CTRL), 0x50u8);
    /// ```
    #[must_use = "set_current_lim_en returns a modified PwrCtrl"]
    pub const fn set_current_lim_en(mut self, en: bool) -> PwrCtrl {
        if en {
            self.val |= 1 << 6;
        } else {
            self.val &= !(1 << 6);
        }
        self
    }

    /// Returns `true` if current limiting is enabled
    ///
    /// # Example
    ///
    /// ```
    /// use stm32wlxx_hal::subghz::PwrCtrl;
    ///
    /// let pc: PwrCtrl = PwrCtrl::RESET;
    /// assert_eq!(pc.current_limit_en(), true);
    /// let pc: PwrCtrl = pc.set_current_lim_en(false);
    /// assert_eq!(pc.current_limit_en(), false);
    /// let pc: PwrCtrl = pc.set_current_lim_en(true);
    /// assert_eq!(pc.current_limit_en(), true);
    /// ```
    pub const fn current_limit_en(&self) -> bool {
        self.val & (1 << 6) != 0
    }

    /// Set the current limit.
    #[must_use = "set_current_lim returns a modified PwrCtrl"]
    pub const fn set_current_lim(mut self, lim: CurrentLim) -> PwrCtrl {
        self.val &= !(0x30);
        self.val |= (lim as u8) << 4;
        self
    }

    /// Get the current limit.
    ///
    /// # Example
    ///
    /// ```
    /// use stm32wlxx_hal::subghz::{CurrentLim, PwrCtrl};
    ///
    /// let pc: PwrCtrl = PwrCtrl::RESET;
    /// assert_eq!(pc.current_lim(), CurrentLim::Milli50);
    ///
    /// let pc: PwrCtrl = pc.set_current_lim(CurrentLim::Milli25);
    /// assert_eq!(pc.current_lim(), CurrentLim::Milli25);
    ///
    /// let pc: PwrCtrl = pc.set_current_lim(CurrentLim::Milli50);
    /// assert_eq!(pc.current_lim(), CurrentLim::Milli50);
    ///
    /// let pc: PwrCtrl = pc.set_current_lim(CurrentLim::Milli100);
    /// assert_eq!(pc.current_lim(), CurrentLim::Milli100);
    ///
    /// let pc: PwrCtrl = pc.set_current_lim(CurrentLim::Milli200);
    /// assert_eq!(pc.current_lim(), CurrentLim::Milli200);
    /// ```
    pub const fn current_lim(&self) -> CurrentLim {
        match (self.val >> 4) & 0b11 {
            0x0 => CurrentLim::Milli25,
            0x1 => CurrentLim::Milli50,
            0x2 => CurrentLim::Milli100,
            _ => CurrentLim::Milli200,
        }
    }
}

impl From<PwrCtrl> for u8 {
    fn from(bs: PwrCtrl) -> Self {
        bs.val
    }
}

impl Default for PwrCtrl {
    fn default() -> Self {
        Self::RESET
    }
}