• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Author: Jon Trulson <jtrulson@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 
DS1307(int bus)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 
writeBytes(uint8_t reg,uint8_t * buffer,int len)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 
readBytes(uint8_t reg,uint8_t * buffer,int len)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 
loadTime()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 
setTime()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 
enableClock()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 
disableClock()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
decToBcd(unsigned int val)203 uint8_t DS1307::decToBcd(unsigned int val)
204 {
205   return ( (val/10*16) + (val%10) );
206 }
207 
208 // Convert BCD to decimal
bcdToDec(uint8_t val)209 unsigned int DS1307::bcdToDec(uint8_t val)
210 {
211   return ( (val/16*10) + (val%16) );
212 }
213 
214