mcp794xx/common/
mod.rs

1use crate::{interface, BitFlags, Config, Error, Mcp794xx, OutputPinLevel, Register, SqWFreq};
2pub mod alarm;
3pub mod conversion;
4pub mod datetime;
5pub mod sram;
6
7impl Config {
8    pub(crate) fn with_high(self, mask: u8) -> Self {
9        Config {
10            bits: self.bits | mask,
11        }
12    }
13    pub(crate) fn with_low(self, mask: u8) -> Self {
14        Config {
15            bits: self.bits & !mask,
16        }
17    }
18}
19
20impl<DI, E, IC> Mcp794xx<DI, IC>
21where
22    DI: interface::WriteData<Error = Error<E>> + interface::ReadData<Error = Error<E>>,
23{
24    /// Enable the oscillator (set the clock running).
25    pub fn enable(&mut self) -> Result<(), Error<E>> {
26        let seconds = self.iface.read_register(Register::SECONDS)?;
27        self.iface
28            .write_register(Register::SECONDS, seconds | BitFlags::ST)?;
29        self.is_enabled = true;
30        Ok(())
31    }
32
33    /// Disable the oscillator (stops the clock) (default).
34    pub fn disable(&mut self) -> Result<(), Error<E>> {
35        let seconds = self.iface.read_register(Register::SECONDS)?;
36        self.iface
37            .write_register(Register::SECONDS, seconds & !BitFlags::ST)?;
38        self.is_enabled = false;
39        Ok(())
40    }
41
42    /// Returns whether the oscillator is running.
43    #[allow(clippy::wrong_self_convention)]
44    pub fn is_oscillator_running(&mut self) -> Result<bool, Error<E>> {
45        let data = self.iface.read_register(Register::WEEKDAY)?;
46        Ok((data & BitFlags::OSCRUN) != 0)
47    }
48
49    /// Enable usage of external oscillator source.
50    pub fn enable_external_oscillator(&mut self) -> Result<(), Error<E>> {
51        self.write_control(self.control.with_high(BitFlags::EXTOSC))
52    }
53
54    /// Disable usage of external oscillator source (Will use internal source).
55    pub fn disable_external_oscillator(&mut self) -> Result<(), Error<E>> {
56        self.write_control(self.control.with_low(BitFlags::EXTOSC))
57    }
58
59    /// Enable square-wave output.
60    ///
61    /// Note that this is not available when running on backup battery power.
62    pub fn enable_square_wave(&mut self) -> Result<(), Error<E>> {
63        self.write_control(self.control.with_high(BitFlags::SQWEN))
64    }
65
66    /// Disable square-wave output.
67    pub fn disable_square_wave(&mut self) -> Result<(), Error<E>> {
68        self.write_control(self.control.with_low(BitFlags::SQWEN))
69    }
70
71    /// Set square-wave output frequency.
72    ///
73    /// Note that this setting will be ignored if the square-wave output is not
74    /// enabled or digital trimming is enabled.
75    pub fn set_square_wave_frequency(&mut self, frequency: SqWFreq) -> Result<(), Error<E>> {
76        let bits = match frequency {
77            SqWFreq::Hz1 => 0,
78            SqWFreq::Hz4_096 => 1,
79            SqWFreq::Hz8_192 => 2,
80            SqWFreq::Hz32_768 => 3,
81        };
82        let control = Config {
83            bits: (self.control.bits & 0b1111_1100) | bits,
84        };
85        self.write_control(control)
86    }
87
88    /// Set output pin logic level.
89    ///
90    /// Note that this setting will be ignored if the square-wave output or any
91    /// of the alarm interrupt outputs are enabled.
92    pub fn set_output_pin(&mut self, level: OutputPinLevel) -> Result<(), Error<E>> {
93        let control = match level {
94            OutputPinLevel::High => self.control.with_high(BitFlags::OUT),
95            OutputPinLevel::Low => self.control.with_low(BitFlags::OUT),
96        };
97        self.write_control(control)
98    }
99
100    /// Enable coarse trim mode.
101    pub fn enable_coarse_trim(&mut self) -> Result<(), Error<E>> {
102        self.write_control(self.control.with_high(BitFlags::CRSTRIM))
103    }
104
105    /// Disable coarse trim mode.
106    pub fn disable_coarse_trim(&mut self) -> Result<(), Error<E>> {
107        self.write_control(self.control.with_low(BitFlags::CRSTRIM))
108    }
109
110    /// Set digital trimming value.
111    ///
112    /// The sign determines whether the value will be added or substracted
113    /// to or from the 32.768kHz clock signal.
114    /// The argument value is always multiplied by two, so a value of 127
115    /// will add 254 clock cycles and a value of -50 will substract 100 cycles.
116    /// Depending on the digital trimming setting, this will be applied
117    /// either once per minute or 128 times per second.
118    /// Set to 0 or -128 to disable digital trimming.
119    pub fn set_trimming(&mut self, value: i8) -> Result<(), Error<E>> {
120        if value < 0 && value != -128 {
121            let rest = !(value - 1) as u8;
122            self.iface
123                .write_register(Register::OSCTRIM, 0b1000_0000 | rest)
124        } else {
125            self.iface.write_register(Register::OSCTRIM, value as u8)
126        }
127    }
128
129    fn write_control(&mut self, control: Config) -> Result<(), Error<E>> {
130        self.iface.write_register(Register::CONTROL, control.bits)?;
131        self.control = control;
132        Ok(())
133    }
134
135    #[allow(clippy::needless_pass_by_value)]
136    fn check_lt<T: PartialOrd>(value: T, reference: T) -> Result<(), Error<E>> {
137        if value < reference {
138            Ok(())
139        } else {
140            Err(Error::InvalidInputData)
141        }
142    }
143
144    #[allow(clippy::needless_pass_by_value)]
145    fn check_gt<T: PartialOrd>(value: T, reference: T) -> Result<(), Error<E>> {
146        if value > reference {
147            Ok(())
148        } else {
149            Err(Error::InvalidInputData)
150        }
151    }
152}