Home | History | Annotate | Download | only in ds1307
      1 /*
      2  * Author: Jon Trulson <jtrulson (at) ics.com>
      3  * Copyright (c) 2014 Intel Corporation.
      4  *
      5  * Adapted from Seeed Studio library:
      6  * https://github.com/Seeed-Studio/RTC_DS1307
      7  *
      8  * Permission is hereby granted, free of charge, to any person obtaining
      9  * a copy of this software and associated documentation files (the
     10  * "Software"), to deal in the Software without restriction, including
     11  * without limitation the rights to use, copy, modify, merge, publish,
     12  * distribute, sublicense, and/or sell copies of the Software, and to
     13  * permit persons to whom the Software is furnished to do so, subject to
     14  * the following conditions:
     15  *
     16  * The above copyright notice and this permission notice shall be
     17  * included in all copies or substantial portions of the Software.
     18  *
     19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     22  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     23  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     24  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     25  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     26  */
     27 
     28 #include <iostream>
     29 #include <string>
     30 #include <stdexcept>
     31 
     32 #include "ds1307.h"
     33 
     34 using namespace upm;
     35 using namespace std;
     36 
     37 
     38 DS1307::DS1307(int bus) : m_i2c(bus)
     39 {
     40   // setup our i2c link
     41   mraa::Result ret = m_i2c.address(DS1307_I2C_ADDR);
     42   if (ret != mraa::SUCCESS){
     43     throw std::invalid_argument(std::string(__FUNCTION__) +
     44                                   ": i2c.address() failed");
     45     return;
     46   }
     47 }
     48 
     49 mraa::Result DS1307::writeBytes(uint8_t reg, uint8_t *buffer, int len)
     50 {
     51   if (!len || !buffer)
     52     return mraa::ERROR_INVALID_PARAMETER;
     53 
     54   // create a buffer 1 byte larger than the supplied buffer,
     55   // store the register in the first byte
     56   uint8_t buf2[len + 1];
     57 
     58   buf2[0] = reg;
     59 
     60   // copy in the buffer after the reg byte
     61   for (int i=1; i<(len + 1); i++)
     62     buf2[i] = buffer[i-1];
     63 
     64   mraa::Result ret = m_i2c.address(DS1307_I2C_ADDR);
     65   if (ret != mraa::SUCCESS){
     66       throw std::invalid_argument(std::string(__FUNCTION__) +
     67                                   ": i2c.address() failed");
     68       return ret;
     69   }
     70 
     71   return m_i2c.write(buf2, len + 1);
     72 }
     73 
     74 int DS1307::readBytes(uint8_t reg, uint8_t *buffer, int len)
     75 {
     76   if (!len || !buffer)
     77     return 0;
     78 
     79   mraa::Result ret = m_i2c.address(DS1307_I2C_ADDR);
     80   if (ret != mraa::SUCCESS){
     81       throw std::invalid_argument(std::string(__FUNCTION__) +
     82                                   ": i2c.address() failed");
     83       return 0;
     84   }
     85   m_i2c.writeByte(reg);
     86 
     87   return m_i2c.read(buffer, len);
     88 }
     89 
     90 bool DS1307::loadTime()
     91 {
     92   // read the first 7 registers
     93   uint8_t buffer[7];
     94   int bytesRead = readBytes(0, buffer, 7);
     95 
     96   if (bytesRead != 7)
     97     {
     98       // problem
     99       throw std::runtime_error(std::string(__FUNCTION__) +
    100                                ": failed to read expected 7 bytes from device");
    101       return false;
    102     }
    103 
    104   // We need to mask some control bits off of some of these values
    105   // and convert the result to decimal from BCD.  We also need to account
    106   // for format (AM/PM or 24hr), and if AM/PM, whether PM should be set.
    107 
    108   // first bit here is the oscillator enable/disable bit
    109   seconds = bcdToDec(buffer[0] & 0x7f);
    110   minutes = bcdToDec(buffer[1]);
    111 
    112   // check AM/PM or 24hr mode
    113   if (buffer[2] & 0x40)
    114     {
    115       // We are in AM/PM mode
    116       hours = bcdToDec(buffer[2] & 0x1f);
    117       amPmMode = true;
    118       pm = (buffer[2] & 0x20) ? true : false;
    119     }
    120   else
    121     {
    122       // 24hr mode
    123       hours = bcdToDec(buffer[2] & 0x3f);
    124       amPmMode = false;
    125       pm = false;
    126     }
    127 
    128   dayOfWeek = bcdToDec(buffer[3]);
    129   dayOfMonth = bcdToDec(buffer[4]);
    130   month = bcdToDec(buffer[5]);
    131   year = bcdToDec(buffer[6]);
    132 
    133   return true;
    134 }
    135 
    136 bool DS1307::setTime()
    137 {
    138   uint8_t buffer[7];
    139 
    140   // seconds
    141   // we need to read in seconds first to preserve the osc enable bit
    142   uint8_t tmpbuf;
    143 
    144   readBytes(0, &tmpbuf, 1);
    145   buffer[0] = decToBcd(seconds) | (tmpbuf & 0x80);
    146 
    147   // minutes
    148   buffer[1] = decToBcd(minutes);
    149 
    150   // hours
    151   if (amPmMode)
    152     {
    153       buffer[2] = decToBcd(hours) | 0x40;
    154       if (pm)
    155         buffer[2] |= 0x20;
    156     }
    157   else
    158     buffer[2] = decToBcd(hours);
    159 
    160   // day of week
    161   buffer[3] = decToBcd(dayOfWeek);
    162 
    163   // day of month
    164   buffer[4] = decToBcd(dayOfMonth);
    165 
    166   // month
    167   buffer[5] = decToBcd(month);
    168 
    169   // year
    170   buffer[6] = decToBcd(year);
    171 
    172   return writeBytes(0, buffer, 7);
    173 }
    174 
    175 mraa::Result DS1307::enableClock()
    176 {
    177   // the oscillator enable bit is the high bit of reg 0
    178   // so read it, clear it, and write it back.
    179 
    180   uint8_t buf;
    181   readBytes(0, &buf, 1);
    182 
    183   buf &= ~0x80;
    184 
    185   return writeBytes(0, &buf, 1);
    186 }
    187 
    188 mraa::Result DS1307::disableClock()
    189 {
    190   // the oscillator enable bit is the high bit of reg 0
    191   // so read it, set it, and write it back.
    192 
    193   uint8_t buf;
    194   readBytes(0, &buf, 1);
    195 
    196   buf |= 0x80;
    197 
    198   return writeBytes(0, &buf, 1);
    199 }
    200 
    201 
    202 // Convert decimal to BCD
    203 uint8_t DS1307::decToBcd(unsigned int val)
    204 {
    205   return ( (val/10*16) + (val%10) );
    206 }
    207 
    208 // Convert BCD to decimal
    209 unsigned int DS1307::bcdToDec(uint8_t val)
    210 {
    211   return ( (val/16*10) + (val%16) );
    212 }
    213 
    214