@@ -181,8 +181,6 @@ void STM32LowPower::enableWakeupFrom(STM32RTC *rtc, voidFuncPtr callback, void *
181181 */
182182void STM32LowPower::programRtcWakeUp (uint32_t ms, LP_Mode lp_mode)
183183{
184- uint32_t epoc;
185- uint32_t sec;
186184 STM32RTC &rtc = STM32RTC::getInstance ();
187185 STM32RTC::Source_Clock clkSrc = rtc.getClockSource ();
188186
@@ -207,21 +205,108 @@ void STM32LowPower::programRtcWakeUp(uint32_t ms, LP_Mode lp_mode)
207205 }
208206 rtc.configForLowPower (clkSrc);
209207
208+ setAlarmTime (ms, rtc);
209+ }
210+
211+ static bool isLeapYear (uint8_t year2k)
212+ {
213+ int year = year2k + 2000 ;
214+
215+ // if year not divisible by 4 - not a leap year
216+ // else if year divisible by 4 and not by 100 - a leap year
217+ // else if year divisible by 400 - a leap year
218+ return (year % 4 != 0 ) ? false : (year % 100 != 0 ) ? true : year % 400 == 0 ;
219+ }
220+
221+ void STM32LowPower::setAlarmTime (uint32_t ms, STM32RTC &rtc)
222+ {
210223 if (ms != 0 ) {
211- // Convert millisecond to second
212- sec = ms / 1000 ;
213-
214- uint32_t epoc_ms;
215- ms = ms % 1000 ;
216- epoc = rtc.getEpoch (&epoc_ms);
217-
218- // Update epoch_ms - might need to add a second to epoch
219- epoc_ms += ms;
220- if (epoc_ms >= 1000 ) {
221- sec ++;
222- epoc_ms -= 1000 ;
224+ uint16_t subSecondsToAdd = ms % 1000 ;
225+
226+ ms = ms / 1000 ;
227+ uint8_t daysToAdd = ms / 86400 ;
228+ uint8_t hoursToAdd = (ms - daysToAdd * 86400 ) / 3600 ;
229+ uint8_t minutesToAdd = (ms - daysToAdd * 86400 - hoursToAdd * 3600 ) / 60 ;
230+ uint8_t secondsToAdd = (ms - daysToAdd * 86400 - hoursToAdd * 3600 - minutesToAdd * 60 );
231+
232+ uint8_t hrCurrent, minCurrent, secCurrent;
233+ uint32_t subSecondsCurrent;
234+ STM32RTC::AM_PM period;
235+ rtc.getTime (&hrCurrent, &minCurrent, &secCurrent, &subSecondsCurrent, &period);
236+
237+ uint8_t weekDay, currentDay, currentMonth, currentYear;
238+ rtc.getDate (&weekDay, ¤tDay, ¤tMonth, ¤tYear);
239+
240+ uint32_t ss = subSecondsCurrent + subSecondsToAdd;
241+ if (ss >= 1000 ) {
242+ ss -= 1000 ;
243+ secondsToAdd++;
244+ }
245+
246+ if (secondsToAdd >= 60 ) {
247+ secondsToAdd = 0 ;
248+ minutesToAdd++;
223249 }
250+ uint8_t s = secCurrent + secondsToAdd;
251+ if (s >= 60 ) {
252+ s -= 60 ;
253+ minutesToAdd++;
254+ }
255+
256+ if (minutesToAdd >= 60 ) {
257+ minutesToAdd -= 60 ;
258+ hoursToAdd++;
259+ }
260+ uint8_t m = minCurrent + minutesToAdd;
261+ if (m >= 60 ) {
262+ m -= 60 ;
263+ hoursToAdd++;
264+ }
265+
266+ if (hoursToAdd >= 24 ) {
267+ hoursToAdd -= 24 ;
268+ daysToAdd++;
269+ }
270+ uint8_t h = hrCurrent + hoursToAdd;
271+ if (rtc._format == STM32RTC::Hour_Format::HOUR_12) {
272+ if (h >= 24 ) {
273+ h -= 24 ;
274+ daysToAdd++;
275+ } else if (h >= 12 ) {
276+ if (period == STM32RTC::AM_PM::AM) {
277+ period = STM32RTC::AM_PM::PM;
278+ } else {
279+ period = STM32RTC::AM_PM::AM;
280+ daysToAdd++;
281+ }
282+
283+ if (h > 12 ) {
284+ h -= 12 ;
285+ }
286+ }
287+ } else if (h >= 24 ) {
288+ h -= 24 ;
289+ daysToAdd++;
290+ }
291+
292+ // numbers of days in each month (february is calculated based on leap year)
293+ static uint8_t daysInMonths[] = {31 , 0 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 };
294+ uint8_t endDay;
295+ if (currentMonth == 2 ) {
296+ endDay = isLeapYear (currentYear) ? 29 : 28 ;
297+ } else {
298+ endDay = daysInMonths[currentMonth];
299+ }
300+
301+ uint8_t d = currentDay + daysToAdd;
302+ if (d > endDay) {
303+ d -= endDay;
304+ }
305+
306+ // month-year overflow isn't handled because its not supported by RTC's alarm
224307
225- rtc.setAlarmEpoch (epoc + sec, STM32RTC::MATCH_DHHMMSS, epoc_ms);
308+ rtc.setAlarmTime (h, m, s, ss, period);
309+ rtc.setAlarmDay (d);
310+ rtc.enableAlarm (STM32RTC::Alarm_Match::MATCH_DHHMMSS);
226311 }
227312}
0 commit comments