/* * Author: Jon Trulson <jtrulson@ics.com> * Copyright (c) 2014 Intel Corporation. * * Adapted from Seeed Studio library: * https://github.com/Seeed-Studio/RTC_DS1307 * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include <iostream> #include <string> #include <stdexcept> #include "ds1307.h" using namespace upm; using namespace std; DS1307::DS1307(int bus) : m_i2c(bus) { // setup our i2c link mraa::Result ret = m_i2c.address(DS1307_I2C_ADDR); if (ret != mraa::SUCCESS){ throw std::invalid_argument(std::string(__FUNCTION__) + ": i2c.address() failed"); return; } } mraa::Result DS1307::writeBytes(uint8_t reg, uint8_t *buffer, int len) { if (!len || !buffer) return mraa::ERROR_INVALID_PARAMETER; // create a buffer 1 byte larger than the supplied buffer, // store the register in the first byte uint8_t buf2[len + 1]; buf2[0] = reg; // copy in the buffer after the reg byte for (int i=1; i<(len + 1); i++) buf2[i] = buffer[i-1]; mraa::Result ret = m_i2c.address(DS1307_I2C_ADDR); if (ret != mraa::SUCCESS){ throw std::invalid_argument(std::string(__FUNCTION__) + ": i2c.address() failed"); return ret; } return m_i2c.write(buf2, len + 1); } int DS1307::readBytes(uint8_t reg, uint8_t *buffer, int len) { if (!len || !buffer) return 0; mraa::Result ret = m_i2c.address(DS1307_I2C_ADDR); if (ret != mraa::SUCCESS){ throw std::invalid_argument(std::string(__FUNCTION__) + ": i2c.address() failed"); return 0; } m_i2c.writeByte(reg); return m_i2c.read(buffer, len); } bool DS1307::loadTime() { // read the first 7 registers uint8_t buffer[7]; int bytesRead = readBytes(0, buffer, 7); if (bytesRead != 7) { // problem throw std::runtime_error(std::string(__FUNCTION__) + ": failed to read expected 7 bytes from device"); return false; } // We need to mask some control bits off of some of these values // and convert the result to decimal from BCD. We also need to account // for format (AM/PM or 24hr), and if AM/PM, whether PM should be set. // first bit here is the oscillator enable/disable bit seconds = bcdToDec(buffer[0] & 0x7f); minutes = bcdToDec(buffer[1]); // check AM/PM or 24hr mode if (buffer[2] & 0x40) { // We are in AM/PM mode hours = bcdToDec(buffer[2] & 0x1f); amPmMode = true; pm = (buffer[2] & 0x20) ? true : false; } else { // 24hr mode hours = bcdToDec(buffer[2] & 0x3f); amPmMode = false; pm = false; } dayOfWeek = bcdToDec(buffer[3]); dayOfMonth = bcdToDec(buffer[4]); month = bcdToDec(buffer[5]); year = bcdToDec(buffer[6]); return true; } bool DS1307::setTime() { uint8_t buffer[7]; // seconds // we need to read in seconds first to preserve the osc enable bit uint8_t tmpbuf; readBytes(0, &tmpbuf, 1); buffer[0] = decToBcd(seconds) | (tmpbuf & 0x80); // minutes buffer[1] = decToBcd(minutes); // hours if (amPmMode) { buffer[2] = decToBcd(hours) | 0x40; if (pm) buffer[2] |= 0x20; } else buffer[2] = decToBcd(hours); // day of week buffer[3] = decToBcd(dayOfWeek); // day of month buffer[4] = decToBcd(dayOfMonth); // month buffer[5] = decToBcd(month); // year buffer[6] = decToBcd(year); return writeBytes(0, buffer, 7); } mraa::Result DS1307::enableClock() { // the oscillator enable bit is the high bit of reg 0 // so read it, clear it, and write it back. uint8_t buf; readBytes(0, &buf, 1); buf &= ~0x80; return writeBytes(0, &buf, 1); } mraa::Result DS1307::disableClock() { // the oscillator enable bit is the high bit of reg 0 // so read it, set it, and write it back. uint8_t buf; readBytes(0, &buf, 1); buf |= 0x80; return writeBytes(0, &buf, 1); } // Convert decimal to BCD uint8_t DS1307::decToBcd(unsigned int val) { return ( (val/10*16) + (val%10) ); } // Convert BCD to decimal unsigned int DS1307::bcdToDec(uint8_t val) { return ( (val/16*10) + (val%16) ); }