1#![no_implicit_prelude]
21
22extern crate core;
23extern crate rpsp;
24
25use core::cmp;
26use core::convert::Into;
27use core::marker::Send;
28use core::option::Option::{self, None, Some};
29use core::result::Result::{self, Err, Ok};
30
31use rpsp::clock::{AlarmConfig, RtcError, TimeSource};
32use rpsp::i2c::mode::Controller;
33use rpsp::i2c::{I2c, I2cAddress, I2cBus};
34use rpsp::int::Acknowledge;
35use rpsp::time::Time;
36
37const CMD_SAVED: u8 = 0x03u8;
38const CMD_CTRL_1: u8 = 0x00u8;
39const CMD_CTRL_2: u8 = 0x01u8;
40const CMD_ALARM2: u8 = 0x0Bu8;
41const CMD_STATUS: u8 = 0x04u8;
42const CMD_TIMER_MODE: u8 = 0x11u8;
43const CMD_TIMER_VALUE: u8 = 0x10u8;
44
45const ADDR: I2cAddress = I2cAddress::new_7bit(0x51u8);
46
47#[repr(u8)]
48pub enum PcfTick {
49 Speed4kHz = 0u8,
50 Speed64Hz = 1u8,
51 Speed1Hz = 2u8,
52 Slow = 3u8,
53}
54#[repr(u8)]
55pub enum PcfOutput {
56 Rate32kHz = 0u8,
57 Rate16kHz = 1u8,
58 Rate8kHz = 2u8,
59 Rate4kHz = 3u8,
60 Rate2kHz = 4u8,
61 Rate1kHz = 5u8,
62 Rate1Hz = 6u8,
63 Off = 7u8,
64}
65
66pub struct PcfRtc<'a> {
67 i2c: I2cBus<'a, Controller>,
68}
69
70impl<'a> PcfRtc<'a> {
71 #[inline(always)]
72 pub fn new(i2c: impl Into<I2cBus<'a, Controller>>) -> PcfRtc<'a> {
73 PcfRtc { i2c: i2c.into() }
74 }
75
76 #[inline(always)]
77 pub fn i2c_bus(&self) -> &I2c<Controller> {
78 &self.i2c
79 }
80 #[inline]
81 pub fn reset(&mut self) -> Result<(), RtcError> {
82 self.i2c.write(ADDR, &[CMD_CTRL_1, 0x58u8])?;
83 loop {
84 self.i2c.write(ADDR, &[CMD_STATUS, 0u8])?;
85 if self.is_stable()? {
86 break;
87 }
88 }
89 Ok(())
90 }
91 #[inline(always)]
92 pub fn now(&mut self) -> Result<Time, RtcError> {
93 self.now_inner()
94 }
95 #[inline(always)]
96 pub fn get_byte(&mut self) -> Result<u8, RtcError> {
97 self.read_reg(CMD_SAVED)
98 }
99 #[inline(always)]
100 pub fn is_24hr(&mut self) -> Result<bool, RtcError> {
101 Ok(self.read_reg(CMD_CTRL_1)? & 0x2 == 0)
102 }
103 #[inline(always)]
104 pub fn is_stable(&mut self) -> Result<bool, RtcError> {
105 Ok(self.read_reg(CMD_STATUS)? & 0x80 == 0)
106 }
107 #[inline]
108 pub fn alarm_disable(&mut self) -> Result<(), RtcError> {
109 self.i2c
112 .write(ADDR, &[CMD_ALARM2, 0x80u8, 0x80u8, 0x80u8, 0x80u8, 0x80u8])?;
113 Ok(())
114 }
115 #[inline]
116 pub fn timer_disable(&mut self) -> Result<(), RtcError> {
117 let v = self.read_reg(CMD_TIMER_MODE)?;
118 self.i2c.write(ADDR, &[CMD_TIMER_MODE, v & 0xF8])?;
126 Ok(())
127 }
128 #[inline(always)]
129 pub fn alarm_state(&mut self) -> Result<bool, RtcError> {
130 Ok(self.read_reg(CMD_CTRL_2)? & 0x40 != 0)
131 }
132 #[inline(always)]
133 pub fn timer_state(&mut self) -> Result<bool, RtcError> {
134 Ok(self.read_reg(CMD_CTRL_2)? & 0x8 != 0)
135 }
136 #[inline(always)]
137 pub fn set_byte(&mut self, v: u8) -> Result<(), RtcError> {
138 self.i2c.write(ADDR, &[CMD_SAVED, v])?;
139 Ok(())
140 }
141 pub fn set_time(&mut self, v: Time) -> Result<(), RtcError> {
142 if !v.is_valid() {
143 return Err(RtcError::InvalidTime);
144 }
145 let r = self.read_reg(CMD_CTRL_1)?;
146 self.i2c.write(ADDR, &[CMD_CTRL_1, r & 0xFD])?;
149 self.i2c.write(ADDR, &[
150 CMD_STATUS,
151 encode(v.secs),
152 encode(v.mins),
153 encode(v.hours),
154 encode(v.day),
155 encode(v.weekday as u8),
156 encode(v.month as u8),
157 encode(v.year.saturating_sub(0x7D0) as u8),
158 ])?;
159 Ok(())
160 }
161 #[inline]
162 pub fn set_24hr(&mut self, en: bool) -> Result<(), RtcError> {
163 let v = self.read_reg(CMD_CTRL_1)?;
164 self.i2c.write(ADDR, &[CMD_CTRL_1, if en { v & 0xFD } else { v | 0x2 }])?;
165 Ok(())
166 }
167 #[inline]
168 pub fn alarm_clear_state(&mut self) -> Result<bool, RtcError> {
169 let v = self.read_reg(CMD_CTRL_2)?;
170 self.i2c.write(ADDR, &[CMD_CTRL_2, v & 0xBF])?;
171 Ok(v & 0x40 != 0)
172 }
173 #[inline]
174 pub fn timer_clear_state(&mut self) -> Result<bool, RtcError> {
175 let v = self.read_reg(CMD_CTRL_2)?;
176 self.i2c.write(ADDR, &[CMD_CTRL_2, v & 0xF7])?;
177 Ok(v & 0x8 != 0)
178 }
179 #[inline(always)]
180 pub fn set_timer_ms(&mut self, ms: u32) -> Result<(), RtcError> {
181 let (t, s) = ms_to_ticks(ms).ok_or(RtcError::ValueTooLarge)?;
182 self.set_timer(t, s)
183 }
184 pub fn set_alarm(&mut self, v: AlarmConfig) -> Result<(), RtcError> {
185 if v.is_empty() {
186 return self.alarm_disable();
187 }
188 if !v.is_valid() {
189 return Err(RtcError::InvalidTime);
190 }
191 let r = self.read_reg(CMD_CTRL_1)?;
192 self.i2c.write(ADDR, &[CMD_CTRL_1, r & 0xFD])?;
195 self.i2c.write(ADDR, &[
196 CMD_ALARM2,
197 v.secs.map_or(0x80u8, encode),
198 v.mins.map_or(0x80u8, encode),
199 v.hours.map_or(0x80u8, encode),
200 v.day.map_or(0x80u8, |i| encode(i.get())),
201 v.weekday.map_or(0x80u8, |i| encode(i as u8)),
202 ])?;
203 Ok(())
204 }
205 #[inline]
206 pub fn set_alarm_interrupt(&mut self, en: bool) -> Result<(), RtcError> {
207 let v = self.read_reg(CMD_CTRL_2)?;
208 self.i2c.write(ADDR, &[
209 CMD_CTRL_2,
210 (if en { v | 0x80 } else { v & 0x7F }) & 0xBF,
211 ])?;
213 Ok(())
214 }
215 #[inline]
220 pub fn set_timer(&mut self, ticks: u8, speed: PcfTick) -> Result<(), RtcError> {
221 let v = self.read_reg(CMD_TIMER_MODE)?;
222 self.i2c.write(ADDR, &[
223 CMD_TIMER_VALUE,
224 ticks,
225 (v & 0xE7) | (((speed as u8) & 0x3) << 3) | 0x4,
226 ])?;
227 Ok(())
228 }
229 #[inline(always)]
230 pub fn set_time_from(&mut self, mut v: impl TimeSource) -> Result<(), RtcError> {
231 self.set_time(v.now().map_err(|e| e.into())?)
232 }
233 #[inline]
234 pub fn set_timer_interrupt(&mut self, en: bool, pulse: bool) -> Result<(), RtcError> {
235 self.timer_clear_state()?; let v = self.read_reg(CMD_TIMER_MODE)?;
237 self.i2c.write(ADDR, &[
238 CMD_TIMER_MODE,
239 (v & 0xFC) | if en { 0x2 } else { 0 } | if pulse { 0x1 } else { 0 },
240 ])?;
241 Ok(())
242 }
243
244 #[inline]
245 fn now_inner(&mut self) -> Result<Time, RtcError> {
246 let mut b: [u8; 7] = [0u8; 7];
247 self.i2c.write_single_then_read(ADDR, CMD_STATUS, &mut b)?;
248 let mut d = Time::new(
249 decode(b[6]) as u16 + 0x7D0,
250 decode(b[5]).into(),
251 decode(b[3]),
252 decode(b[2]),
253 decode(b[1]),
254 decode(b[0] & 0x7F),
255 decode(b[4]).into(),
256 );
257 if d.hours >= 24 {
258 d.hours = cmp::max(decode(b[2] & 0x7), 9) + if b[2] & 0x10 != 0 { 10 } else { 0 } + if b[2] & 0x20 != 0 { 12 } else { 0 }
269 }
270 if !d.is_valid() { Err(RtcError::InvalidTime) } else { Ok(d) }
271 }
272 #[inline]
273 fn read_reg(&mut self, r: u8) -> Result<u8, RtcError> {
274 self.i2c.write_single(ADDR, r)?;
275 Ok(self.i2c.read_single(ADDR)?)
276 }
277}
278
279impl TimeSource for PcfRtc<'_> {
280 type Error = RtcError;
281
282 #[inline(always)]
283 fn now(&mut self) -> Result<Time, RtcError> {
284 self.now_inner()
285 }
286}
287impl Acknowledge for PcfRtc<'_> {
288 #[inline(always)]
289 fn ack_interrupt(&mut self) -> bool {
290 self.alarm_clear_state().unwrap_or(false) | self.timer_clear_state().unwrap_or(false)
291 }
292}
293
294unsafe impl Send for PcfRtc<'_> {}
295
296#[inline]
297fn encode(v: u8) -> u8 {
298 let i = v / 10;
299 (v - (i * 10)) | (i << 4)
300}
301#[inline]
302fn decode(v: u8) -> u8 {
303 (v & 0xF) + ((v >> 4) & 0xF).wrapping_mul(10)
304}
305#[inline]
306fn ms_to_ticks(v: u32) -> Option<(u8, PcfTick)> {
307 match v {
308 0..=62 => Some((cmp::min((v * 1_000) / 244, 0xFF) as u8, PcfTick::Speed4kHz)),
309 0..=3_800 => Some((cmp::min(v / 15, 0xFF) as u8, PcfTick::Speed64Hz)),
310 0..=255_000 => Some((cmp::min(v / 1_000, 0xFF) as u8, PcfTick::Speed1Hz)),
311 0..=15_300_000 => Some((cmp::min((v / 1_000) / 60, 0xFF) as u8, PcfTick::Slow)),
312 _ => None,
313 }
314}