@@ -4,6 +4,8 @@ | |||||
#define LOGGER_NAME "Core" | #define LOGGER_NAME "Core" | ||||
using namespace utils; | |||||
namespace core { | namespace core { | ||||
uint16_t sleepTime = SLEEP_DEFAULT_TIME_SECONDS;; | uint16_t sleepTime = SLEEP_DEFAULT_TIME_SECONDS;; | ||||
@@ -103,6 +103,8 @@ int freeRam2() { // dirty hack because putting it in namespace doesn't compile | |||||
return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval); | return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval); | ||||
} | } | ||||
using namespace utils; | |||||
namespace debug { | namespace debug { | ||||
namespace details { | namespace details { | ||||
@@ -19,7 +19,7 @@ | |||||
#define VERBOSE_FORMAT(f, msg, ...) LOG_FORMAT(verbose, f, msg, __VA_ARGS__) | #define VERBOSE_FORMAT(f, msg, ...) LOG_FORMAT(verbose, f, msg, __VA_ARGS__) | ||||
#else | #else | ||||
#define DISABLE_LOGGING 1 | |||||
#define DISABLE_LOGGING 1 //TODO : does nothing if not included before ArduinoLog.h | |||||
#define VERBOSE(f) | #define VERBOSE(f) | ||||
#define VERBOSE_MSG(f, msg) | #define VERBOSE_MSG(f, msg) | ||||
@@ -2,10 +2,12 @@ | |||||
#include <Arduino.h> | #include <Arduino.h> | ||||
namespace flash { | |||||
namespace utils { | |||||
namespace flash { | |||||
template<typename T, size_t N> size_t getArraySize(T(&)[N]) { return N; } | |||||
template<typename T> void read(const T *source, T &dest) { | |||||
memcpy_P(&dest, source, sizeof(T)); | |||||
template<typename T, size_t N> size_t getArraySize(T(&)[N]) { return N; } | |||||
template<typename T> void read(const T *source, T &dest) { | |||||
memcpy_P(&dest, source, sizeof(T)); | |||||
} | |||||
} | } | ||||
} | } |
@@ -4,35 +4,13 @@ | |||||
#include "Pins.h" | #include "Pins.h" | ||||
#include <Wire.h> | #include <Wire.h> | ||||
#include <MD_DS3231.h> | |||||
#include <uDS3231.h> | |||||
#define LOGGER_NAME "Rtc" | #define LOGGER_NAME "Rtc" | ||||
namespace rtc { | |||||
namespace details { | |||||
void readTimeFromRegisters(tmElements_t &time) { | |||||
time.Second = RTC.s; | |||||
time.Minute = RTC.m; | |||||
time.Hour = RTC.h; | |||||
time.Wday = RTC.dow; | |||||
time.Day = RTC.dd; | |||||
time.Month = RTC.mm; | |||||
time.Year = CalendarYrToTm(RTC.yyyy); | |||||
} | |||||
void writeTimeToRegisters(const tmElements_t &time) { | |||||
RTC.s = time.Second; | |||||
RTC.m = time.Minute; | |||||
RTC.h = time.Hour; | |||||
RTC.dow = time.Wday; | |||||
RTC.dd = time.Day; | |||||
RTC.mm = time.Month; | |||||
RTC.yyyy = tmYearToCalendar(time.Year); | |||||
} | |||||
using namespace utils; | |||||
} | |||||
namespace rtc { | |||||
void setup() { | void setup() { | ||||
VERBOSE("setup"); | VERBOSE("setup"); | ||||
@@ -56,30 +34,22 @@ namespace rtc { | |||||
timestamp_t getTime() { | timestamp_t getTime() { | ||||
tmElements_t time; | tmElements_t time; | ||||
getTime(time); | getTime(time); | ||||
return makeTimestamp(time); | |||||
return time::makeTimestamp(time); | |||||
} | } | ||||
void getTime(tmElements_t &time) { | void getTime(tmElements_t &time) { | ||||
hardware::i2c::powerOn(); | hardware::i2c::powerOn(); | ||||
RTC.readTime(); | |||||
RTC.readTime(time); | |||||
hardware::i2c::powerOff(); | hardware::i2c::powerOff(); | ||||
details::readTimeFromRegisters(time); | |||||
VERBOSE_FORMAT("getTime", "%d/%d/%d %d:%d:%d", tmYearToCalendar(time.Year), time.Month, time.Day, time.Hour, time.Minute, time.Second); | VERBOSE_FORMAT("getTime", "%d/%d/%d %d:%d:%d", tmYearToCalendar(time.Year), time.Month, time.Day, time.Hour, time.Minute, time.Second); | ||||
} | } | ||||
void setTime(const timestamp_t timestamp) { | |||||
tmElements_t time; | |||||
breakTime(timestamp, time); | |||||
setTime(time); | |||||
} | |||||
void setTime(const tmElements_t &time) { | void setTime(const tmElements_t &time) { | ||||
VERBOSE_FORMAT("setTime", "%d/%d/%d %d:%d:%d", tmYearToCalendar(time.Year), time.Month, time.Day, time.Hour, time.Minute, time.Second); | VERBOSE_FORMAT("setTime", "%d/%d/%d %d:%d:%d", tmYearToCalendar(time.Year), time.Month, time.Day, time.Hour, time.Minute, time.Second); | ||||
details::writeTimeToRegisters(time); | |||||
hardware::i2c::powerOn(); | hardware::i2c::powerOn(); | ||||
RTC.writeTime(); | |||||
RTC.writeTime(time); | |||||
hardware::i2c::powerOff(); | hardware::i2c::powerOff(); | ||||
} | } | ||||
@@ -88,23 +58,22 @@ namespace rtc { | |||||
tmElements_t alarmTime; | tmElements_t alarmTime; | ||||
getTime(currentTime); | getTime(currentTime); | ||||
breakTime(makeTimestamp(currentTime) + seconds, alarmTime); | |||||
time::breakTime(time::makeTimestamp(currentTime) + seconds, alarmTime); | |||||
setAlarm(alarmTime); | setAlarm(alarmTime); | ||||
} | } | ||||
void setAlarm(const tmElements_t &time) { | void setAlarm(const tmElements_t &time) { | ||||
details::writeTimeToRegisters(time); | |||||
hardware::i2c::powerOn(); | hardware::i2c::powerOn(); | ||||
RTC.writeAlarm1(DS3231_ALM_DTHMS); | |||||
RTC.writeAlarm1(DS3231_ALM_HMS, time); | |||||
RTC.control(DS3231_A1_FLAG, DS3231_OFF); //reset Alarm 1 flag | RTC.control(DS3231_A1_FLAG, DS3231_OFF); //reset Alarm 1 flag | ||||
RTC.control(DS3231_A1_INT_ENABLE, DS3231_ON); //Alarm 1 ON | RTC.control(DS3231_A1_INT_ENABLE, DS3231_ON); //Alarm 1 ON | ||||
RTC.control(DS3231_INT_ENABLE, DS3231_ON); //INTCN ON | RTC.control(DS3231_INT_ENABLE, DS3231_ON); //INTCN ON | ||||
hardware::i2c::powerOff(); | |||||
NOTICE_FORMAT("setAlarm", "Next alarm : %d/%d/%d %d:%d:%d", tmYearToCalendar(time.Year), time.Month, time.Day, time.Hour, time.Minute, time.Second); | |||||
NOTICE_FORMAT("setAlarm", "Next alarm : %d:%d:%d", time.Hour, time.Minute, time.Second); | |||||
hardware::i2c::powerOff(); | |||||
} | } | ||||
} | } |
@@ -9,7 +9,6 @@ namespace rtc { | |||||
timestamp_t getTime(); | timestamp_t getTime(); | ||||
void getTime(tmElements_t &time); | void getTime(tmElements_t &time); | ||||
void setTime(timestamp_t time); | |||||
void setTime(const tmElements_t &time); | void setTime(const tmElements_t &time); | ||||
void setAlarm(uint16_t seconds); | void setAlarm(uint16_t seconds); | ||||
@@ -10,123 +10,38 @@ | |||||
#define SECS_PER_YEAR (SECS_PER_WEEK * 52UL) | #define SECS_PER_YEAR (SECS_PER_WEEK * 52UL) | ||||
#define SECS_YR_2000 (946684800UL) // the time at the start of y2k | #define SECS_YR_2000 (946684800UL) // the time at the start of y2k | ||||
/* Useful Macros for getting elapsed time */ | |||||
#define numberOfSeconds(_time_) (_time_ % SECS_PER_MIN) | |||||
#define numberOfMinutes(_time_) ((_time_ / SECS_PER_MIN) % SECS_PER_MIN) | |||||
#define numberOfHours(_time_) (( _time_% SECS_PER_DAY) / SECS_PER_HOUR) | |||||
#define dayOfWeek(_time_) ((( _time_ / SECS_PER_DAY + 4) % DAYS_PER_WEEK)+1) // 1 = Sunday | |||||
#define elapsedDays(_time_) ( _time_ / SECS_PER_DAY) // this is number of days since Jan 1 1970 | |||||
#define elapsedSecsToday(_time_) (_time_ % SECS_PER_DAY) // the number of seconds since last midnight | |||||
// The following macros are used in calculating alarms and assume the clock is set to a date later than Jan 1 1971 | |||||
// Always set the correct time before settting alarms | |||||
#define previousMidnight(_time_) (( _time_ / SECS_PER_DAY) * SECS_PER_DAY) // time at the start of the given day | |||||
#define nextMidnight(_time_) ( previousMidnight(_time_) + SECS_PER_DAY ) // time at the end of the given day | |||||
#define elapsedSecsThisWeek(_time_) (elapsedSecsToday(_time_) + ((dayOfWeek(_time_)-1) * SECS_PER_DAY) ) // note that week starts on day 1 | |||||
#define previousSunday(_time_) (_time_ - elapsedSecsThisWeek(_time_)) // time at the start of the week for the given time | |||||
#define nextSunday(_time_) ( previousSunday(_time_)+SECS_PER_WEEK) // time at the end of the week for the given time | |||||
/* Useful Macros for converting elapsed time to a timestamp_t */ | |||||
#define minutesTotimestamp_t ((M)) ( (M) * SECS_PER_MIN) | |||||
#define hoursTotimestamp_t ((H)) ( (H) * SECS_PER_HOUR) | |||||
#define daysTotimestamp_t ((D)) ( (D) * SECS_PER_DAY) // fixed on Jul 22 2011 | |||||
#define weeksTotimestamp_t ((W)) ( (W) * SECS_PER_WEEK) | |||||
// leap year calulator expects year argument as years offset from 1970 | |||||
#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) | |||||
static const uint8_t monthDays[] = { 31,28,31,30,31,30,31,31,30,31,30,31 }; // API starts months from 1, this array starts from 0 | |||||
/*==============================================================================*/ | |||||
/* Utility functions */ | |||||
__attribute__((__optimize__("O2"))) | |||||
void breakTime(const timestamp_t timeInput, tmElements_t &tm) { | |||||
// break the given timestamp_t into time components | |||||
// this is a more compact version of the C library localtime function | |||||
// note that year is offset from 1970 !!! | |||||
namespace utils { | |||||
namespace time { | |||||
uint8_t year; | |||||
uint8_t month, monthLength; | |||||
uint32_t time; | |||||
unsigned long days; | |||||
__attribute__((__optimize__("O2"))) | |||||
timestamp_t makeTimestamp(const tmElements_t &time) { | |||||
timestamp_t timestamp; | |||||
time = (uint32_t)timeInput; | |||||
tm.Second = time % 60; | |||||
time /= 60; // now it is minutes | |||||
tm.Minute = time % 60; | |||||
time /= 60; // now it is hours | |||||
tm.Hour = time % 24; | |||||
time /= 24; // now it is days | |||||
tm.Wday = ((time + 4) % 7) + 1; // Sunday is day 1 | |||||
timestamp += (time.Day - 1) * SECS_PER_DAY; | |||||
timestamp += time.Hour * SECS_PER_HOUR; | |||||
timestamp += time.Minute * SECS_PER_MIN; | |||||
timestamp += time.Second; | |||||
year = 0; | |||||
days = 0; | |||||
while ((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) { | |||||
year++; | |||||
return timestamp; | |||||
} | } | ||||
tm.Year = year; // year is offset from 1970 | |||||
days -= LEAP_YEAR(year) ? 366 : 365; | |||||
time -= days; // now it is days in this year, starting at 0 | |||||
days = 0; | |||||
month = 0; | |||||
monthLength = 0; | |||||
for (month = 0; month<12; month++) { | |||||
if (month == 1) { // february | |||||
if (LEAP_YEAR(year)) { | |||||
monthLength = 29; | |||||
} | |||||
else { | |||||
monthLength = 28; | |||||
} | |||||
} | |||||
else { | |||||
monthLength = monthDays[month]; | |||||
} | |||||
if (time >= monthLength) { | |||||
time -= monthLength; | |||||
} | |||||
else { | |||||
break; | |||||
} | |||||
__attribute__((__optimize__("O2"))) | |||||
void breakTime(timestamp_t timestamp, tmElements_t &time) { | |||||
time.Year = 0; | |||||
time.Month = 0; | |||||
time.Day = 0; | |||||
time.Second = timestamp % 60; | |||||
timestamp /= 60; // now it is minutes | |||||
time.Minute = timestamp % 60; | |||||
timestamp /= 60; // now it is hours | |||||
time.Hour = timestamp % 24; | |||||
timestamp /= 24; // now it is days | |||||
time.Day = timestamp; //this is purely for indication / computation only as it might get over the number of days in a month | |||||
} | } | ||||
tm.Month = month + 1; // jan is month 1 | |||||
tm.Day = time + 1; // day of month | |||||
} | |||||
__attribute__((__optimize__("O2"))) | |||||
timestamp_t makeTimestamp(const tmElements_t &tm) { | |||||
// assemble time elements into timestamp_t | |||||
// note year argument is offset from 1970 (see macros in time.h to convert to other formats) | |||||
// previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9 | |||||
int i; | |||||
uint32_t seconds; | |||||
// seconds from 1970 till 1 jan 00:00:00 of the given year | |||||
seconds = tm.Year*(SECS_PER_DAY * 365); | |||||
for (i = 0; i < tm.Year; i++) { | |||||
if (LEAP_YEAR(i)) { | |||||
seconds += SECS_PER_DAY; // add extra days for leap years | |||||
} | |||||
} | } | ||||
// add days for this year, months start from 1 | |||||
for (i = 1; i < tm.Month; i++) { | |||||
if ((i == 2) && LEAP_YEAR(tm.Year)) { | |||||
seconds += SECS_PER_DAY * 29; | |||||
} | |||||
else { | |||||
seconds += SECS_PER_DAY * monthDays[i - 1]; //monthDay array starts from 0 | |||||
} | |||||
} | |||||
seconds += (tm.Day - 1) * SECS_PER_DAY; | |||||
seconds += tm.Hour * SECS_PER_HOUR; | |||||
seconds += tm.Minute * SECS_PER_MIN; | |||||
seconds += tm.Second; | |||||
return (timestamp_t)seconds; | |||||
} | |||||
/*=====================================================*/ | |||||
/* Low level system time functions */ | |||||
//TODO : + and - operator between tmElements_t and timestamp_t | |||||
} |
@@ -1,27 +1,12 @@ | |||||
#pragma once | #pragma once | ||||
#include <Arduino.h> | #include <Arduino.h> | ||||
#include <uDS3231.h> | |||||
//convenience macros to convert to and from tm years | |||||
#define tmYearToCalendar(Y) ((Y) + 1970) // full four digit year | |||||
#define CalendarYrToTm(Y) ((Y) - 1970) | |||||
#define tmYearToY2k(Y) ((Y) - 30) // offset is from 2000 | |||||
#define y2kYearToTm(Y) ((Y) + 30) | |||||
namespace utils { | |||||
namespace time { | |||||
/*============================================================================*/ | |||||
typedef unsigned long timestamp_t; | |||||
typedef struct { | |||||
uint8_t Second; | |||||
uint8_t Minute; | |||||
uint8_t Hour; | |||||
uint8_t Wday; // day of week, sunday is day 1 | |||||
uint8_t Day; | |||||
uint8_t Month; | |||||
uint8_t Year; // offset from 1970; | |||||
} tmElements_t, TimeElements, *tmElementsPtr_t; | |||||
/* low level functions to convert to and from system time */ | |||||
void breakTime(const timestamp_t time, tmElements_t &tm); // break timestamp_t into elements | |||||
timestamp_t makeTimestamp(const tmElements_t &tm); // convert time elements into timestamp_t | |||||
void breakTime(const timestamp_t time, tmElements_t &tm); | |||||
timestamp_t makeTimestamp(const tmElements_t &tm); | |||||
} | |||||
} |