rv3028c7_rtc/
lib.rs

1#![cfg_attr(not(test), no_std)]
2
3
4pub use chrono::{Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Weekday};
5pub use rtcc::{  DateTimeAccess };
6
7use embedded_hal::blocking::i2c::{Write, Read, WriteRead};
8
9// Fixed i2c bus address of the device (7-bit)
10const RV3028_ADDRESS: u8 = 0xA4 >> 1;
11
12// Main time register addresses
13const REG_SECONDS: u8 = 0x00;
14// const REG_MINUTES: u8 = 0x01;
15// const REG_HOURS: u8 = 0x02;
16
17
18// Holds the current day of the week.
19// Each value represents one weekday that is assigned by the user.
20// Values will range from 0 to 6.
21// The weekday counter is simply a 3-bit counter which counts up to 6 and then resets to 0.
22const REG_WEEKDAY: u8 = 0x03;
23
24// Holds the current day of the month, in two binary coded decimal (BCD) digits.
25// Values will range from 01 to 31.
26// Leap years are correctly handled from 2000 to 2099.
27const REG_DATE: u8 = 0x04;
28
29// Holds the current month, in two binary coded decimal (BCD) digits.
30// Values will range from 01 to 12.
31// const REG_MONTH: u8 = 0x05;
32// const REG_YEAR: u8 = 0x06;
33
34// Holds the Minutes Alarm Enable bit AE_M,
35// and the alarm value for minutes,
36// in two binary coded decimal (BCD) digits.
37// Values will range from 00 to 59.
38const REG_MINUTES_ALARM: u8 = 0x07;
39
40// Holds the Hours Alarm Enable bit AE_H and the alarm value for hours,
41// in two binary coded decimal (BCD) digits.
42// - If the 12_24 bit is cleared (default value) (see Control 2 register),
43// the values will range from 0 to 23.
44// - If the 12_24 bit is set, the hour values will be from 1 to 12
45// and the AMPM bit will be 0 for AM hours and 1 for PM hours.
46// - If the 12_24 hour mode bit is changed then the value in the Hours Alarm register must be re-initialized.
47const REG_HOURS_ALARM: u8 = 0x08;
48
49// Holds the Weekday/Date Alarm (WADA) Enable bit AE_WD.
50// - If the WADA bit is 0 (Bit 5 in Register REG_CONTROL1),
51// it holds the alarm value for the weekday (weekdays assigned by the user),
52// in two binary coded decimal (BCD) digits.
53// Values will range from 0 to 6.
54// - If the WADA bit is 1, it holds the alarm value for the date, in two binary coded decimal (BCD)
55// digits. Values will range from 01 to 31.
56const REG_WEEKDAY_DATE_ALARM: u8 = 0x09;
57
58// This register is used to set the lower 8 bits of the 12 bit Timer Value (preset value)
59// for the Periodic Countdown Timer.
60// This value will be automatically reloaded into the Countdown Timer when it reaches zero
61// If the TRPT bit is 1, this value will be automatically reloaded into the Countdown Timer
62// when it reaches zero: this allows for periodic timer interrupts
63const REG_TIMER_VALUE0: u8 = 0x0A;
64
65// This register is used to set the upper 4 bits of the 12 bit Timer Value (preset value)
66// for the Periodic Countdown Timer.
67// If the TRPT bit is 1, this value will be automatically reloaded into the Countdown Timer
68// when it reaches zero: this allows for periodic timer interrupts
69// const REG_TIMER_VALUE1: u8 = 0x0B;
70
71const REG_TIMER_STATUS0: u8 = 0x0C; // Read-only lower 8 bits of Periodic Countdown Timer
72// const REG_TIMER_STATUS1: u8 = 0x0D; // Read-only upper 4 bits of Periodic Countdown Timer
73
74
75// This register is used to detect the occurrence of various interrupt events
76// and reliability problems in internal data.
77const REG_STATUS: u8 = 0x0E;
78
79// This register is used to configure
80// - the Alarm Interrupt function
81// - the Periodic Time Update Interrupt function
82// - and to select or set operations for the Periodic Countdown Timer.
83const REG_CONTROL1:u8  = 0x0F;
84
85// This register is used to control:
86// - interrupt event output for the INT̅ pin
87// - stop/start status of clock and calendar operations
88// - interrupt controlled clock output on CLKOUT pin
89// - hour mode and time stamp enable
90const REG_CONTROL2:u8 = 0x10;
91
92// Clock Interrupt Mask
93// This register is used to select a predefined interrupt for automatic clock output.
94// Setting a bit to 1 selects the corresponding interrupt.
95// Multiple interrupts can be selected.
96// After power on, no interrupt is selected (see CLOCK OUTPUT SCHEME).
97const REG_CLOCK_INTERRUPT_MASK:u8 = 0x12;
98
99// Event Control register: EHL, ET,TSR, TSOW, TSS
100const REG_EVENT_CONTROL: u8 = 0x13;
101
102// Time Stamp function registers (Event Logging)
103const REG_COUNT_EVENTS_TS: u8 = 0x14; // Count TS
104// const REG_SECONDS_TS: u8 = 0x15; // Seconds TS
105// const REG_MINUTES_TS: u8 = 0x16; // Minutes TS
106// const REG_HOURS_TS: u8 = 0x17; // Hours TS
107// const REG_DATE_TS: u8 = 0x18; // Date TS
108// const REG_MONTH_TS: u8 = 0x19; // Month TS
109// const REG_YEAR_TS: u8 = 0x1A; // Month TS
110
111
112// First address of "Unix Time Counter"
113const REG_UNIX_TIME_0: u8 = 0x1B;
114// const REG_UNIX_TIME_1: u8 = 0x1C;
115// const REG_UNIX_TIME_2: u8 = 0x1D;
116// const REG_UNIX_TIME_3: u8 = 0x1E;
117
118// REG_CONTROL1 "Control 1" register bits:
119#[repr(u8)]
120enum RegControl1Bits {
121  // TRPT / Timer Repeat bit. Single or Repeat countdown timer
122  TimerRepeatBit =  1 << 7,
123  // WADA / Weekday Alarm / Date Alarm selection bit
124  WadaBit = 1 << 5,
125  //  USEL / Update Interrupt Select bit. Seconds or minutes.
126  UselBit = 1 << 4,
127  //  EERD_BIT: u8 = 1 << 3,
128  // TE / Periodic Countdown Timer Enable bit.
129  TimerEnableBit = 1 << 2,
130  // TD / Timer Clock Frequency selection bits
131  TimerClockFreqBits = 0b11,
132}
133
134/// Countown timer clock frequency selector
135#[derive(Clone, Copy, Debug, PartialEq)]
136enum TimerClockFreq {
137  Hertz4096 = 0b00, // 4096 Hz, 244.14 μs period
138  Hertz64 = 0b01, // 64 Hz, 15.625 ms period
139  Hertz1 = 0b10, // 1 Hz, One second period
140  HertzSixtieth = 0b11, // 1/60 Hz, One minute period
141}
142
143// REG_STATUS Status register bits:
144#[repr(u8)]
145enum RegStatusBits {
146  //EEBUSY_BIT = 1 << 7,
147  // CLKF  / Clock Output Interrupt Flag
148  ClockIntFlagBit = 1 << 6,
149  // BSF bit
150  BackupSwitchFlag = 1 << 5,
151  // UF / Periodic Time Update Flag
152  TimeUpdateFlag = 1 << 4,
153  // TF bit / Periodic Countdown Timer Flag
154  PeriodicTimerFlag = 1 << 3,
155  // AF / Alarm Flag
156  AlarmFlagBit = 1 << 2,
157  // EVF / Event Flag (external event interrupt)
158  EventFlagBit = 1 << 1,
159  // PORF / Power On Reset Flag
160  PowerOnResetFlagBit = 1 << 0,
161}
162
163// EEPROM register addresses and commands
164const EEPROM_MIRROR_ADDRESS: u8 = 0x37;// RAM mirror of EEPROM config values
165// const EEPROM_CMD_READ: u8 = 0x00;
166// const EEPROM_CMD_WRITE: u8 = 0x01;
167
168
169// REG_EVENT_CONTROL Event Control register bits:   EHL, ET, TSR, TSOW, TSS
170#[repr(u8)]
171enum RegEventControlBits {
172  // EHL bit / Event High/Low Level (Rising/Falling Edge) selection for detection
173  EventHighLowBit = 1 << 6,
174  // ET bits / Event Filtering Time
175  EventFilteringTimeBits = 0b11 << 4,
176  // TSR bit
177  TimeStampResetBit = 1 << 2,
178  // TSOW bit
179  TimeStampOverwriteBit = 1 << 1,
180  // TSS / Time Stamp Source bit
181  TimeStampSourceBit = 1 << 0,
182}
183
184pub const TS_EVENT_SOURCE_EVI: u8 = 0; /// Event log source is external interrupt EVI (default)
185pub const TS_EVENT_SOURCE_BSF: u8 = 1; /// Event log source is backup power switchover
186
187// REG_CLOCK_INTERRUPT_MASK bits
188#[repr(u8)]
189enum RegClockIntMaskBits {
190  // CEIE / Clock output on Event Interrupt bit
191  ClockoutOnExtEvtBit = 1 << 3,
192  // CAIE / Clock output on Alarm Interrupt bit
193  ClockoutOnAlarmBit = 1 << 2,
194  // CTIE / Clock output on Periodic Countdown Timer Interrupt bit
195  ClockoutOnPctBit = 1 << 1,
196  // CUIE / Clock output on Periodic Time Update Interrupt bit
197  ClockoutOnUpdateBit = 1 << 0,
198}
199
200// REG_CONTROL2 "Control 2" register bits: TSE CLKIE UIE TIE AIE EIE 12_24 RESET
201#[repr(u8)]
202enum RegControl2Bits {
203  // TSE / Time Stamp Enable bit
204  TimeStampEnableBit = 1 << 7,
205  // CLKIE / Clock Output enabled by Interrupt source. (see also CLKOE)
206  ClockoutIntEnableBit = 1 << 6,
207  // UIE / Time Update Interrupt Enable
208  TimeUpdateIntEnableBit = 1 << 5,
209  // TIE Countdown Timer Interrupt Enable bit
210  TimerIntEnableBit = 1 << 4,
211  // AIE / Alarm Interrupt Enable bit
212  AlarmIntEnableBit = 1 << 3,
213  // EIE / Event Interrupt Enable bit
214  EventIntEnableBit = 1 << 2,
215}
216
217// EEPROM_MIRROR_ADDRESS / EEPROM mirror register bits:
218#[repr(u8)]
219enum RegEepromMirrorBits {
220  // CLKOE / CLKOUT Enable bit -- if 1 (default) then normal clock output
221  ClockoutOutputEnableBit = 1 << 7,
222  // BCIE / Backup Switchover Interrupt Enable bit bit
223  BackupSwitchIntEnableBit = 1 << 6,
224  // TCE bit
225  TrickleChargeEnableBit = 1 << 5,
226  // BackupSwitchoverLsm = 0b11 << 2,
227  // Backup Switchover Mode / BSM bits as DSM
228  BackupSwitchoverDsm = 0b01 << 2,
229  TrickleChargeResistanceBits = 0b11, // TCR bits
230}
231
232#[derive(Clone, Copy)]
233pub enum TrickleChargeCurrentLimiter {
234  Ohms3k = 0b00,
235  Ohms5k = 0b01,
236  Ohms9k = 0b10,
237  Ohms15k = 0b11,
238}
239
240// Special alarm register value
241const ALARM_NO_WATCH_FLAG: u8 = 1 <<  7;
242
243
244/// RV-3028-C7
245/// Extreme Low Power Real-Time Clock (RTC) Module with I2C-Bus Interface
246/// rust no_std driver (utilizes the embedded_hal i2c interface)
247pub struct RV3028<I2C> {
248  i2c: I2C,
249  mux_addr: u8,
250  mux_chan: u8,
251}
252
253impl<I2C, E> RV3028<I2C>
254  where
255    I2C: Write<Error = E> + Read<Error = E> + WriteRead<Error = E>,
256{
257
258  /// New driver instance, assumes that there is no i2c mux
259  /// sitting between the RTC and the host.
260  pub fn new(i2c: I2C) -> Self {
261    RV3028 {
262      i2c,
263      mux_addr: 0u8,
264      mux_chan: 0u8
265    }
266  }
267
268  /// Allows the caller to create a new driver instance with
269  /// an i2c mux between the RTC and the host.
270  /// - `mux_addr` : the i2c address of the mux itself
271  /// - `mux_chan` : the mux channel assigned to the RTC
272  pub fn new_with_mux(i2c: I2C, mux_addr: u8, mux_chan: u8) -> Self {
273    RV3028 {
274      i2c,
275      mux_addr,
276      mux_chan
277    }
278  }
279
280  // Converts a binary value to BCD format
281  fn bin_to_bcd(value: u8) -> u8 {
282    ((value / 10) << 4) | (value % 10)
283  }
284
285  // Converts a BCD value to binary format
286  fn bcd_to_bin(value: u8) -> u8 {
287    ((value & 0xF0) >> 4) * 10 + (value & 0x0F)
288  }
289
290  // If using an i2c mux, tell the mux to select our channel
291  fn select_mux_channel(&mut self) -> Result<(), E> {
292    if self.mux_addr != 0u8 {
293      self.i2c.write(self.mux_addr, &[self.mux_chan])
294    }
295    else {
296      Ok(())
297    }
298  }
299
300  // fn write_register(&mut self, reg: u8, data: u8) -> Result<(), E> {
301  //   self.select_mux_channel()?;
302  //   self.write_register_raw(reg, data)
303  // }
304
305  fn write_register_raw(&mut self, reg: u8, data: u8) -> Result<(), E> {
306    self.i2c.write(RV3028_ADDRESS, &[reg, data])
307  }
308
309  // fn read_register(&mut self, reg: u8) -> Result<u8, E> {
310  //   self.select_mux_channel()?;
311  //   self.read_register_raw(reg)
312  // }
313
314  fn read_register_raw(&mut self, reg: u8) -> Result<u8, E> {
315    let mut buf = [0];
316    self.i2c.write_read(RV3028_ADDRESS, &[reg], &mut buf)?;
317    Ok(buf[0])
318  }
319
320
321  /// Check whether the Power On Reset flag is set.
322  /// If this flag is cleared (set to zero) beforehand,
323  /// indicates a voltage drop below VPOR.
324  /// If this flag is set, the data in the device RAM registers are no longer valid
325  /// and all registers must be (re)initialized.
326  /// The flag value 1 is retained until a 0 is written by the user.
327  /// At power up (POR) the value is set to 1, the user has to write 0 to the flag to use it.
328  pub fn check_and_clear_power_on_reset(&mut self) -> Result<bool, E>  {
329    let flag_set = 0 != self.check_and_clear_bits(
330      REG_STATUS, RegStatusBits::PowerOnResetFlagBit as u8)?;
331    Ok(flag_set)
332  }
333
334  /// Check whether an external event has been detected
335  /// (an appropriate input signal on the EVI pin)
336  pub fn check_and_clear_ext_event(&mut self)-> Result<bool, E>  {
337    let flag_set = 0 != self.check_and_clear_bits(
338      REG_STATUS, RegStatusBits::EventFlagBit as u8)?;
339    Ok(flag_set)
340  }
341
342  // TODO these methods have not been thoroughly tested, and are believed broken.
343  // fn is_eeprom_busy(&mut self) -> Result<bool, E> {
344  //   let status = self.read_register(REG_STATUS)?;
345  //   Ok(status & EEBUSY_BIT != 0)
346  // }
347  //
348  // fn disable_auto_eeprom_refresh(&mut self) -> Result<(), E> {
349  //   let mut control_1 = self.read_register(REG_CONTROL1)?;
350  //   control_1 |= EERD_BIT; // Set EERD bit
351  //   self.write_register(REG_CONTROL1, control_1)
352  // }
353  //
354  // fn enable_auto_eeprom_refresh(&mut self) -> Result<(), E> {
355  //   let mut control_1 = self.read_register(REG_CONTROL1)?;
356  //   control_1 &= !(EERD_BIT); // Clear EERD bit
357  //   self.write_register(REG_CONTROL1, control_1)
358  // }
359  //
360  // pub fn eeprom_read(&mut self, address: u8) -> Result<u8, E> {
361  //   self.disable_auto_eeprom_refresh()?;
362  //   while self.is_eeprom_busy()? {}
363  //   // Read from EEPROM
364  //   self.write_register(EEPROM_ADDRESS, address)?;
365  //   let res = self.read_register(EEPROM_ADDRESS);
366  //   self.enable_auto_eeprom_refresh()?;
367  //   res
368  // }
369  //
370  // pub fn eeprom_write(&mut self, address: u8, data: u8) -> Result<(), E> {
371  //   self.disable_auto_eeprom_refresh()?;
372  //   while self.is_eeprom_busy()? {}
373  //   self.write_register(EEPROM_ADDRESS, address)?;
374  //   let res = self.write_register(EEPROM_ADDRESS, data);
375  //
376  //   self.enable_auto_eeprom_refresh()?;
377  //   res
378  // }
379
380  // // set specific bits in a register:
381  // // all bits must be high that you wish to set
382  // fn set_reg_bits(&mut self, reg: u8, bits: u8) -> Result<(), E> {
383  //   self.select_mux_channel()?;
384  //   self.set_reg_bits_raw(reg, bits)
385  // }
386
387  // Set specific bits in a register: "raw" means it skips the mux
388  // all bits must be high that you wish to set
389  fn set_reg_bits_raw(&mut self, reg: u8, bits: u8) -> Result<(), E> {
390    let mut reg_val = self.read_register_raw(reg)?;
391    reg_val |= bits; // Set bits that are high
392    self.write_register_raw(reg, reg_val)
393  }
394
395  // clear specific bits in a register:
396  // all bits must be high that you wish to be cleared
397  // fn clear_reg_bits(&mut self, reg: u8, bits: u8) -> Result<(), E> {
398  //   self.select_mux_channel()?;
399  //   self.clear_reg_bits_raw(reg,bits)
400  // }
401
402  // Clears specific bits in a register, skips the mux.
403  // All bits must be high that you wish to be cleared
404  fn clear_reg_bits_raw(&mut self, reg: u8, bits: u8) -> Result<(), E> {
405    let mut reg_val = self.read_register_raw(reg)?;
406    reg_val &= !(bits); // Clear  bits that are high
407    self.write_register_raw(reg, reg_val)
408  }
409
410  /// Enable or disable trickle charging
411  /// - `enable` enables trickle charging if true, disables if false
412  /// - `limit_resistance` Sets the current limiting resistor value: higher means less current
413  /// Disabling also resets the `limit_resistance` to 3 kΩ, the factory default.
414  /// Returns the status of trickle charging (true for enabled, false for disabled)
415  pub fn toggle_trickle_charge(&mut self, enable: bool,
416                               limit_resistance: TrickleChargeCurrentLimiter) -> Result<bool, E>  {
417    self.select_mux_channel()?;
418
419    // First disable charging before changing settings
420    self.clear_reg_bits_raw(
421      EEPROM_MIRROR_ADDRESS,  RegEepromMirrorBits::TrickleChargeEnableBit as u8)?;
422    // Reset TCR to 3 kΩ, the factory default, by clearing the TCR bits
423    self.clear_reg_bits_raw(
424      EEPROM_MIRROR_ADDRESS,  RegEepromMirrorBits::TrickleChargeResistanceBits as u8 )?;
425
426    if enable {
427      self.set_reg_bits_raw(EEPROM_MIRROR_ADDRESS, limit_resistance as u8)?; //TODO
428      self.set_reg_bits_raw(
429        EEPROM_MIRROR_ADDRESS, RegEepromMirrorBits::TrickleChargeEnableBit as u8)?;
430    }
431
432    // confirm the value set
433    let conf_val =
434      0 != self.read_register_raw(EEPROM_MIRROR_ADDRESS)?
435        & RegEepromMirrorBits::TrickleChargeEnableBit as u8;
436    Ok(conf_val)
437  }
438
439  /// Toggle whether the Vbackup power source should be used
440  /// when Vdd supply level drops below useful level.
441  /// - `enable` enables switching to Vbackup, disables if false
442  /// Returns the set value
443  pub fn toggle_backup_switchover(&mut self, enable: bool) -> Result<bool, E> {
444    self.select_mux_channel()?;
445    self.set_or_clear_reg_bits_raw(
446      EEPROM_MIRROR_ADDRESS, RegEepromMirrorBits::BackupSwitchoverDsm as u8, enable)?;
447    let conf_val =
448      0 != self.read_register_raw(
449        EEPROM_MIRROR_ADDRESS)? & RegEepromMirrorBits::BackupSwitchoverDsm as u8;
450    Ok(conf_val)
451  }
452
453  /// Disable all clock outputs triggered by interrupts
454  pub fn clear_all_int_clockout_bits(&mut self) -> Result<(), E> {
455    self.select_mux_channel()?;
456    self.clear_reg_bits_raw(REG_CLOCK_INTERRUPT_MASK,
457                            RegClockIntMaskBits::ClockoutOnExtEvtBit as u8 |
458                              RegClockIntMaskBits::ClockoutOnAlarmBit as u8 |
459                            RegClockIntMaskBits::ClockoutOnPctBit as u8 |
460                              RegClockIntMaskBits::ClockoutOnUpdateBit as u8)
461  }
462
463
464  /// Get the current value of the EEPROM mirror from RAM
465  pub fn get_eeprom_mirror_value(&mut self) -> Result<u8, E> {
466    self.select_mux_channel()?;
467    let reg_val = self.read_register_raw(EEPROM_MIRROR_ADDRESS)?;
468    Ok(reg_val)
469  }
470
471  // Set the bcd time tracking registers
472  // assumes `select_mux_channel` has already been called
473  fn set_time_raw(&mut self, time: &NaiveTime) -> Result<(), E> {
474    let write_buf = [
475      REG_SECONDS, // select the first register
476      Self::bin_to_bcd(time.second() as u8 ),
477      Self::bin_to_bcd(time.minute() as u8 ),
478      Self::bin_to_bcd(time.hour() as u8 )
479    ];
480    self.i2c.write(RV3028_ADDRESS, &write_buf)
481  }
482
483
484  // Set the internal BCD date registers.
485  // Note that only years from 2000 to 2099 are supported.
486  // Assumes `select_mux_channel` has already been called
487  fn set_date_raw(&mut self, date: &NaiveDate) -> Result<(), E> {
488    let year = if date.year() > 2000 { (date.year() - 2000) as u8} else {0};
489    let month = (date.month() % 13) as u8;
490    let day = (date.day() % 32) as u8;
491    let weekday = (date.weekday() as u8) % 7;
492
493    let write_buf = [
494      REG_WEEKDAY, // select the first register
495      Self::bin_to_bcd(weekday ),
496      Self::bin_to_bcd(day ),
497      Self::bin_to_bcd(month ),
498      Self::bin_to_bcd(year )
499    ];
500    self.i2c.write(RV3028_ADDRESS, &write_buf)
501  }
502
503  /// Get the year, month, day from the internal BCD registers
504  pub fn get_ymd(&mut self) -> Result<(i32, u8, u8), E> {
505    let mut read_buf = [0u8;3];
506    self.read_multi_registers(REG_DATE, &mut read_buf)?;
507    let day = Self::bcd_to_bin(read_buf[0]);
508    let month = Self::bcd_to_bin(read_buf[1]);
509    let year:i32 = Self::bcd_to_bin(read_buf[2]) as i32 + 2000;
510
511    Ok((year, month, day))
512  }
513
514  /// Get the hour, minute, second from the internal BCD registers
515  pub fn get_hms(&mut self) -> Result<(u8, u8, u8), E> {
516    let mut read_buf = [0u8;3];
517    self.read_multi_registers(REG_SECONDS, &mut read_buf)?;
518    let seconds = Self::bcd_to_bin(read_buf[0]);
519    let minutes = Self::bcd_to_bin(read_buf[1]);
520    let hours = Self::bcd_to_bin(read_buf[2]);
521    Ok( (hours, minutes, seconds) )
522  }
523
524  // read a block of registers all at once
525  fn read_multi_registers(&mut self, reg: u8, read_buf: &mut [u8] )  -> Result<(), E> {
526    self.select_mux_channel()?;
527    self.read_multi_registers_raw(reg, read_buf)
528  }
529
530  // read a block of registers all at once: skip mux
531  fn read_multi_registers_raw(&mut self, reg: u8, read_buf: &mut [u8] )  -> Result<(), E> {
532    self.i2c.write_read(RV3028_ADDRESS, &[reg], read_buf)
533  }
534
535  /// Set just the Unix time counter.
536  /// Prefer the `set_datetime` method to properly set all internal BCD registers.
537  /// Note:
538  /// - This does NOT set other internal BCD registers
539  /// such as Year or Hour: if you want to set those as well, use the
540  /// `set_datetime` method instead.
541  /// - This does not reset the prescaler pipeline,
542  /// which means subseconds are not reset to zero.
543  ///
544  pub fn set_unix_time(&mut self, unix_time: u32) -> Result<(), E> {
545    self.select_mux_channel()?;
546    self.set_unix_time_raw(unix_time)
547  }
548
549  // sets the unix time counter but skips the mux
550  fn set_unix_time_raw(&mut self, unix_time: u32) -> Result<(), E> {
551    let bytes = unix_time.to_le_bytes(); // Convert to little-endian byte array
552    self.i2c.write(RV3028_ADDRESS, &[REG_UNIX_TIME_0, bytes[0], bytes[1], bytes[2], bytes[3]])
553  }
554
555  /// Reads the value of the RTC's unix time counter, notionally seconds elapsed since the
556  /// common "unix epoch" in the year 1970. It cannot represent datetimes from prior to 1970.
557  /// - Note that this is an unsigned u32 value, with different characteristics from the
558  /// widely used rust / chrono i64 system timestamp.
559  /// - The RTC will continue to increment this counter until it wraps at 0xFFFFFFFF
560  /// which defers the "Year 2038 problem" until about the year 2106.
561  /// - Note that the RTC's automatic leap year correction is only valid until 2099
562  /// See the App Manual section "3.10. UNIX TIME REGISTERS"
563  pub fn get_unix_time(&mut self) -> Result<u32, E> {
564    let mut read_buf = [0u8; 4];
565    self.read_multi_registers(REG_UNIX_TIME_0, &mut read_buf)?;
566    let val = u32::from_le_bytes(read_buf);
567    Ok(val)
568  }
569
570  /// The vendor application manual suggest we read the unix time twice,
571  /// in case an internal increment or timestamp set is interspersed between the multi-byte read.
572  /// This method performs the recommended read-twice.
573  pub fn get_unix_time_blocking(&mut self) -> Result<u32, E> {
574    loop {
575      let val1 = self.get_unix_time()?;
576      let val2 = self.get_unix_time()?;
577
578      if val1 == val2 {
579        return Ok(val2)
580      }
581    }
582  }
583
584  /// Toggle whether EVI events trigger on high/rising or low/falling edges
585  pub fn toggle_event_high_low(&mut self, high: bool) -> Result<(), E> {
586    self.set_or_clear_reg_bits(REG_EVENT_CONTROL, RegEventControlBits::EventHighLowBit as u8, high)
587  }
588
589  /// Enable INT pin output when alarm occurs
590  pub fn toggle_alarm_int_enable(&mut self, enable: bool) -> Result<(), E> {
591    self.set_or_clear_reg_bits(REG_CONTROL2, RegControl2Bits::AlarmIntEnableBit as u8, enable)
592  }
593
594  /// Toggle whether the RTC outputs a pulse (active low) on INT pin,
595  /// when the countdown timer expires.
596  pub fn toggle_countdown_int_enable(&mut self, enable: bool) -> Result<(), E> {
597    self.set_or_clear_reg_bits(REG_CONTROL2, RegControl2Bits::TimerIntEnableBit as u8, enable)
598  }
599
600  /// Toggle whether interrupt signal is generated on the INT pin:
601  /// - when an External Event on EVI pin occurs and TSS = 0
602  /// - or when an Automatic Backup Switchover occurs and TSS = 1.
603  /// The signal on the INT pin is retained until the EVF flag is cleared
604  /// to 0 (no automatic cancellation)
605  pub fn toggle_ext_event_int_enable(&mut self, enable: bool) -> Result<(), E> {
606    self.set_or_clear_reg_bits(REG_CONTROL2, RegControl2Bits::EventIntEnableBit as u8, enable)
607  }
608
609  /// Toggles whether an interrupt signal is generated on the INT pin:
610  /// - when the time updates at either 1 second or 1 minute intervals
611  pub fn toggle_time_up_int_enable(&mut self, enable: bool) -> Result<(), E> {
612    self.set_or_clear_reg_bits(REG_CONTROL2, RegControl2Bits::TimeUpdateIntEnableBit as u8, enable)
613  }
614
615  /// Disable all INT pin output selector bits in RAM, excludes PORIE
616  pub fn clear_all_int_out_bits(&mut self) -> Result<(), E> {
617    self.select_mux_channel()?;
618    // UIE, TIE, AIE,  EIE
619    self.clear_reg_bits_raw(REG_CONTROL2,
620                        RegControl2Bits::TimeUpdateIntEnableBit as u8 |
621                          RegControl2Bits::TimerIntEnableBit as u8 |
622                          RegControl2Bits::AlarmIntEnableBit as u8 |
623                          RegControl2Bits::EventIntEnableBit as u8  )?;
624    // BSIE
625    self.clear_reg_bits_raw(
626      EEPROM_MIRROR_ADDRESS, RegEepromMirrorBits::BackupSwitchIntEnableBit as u8)?;
627
628    // PORIE -- must be set in EEPROM -- don't bother to set?
629    Ok(())
630  }
631
632
633  /// Clear all of the status registers that indicate whether
634  /// various conditions have triggered
635  pub fn clear_all_status_flags(&mut self) -> Result<(), E> {
636    self.select_mux_channel()?;
637    self.clear_reg_bits_raw(REG_STATUS,
638                            RegStatusBits::ClockIntFlagBit  as u8 |
639                              RegStatusBits::BackupSwitchFlag  as u8 |
640                              RegStatusBits::TimeUpdateFlag  as u8 |
641                              RegStatusBits::PeriodicTimerFlag  as u8 |
642                              RegStatusBits::AlarmFlagBit  as u8 |
643                              RegStatusBits::EventFlagBit  as u8 |
644                              RegStatusBits::PowerOnResetFlagBit as u8
645    )
646
647  }
648
649  /// - `int_enable` enables INT output on the periodic time updates
650  pub fn configure_periodic_time_update(&mut self, minutes: bool, int_enable: bool) -> Result<(), E> {
651    self.select_mux_channel()?;
652
653    // 1. Initialize bits UIE and UF to 0.
654    // 2. Choose the timer source clock and write the corresponding value in the USEL bit.
655    // 3. Set the UIE bit to 1 if you want to get a hardware interrupt on INT̅ ̅ ̅ ̅ ̅
656    // pin.
657    // 4. Set CUIE bit to 1 to enable clock output when a time update interrupt occurs. See also CLOCK OUTPUT
658    // SCHEME.
659    // 5. The first interrupt will occur after the next event, either second or minute change.
660
661    // UIE clear
662    self.clear_reg_bits_raw(
663      REG_CONTROL2, RegControl2Bits::TimeUpdateIntEnableBit as u8)?;
664    // UF clear
665    self.clear_reg_bits_raw(REG_STATUS, RegStatusBits::TimeUpdateFlag as u8)?;
666    // USEL set/clear
667    self.set_or_clear_reg_bits_raw(
668      REG_CONTROL1, RegControl1Bits::UselBit as u8, minutes)?;
669    // UIE re-set
670    self.set_or_clear_reg_bits_raw(
671      REG_CONTROL2, RegControl2Bits::TimeUpdateIntEnableBit as u8, int_enable)?;
672
673    Ok(())
674  }
675
676
677  /// Check the alarm status, and if it's triggered, clear it
678  /// return bool indicating whether the alarm triggered
679  pub fn check_and_clear_alarm(&mut self) -> Result<bool, E> {
680    // Check if the AF flag is set
681    let alarm_flag_set = 0 != self.check_and_clear_bits(
682      REG_STATUS, RegStatusBits::AlarmFlagBit as u8)?;
683    Ok(alarm_flag_set)
684  }
685
686  /// All-in-one method to set an alarm:
687  /// See the App Note section "Procedure to use the Alarm Interrupt"
688  /// Note only date/weekday, hour, minute are supported
689  /// - If `weekday` is provided then it'll setup a weekday alarm rather than date alarm
690  /// - `match_day` indicates whether the day (or weekday) should be matched for the alarm
691  /// - `match_hour` indicates whether the hour should be matched for the alarm
692  /// - `match_minute` indicates whether the minutes should be matched for the alarm
693  pub fn set_alarm(&mut self, datetime: &NaiveDateTime,
694                   weekday: Option<Weekday>, match_day: bool, match_hour: bool, match_minute: bool) -> Result<(), E> {
695
696    self.select_mux_channel()?;
697    // Initialize AF to 0; AIE/AlarmIntEnableBit is managed independently
698    self.clear_reg_bits_raw(REG_STATUS, RegStatusBits::AlarmFlagBit as u8)?;
699
700    // Procedure suggested by App Notes:
701    // 1. Initialize bits AIE and AF to 0.
702    // 2. Choose weekday alarm or date alarm (weekday/date) by setting the WADA bit.
703    // WADA = 0 for weekday alarm or WADA = 1 for date alarm.
704    // 3. Write the desired alarm settings in registers 07h to 09h. The three alarm enable bits, AE_M, AE_H and
705    // AE_WD, are used to select the corresponding register that has to be taken into account for match or not.
706    // See the following table.
707
708    // Clear WADA for weekday alarm, or set for date alarm
709    self.set_or_clear_reg_bits_raw(
710      REG_CONTROL1, RegControl1Bits::WadaBit as u8, !weekday.is_some())?;
711
712    let bcd_minute = Self::bin_to_bcd(datetime.time().minute() as u8);
713    self.write_register_raw(REG_MINUTES_ALARM,
714                        if match_minute { bcd_minute }
715                        else { ALARM_NO_WATCH_FLAG | bcd_minute })?;
716
717    let bcd_hour = Self::bin_to_bcd(datetime.time().hour() as u8);
718    self.write_register_raw(REG_HOURS_ALARM,
719                        if match_hour { bcd_hour  }
720                        else { ALARM_NO_WATCH_FLAG | bcd_hour })?;
721
722    if let Some(inner_weekday) = weekday {
723      let bcd_weekday = Self::bin_to_bcd(inner_weekday as u8);
724      self.write_register_raw(REG_WEEKDAY_DATE_ALARM,
725                          if match_day { bcd_weekday }
726                          else { ALARM_NO_WATCH_FLAG | bcd_weekday }
727      )?;
728    }
729    else {
730      let bcd_day = Self::bin_to_bcd(datetime.date().day() as u8);
731      self.write_register_raw(REG_WEEKDAY_DATE_ALARM,
732                          if match_day { bcd_day }
733                          else { ALARM_NO_WATCH_FLAG | bcd_day })?;
734    }
735
736    // Clear AF again in case the above setting process immediately triggered the alarm
737    self.clear_reg_bits_raw(REG_STATUS, RegStatusBits::AlarmFlagBit as u8)?;
738
739    Ok(())
740  }
741
742  /// Read the alarm settings
743  /// Matches are flag settings for whether the alarm should match day, hour, minute
744  ///
745  pub fn get_alarm_datetime_wday_matches(&mut self)
746    -> Result<(NaiveDateTime, Option<Weekday>, bool, bool, bool), E> {
747
748    self.select_mux_channel()?;
749
750    let raw_day = self.read_register_raw(REG_WEEKDAY_DATE_ALARM)?;
751    let match_day = 0 == (raw_day & ALARM_NO_WATCH_FLAG);
752    let day = Self::bcd_to_bin(0x7F & raw_day);
753
754    let raw_hour = self.read_register_raw(REG_HOURS_ALARM)?;
755    let match_hour = 0 == (raw_hour & ALARM_NO_WATCH_FLAG);
756    let hour = Self::bcd_to_bin(0x7F & raw_hour);
757
758    let raw_minutes = self.read_register_raw(REG_MINUTES_ALARM)?;
759    let match_minutes = 0 == (raw_minutes & ALARM_NO_WATCH_FLAG);
760    let minutes = Self::bcd_to_bin(0x7F & raw_minutes);
761
762    let mut weekday = None;
763
764    let wada_state = self.read_register_raw(REG_CONTROL1)? & RegControl1Bits::WadaBit as u8;
765
766    let dt =
767      if 0 == wada_state {
768        // weekday alarm
769        weekday = Some(Weekday::try_from(day).unwrap());
770        NaiveDateTime::UNIX_EPOCH.with_hour(hour as u32).unwrap()
771          .with_minute(minutes as u32).unwrap()
772      }
773      else {
774        // date alarm
775        NaiveDateTime::UNIX_EPOCH.with_day(day as u32).unwrap()
776          .with_hour(hour as u32).unwrap()
777          .with_minute(minutes as u32).unwrap()
778      };
779
780    Ok((dt, weekday, match_day, match_hour, match_minutes))
781  }
782
783
784
785  // If `set` is true, set the high bits given in `bits`, otherwise clear those bits
786  fn set_or_clear_reg_bits(&mut self, reg: u8, bits: u8, set: bool) -> Result<(), E> {
787    self.select_mux_channel()?;
788    self.set_or_clear_reg_bits_raw(reg, bits, set)
789  }
790
791  fn set_or_clear_reg_bits_raw(&mut self, reg: u8, bits: u8, set: bool) -> Result<(), E> {
792    if set {
793      self.set_reg_bits_raw(reg, bits)
794    }
795    else {
796      self.clear_reg_bits_raw(reg, bits)
797    }
798  }
799
800
801  /// Enables or disables default CLKOUT behavior
802  pub fn toggle_plain_clockout(&mut self, enable: bool) -> Result<(), E> {
803    self.select_mux_channel()?;
804    // TODO self.clear_reg_bits_raw(REG_STATUS, RegStatusBits::ClockIntFlagBit as u8)?;
805    self.set_or_clear_reg_bits_raw(
806      EEPROM_MIRROR_ADDRESS, RegEepromMirrorBits::ClockoutOutputEnableBit as u8, enable)
807  }
808
809  /// Enables or disables interrupt-controlled CLKOUT
810  pub fn toggle_int_clockout(&mut self, enable: bool)  -> Result<(), E> {
811    self.select_mux_channel()?;
812    self.set_or_clear_reg_bits_raw(
813    REG_CONTROL2,  RegControl2Bits::ClockoutIntEnableBit as u8, enable)
814  }
815
816  // Configure the Periodic Countdown Timer prior to the next countdown.
817  fn config_pct_raw(&mut self, value: u16, freq: TimerClockFreq, repeat: bool ) -> Result<(), E> {
818    let value_high: u8 = ((value >> 8) as u8) & 0x0F;
819    let value_low: u8 = (value & 0xFF) as u8;
820
821    // configure the timer clock source / period
822    self.clear_reg_bits_raw(REG_CONTROL1, RegControl1Bits::TimerEnableBit as u8)?;
823    self.set_or_clear_reg_bits_raw(REG_CONTROL1, RegControl1Bits::TimerRepeatBit as u8, repeat)?;
824
825    self.clear_reg_bits_raw(REG_CONTROL1, RegControl1Bits::TimerClockFreqBits as u8)?;
826    self.set_reg_bits_raw(REG_CONTROL1, freq as u8)?; //TODO verify
827
828    // write to REG_TIMER_VALUE0 and REG_TIMER_VALUE1
829    let write_buf = [ REG_TIMER_VALUE0, value_low, value_high];
830    self.i2c.write(RV3028_ADDRESS, &write_buf)?;
831
832    self.clear_reg_bits_raw(REG_STATUS, RegStatusBits::PeriodicTimerFlag as u8)?;
833    Ok(())
834  }
835
836  const MAX_PCT_TICKS: u16 = 0x0FFF; // 4095
837  const PCT_MILLIS_PERIOD:i64 = 15; // 15.625 ms period
838  const PCT_MICROS_PERIOD:i64 = 244; // 244.14 μs period
839
840  const MAX_PCT_COUNT:i64 = Self::MAX_PCT_TICKS as i64;
841  const MAX_PCT_MILLIS:i64 = Self::MAX_PCT_COUNT * Self::PCT_MILLIS_PERIOD;
842  const MAX_PCT_MICROS:i64 = Self::MAX_PCT_COUNT * Self::PCT_MICROS_PERIOD;
843  const PCT_MILLIS_SECOND_BARRIER: i64 =  Self::PCT_MILLIS_PERIOD*(1000/Self::PCT_MILLIS_PERIOD);
844
845  // Calculate the closest clock frequency and
846  // number of ticks to match the requested duration using the
847  // Periodic Countdown Timer (PCT)
848  fn pct_ticks_and_rate_for_duration(duration: &Duration) -> (u16, TimerClockFreq, Duration)
849  {
850    let whole_minutes = duration.num_minutes();
851    let whole_seconds = duration.num_seconds();
852    let whole_milliseconds = duration.num_milliseconds();
853    let frac_milliseconds = whole_milliseconds % 1_000;
854    let infrac_milliseconds = whole_milliseconds % Self::PCT_MILLIS_PERIOD;
855    let whole_microseconds = duration.num_microseconds().unwrap();
856
857    return if whole_minutes >= Self::MAX_PCT_COUNT {
858      (Self::MAX_PCT_TICKS, TimerClockFreq::HertzSixtieth, Duration::minutes(Self::MAX_PCT_COUNT))
859    } else if whole_seconds > Self::MAX_PCT_COUNT {
860      // use minutes
861      let ticks = whole_minutes;
862      (ticks as u16, TimerClockFreq::HertzSixtieth, Duration::minutes(ticks))
863    } else if  (whole_milliseconds > Self::MAX_PCT_MILLIS) ||
864      ((0 == frac_milliseconds) && (whole_milliseconds > Self::PCT_MILLIS_SECOND_BARRIER))  {
865      // use seconds
866      let ticks = whole_seconds;
867      (ticks as u16, TimerClockFreq::Hertz1, Duration::seconds(ticks))
868    } else if (whole_microseconds > Self::MAX_PCT_MICROS) ||
869      ((0 == infrac_milliseconds) && (whole_milliseconds >= Self::PCT_MILLIS_PERIOD)) {
870      // use milliseconds
871      let ticks = whole_milliseconds / Self::PCT_MILLIS_PERIOD;
872      (ticks as u16, TimerClockFreq::Hertz64,
873       Duration::milliseconds(ticks * Self::PCT_MILLIS_PERIOD))
874    } else {
875      // use microseconds
876      let ticks = whole_microseconds / Self::PCT_MICROS_PERIOD;
877      (ticks as u16, TimerClockFreq::Hertz4096,
878       Duration::microseconds(ticks * Self::PCT_MICROS_PERIOD))
879    }
880
881  }
882
883  /// Prepare the Periodic Countdown Timer for a countdown,
884  /// and optionally start the countdown.
885  ///
886  /// - `repeat`: If true, the countdown timer will repeat as a periodic timer.
887  /// If false, the countdown timer will only run once ("one-shot" mode).
888  /// Returns the estimated actual duration (which may vary from the requested duration
889  /// dur to discrete RTC clock ticks).
890  /// - `start`: If true, start the countdown
891  pub fn config_countdown_timer(&mut self, duration: &Duration,
892                                repeat: bool, start: bool
893  ) -> Result<Duration, E> {
894    let (ticks, freq, estimated) =
895      Self::pct_ticks_and_rate_for_duration(duration);
896
897    self.select_mux_channel()?;
898    self.config_pct_raw(ticks, freq, repeat)?;
899    if start {
900      self.set_reg_bits_raw(REG_CONTROL1, RegControl1Bits::TimerEnableBit as u8)?;
901    }
902
903    Ok(estimated)
904  }
905
906  /// Set whether the Periodic Countdown Timer mode is repeating (periodic) or one-shot.
907  /// - `enable`: If true, starts the timer countdown. If false, stops the timer.
908  pub fn toggle_countdown_timer(&mut self, enable: bool)  -> Result<(), E> {
909    self.set_or_clear_reg_bits(
910      REG_CONTROL1, RegControl1Bits::TimerEnableBit as u8, enable)
911  }
912
913  /// Check whether countdown timer has finished counting down, and clear it
914  pub fn check_and_clear_countdown(&mut self) -> Result<bool, E> {
915    let flag_set = 0 != self.check_and_clear_bits(
916      REG_STATUS, RegStatusBits::PeriodicTimerFlag as u8)?;
917    Ok(flag_set)
918  }
919
920  /// Read the current value of the Periodic Countdown Timer,
921  /// which is only valid after the timer has been enabled.
922  /// The meaning of the value depends on the configured TimerClockFreq
923  pub fn get_countdown_value(&mut self) -> Result<u16, E> {
924    let mut read_buf = [0u8;2];
925    self.read_multi_registers(REG_TIMER_STATUS0, &mut read_buf)?;
926    let value = ((read_buf[1] as u16) << 8) | (read_buf[0] as u16);
927    Ok(value)
928  }
929
930  // check and clear a flag
931  fn check_and_clear_bits(&mut self, reg: u8, bits: u8) -> Result<u8, E> {
932    self.select_mux_channel()?;
933    let reg_val = self.read_register_raw(reg)?;
934    let bits_val =  reg_val & bits;
935    if 0 != bits_val {
936      self.clear_reg_bits_raw(reg, bits)?;
937    }
938    Ok(bits_val)
939  }
940
941
942  /// Configure event detection on the EVI pin
943  /// - `rising` whether edge detection is on rising edge / high level
944  /// - `int_enable` whether events detected on EVI pin should generate an interrupt on INT pin
945  /// - `filtering` 00..11 time filtering
946  pub fn config_ext_event_detection(
947    &mut self, rising: bool, int_enable: bool, filtering: u8, clockout_enable: bool) -> Result<(), E>
948  {
949    self.select_mux_channel()?;
950
951    // 1. Initialize bits TSE and EIE to 0.
952    // 2. Clear flag EVF to 0.
953    // 4. Set EHL bit to 1 or 0 to choose high or low level (or rising or falling edge) detection on pin EVI.
954    // 5. Select EDGE DETECTION (ET = 00) or LEVEL DETECTION WITH FILTERING (ET ≠ 00).
955    // 8. Set CEIE bit to 1 to enable clock output when external event occurs. See also CLOCK OUTPUT SCHEME.
956    // 10. Set EIE bit to 1 if you want to get a hardware interrupt on INT̅ ̅ ̅ ̅ ̅
957    // pin.
958
959    // Pause listening for external events on EVI pin
960    // 1. Initialize EIE to 0.
961    self.clear_reg_bits_raw(REG_CONTROL2,
962                              RegControl2Bits::EventIntEnableBit  as u8)?;
963    // 2. Clear flag EVF to 0.
964    self.clear_reg_bits_raw(
965      REG_STATUS, RegStatusBits::EventFlagBit as u8)?;
966
967    // 4. Set EHL bit to 1 or 0 to choose high or low level
968    // (or rising or falling edge) detection on pin EVI.
969    self.set_or_clear_reg_bits_raw(
970      REG_EVENT_CONTROL, RegEventControlBits::EventHighLowBit as u8, rising)?;
971
972    // 5. Select EDGE DETECTION (ET = 00) or LEVEL DETECTION WITH FILTERING (ET ≠ 00).
973    self.clear_reg_bits_raw(REG_EVENT_CONTROL,RegEventControlBits::EventFilteringTimeBits as u8)?;
974    if 0 != filtering {
975      // TODO verify this sets the correct filtering
976      self.set_reg_bits_raw(REG_EVENT_CONTROL, filtering << 4)?;
977    }
978
979    // 8. Set CEIE bit to 1 to enable clock output when external event occurs.
980    // See also CLOCK OUTPUT SCHEME.
981    self.set_or_clear_reg_bits_raw(
982      REG_CLOCK_INTERRUPT_MASK, RegClockIntMaskBits::ClockoutOnExtEvtBit as u8, clockout_enable)?;
983
984    // 10. Set EIE bit to 1 if you want to get a hardware interrupt on INT pin
985    self.set_or_clear_reg_bits_raw(
986      REG_CONTROL2, RegControl2Bits::EventIntEnableBit as u8, int_enable)?;
987
988    Ok(())
989  }
990
991}
992
993
994pub trait EventTimeStampLogger {
995  /// Error type
996  type Error;
997
998  /// Enable or disable the Time Stamp Function for event logging
999  /// This logs external interrupts or other events
1000  fn toggle_timestamp_logging(&mut self, enable: bool) -> Result<(), Self::Error>;
1001
1002  /// clear out any existing logged event timestamps
1003  fn reset_timestamp_log(&mut self) -> Result<(), Self::Error>;
1004
1005  /// Setup time stamp logging for events
1006  /// - `evt_source` source for timestamp events, eg TS_EVENT_SOURCE_BSF
1007  /// - `overwrite` Save the most recent event timestamp?
1008  /// - `start` Should event timestamp logging immediately start?
1009  fn config_timestamp_logging(
1010    &mut self, evt_source: u8, overwrite: bool,   start: bool)
1011    -> Result<(), Self::Error>;
1012
1013  /// Get event count -- the number of events that have been logged since enabling logging
1014  /// Returns the count of events since last reset, and the datetime of one event
1015  fn get_event_count_and_datetime(&mut self) -> Result<(u32, Option<NaiveDateTime>), Self::Error>;
1016
1017  /// Enable or disable event time stamp overwriting
1018  /// If this is disabled (default), the first event time stamp is saved.
1019  /// If this is enabled, the most recent event time stamp is saved.
1020  fn toggle_time_stamp_overwrite(&mut self, enable: bool) -> Result<(), Self::Error>;
1021
1022  /// Select a source for events to be logged, device-specific
1023  fn set_event_timestamp_source(&mut self, source: u8) -> Result<(), Self::Error>;
1024}
1025
1026impl<I2C, E> DateTimeAccess for  RV3028<I2C>
1027  where
1028    I2C: Write<Error = E> + Read<Error = E> + WriteRead<Error = E>,
1029{
1030  type Error = E;
1031
1032  /// This particular RTC's timestamps wrap at 0xFFFF_FFFF, around the year 2106.
1033  /// It doesn't support:
1034  /// - years prior to 1970
1035  /// - leap year calculations past 2099
1036  fn datetime(&mut self) -> Result<NaiveDateTime, Self::Error> {
1037    let unix_timestamp = self.get_unix_time()?;
1038    Ok(NaiveDateTime::from_timestamp_opt(unix_timestamp.into(), 0).unwrap())
1039  }
1040
1041  /// This implementation assumes (but doesn't verify)
1042  /// that the caller is setting the RTC datetime to values within its range (from 2000 to 2099).
1043  /// The RTC doesn't support leap year corrections beyond 2099,
1044  /// and the internal Year BCD register only runs from 0..99 (for 2000..2099).
1045  /// This method resets the internal prescaler pipeline, which means that
1046  /// subsecond counters are zeroed, when it writes to the Seconds register.
1047  /// This assists with clock synchronization with external clocks.
1048  fn set_datetime(&mut self, datetime: &NaiveDateTime) -> Result<(), Self::Error> {
1049    let unix_timestamp: u32 = datetime.timestamp().try_into().unwrap();
1050    self.select_mux_channel()?;
1051    // unix timestamp counter is stored in registers separate from everything else:
1052    // this method tries to align both, because the unix timestamp is not
1053    // used by eg the Event or Alarm interrupts
1054    self.set_unix_time_raw(unix_timestamp)?;
1055    self.set_date_raw(&datetime.date())?;
1056    // this must come last because writing to the seconds register resets
1057    // the upper stage of the prescaler
1058    self.set_time_raw(&datetime.time())?;
1059    Ok(())
1060  }
1061
1062}
1063impl<I2C, E> EventTimeStampLogger for  RV3028<I2C>
1064  where
1065    I2C: Write<Error = E> + Read<Error = E> + WriteRead<Error = E>
1066{
1067  type Error = E;
1068
1069
1070  fn toggle_timestamp_logging(&mut self, enable: bool) -> Result<(), Self::Error> {
1071    self.select_mux_channel()?;
1072    self.set_or_clear_reg_bits_raw(REG_CONTROL2, RegControl2Bits::TimeStampEnableBit as u8, enable)
1073  }
1074
1075  fn reset_timestamp_log(&mut self) -> Result<(), Self::Error> {
1076    self.select_mux_channel()?;
1077    self.set_reg_bits_raw(
1078      REG_EVENT_CONTROL, RegEventControlBits::TimeStampResetBit as u8)
1079
1080  }
1081
1082  fn config_timestamp_logging(
1083    &mut self, evt_source: u8, overwrite: bool,  start:bool) -> Result<(), E>
1084  {
1085    self.select_mux_channel()?;
1086
1087    // Pause listening for events
1088    // 1. Initialize bits TSE to 0.
1089    self.clear_reg_bits_raw(REG_CONTROL2,
1090                            RegControl2Bits::TimeStampEnableBit as u8)?;
1091
1092    // 2. Clear EVF and BSF
1093    self.clear_reg_bits_raw(
1094      REG_STATUS, RegStatusBits::EventFlagBit as u8 | RegStatusBits::BackupSwitchFlag as u8)?;
1095
1096    // 3. Set TSS bit to
1097    // External Event Interrupt function (TSS = 0) or the
1098    // Automatic Backup Switchover Interrupt function (TSS = 1)
1099    // as time stamp source and initialize the appropriate function
1100    let enable_bsf = evt_source == TS_EVENT_SOURCE_BSF;
1101    self.set_or_clear_reg_bits_raw(
1102      REG_EVENT_CONTROL, RegEventControlBits::TimeStampSourceBit as u8, enable_bsf)?;
1103
1104    // 6. Set TSOW bit to 1 if the last occurred event has to be recorded and TS registers are overwritten.
1105    self.set_or_clear_reg_bits_raw(
1106      REG_EVENT_CONTROL, RegEventControlBits::TimeStampOverwriteBit as u8, overwrite)?;
1107
1108    // 7. Write 1 to TSR bit, to clear all Time Stamp registers to 0x00
1109    self.set_reg_bits_raw(
1110      REG_EVENT_CONTROL, RegEventControlBits::TimeStampResetBit as u8)?;
1111
1112    // 9. Set TSE bit to 1 if you want to enable the Time Stamp function.
1113    // see also: toggle_timestamp_logging
1114    self.set_or_clear_reg_bits_raw(
1115      REG_CONTROL2, RegControl2Bits::TimeStampEnableBit as u8, start)?;
1116
1117    // 1. Initialize bits TSE and EIE to 0.
1118    // 2. Clear flag EVF and BSF to 0.
1119    // 3. Set TSS bit to 0 to select External Event on EVI pin as Time Stamp and Interrupt source.
1120    // 6. Set TSOW bit to 1 to record the last occurred event (and TS registers are overwritten).
1121    // 7. Write 1 to TSR bit, to reset all Time Stamp registers to 00h. Bit TSR always returns 0 when read.
1122    // 9. Set TSE bit to 1 if you want to enable the Time Stamp function.
1123    // pin.
1124    Ok(())
1125  }
1126
1127  fn get_event_count_and_datetime(&mut self) -> Result<(u32, Option<NaiveDateTime>), Self::Error> {
1128    // Read the seven raw Time Stamp Function registers in one go
1129    let mut read_buf:[u8;7] = [0u8;7];
1130    self.read_multi_registers(REG_COUNT_EVENTS_TS, &mut read_buf)?;
1131
1132    // Convert BCD values to binary
1133    let count = read_buf[0]; // Count is already in binary
1134
1135    let odt = {
1136      if count > 0 {
1137        let seconds = Self::bcd_to_bin(read_buf[1]);
1138        let minutes = Self::bcd_to_bin(read_buf[2]);
1139        let hours = Self::bcd_to_bin(read_buf[3]);
1140        let date = Self::bcd_to_bin(read_buf[4]);
1141        let month = Self::bcd_to_bin(read_buf[5]);
1142        let year:i32 = Self::bcd_to_bin(read_buf[6]) as i32 + 2000;
1143        Some(NaiveDate::from_ymd_opt(year as i32, month as u32, date as u32)
1144        .expect("YMD")
1145          .and_hms_opt(hours as u32, minutes as u32, seconds as u32)
1146          .expect("HMS"))
1147      }
1148      else {
1149        None
1150      }
1151    };
1152
1153    Ok((count as u32, odt))
1154  }
1155
1156  fn toggle_time_stamp_overwrite(&mut self, enable: bool) -> Result<(), Self::Error> {
1157    self.set_or_clear_reg_bits(
1158      REG_EVENT_CONTROL, RegEventControlBits::TimeStampOverwriteBit as u8, enable)
1159  }
1160
1161  fn set_event_timestamp_source(&mut self, source: u8) -> Result<(), Self::Error> {
1162    let enable = TS_EVENT_SOURCE_BSF == source;
1163    self.set_or_clear_reg_bits(
1164      REG_EVENT_CONTROL, RegEventControlBits::TimeStampSourceBit as u8, enable)
1165  }
1166
1167}
1168
1169#[cfg(test)]
1170mod tests {
1171  use super::*;
1172  use embedded_hal_mock::i2c::{Mock as I2cMock, Transaction as I2cTrans};
1173  use std::vec;
1174
1175
1176  type TestClass = RV3028<I2cMock>;
1177
1178
1179  #[test]
1180  fn test_set_unix_time() {
1181    let unix_time: u32 = 1_614_456_789; // Example Unix time
1182    let bytes = unix_time.to_le_bytes(); // Convert to little-endian byte array
1183    let expectations = [
1184      I2cTrans::write(
1185        RV3028_ADDRESS,
1186        vec![
1187          REG_UNIX_TIME_0,
1188          bytes[0],
1189          bytes[1],
1190          bytes[2],
1191          bytes[3],
1192        ],
1193      ),
1194    ];
1195    let mock = I2cMock::new(&expectations);
1196    let mut rv3028 = RV3028::new(mock);
1197    rv3028.set_unix_time(unix_time).unwrap();
1198  }
1199
1200  #[test]
1201  fn test_get_unix_time() {
1202    let unix_time: u32 = 1_614_456_789; // Example Unix time
1203    let bytes = unix_time.to_le_bytes(); // Convert to little-endian byte array
1204    let expectations = [
1205      I2cTrans::write_read(
1206        RV3028_ADDRESS,
1207        vec![REG_UNIX_TIME_0],
1208        bytes.to_vec(),
1209      ),
1210      I2cTrans::write_read(
1211        RV3028_ADDRESS,
1212        vec![REG_UNIX_TIME_0],
1213        bytes.to_vec(),
1214      ),
1215    ];
1216    let mock = I2cMock::new(&expectations);
1217    let mut rv3028 = RV3028::new(mock);
1218    assert_eq!(rv3028.get_unix_time().unwrap(), unix_time);
1219  }
1220
1221  // The duration requested should exactly match the duration the RTC can deliver with
1222  // pct_ticks_and_rate_for_duration
1223  fn verify_whole_time_estimate(duration: &Duration, known_freq: TimerClockFreq, known_ticks: u16) {
1224    let (ticks, freq, estimated) =
1225      TestClass::pct_ticks_and_rate_for_duration(&duration);
1226    assert_eq!(freq, known_freq);
1227    assert_eq!(ticks, known_ticks);
1228    assert_eq!(*duration, estimated);
1229  }
1230
1231  // We know that the RTC can't precisely match the requested duration with
1232  // pct_ticks_and_rate_for_duration, so just match ticks and freq
1233  fn verify_ticks_and_freq(duration: &Duration, known_freq: TimerClockFreq, known_ticks: u16) {
1234    let (ticks, freq, _estimated) =
1235      TestClass::pct_ticks_and_rate_for_duration(&duration);
1236    assert_eq!(freq, known_freq);
1237    assert_eq!(ticks, known_ticks);
1238    // assert_eq!(*duration, estimated); // TODO calculate
1239  }
1240
1241  #[test]
1242  fn test_countdown_timer_conversion_minutes() {
1243    // should be fulfilled as minutes
1244    let minutes_clock_freq = TimerClockFreq::HertzSixtieth;
1245
1246    // request a longer countdown than th RTC can fulfill
1247    verify_ticks_and_freq(
1248      &Duration::minutes(TestClass::MAX_PCT_COUNT + 32),
1249      minutes_clock_freq, TestClass::MAX_PCT_TICKS);
1250
1251    verify_whole_time_estimate(
1252      &Duration::minutes(TestClass::MAX_PCT_COUNT),
1253      minutes_clock_freq, TestClass::MAX_PCT_TICKS);
1254
1255    // exceed the Seconds counter just slightly to invoke Minutes counter
1256    const MAX_SECONDS_IN_MINUTES: i64 = (TestClass::MAX_PCT_COUNT/ 60) + 1;
1257    verify_whole_time_estimate(
1258      &Duration::minutes(MAX_SECONDS_IN_MINUTES),
1259      minutes_clock_freq, MAX_SECONDS_IN_MINUTES as u16);
1260
1261    verify_whole_time_estimate(
1262      &Duration::minutes(2047),
1263      minutes_clock_freq, 2047);
1264
1265  }
1266
1267  #[test]
1268  fn test_countdown_timer_conversion_seconds() {
1269    // should be fulfilled as seconds
1270    let seconds_clock_freq = TimerClockFreq::Hertz1;
1271
1272    // Maximum seconds ticks
1273    verify_whole_time_estimate(
1274      &Duration::seconds(TestClass::MAX_PCT_COUNT),
1275      seconds_clock_freq, TestClass::MAX_PCT_TICKS);
1276
1277    verify_whole_time_estimate(
1278      &Duration::seconds(2047),
1279      seconds_clock_freq, 2047);
1280
1281    verify_whole_time_estimate(
1282      &Duration::seconds(61),
1283      seconds_clock_freq, 61);
1284
1285    // we serve whole minutes (under max seconds) with a seconds countdown
1286    verify_whole_time_estimate(
1287      &Duration::seconds(60),
1288      seconds_clock_freq, 60);
1289
1290    verify_whole_time_estimate(
1291      &Duration::minutes(1),
1292      seconds_clock_freq, 60);
1293
1294    verify_whole_time_estimate(
1295      &Duration::minutes(45),
1296      seconds_clock_freq, 45*60);
1297
1298    // minimum Seconds ticks
1299    verify_whole_time_estimate(
1300      &Duration::seconds(1),
1301      seconds_clock_freq, 1);
1302
1303  }
1304
1305  #[test]
1306  fn test_countdown_timer_conversion_micros() {
1307    // should be fulfilled as microseconds
1308    let micros_clock_freq = TimerClockFreq::Hertz4096;
1309
1310    verify_whole_time_estimate(
1311      &Duration::microseconds(TestClass::MAX_PCT_MICROS),
1312      micros_clock_freq, TestClass::MAX_PCT_TICKS);
1313
1314    verify_ticks_and_freq(
1315      &Duration::microseconds(2048),
1316      micros_clock_freq, (2048 / TestClass::PCT_MICROS_PERIOD) as u16);
1317
1318    verify_ticks_and_freq(
1319      &Duration::microseconds(655),
1320      micros_clock_freq, (655 / TestClass::PCT_MICROS_PERIOD) as u16);
1321
1322    verify_ticks_and_freq(
1323      &Duration::microseconds(1024),
1324      micros_clock_freq, (1024 / TestClass::PCT_MICROS_PERIOD) as u16);
1325
1326    // some exact micros values
1327
1328    verify_whole_time_estimate(
1329      &Duration::microseconds(999*TestClass::PCT_MICROS_PERIOD),
1330      micros_clock_freq, 999);
1331
1332    verify_whole_time_estimate(
1333      &Duration::microseconds(100*TestClass::PCT_MICROS_PERIOD),
1334      micros_clock_freq, 100);
1335
1336    verify_whole_time_estimate(
1337      &Duration::microseconds(17*TestClass::PCT_MICROS_PERIOD),
1338      micros_clock_freq, 17);
1339
1340    // minimum microseconds tick
1341    verify_whole_time_estimate(
1342      &Duration::microseconds(TestClass::PCT_MICROS_PERIOD),
1343      micros_clock_freq, 1);
1344
1345  }
1346
1347  #[test]
1348  fn test_countdown_timer_conversion_millis() {
1349    // should be fulfilled as milliseconds
1350    let millis_clock_freq = TimerClockFreq::Hertz64;
1351
1352    // a bit more than max micros counter, but less than max millis counter
1353    verify_ticks_and_freq(
1354      &Duration::microseconds(TestClass::MAX_PCT_MICROS + 1),
1355      millis_clock_freq,
1356      ((TestClass::MAX_PCT_MICROS + 1) / (TestClass::PCT_MILLIS_PERIOD * 1_000)) as u16
1357    );
1358
1359    // maximum millis counter
1360    verify_whole_time_estimate(
1361      &Duration::milliseconds(TestClass::MAX_PCT_MILLIS),
1362      millis_clock_freq, TestClass::MAX_PCT_TICKS);
1363
1364    // mid-value millis
1365    verify_ticks_and_freq(
1366      &Duration::milliseconds(2047),
1367      millis_clock_freq, (2047 / TestClass::PCT_MILLIS_PERIOD) as u16);
1368
1369    // exactly on the seconds clock
1370    verify_whole_time_estimate(
1371      &Duration::milliseconds(1000*TestClass::PCT_MILLIS_PERIOD),
1372      TimerClockFreq::Hertz1, TestClass::PCT_MILLIS_PERIOD as u16 );
1373
1374    // exactly on the millis period
1375
1376    verify_whole_time_estimate(
1377      &Duration::milliseconds(999*TestClass::PCT_MILLIS_PERIOD),
1378      millis_clock_freq, 999);
1379
1380    verify_whole_time_estimate(
1381      &Duration::milliseconds(100*TestClass::PCT_MILLIS_PERIOD),
1382      millis_clock_freq, 100);
1383
1384    // minimum millis ticks
1385    verify_whole_time_estimate(
1386      &Duration::milliseconds(TestClass::PCT_MILLIS_PERIOD),
1387      millis_clock_freq, 1);
1388
1389  }
1390
1391
1392
1393}
1394