diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index b1c46d1d..6c97866b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -54,6 +54,7 @@ add_executable (am2315-example am2315.cxx) add_executable (itg3200-example itg3200.cxx) add_executable (enc03r-example enc03r.cxx) add_executable (adc121c021-example adc121c021.cxx) +add_executable (ds1307-example ds1307.cxx) include_directories (${PROJECT_SOURCE_DIR}/src/hmc5883l) include_directories (${PROJECT_SOURCE_DIR}/src/grove) @@ -95,6 +96,7 @@ include_directories (${PROJECT_SOURCE_DIR}/src/am2315) include_directories (${PROJECT_SOURCE_DIR}/src/itg3200) include_directories (${PROJECT_SOURCE_DIR}/src/enc03r) include_directories (${PROJECT_SOURCE_DIR}/src/adc121c021) +include_directories (${PROJECT_SOURCE_DIR}/src/ds1307) target_link_libraries (hmc5883l-example hmc5883l ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (groveled-example grove ${CMAKE_THREAD_LIBS_INIT}) @@ -152,3 +154,4 @@ target_link_libraries (am2315-example am2315 ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (itg3200-example itg3200 ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (enc03r-example enc03r ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (adc121c021-example adc121c021 ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (ds1307-example ds1307 ${CMAKE_THREAD_LIBS_INIT}) diff --git a/examples/ds1307.cxx b/examples/ds1307.cxx new file mode 100644 index 00000000..44a0b089 --- /dev/null +++ b/examples/ds1307.cxx @@ -0,0 +1,77 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2014 Intel Corporation. + * + * 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 +#include +#include "ds1307.h" + +using namespace std; + +void printTime(upm::DS1307 *rtc) +{ + cout << "The time is: " << + rtc->month << "/" << rtc->dayOfMonth << "/" << rtc->year << " " + << rtc->hours << ":" << rtc->minutes << ":" << rtc->seconds; + + if (rtc->amPmMode) + cout << (rtc->pm) ? " PM " : " AM "; + + cout << endl; + + cout << "Clock is in " << ((rtc->amPmMode) ? "AM/PM mode" : "24hr mode") + << endl; +} + +int +main(int argc, char **argv) +{ +//! [Interesting] + // Instantiate a DS1037 on I2C bus 0 + upm::DS1307 *rtc = new upm::DS1307(0); + + // always do this first + cout << "Loading the current time... " << endl; + if (!rtc->loadTime()) + { + cerr << "rtc->loadTime() failed." << endl; + return 0; + } + + printTime(rtc); + + // set the year as an example + cout << "setting the year to 50" << endl; + rtc->year = 50; + + rtc->setTime(); + + // reload the time and print it + rtc->loadTime(); + printTime(rtc); + + //! [Interesting] + + delete rtc; + return 0; +} diff --git a/examples/javascript/ds1307.js b/examples/javascript/ds1307.js new file mode 100644 index 00000000..9d11319a --- /dev/null +++ b/examples/javascript/ds1307.js @@ -0,0 +1,68 @@ +/*jslint node:true, vars:true, bitwise:true, unparam:true */ +/*jshint unused:true */ +/*global */ +/* +* Author: Zion Orent +* Copyright (c) 2014 Intel Corporation. +* +* 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. +*/ + +// Load RTC Clock module for Grove - RTC clock +var ds1307 = require('jsupm_ds1307'); +// load this on i2c bus 0 +var myRTCClockObj = new ds1307.DS1307(0); + +// always do this first +console.log("Loading the current time... "); + +var result = myRTCClockObj.loadTime(); +if (!result) +{ + console.log("myRTCClockObj.loadTime() failed."); + process.exit(1); +} + +printTime(myRTCClockObj); + +// set the year as an example +console.log("setting the year to 50"); +myRTCClockObj.year = 50; +myRTCClockObj.setTime(); + +// reload the time and print it +myRTCClockObj.loadTime(); +printTime(myRTCClockObj); + +function printTime(RTCObj) +{ + var timeStr = "The time is: " + + RTCObj.month + "/" + RTCObj.dayOfMonth + "/" + RTCObj.year + " " + + RTCObj.hours + ":" + RTCObj.minutes + ":" + RTCObj.seconds; + + if (RTCObj.amPmMode) + timeStr += (RTCObj.pm ? " PM " : " AM "); + + console.log(timeStr); + + console.log("Clock is in " + + (RTCObj.amPmMode ? "AM/PM mode" : "24hr mode")); +} + diff --git a/src/ds1307/CMakeLists.txt b/src/ds1307/CMakeLists.txt new file mode 100644 index 00000000..3ee7e08c --- /dev/null +++ b/src/ds1307/CMakeLists.txt @@ -0,0 +1,5 @@ +set (libname "ds1307") +set (libdescription "upm ds1307 RTC module") +set (module_src ${libname}.cxx) +set (module_h ${libname}.h) +upm_module_init() diff --git a/src/ds1307/ds1307.cxx b/src/ds1307/ds1307.cxx new file mode 100644 index 00000000..bc748e6b --- /dev/null +++ b/src/ds1307/ds1307.cxx @@ -0,0 +1,207 @@ +/* + * Author: Jon Trulson + * 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 +#include + +#include "ds1307.h" + +using namespace upm; +using namespace std; + + +DS1307::DS1307(int bus) +{ + // setup our i2c link + m_i2c = mraa_i2c_init(bus); + + mraa_result_t ret = mraa_i2c_address(m_i2c, DS1307_I2C_ADDR); + + if (ret != MRAA_SUCCESS) + cerr << "DS1307: Could not initialize i2c bus. " << endl; +} + +DS1307::~DS1307() +{ + mraa_i2c_stop(m_i2c); +} + +mraa_result_t DS1307::writeBytes(uint8_t reg, uint8_t *buffer, unsigned 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_i2c_address(m_i2c, DS1307_I2C_ADDR); + + return mraa_i2c_write(m_i2c, buf2, len + 1); +} + +uint8_t DS1307::readBytes(uint8_t reg, uint8_t *buffer, unsigned int len) +{ + if (!len || !buffer) + return 0; + + mraa_i2c_address(m_i2c, DS1307_I2C_ADDR); + mraa_i2c_write_byte(m_i2c, reg); + + return mraa_i2c_read(m_i2c, buffer, len); +} + +bool DS1307::loadTime() +{ + // read the first 7 registers + uint8_t buffer[7]; + int bytesRead = readBytes(0, buffer, 7); + + if (bytesRead != 7) + { + // problem + cerr << __FUNCTION__ << ": read " << bytesRead << + " bytes, expected 7." << endl; + 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_t 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_t 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) ); +} + diff --git a/src/ds1307/ds1307.h b/src/ds1307/ds1307.h new file mode 100644 index 00000000..3bbcafbc --- /dev/null +++ b/src/ds1307/ds1307.h @@ -0,0 +1,186 @@ +/* + * Author: Jon Trulson + * 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. + */ +#pragma once + +#include +#include + +#define DS1307_I2C_BUS 0 +#define DS1307_I2C_ADDR 0x68 + +// Days of the week +#define DS1307_DAY_MON 1 +#define DS1307_DAY_TUE 2 +#define DS1307_DAY_WED 3 +#define DS1307_DAY_THU 4 +#define DS1307_DAY_FRI 5 +#define DS1307_DAY_SAT 6 +#define DS1307_DAY_SUN 7 + +namespace upm { + + /** + * @brief C++ API for the DS1307 Real Time CLock + * + * UPM module for the DS1307 based RTC. The clock can provide information + * about the seconds, minutes, hours, day of the week, day of the month, + * month, and year. It can operate in either 24-hour or 12-hour format. + * + * This device can also output a square wave at 1Khz, 4Khz, 8Khz, and 32Khz. + * However, this capability is not implemented in this module. + * + * @ingroup i2c ds1307 RTC + * @snippet ds1307.cxx Interesting + */ + class DS1307 { + public: + /** + * ds1307 Real Time Clock constructor + * + * @param bus i2c bus to use + */ + DS1307(int bus); + + /** + * DS1307 Destructor + */ + ~DS1307(); + + /** + * Load all of the time values + * + * @return True if time data loaded successfully + */ + bool loadTime(); + + /** + * Set the time. You should call loadTime() beforehand to + * maintain consistency + * + * @return True if time saved successfully + */ + bool setTime(); + + /** + * Enable the oscillator on the clock. + * + * @return 0 (MRAA_SUCCESS) if successful; non-zero otherwise + */ + mraa_result_t enableClock(); + + /** + * Disable the oscillator on the clock. This will prevent the clock + * from updating any time/date values + * + * @return 0 (MRAA_SUCCESS) if successful; non-zero otherwise + */ + mraa_result_t disableClock(); + + /** + * Write value(s) into registers + * + * @param reg register location to start writing into + * @param buffer buffer for data storage + * @param len number of bytes to write + * @return 0 (MRAA_SUCCESS) if successful; non-zero otherwise + */ + mraa_result_t writeBytes(uint8_t reg, uint8_t *buffer, unsigned int len); + + /** + * Read value(s) from registers + * + * @param reg register location to start reading from + * @param buffer buffer for data storage + * @param len number of bytes to read + * @return number of bytes read + */ + uint8_t readBytes(uint8_t reg, uint8_t *buffer, unsigned int len); + + /** + * Convert a BCD value into decimal + * + * @param val BCD value to convert + * @return the converted value in decimal + */ + unsigned int bcdToDec(uint8_t val); + + /** + * Convert a decimal value into BCD + * + * @param val decimal value to convert + * @return the converted value in BCD + */ + uint8_t decToBcd(unsigned int val); + + // These variables store the time data loaded with loadTime(), and + // will be the source of data when setTime() is called. It is a + // good idea call loadTime() to setup the current values before + // calling setTime() to ensure RTC data is consistent + + /** + * holds the seconds + */ + unsigned int seconds; + /** + * holds the minutes + */ + unsigned int minutes; + /** + * holds the hours, 1-12 in am/pm mode, 0-23 otherwise + */ + unsigned int hours; + /** + * holds the day of the week, 1-7 where 1 is Sunday + */ + unsigned int dayOfWeek; + /** + * holds the day of the month, 1-31 + */ + unsigned int dayOfMonth; + /** + * holds the month, 1-12 + */ + unsigned int month; + /** + * holds the year, 0-99 + */ + unsigned int year; + /** + * True if in AM/PM mode, false if 24h format. + */ + bool amPmMode; + /** + * If in AmPmMode (12-hr), then this is true if it's PM, clear if AM + */ + bool pm; + + private: + mraa_i2c_context m_i2c; + }; +} + + diff --git a/src/ds1307/jsupm_ds1307.i b/src/ds1307/jsupm_ds1307.i new file mode 100644 index 00000000..f102ea0d --- /dev/null +++ b/src/ds1307/jsupm_ds1307.i @@ -0,0 +1,8 @@ +%module jsupm_ds1307 +%include "../upm.i" + +%{ + #include "ds1307.h" +%} + +%include "ds1307.h" diff --git a/src/ds1307/pyupm_ds1307.i b/src/ds1307/pyupm_ds1307.i new file mode 100644 index 00000000..3467d5df --- /dev/null +++ b/src/ds1307/pyupm_ds1307.i @@ -0,0 +1,13 @@ +%module pyupm_ds1307 +%include "../upm.i" + +%feature("autodoc", "3"); + +#ifdef DOXYGEN +%include "ds1307_doc.i" +#endif + +%include "ds1307.h" +%{ + #include "ds1307.h" +%}