M5Unified
RTC8563_Class.cpp
Go to the documentation of this file.
1 // Copyright (c) M5Stack. All rights reserved.
2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 
4 #include "RTC8563_Class.hpp"
5 
6 #include <stdlib.h>
7 
8 namespace m5
9 {
10  tm rtc_datetime_t::get_tm(void) const
11  {
12  tm t_st = {
13  time.seconds,
14  time.minutes,
15  time.hours,
16  date.date,
17  date.month - 1,
18  date.year - 1900,
19  date.weekDay,
20  0,
21  0,
22  };
23  return t_st;
24  }
25 
26  void rtc_datetime_t::set_tm(tm& datetime)
27  {
28  date = rtc_date_t { datetime };
29  time = rtc_time_t { datetime };
30  }
31 
32  static std::uint8_t bcd2ToByte(std::uint8_t value)
33  {
34  return ((value >> 4) * 10) + (value & 0x0F);
35  }
36 
37  static std::uint8_t byteToBcd2(std::uint8_t value)
38  {
39  std::uint_fast8_t bcdhigh = value / 10;
40  return (bcdhigh << 4) | (value - (bcdhigh * 10));
41  }
42 
44  {
45  if (i2c)
46  {
47  _i2c = i2c;
48  i2c->begin();
49  }
51  writeRegister8(0x00, 0x00);
52  _init = writeRegister8(0x00, 0x00) && writeRegister8(0x0E, 0x03);
53  return _init;
54  }
55 
57  {
58  return readRegister8(0x02) & 0x80; // RTCC_VLSEC_MASK
59  }
60 
61  bool RTC8563_Class::getDateTime(rtc_datetime_t* datetime) const
62  {
63  std::uint8_t buf[7] = { 0 };
64 
65  if (!isEnabled() || !readRegister(0x02, buf, 7)) { return false; }
66 
67  datetime->time.seconds = bcd2ToByte(buf[0] & 0x7f);
68  datetime->time.minutes = bcd2ToByte(buf[1] & 0x7f);
69  datetime->time.hours = bcd2ToByte(buf[2] & 0x3f);
70 
71  datetime->date.date = bcd2ToByte(buf[3] & 0x3f);
72  datetime->date.weekDay = bcd2ToByte(buf[4] & 0x07);
73  datetime->date.month = bcd2ToByte(buf[5] & 0x1f);
74  datetime->date.year = bcd2ToByte(buf[6] & 0xff)
75  + ((0x80 & buf[5]) ? 1900 : 2000);
76  return true;
77  }
78 
79 
80  bool RTC8563_Class::getTime(rtc_time_t* time) const
81  {
82  std::uint8_t buf[3] = { 0 };
83 
84  if (!isEnabled() || !readRegister(0x02, buf, 3)) { return false; }
85 
86  time->seconds = bcd2ToByte(buf[0] & 0x7f);
87  time->minutes = bcd2ToByte(buf[1] & 0x7f);
88  time->hours = bcd2ToByte(buf[2] & 0x3f);
89  return true;
90  }
91 
92  void RTC8563_Class::setTime(const rtc_time_t& time)
93  {
94  std::uint8_t buf[] =
95  { byteToBcd2(time.seconds)
96  , byteToBcd2(time.minutes)
97  , byteToBcd2(time.hours)
98  };
99  writeRegister(0x02, buf, sizeof(buf));
100  }
101 
102  bool RTC8563_Class::getDate(rtc_date_t* date) const
103  {
104  std::uint8_t buf[4] = {0};
105 
106  if (!readRegister(0x05, buf, 4)) { return false; }
107 
108  date->date = bcd2ToByte(buf[0] & 0x3f);
109  date->weekDay = bcd2ToByte(buf[1] & 0x07);
110  date->month = bcd2ToByte(buf[2] & 0x1f);
111  date->year = bcd2ToByte(buf[3] & 0xff)
112  + ((0x80 & buf[2]) ? 1900 : 2000);
113  return true;
114  }
115 
116  void RTC8563_Class::setDate(const rtc_date_t& date)
117  {
118  std::uint8_t w = date.weekDay;
119  if (w > 6 && date.year >= 1900 && ((std::size_t)(date.month - 1)) < 12)
120  {
121  int32_t year = date.year;
122  int32_t month = date.month;
123  int32_t day = date.date;
124  if (month < 3) {
125  year--;
126  month += 12;
127  }
128  int32_t ydiv100 = year / 100;
129  w = (year + (year >> 2) - ydiv100 + (ydiv100 >> 2) + (13 * month + 8) / 5 + day) % 7;
130  }
131 
132  std::uint8_t buf[] =
133  { byteToBcd2(date.date)
134  , w
135  , (std::uint8_t)(byteToBcd2(date.month) + (date.year < 2000 ? 0x80 : 0))
136  , byteToBcd2(date.year % 100)
137  };
138  writeRegister(0x05, buf, sizeof(buf));
139  }
140 
141  int RTC8563_Class::setAlarmIRQ(int afterSeconds)
142  {
143  std::uint8_t reg_value = readRegister8(0x01) & ~0x0C;
144 
145  if (afterSeconds < 0)
146  { // disable timer
147  writeRegister8(0x01, reg_value & ~0x01);
148  writeRegister8(0x0E, 0x03);
149  return -1;
150  }
151 
152  std::size_t div = 1;
153  std::uint8_t type_value = 0x82;
154  if (afterSeconds < 270)
155  {
156  if (afterSeconds > 255) { afterSeconds = 255; }
157  }
158  else
159  {
160  div = 60;
161  afterSeconds = (afterSeconds + 30) / div;
162  if (afterSeconds > 255) { afterSeconds = 255; }
163  type_value = 0x83;
164  }
165 
166  writeRegister8(0x0E, type_value);
167  writeRegister8(0x0F, afterSeconds);
168 
169  writeRegister8(0x01, (reg_value | 0x01) & ~0x80);
170  return afterSeconds * div;
171  }
172 
173  int RTC8563_Class::setAlarmIRQ(const rtc_time_t &time)
174  {
175  union
176  {
177  std::uint32_t raw = ~0;
178  std::uint8_t buf[4];
179  };
180  bool irq_enable = false;
181 
182  if (time.minutes >= 0)
183  {
184  irq_enable = true;
185  buf[0] = byteToBcd2(time.minutes) & 0x7f;
186  }
187 
188  if (time.hours >= 0)
189  {
190  irq_enable = true;
191  buf[1] = byteToBcd2(time.hours) & 0x3f;
192  }
193 
194  writeRegister(0x09, buf, 4);
195 
196  if (irq_enable)
197  {
198  bitOn(0x01, 0x02);
199  } else {
200  bitOff(0x01, 0x02);
201  }
202 
203  return irq_enable;
204  }
205 
206  int RTC8563_Class::setAlarmIRQ(const rtc_date_t &date, const rtc_time_t &time)
207  {
208  union
209  {
210  std::uint32_t raw = ~0;
211  std::uint8_t buf[4];
212  };
213  bool irq_enable = false;
214 
215  if (time.minutes >= 0)
216  {
217  irq_enable = true;
218  buf[0] = byteToBcd2(time.minutes) & 0x7f;
219  }
220 
221  if (time.hours >= 0)
222  {
223  irq_enable = true;
224  buf[1] = byteToBcd2(time.hours) & 0x3f;
225  }
226 
227  if (date.date >= 0)
228  {
229  irq_enable = true;
230  buf[2] = byteToBcd2(date.date) & 0x3f;
231  }
232 
233  if (date.weekDay >= 0)
234  {
235  irq_enable = true;
236  buf[3] = byteToBcd2(date.weekDay) & 0x07;
237  }
238 
239  writeRegister(0x09, buf, 4);
240 
241  if (irq_enable)
242  {
243  bitOn(0x01, 0x02);
244  }
245  else
246  {
247  bitOff(0x01, 0x02);
248  }
249 
250  return irq_enable;
251  }
252 
254  {
255  return _init && (0x0C & readRegister8(0x01));
256  }
257 
259  {
260  if (!_init) { return; }
261  bitOff(0x01, 0x0C);
262  }
263 
265  {
266  if (!_init) { return; }
267  // disable alerm (bit7:1=disabled)
268  static constexpr const std::uint8_t buf[4] = { 0x80, 0x80, 0x80, 0x80 };
269  writeRegister(0x09, buf, 4);
270 
271  // disable timer (bit7:0=disabled)
272  writeRegister8(0x0E, 0);
273 
274  // clear flag and INT enable bits
275  writeRegister8(0x01, 0x00);
276  }
277 
279  {
280 #if !defined (M5UNIFIED_PC_BUILD)
281  rtc_datetime_t dt;
282  if (getDateTime(&dt))
283  {
284  tm t_st;
285  t_st.tm_isdst = -1;
286  t_st.tm_year = dt.date.year - 1900;
287  t_st.tm_mon = dt.date.month - 1;
288  t_st.tm_mday = dt.date.date;
289  t_st.tm_hour = dt.time.hours;
290  t_st.tm_min = dt.time.minutes;
291  t_st.tm_sec = dt.time.seconds;
292  timeval now;
293  // mktime(3) uses localtime, force UTC
294  char *oldtz = getenv("TZ");
295  setenv("TZ", "GMT0", 1);
296  tzset(); // Workaround for https://github.com/espressif/esp-idf/issues/11455
297  now.tv_sec = mktime(&t_st);
298  if (oldtz)
299  {
300  setenv("TZ", oldtz, 1);
301  } else {
302  unsetenv("TZ");
303  }
304  now.tv_usec = 0;
305  settimeofday(&now, tz);
306  }
307 #endif
308  }
309 }
int16_t value[3]
Definition: IMU_Base.hpp:0
void timezone
bool begin(i2c_port_t port_num, int pin_sda, int pin_scl)
Definition: I2C_Class.cpp:21
bool bitOn(std::uint8_t reg, std::uint8_t bit) const
Definition: I2C_Class.hpp:182
bool bitOff(std::uint8_t reg, std::uint8_t bit) const
Definition: I2C_Class.hpp:187
bool readRegister(std::uint8_t reg, std::uint8_t *result, std::size_t length) const
Definition: I2C_Class.hpp:177
std::uint8_t readRegister8(std::uint8_t reg) const
Definition: I2C_Class.hpp:165
I2C_Class * _i2c
Definition: I2C_Class.hpp:195
bool isEnabled(void) const
Definition: I2C_Class.hpp:192
bool writeRegister8(std::uint8_t reg, std::uint8_t data) const
Definition: I2C_Class.hpp:160
bool writeRegister(std::uint8_t reg, const std::uint8_t *data, std::size_t length) const
Definition: I2C_Class.hpp:172
bool getIRQstatus(void)
bool begin(I2C_Class *i2c=nullptr)
void setSystemTimeFromRtc(struct timezone *tz=nullptr)
rtc_date_t getDate(void) const
rtc_time_t getTime(void) const
bool getVoltLow(void)
rtc_datetime_t getDateTime(void) const
void setDate(const rtc_date_t &date)
void setTime(const rtc_time_t &time)
int setAlarmIRQ(int afterSeconds)
Definition: M5Unified.cpp:48