@@ -69,7 +69,7 @@ void MCP79412RTC::read(tmElements_t &tm)
6969 tm.Second = bcd2dec (i2cRead () & ~_BV (ST));
7070 tm.Minute = bcd2dec (i2cRead ());
7171 tm.Hour = bcd2dec (i2cRead () & ~_BV (HR1224)); // assumes 24hr clock
72- tm.Wday = bcd2dec ( i2cRead () & ~(_BV (OSCON) | _BV (VBAT) | _BV (VBATEN)) ); // mask off OSCON, VBAT, VBATEN bits
72+ tm.Wday = i2cRead () & ~(_BV (OSCON) | _BV (VBAT) | _BV (VBATEN)); // mask off OSCON, VBAT, VBATEN bits
7373 tm.Day = bcd2dec (i2cRead ());
7474 tm.Month = bcd2dec (i2cRead () & ~_BV (LP)); // mask off the leap year bit
7575 tm.Year = y2kYearToTm (bcd2dec (i2cRead ()));
@@ -85,7 +85,7 @@ void MCP79412RTC::write(tmElements_t &tm)
8585 i2cWrite (0x00 ); // stops the oscillator (Bit 7, ST == 0)
8686 i2cWrite (dec2bcd (tm.Minute ));
8787 i2cWrite (dec2bcd (tm.Hour )); // sets 24 hour format (Bit 6 == 0)
88- i2cWrite (dec2bcd ( tm.Wday ) | _BV (VBATEN)); // enable battery backup operation
88+ i2cWrite (tm.Wday | _BV (VBATEN)); // enable battery backup operation
8989 i2cWrite (dec2bcd (tm.Day ));
9090 i2cWrite (dec2bcd (tm.Month ));
9191 i2cWrite (dec2bcd (tmYearToY2k (tm.Year )));
@@ -328,6 +328,161 @@ void MCP79412RTC::idRead(byte *uniqueID)
328328 for (byte i=0 ; i<UNIQUE_ID_SIZE; i++) uniqueID[i] = i2cRead ();
329329}
330330
331+ /* ----------------------------------------------------------------------*
332+ * Check to see if a power failure has occurred. If so, returns TRUE *
333+ * as the function value, and returns the power down and power up *
334+ * timestamps. After returning the time stamps, the RTC's timestamp *
335+ * registers are cleared and the VBAT bit which indicates a power *
336+ * failure is reset. *
337+ * *
338+ * Note that the power down and power up timestamp registers do not *
339+ * contain values for seconds or for the year. The returned time stamps *
340+ * will therefore contain the current year from the RTC. However, there *
341+ * is a chance that a power outage spans from one year to the next. *
342+ * If we find the power down timestamp to be later (larger) than the *
343+ * power up timestamp, we will assume this has happened, and well *
344+ * subtract one year from the power down timestamp. *
345+ * *
346+ * Still, there is an assumption that the timestamps are being read *
347+ * in the same year as that when the power up occurred. *
348+ * *
349+ * Finally, note that once the RTC records a power outage, it must be *
350+ * cleared before another will be recorded. *
351+ *----------------------------------------------------------------------*/
352+ boolean MCP79412RTC::powerFail (time_t *powerDown, time_t *powerUp)
353+ {
354+ byte day, yr; // copies of the RTC Day and Year registers
355+ tmElements_t dn, up; // power down and power up times
356+
357+ ramRead (DAY_REG, &day, 1 );
358+ ramRead (YEAR_REG, &yr, 1 );
359+ yr = y2kYearToTm (bcd2dec (yr));
360+ if ( day & _BV (VBAT) ) {
361+ Wire.beginTransmission (RTC_ADDR);
362+ i2cWrite (PWRDWN_TS_REG);
363+ Wire.endTransmission ();
364+
365+ Wire.requestFrom (RTC_ADDR, TIMESTAMP_SIZE); // read both timestamp registers, 8 bytes total
366+ dn.Second = 0 ;
367+ dn.Minute = bcd2dec (i2cRead ());
368+ dn.Hour = bcd2dec (i2cRead () & ~_BV (HR1224)); // assumes 24hr clock
369+ dn.Day = bcd2dec (i2cRead ());
370+ dn.Month = bcd2dec (i2cRead () & 0x1F ); // mask off the day, we don't need it
371+ dn.Year = yr; // assume current year
372+ up.Second = 0 ;
373+ up.Minute = bcd2dec (i2cRead ());
374+ up.Hour = bcd2dec (i2cRead () & ~_BV (HR1224)); // assumes 24hr clock
375+ up.Day = bcd2dec (i2cRead ());
376+ up.Month = bcd2dec (i2cRead () & 0x1F ); // mask off the day, we don't need it
377+ up.Year = yr; // assume current year
378+
379+ *powerDown = makeTime (dn);
380+ *powerUp = makeTime (up);
381+
382+ // clear the VBAT bit, which causes the RTC hardware to clear the timestamps too.
383+ // I suppose there is a risk here that the day has changed since we read it,
384+ // but the Day of Week is actually redundant data and the makeTime() function
385+ // does not use it. This could be an issue if someone is reading the RTC
386+ // registers directly, but as this library is meant to be used with the Time library,
387+ // and also because we don't provide a method to read the RTC clock/calendar
388+ // registers directly, we won't lose any sleep about it at this point unless
389+ // some issue is actually brought to our attention ;-)
390+ day &= ~_BV (VBAT);
391+ ramWrite (DAY_REG, &day , 1 );
392+
393+ // adjust the powerDown timestamp if needed (see notes above)
394+ if (*powerDown > *powerUp) {
395+ --dn.Year ;
396+ *powerDown = makeTime (dn);
397+ }
398+ }
399+ else
400+ return false ;
401+ }
402+
403+ /* ----------------------------------------------------------------------*
404+ * Enable or disable the square wave output. *
405+ *----------------------------------------------------------------------*/
406+ void MCP79412RTC::squareWave (uint8_t freq)
407+ {
408+ uint8_t ctrlReg;
409+
410+ ramRead (CTRL_REG, &ctrlReg, 1 );
411+ if (freq > 3 ) {
412+ ctrlReg &= ~_BV (SQWE);
413+ }
414+ else {
415+ ctrlReg = (ctrlReg & 0xF8 ) | _BV (SQWE) | freq;
416+ }
417+ ramWrite (CTRL_REG, &ctrlReg, 1 );
418+ }
419+
420+ /* ----------------------------------------------------------------------*
421+ * Set an alarm time. Sets the alarm registers only, does not enable *
422+ * the alarm. See enableAlarm(). *
423+ *----------------------------------------------------------------------*/
424+ void MCP79412RTC::setAlarm (uint8_t alarmNumber, time_t alarmTime)
425+ {
426+ tmElements_t tm;
427+ uint8_t day; // need to preserve bits in the day (of week) register
428+
429+ alarmNumber &= 0x01 ; // ensure a valid alarm number
430+ ramRead ( ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG) , &day, 1 );
431+ breakTime (alarmTime, tm);
432+ Wire.beginTransmission (RTC_ADDR);
433+ i2cWrite ( ALM0_REG + alarmNumber * (ALM1_REG - ALM0_REG) );
434+ i2cWrite (dec2bcd (tm.Second ));
435+ i2cWrite (dec2bcd (tm.Minute ));
436+ i2cWrite (dec2bcd (tm.Hour )); // sets 24 hour format (Bit 6 == 0)
437+ i2cWrite ( (day & 0xF8 ) + tm.Wday );
438+ i2cWrite (dec2bcd (tm.Day ));
439+ i2cWrite (dec2bcd (tm.Month ));
440+ Wire.endTransmission ();
441+ }
442+
443+ /* ----------------------------------------------------------------------*
444+ * Enable or disable an alarm, and set the trigger criteria, *
445+ * e.g. match only seconds, only minutes, entire time and date, etc. *
446+ *----------------------------------------------------------------------*/
447+ void MCP79412RTC::enableAlarm (uint8_t alarmNumber, uint8_t alarmType)
448+ {
449+ uint8_t day; // alarm day register has config & flag bits
450+ uint8_t ctrl; // control register has alarm enable bits
451+
452+ alarmNumber &= 0x01 ; // ensure a valid alarm number
453+ ramRead (CTRL_REG, &ctrl, 1 );
454+ if (alarmType < ALM_DISABLE) {
455+ ramRead (ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG), &day, 1 );
456+ day = ( day & 0x07 ) | alarmType << 4 ; // reset interrupt flag, OR in the config bits
457+ ramWrite (ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG), &day, 1 );
458+ ctrl |= _BV (ALM0 + alarmNumber); // enable the alarm
459+ }
460+ else {
461+ ctrl &= ~(_BV (ALM0 + alarmNumber)); // disable the alarm
462+ }
463+ ramWrite (CTRL_REG, &ctrl, 1 );
464+ }
465+
466+ /* ----------------------------------------------------------------------*
467+ * Returns true or false depending on whether the given alarm has been *
468+ * triggered, and resets the alarm "interrupt" flag. This is not a real *
469+ * interrupt, just a bit that's set when an alarm is triggered. *
470+ *----------------------------------------------------------------------*/
471+ boolean MCP79412RTC::alarm (uint8_t alarmNumber)
472+ {
473+ uint8_t day; // alarm day register has config & flag bits
474+
475+ alarmNumber &= 0x01 ; // ensure a valid alarm number
476+ ramRead ( ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG) , &day, 1 );
477+ if (day & _BV (ALMIF)) {
478+ day &= ~_BV (ALMIF); // turn off the alarm "interrupt" flag
479+ ramWrite ( ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG) , &day, 1 );
480+ return true ;
481+ }
482+ else
483+ return false ;
484+ }
485+
331486/* ----------------------------------------------------------------------*
332487 * Check to see if the RTC's oscillator is started (ST bit in seconds *
333488 * register). Returns true if started. *
0 commit comments