Wiblocks --- RTC

RTC/RTC.cpp

00001 // RTC clock library for the NB1A
00002 
00003 // DS1337 IC
00004 
00005 
00006 #include "RTC.h"
00007 #if defined(ARDUINO) && (ARDUINO >= 100)
00008 #include "Arduino.h"
00009 #else
00010 #endif
00011 
00012 extern "C" 
00013 {
00014 #if defined(ARDUINO) && (ARDUINO >= 100)
00015 #else
00016 #include <inttypes.h>
00017 #include "WConstants.h"
00018 #endif
00019 #include "TWI.h"
00020 }
00021 
00032 
00039 
00040 RTC::RTC() {
00041   
00042 };
00043 
00044 #define _rtc_reg_p_(reg) (reg <= RTC_LAST_REG ? 1 : 0)
00045 
00054 char RTC::write_reg(unsigned char reg, unsigned char v) {
00055   if (!_rtc_reg_p_(reg)) return(-1);
00056   _buf[0] = _i2c_wr_address;
00057   _buf[1] = reg;
00058   _buf[2] = v;
00059   twi_transmit(_buf, 3);
00060   return(0);
00061 }
00062 
00072 char RTC::write_regs(unsigned char reg, unsigned char *v, unsigned char n) {
00073   unsigned char *p;
00074   unsigned char i;
00075   if (!_rtc_reg_p_(reg)) return(-1);
00076   if (n > 16) return(-1);
00077   _buf[0] = _i2c_wr_address;
00078   _buf[1] = reg;
00079   p = v;
00080   for (i = 0; i < n; i++) _buf[i + 2] = *p++;
00081   twi_transmit(_buf, n + 2);
00082   return(0);
00083 }
00084 
00092 
00093 char RTC::write_reg_ptr(unsigned char reg) {
00094   if (!_rtc_reg_p_(reg)) return(-1);
00095   _buf[0] = _i2c_wr_address;
00096   _buf[1] = reg;
00097   twi_transmit(_buf, 2);
00098   return(0);
00099 }
00100 
00106 
00107 char RTC::read_regs() {
00108   unsigned char i;
00109   write_reg_ptr(0);
00110   _buf[0] = _i2c_rd_address;
00111   twi_transmit(_buf, 17); // 16 register bytes + ADDR
00112   delay(10);
00113   while(twi_busy_p());
00114   // retrieve the data bytes from the twi buffer
00115   if (!twi_status_reg.last_trans_ok) return(-1);
00116   twi_get_data(_regs.reg_array, 17);
00117   return(0);
00118 }
00119 
00120 
00127 
00128 unsigned char RTC::read_reg(unsigned char reg) {
00129   unsigned char i;
00130   unsigned char data[1];
00131   if (!_rtc_reg_p_(reg)) return(-2);
00132   write_reg_ptr(reg);
00133   _buf[0] = _i2c_rd_address;
00134   _buf[1] = reg;
00135   delay(10);
00136   twi_transmit(_buf, 2); // addr + reg
00137   while(twi_busy_p());
00138   // retrieve the data bytes from the twi buffer
00139   if (!twi_status_reg.last_trans_ok) return(-1);
00140   twi_get_data(data, 2);
00141   return(data[1]);
00142 }
00143 
00144 
00145 #define PM_BIT 0x02
00146 #define _rb_(name) (_regs.reg_bits.name)   ///< register bits for <B>name</B>
00147 #define _digit_(name) (_rb_(name) + '0')   ///< ASCII digit
00148 #define _hours_10_ ( _rb_(hour12) ? (_rb_(hours_10) & 0x01) : _rb_(hours_10)) ///< left digit of hours
00149 #define _hours_    ( _rb_(hours) )
00150 #define _pm_p_ (_rb_(hours_10) & PM_BIT)
00151 
00155 unsigned char RTC::get_secs()  { return(_rb_(secs_10) * 10 + _rb_(secs)); }
00159 unsigned char RTC::get_mins()  { return(_rb_(mins_10) * 10 + _rb_(mins)); }
00163 unsigned char RTC::get_hours() { return(_hours_10_ * 10 + _hours_); }
00167 unsigned char RTC::get_day()   { return(_rb_(day_10) * 10 + _rb_(day)); }
00171 unsigned char RTC::get_month() { return(_rb_(month_10) * 10 + _rb_(month)); }
00175 unsigned int  RTC::get_year()  { return(2000 + _rb_(year_10) * 10 + _rb_(year)); }
00176 
00177 // breaks a binary value into two BCD digits
00178 
00179 #define _break_(x, x10, x1) { x1  = x % 10; x10 = (unsigned char)((x - x1) / 10); }
00180 
00181 
00185 #define valid_year_p(y)  (((y > 2099) || (y < 2000)) ? 0 : 1)
00186 #define valid_month_p(m) (((m > 12)   || (m < 1))    ? 0 : 1)
00187 #define valid_day_p(d)   (((d > 31)   || (d < 1))    ? 0 : 1)
00188 
00189 
00196 unsigned char RTC::set_year(unsigned int year) {
00197   unsigned char y10;
00198   unsigned char y1; 
00199   if (year > 2099) return(-1);
00200   if (year < 2000) return(-1);
00201   year -= 2000;
00202   _break_(year, y10, y1);
00203   write_reg(RTC_REG_YEAR, (y10 << 4) | y1);
00204   return(0);
00205 }
00206 
00213 unsigned char RTC::set_month(unsigned char month) {
00214   unsigned char m10, m1;
00215   if (month > 12) return(-1);
00216   if (month < 1)  return(-1);
00217   _break_(month, m10, m1);
00218   write_reg(RTC_REG_MONTH, (m10 << 4) | m1);
00219   return(0);
00220 }
00221 
00228 unsigned char RTC::set_day(unsigned char day) {
00229   unsigned char d10, d1;
00230   if (day > 31) return(-1);
00231   if (day < 1)  return(-1);
00232   _break_(day, d10, d1);
00233   write_reg(RTC_REG_DAY, (d10 << 4) | d1);
00234   return(0);
00235 }
00236 
00246 unsigned char RTC::set_date(unsigned int year, unsigned char month, 
00247                             unsigned char day) {
00248   if (set_year(year)) return(-1);
00249   if (set_month(month)) return(-1);
00250   if (set_day(day)) return(-1);
00251   return(0);
00252 }
00253 
00254 
00261 unsigned char RTC::set_secs(unsigned char secs) {
00262   unsigned char s10, s1;
00263   if (secs > 59) return(-1);
00264   _break_(secs, s10, s1);
00265   write_reg(RTC_REG_SECS, (s10 << 4) | s1);
00266   return(0);
00267 }
00268 
00275 unsigned char RTC::set_mins(unsigned char mins) {
00276   unsigned char m10, m1;
00277   if (mins > 59) return(-1);
00278   _break_(mins, m10, m1);
00279   write_reg(RTC_REG_MINS, (m10 << 4) | m1);
00280   return(0);
00281 }
00282 
00284 union hours_reg {
00285   struct {
00286     unsigned hours    : 4;
00287     unsigned hours_10 : 1;
00288     unsigned pm       : 1;
00289     unsigned hour12   : 1;
00290     unsigned UNUSED   : 1;
00291   } _bits12; 
00292   struct {
00293     unsigned hours    : 4;
00294     unsigned hours_10 : 2;
00295     unsigned hour12   : 1;
00296     unsigned UNUSED   : 1;
00297   } _bits24; 
00298   unsigned char _byte; 
00299 };
00300 
00302 
00306 
00312 
00313 unsigned char RTC::set_hours12(unsigned char hours, unsigned char pm_p) {
00314   union hours_reg reg;
00315   if (hours > 12) return(-1);
00316   reg._bits12.hour12 = 1;
00317   reg._bits12.pm = pm_p ? 1 : 0;
00318   _break_(hours, reg._bits12.hours_10, reg._bits12.hours);
00319   write_reg(RTC_REG_HOURS, reg._byte);
00320   return(0);
00321 }
00322 
00328 
00329 unsigned char RTC::set_hours(unsigned char hours) {
00330   union hours_reg reg;
00331   if (hours > 23) return(-1);
00332   reg._bits24.hour12 = 0;
00333   _break_(hours, reg._bits24.hours_10, reg._bits24.hours);
00334   write_reg(RTC_REG_HOURS, reg._byte);
00335   return(0);
00336 }
00337 
00341 
00342 unsigned char RTC::set_time(unsigned char hours, unsigned char mins, 
00343                             unsigned char secs) {
00344   if (set_hours(hours)) return(-1);
00345   if (set_mins(mins)) return(-1);
00346   if (set_secs(secs)) return(-1);
00347   return(0);
00348 }
00349 
00357 
00358 unsigned char RTC::set_time12(unsigned char hours, 
00359                               unsigned char mins, 
00360                               unsigned char secs,
00361                               unsigned char pm_p) {
00362   if (set_hours12(hours, pm_p)) return(-1);
00363   if (set_mins(mins)) return(-1);
00364   if (set_secs(secs)) return(-1);
00365   return(0);
00366 }
00367 
00368 #define _ar_(n) alarm_reg._bits.n
00369 #define _a1_bits_(dy, m4, m3, m2, m1) { _ar_(a1_dy) = dy; \
00370                                         _ar_(a1m4) = m4; _ar_(a1m3) = m3; \
00371                                         _ar_(a1m2) = m2; _ar_(a1m1) = m1; }
00372 
00373 
00396 unsigned char RTC::set_alarm1(unsigned char mode, unsigned char day_or_dow,
00397                               unsigned char hours, unsigned char mins, 
00398                               unsigned char secs) {
00399   union {
00400     struct {
00401       unsigned a1_secs       : 4;
00402       unsigned a1_secs_10    : 3;
00403       unsigned a1m1          : 1;
00404       
00405       unsigned a1_mins       : 4;
00406       unsigned a1_mins_10    : 3;
00407       unsigned a1m2          : 1;
00408 
00409       unsigned a1_hours      : 4;
00410       unsigned a1_hours_10   : 2;
00411       unsigned a1_hour12     : 1;
00412       unsigned a1m3          : 1;
00413 
00414       unsigned a1_day        : 4;
00415       unsigned a1_day_10     : 2;
00416       unsigned a1_dy         : 1;
00417       unsigned a1m4          : 1;
00418     } _bits;
00419     unsigned char _bytes[4];
00420   } alarm_reg = { 0, 0, 0, 0 };
00421   switch(mode) {
00422   case RTC_ALARM1_MODE1: _a1_bits_(0, 1, 1, 1, 1); break;
00423   case RTC_ALARM1_MODE2: _a1_bits_(0, 1, 1, 1, 0); break;
00424   case RTC_ALARM1_MODE3: _a1_bits_(0, 1, 1, 0, 0); break;
00425   case RTC_ALARM1_MODE4: _a1_bits_(0, 1, 0, 0, 0); break;
00426   case RTC_ALARM1_MODE5: _a1_bits_(0, 0, 0, 0, 0); break;
00427   case RTC_ALARM1_MODE6: _a1_bits_(1, 0, 0, 0, 0); break;
00428   default:               _a1_bits_(0, 0, 0, 0, 0); break;
00429   }
00430   _break_(secs,       alarm_reg._bits.a1_secs_10,  alarm_reg._bits.a1_secs);
00431   _break_(mins,       alarm_reg._bits.a1_mins_10,  alarm_reg._bits.a1_mins);
00432   _break_(hours,      alarm_reg._bits.a1_hours_10, alarm_reg._bits.a1_hours);
00433   _break_(day_or_dow, alarm_reg._bits.a1_day_10,   alarm_reg._bits.a1_day);
00434 
00435   write_regs(RTC_REG_A1SECS, alarm_reg._bytes, 4);
00436 
00437   return(0);
00438 }
00439 
00444 unsigned char RTC::clear_alarm1(void) {
00445   unsigned char reg_value;
00446   reg_value = read_reg(RTC_REG_STATUS);
00447   reg_value &= ~RTC_A1F;
00448   write_reg(RTC_REG_STATUS, reg_value);
00449   return(0);
00450 }
00451 
00456 unsigned char RTC::enable_alarm1(void) {
00457   unsigned char reg_value;
00458   clear_alarm1();
00459   reg_value = read_reg(RTC_REG_CONTROL);
00460   reg_value |= RTC_A1IE;
00461   write_reg(RTC_REG_CONTROL, reg_value);
00462   return(0);
00463 }
00464 
00465 
00466 #define _substr_(str) { *p++ = _digit_(str##_10); *p++ = _digit_(str); }
00467 
00476 
00477 void RTC::localtime(char *str) {
00478   char *p;
00479   p = str;
00480   *p++ = '2';
00481   *p++ = '0';
00482   _substr_(year);  *p++ = '-';
00483   _substr_(month); *p++ = '-';
00484   _substr_(day);   *p++ = ' ';
00485   *p++ = _hours_10_ + '0';
00486   *p++ = _hours_ + '0';
00487   *p++ = ':';
00488   _substr_(mins);  *p++ = ':';
00489   _substr_(secs);  
00490   if (_rb_(hour12)) {
00491     *p++ = ' ';
00492     *p++ = _pm_p_ ? 'P' : 'A';
00493     *p++ = 'M';
00494   }
00495   *p   = '\0';
00496 }
00497 
00503 unsigned char RTC::get_reg(unsigned char reg) {
00504   if (reg > RTC_LAST_REG) return(0xFF);
00505   return(_regs.reg_array[reg + 1]);
00506 }
00507