diff --git a/STM32F4/libraries/RTClock/examples/Test_RTClock/Test_RTClock.ino b/STM32F4/libraries/RTClock/examples/Test_RTClock/Test_RTClock.ino new file mode 100644 index 0000000..ec6afa4 --- /dev/null +++ b/STM32F4/libraries/RTClock/examples/Test_RTClock/Test_RTClock.ino @@ -0,0 +1,209 @@ +/* + This is an example of how to use the RTclock of STM32F4 device + + This example can also be used to set the RTC to the current epoch time: + - goto: http://www.unixtimestamp.com/ + - enter the current date and time to the right field "Timestamp converter" + - press the "Convert" button + - +*/ + +#include + +#include + + +//RTClock rt(RTCSEL_LSE); // initialise +RTClock rtc; + +time_t tt; +tm_t tm; + +const uint32_t DEFAULT_TIME = 1498944019; // 2017.07.01, 21:20:19 used as reference epoch time + +#define TIME_HEADER 'T' // Header tag for serial time sync message +#define TIME_REQUEST 7 // ASCII bell character requests a time sync message + +#define LED_PIN BOARD_LED_PIN + +//----------------------------------------------------------------------------- +void blink () +{ + digitalWrite(LED_PIN, digitalRead(LED_PIN)?LOW:HIGH); +} + +uint8_t s[20]; // for serial parsing + +//----------------------------------------------------------------------------- +char * read_line() +{ + while ( Serial.available() ) Serial.read(); // empty Rx buffer + while ( Serial.available()<=0 ) ; // wait for new characters + uint8_t c, i = 0; + s[0] = 0; + while ( Serial.available() && (i<20) ) { + c = Serial.read(); + if ( c=='\n' || c== '\r') { + s[i] = 0; + break; + } + s[i++] = c; + } + while ( Serial.available() ) Serial.read(); // flush Rx + return (char*)&s[0]; +} + +//----------------------------------------------------------------------------- +void processSyncMessage(void) +{ + if ( Serial.available() ) { + if( *read_line()==(TIME_HEADER) ) { + uint32_t pctime = atoi((const char*)&s[1]); + Serial << ("Epoch time received: ") << pctime << endl; + if ( pctime >= DEFAULT_TIME) { // check the integer is a valid epoch time + rtc.setTime(pctime); // Set RTC to the time received via the serial port + } + } + Serial << endl; + } +} + +//----------------------------------------------------------------------------- +void Change_DateTime(void) +{ + // check and correct the weekday if necessary + rtc.getTime(tm); + Serial << "Current weekday is " << (tm.weekday); + // get time elements + tt = rtc.makeTime(tm); + uint16_t tmp = rtc.weekday(tt); + if ( tmp!=tm.weekday ) {// correct weekday + rtc.setTime(tt); + Serial << " instead of " << tmp << ". Now is corrected.\n"; + } else { + Serial << " - seems to be fine, no need to change it.\n"; + } + + uint8_t chg = 0; + // get time elements + rtc.getTime(tm); + Serial << "\nCurrent RTC date: " << (1970+tm.year) << "." << (tm.month) << (".") << (tm.day) << (", weekday: ") << (tm.weekday) << endl; + Serial << "Do you want to change it? (y/n)\n"; + if ( *read_line()=='y' ) { + // change here the date +change_year: + Serial << "Current year: " << (1970+tm.year) << ". Enter new year in \"YYYY\" format (numbers only) or press enter to skip.\n"; + if (*read_line()==0) goto change_month; + tmp = atoi((const char*)s); + if ( tmp<1970 ) { Serial << "Please enter a valid number greater than 1970\n"; goto change_year; } + Serial << "You entered: " << tmp << ". Accept value? (y/n)\n"; + if ( *read_line()=='n' ) goto change_year; + tm.year = tmp-1970; + chg = 1; +change_month: + Serial << "Current month: " << tm.month << ". Enter new month in \"MM\" format [1..12] or press enter to skip.\n"; + if (*read_line()==0) goto change_day; + tmp = atoi((const char*)s); + if ( tmp<1 || tmp>12 ) { Serial << "Please enter a valid number [1..12]\n"; goto change_month; } + Serial << "You entered: " << tmp << ". Accept value? (y/n)\n"; + if ( *read_line()=='n' ) goto change_month; + tm.month = tmp; + chg = 1; +change_day: + Serial << "Current day: " << tm.day << ". Enter new day in \"DD\" format [1..31] or press enter to skip.\n"; + if (*read_line()==0) goto change_weekday; + tmp = atoi((const char*)s); + if ( tmp<1 || tmp>31 ) { Serial << "Please enter a valid number [1..31]\n"; goto change_day; } + Serial << "You entered: " << tmp << ". Accept value? (y/n)\n"; + if ( *read_line()=='n' ) goto change_day; + tm.day = tmp; + chg = 1; +change_weekday: + Serial << "Current weekday: " << tm.weekday << ". Enter new weekday [1(=Monday)..7(=Sunday)] or press enter to skip.\n"; + if (*read_line()==0) goto change_time; + tmp = atoi((const char*)s); + if ( tmp<1 || tmp>7 ) { Serial << "Please enter a valid number [1..7]\n"; goto change_weekday; } + Serial << "You entered: " << tmp << ". Accept value? (y/n)\n"; + if ( *read_line()=='n' ) goto change_weekday; + tm.weekday = tmp; + chg = 1; +change_time: + Serial << "Current RTC time: " << _TIME(tm.hour, tm.minute, tm.second) << endl; + Serial << "Do you want to change it? (y/n)\n"; + if ( *read_line()=='n' ) goto change_end; +change_hour: + Serial << "Current hour: " << tm.hour << ". Enter new hour [0..23] or press enter to skip.\n"; + if (*read_line()==0) goto change_minute; + tmp = atoi((const char*)s); + if ( tmp>23 ) { Serial << "Please enter a valid number [0..23]\n"; goto change_hour; } + Serial << "You entered: " << tmp << ". Accept value? (y/n)\n"; + if ( *read_line()=='n' ) goto change_hour; + tm.hour = tmp; + chg = 1; +change_minute: + Serial << "Current minute: " << tm.minute << ". Enter new minute [0..59] or press enter to skip.\n"; + if (*read_line()==0) goto change_second; + tmp = atoi((const char*)s); + if ( tmp>59 ) { Serial << "Please enter a valid number [0..59]\n"; goto change_minute; } + Serial << "You entered: " << tmp << ". Accept value? (y/n)\n"; + if ( *read_line()=='n' ) goto change_minute; + tm.minute = tmp; + chg = 1; +change_second: + Serial << "Current second: " << tm.second << ". Enter new second [0..59] or press enter to skip.\n"; + if (*read_line()==0) goto change_end; + tmp = atoi((const char*)s); + if ( tmp>59 ) { Serial << "Please enter a valid number [0..59]\n"; goto change_second; } + Serial << "You entered: " << tmp << ". Accept value? (y/n)\n"; + if ( *read_line()=='n' ) goto change_second; + tm.second = tmp; + chg = 1; + } else { + goto change_time; + } + +change_end: + if ( chg ) { + // set here the RTC time. + Serial << "Changed date & time: " << (1970+tm.year) << "." << (tm.month) << (".") << (tm.day) << (", weekday: ") << (tm.weekday) << ", " << _TIME(tm.hour, tm.minute, tm.second) << endl; + Serial << "Write now to RTC? (y/n)\n"; + read_line(); + if ( s[0]=='y' ) { + rtc.setTime(tm); + Serial << "Data written to RTC.\n\n"; + } + } else + Serial << "RTC was not changed.\n\n"; +} +//----------------------------------------------------------------------------- +void setup() +{ + Serial.begin(); + delay(3000); + + pinMode(LED_PIN, OUTPUT); + + Serial << "This is an example of how to use the STM32F4 RTC library.\n\n"; + + Change_DateTime(); +} + +//----------------------------------------------------------------------------- +void loop() +{ + if ( Serial.available() ) { + // adjust time according to received epoch time from PC + processSyncMessage(); + } + + if (tt!=rtc.now()) { + // get epoch time + tt = rtc.now(); + Serial << ("- RTC epoch timestamp = ") << (tt); + // get time elements + rtc.getTime(tm); + //rtc.breakTime(tt, tm); + Serial << (" == ") << (1970+tm.year) << "." << (tm.month) << (".") << (tm.day) << (", weekday ") << (tm.weekday) << (", "); + Serial << _TIME(tm.hour, tm.minute, tm.second) << endl; + } +} \ No newline at end of file diff --git a/STM32F4/libraries/RTClock/library.properties b/STM32F4/libraries/RTClock/library.properties index 5a5e4b7..a8878f6 100644 --- a/STM32F4/libraries/RTClock/library.properties +++ b/STM32F4/libraries/RTClock/library.properties @@ -7,3 +7,4 @@ paragraph=Real Time Clock for STM32F4 category=Other url= architectures=STM32F4 +maintainer=www.stm32duino.com diff --git a/STM32F4/libraries/RTClock/src/RTClock.cpp b/STM32F4/libraries/RTClock/src/RTClock.cpp index ee82c95..e7c2ca8 100644 --- a/STM32F4/libraries/RTClock/src/RTClock.cpp +++ b/STM32F4/libraries/RTClock/src/RTClock.cpp @@ -42,15 +42,7 @@ voidFuncPtr handlerAlarmA = NULL; voidFuncPtr handlerAlarmB = NULL; voidFuncPtr handlerPeriodicWakeup = NULL; - -RTClock::RTClock() { - RTClock(RTCSEL_HSE, 7999, 124); -} - -RTClock::RTClock(rtc_clk_src src) { - RTClock(src, 0, 0); -} - +//----------------------------------------------------------------------------- RTClock::RTClock(rtc_clk_src src, uint16 sync_prescaler, uint16 async_prescaler) { uint32 t = 0; RCC_BASE->APB1ENR |= RCC_APB1RSTR_PWRRST; @@ -144,117 +136,155 @@ RTClock::~RTClock() { } */ -void RTClock::setTime (time_t time_stamp) { - unsigned char years = 0; - unsigned char months = 0; - unsigned char monthLength = 0; - unsigned char wdays = 0; - unsigned char hours = 0; - unsigned char mins = 0; - unsigned char secs = 0; - unsigned long days; +//----------------------------------------------------------------------------- +void RTClock::setTime (time_t time_stamp) +{ + breakTime(time_stamp, tm); // time will be broken to tm + setTime(tm); +} - secs = time_stamp % 60; - time_stamp /= 60; // now it is minutes - mins = time_stamp % 60; - time_stamp /= 60; // now it is hours - hours = time_stamp % 24; - time_stamp /= 24; // now it is days - wdays = ((time_stamp + 4) % 7) + 1; // Sunday is day 1 - - while((unsigned)(days += (LEAP_YEAR(years) ? 366 : 365)) <= time_stamp) { - years++; - } - - days -= LEAP_YEAR(years) ? 366 : 365; - time_stamp -= days; // now it is days in this year, starting at 0 - - for (months = 0; months < 12; months++) { - if (months == 1) { // february - if (LEAP_YEAR(years)) { - monthLength = 29; - } else { - monthLength = 28; - } - } else { - monthLength = monthDays[months]; - } - - if (time_stamp >= monthLength) { - time_stamp -= monthLength; - } else { - break; - } - } - months++; // jan is month 1 - days = time_stamp + 1; // day of month +//----------------------------------------------------------------------------- +void RTClock::setTime (tm_t & tm) +{ + if (tm.year > 99) + tm.year = tm.year % 100; rtc_enter_config_mode(); - RTC_BASE->TR = ((hours / 10) << 20) | ((hours % 10) << 16) | ((mins / 10) << 12) | ((mins % 10) << 8) | ((secs / 10) << 4) | (secs % 10); - RTC_BASE->DR = ((years / 10) << 20) | ((years % 10) << 16) | (wdays << 13) | ((months / 10) << 12) | ((months % 10) << 8) | ((days / 10) << 4) | (days % 10); + RTC_BASE->TR = BUILD_TIME_REGISTER(tm.hour, tm.minute, tm.second); + RTC_BASE->DR = BUILD_DATE_REGISTER(tm.year, tm.month, tm.day, tm.weekday); rtc_exit_config_mode(); } - -void RTClock::setTime (struct tm* tm_ptr) { - rtc_enter_config_mode(); - if (tm_ptr->tm_year > 99) - tm_ptr->tm_year = tm_ptr->tm_year % 100; - tm_ptr->tm_wday = tm_ptr->tm_wday & 0x7; - RTC_BASE->TR = ((tm_ptr->tm_hour / 10) << 20) | ((tm_ptr->tm_hour % 10) << 16) | - ((tm_ptr->tm_min / 10) << 12) | ((tm_ptr->tm_min % 10) << 8) | - ((tm_ptr->tm_sec / 10) << 4) | (tm_ptr->tm_sec % 10); - RTC_BASE->DR = ((tm_ptr->tm_year / 10) << 20) | ((tm_ptr->tm_year % 10) << 16) | (tm_ptr->tm_wday << 13) | - ((tm_ptr->tm_mon / 10) << 12) | ((tm_ptr->tm_mon % 10) << 8) | - ((tm_ptr->tm_mday / 10) << 4) | (tm_ptr->tm_mday % 10); - rtc_exit_config_mode(); -} - -time_t RTClock::getTime() { - uint32 dr_reg = RTC_BASE->DR; - uint32 tr_reg = RTC_BASE->TR; - int years = 10 * ((dr_reg & 0x00F00000) >> 20) + ((dr_reg & 0x000F0000) >> 16); - int months = 10 * ((dr_reg & 0x00001000) >> 12) + ((dr_reg & 0x00000F00) >> 8); - int days = 10 * ((dr_reg & 0x00000030) >> 4) + (dr_reg & 0x000000F); - int hours = 10 * ((tr_reg & 0x00300000) >> 20) + ((tr_reg & 0x000F0000) >> 16); - int mins = 10 * ((tr_reg & 0x00007000) >> 12) + ((tr_reg & 0x0000F00) >> 8); - int secs = 10 * ((tr_reg & 0x00000070) >> 4) + (tr_reg & 0x0000000F); - // seconds from 1970 till 1 jan 00:00:00 of the given year - time_t t = (years + 30) * SECS_PER_DAY * 365; - for (int i = 0; i < (years + 30); i++) { - if (LEAP_YEAR(i)) { - t += SECS_PER_DAY; // add extra days for leap years + +/*============================================================================*/ +/* functions to convert to and from system time */ +/* These are for interfacing with time serivces and are not normally needed in a sketch */ + +// 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 + +//----------------------------------------------------------------------------- +void RTClock::breakTime(time_t timeInput, tm_t & tm) +{ +// break the given time_t into time components +// this is a more compact version of the C library localtime function +// note that year is offset from 1970 !!! + + uint8_t year; + uint8_t month, monthLength; + uint32_t time; + uint32_t days; + + 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.weekday = ((time + 4) % 7); // Monday is day 1 // + 1; // Sunday is day 1 + + year = 0; + days = 0; + while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) { + year++; } - } - // add days for this year, months start from 1 - for (int i = 1; i < months; i++) { - if ( (i == 2) && LEAP_YEAR(years)) { - t += SECS_PER_DAY * 29; - } else { - t += SECS_PER_DAY * monthDays[i - 1]; //monthDays array starts from 0 + 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; + } } - } - t += (days - 1) * SECS_PER_DAY + hours * SECS_PER_HOUR + mins * SECS_PER_MIN + secs; - return t; + tm.month = month + 1; // jan is month 1 + tm.day = time + 1; // day of month } - -struct tm* RTClock::getTime(struct tm* tm_ptr) { - uint32 dr_reg = RTC_BASE->DR; - uint32 tr_reg = RTC_BASE->TR; - tm_ptr->tm_year = 10 * ((dr_reg & 0x00F00000) >> 20) + ((dr_reg & 0x000F0000) >> 16); - tm_ptr->tm_mon = 10 * ((dr_reg & 0x00001000) >> 12) + ((dr_reg & 0x00000F00) >> 8); - tm_ptr->tm_mday = 10 * ((dr_reg & 0x00000030) >> 4) + (dr_reg & 0x000000F); - tm_ptr->tm_hour = 10 * ((tr_reg & 0x00300000) >> 20) + ((tr_reg & 0x000F0000) >> 16); - tm_ptr->tm_min = 10 * ((tr_reg & 0x00007000) >> 12) + ((tr_reg & 0x0000F00) >> 8); - tm_ptr->tm_sec = 10 * ((tr_reg & 0x00000070) >> 4) + (tr_reg & 0x0000000F); - return tm_ptr; + +//----------------------------------------------------------------------------- +time_t RTClock::makeTime(tm_t & tm) +{ +// assemble time elements into time_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 (time_t)seconds; } - -void RTClock::setAlarmATime (tm * tm_ptr, bool hours_match, bool mins_match, bool secs_match, bool date_match) { + +//----------------------------------------------------------------------------- +void RTClock::getTime(tm_t & tm) +{ + uint32_t dr_reg, tr_reg; + do { // read multiple time till both readings are equal + dr_reg = getDReg(); + tr_reg = getTReg(); + } while ( (dr_reg!=getDReg()) || (tr_reg!=getTReg()) ); + tm.year = _year(dr_reg); + tm.month = _month(dr_reg); + tm.day = _day(dr_reg); + tm.weekday = _weekday(dr_reg); + tm.pm = _pm(tr_reg); + tm.hour = _hour(tr_reg); + tm.minute = _minute(tr_reg); + tm.second = _second(tr_reg); +} + +//----------------------------------------------------------------------------- +time_t RTClock::getTime() +{ + getTime(tm); + return makeTime(tm); +} + +//----------------------------------------------------------------------------- +void RTClock::setAlarmATime (tm_t * tm_ptr, bool hours_match, bool mins_match, bool secs_match, bool date_match) +{ uint32 t = 0; rtc_enter_config_mode(); - unsigned int bits = ((tm_ptr->tm_mday / 10) << 28) | ((tm_ptr->tm_mday % 10) << 24) | - ((tm_ptr->tm_hour / 10) << 20) | ((tm_ptr->tm_hour % 10) << 16) | - ((tm_ptr->tm_min / 10) << 12) | ((tm_ptr->tm_min % 10) << 8) | - ((tm_ptr->tm_sec / 10) << 4) | (tm_ptr->tm_sec % 10); + unsigned int bits = ((tm_ptr->day / 10) << 28) | ((tm.day % 10) << 24) | + ((tm_ptr->hour / 10) << 20) | ((tm_ptr->hour % 10) << 16) | + ((tm_ptr->minute / 10) << 12) | ((tm_ptr->minute % 10) << 8) | + ((tm_ptr->second / 10) << 4) | (tm_ptr->second % 10); if (!date_match) bits |= (1 << 31); if (!hours_match) bits |= (1 << 23); if (!mins_match) bits |= (1 << 15); @@ -276,27 +306,30 @@ void RTClock::setAlarmATime (tm * tm_ptr, bool hours_match, bool mins_match, boo rtc_enable_alarm_event(); } - -void RTClock::setAlarmATime (time_t alarm_time, bool hours_match, bool mins_match, bool secs_match, bool date_match) { - struct tm* tm_ptr = gmtime(&alarm_time); - setAlarmATime(tm_ptr, hours_match, mins_match, secs_match, date_match); +//----------------------------------------------------------------------------- +void RTClock::setAlarmATime (time_t alarm_time, bool hours_match, bool mins_match, bool secs_match, bool date_match) +{ + breakTime(alarm_time, tm); + setAlarmATime(&tm, hours_match, mins_match, secs_match, date_match); } - -void RTClock::turnOffAlarmA() { +//----------------------------------------------------------------------------- +void RTClock::turnOffAlarmA(void) +{ rtc_enter_config_mode(); RTC_BASE->CR &= ~(1 << RTC_CR_ALRAIE_BIT); // turn off ALRAIE rtc_exit_config_mode(); } - -void RTClock::setAlarmBTime (tm * tm_ptr, bool hours_match, bool mins_match, bool secs_match, bool date_match) { +//----------------------------------------------------------------------------- +void RTClock::setAlarmBTime (tm_t * tm_ptr, bool hours_match, bool mins_match, bool secs_match, bool date_match) +{ uint32 t = 0; rtc_enter_config_mode(); - unsigned int bits = ((tm_ptr->tm_mday / 10) << 28) | ((tm_ptr->tm_mday % 10) << 24) | - ((tm_ptr->tm_hour / 10) << 20) | ((tm_ptr->tm_hour % 10) << 16) | - ((tm_ptr->tm_min / 10) << 12) | ((tm_ptr->tm_min % 10) << 8) | - ((tm_ptr->tm_sec / 10) << 4) | (tm_ptr->tm_sec % 10); + unsigned int bits = ((tm_ptr->day / 10) << 28) | ((tm_ptr->day % 10) << 24) | + ((tm_ptr->hour / 10) << 20) | ((tm_ptr->hour % 10) << 16) | + ((tm_ptr->minute / 10) << 12) | ((tm_ptr->minute % 10) << 8) | + ((tm_ptr->second / 10) << 4) | (tm_ptr->second % 10); if (!date_match) bits |= (1 << 31); if (!hours_match) bits |= (1 << 23); if (!mins_match) bits |= (1 << 15); @@ -318,21 +351,23 @@ void RTClock::setAlarmBTime (tm * tm_ptr, bool hours_match, bool mins_match, boo rtc_enable_alarm_event(); } - -void RTClock::setAlarmBTime (time_t alarm_time, bool hours_match, bool mins_match, bool secs_match, bool date_match) { - struct tm* tm_ptr = gmtime(&alarm_time); - setAlarmBTime(tm_ptr, hours_match, mins_match, secs_match, date_match); +//----------------------------------------------------------------------------- +void RTClock::setAlarmBTime (time_t alarm_time, bool hours_match, bool mins_match, bool secs_match, bool date_match) +{ + breakTime(alarm_time, tm); + setAlarmBTime(&tm, hours_match, mins_match, secs_match, date_match); } - +//----------------------------------------------------------------------------- void RTClock::turnOffAlarmB() { rtc_enter_config_mode(); RTC_BASE->CR &= ~(1 << RTC_CR_ALRBIE_BIT); // turn off ALRBIE rtc_exit_config_mode(); } - -void RTClock::setPeriodicWakeup(uint16 period) { +//----------------------------------------------------------------------------- +void RTClock::setPeriodicWakeup(uint16 period) +{ uint32 t = 0; rtc_enter_config_mode(); RTC_BASE->CR &= ~(1 << RTC_CR_WUTE_BIT); diff --git a/STM32F4/libraries/RTClock/src/RTClock.h b/STM32F4/libraries/RTClock/src/RTClock.h index facaa00..c13bf5f 100644 --- a/STM32F4/libraries/RTClock/src/RTClock.h +++ b/STM32F4/libraries/RTClock/src/RTClock.h @@ -1,29 +1,35 @@ -#include -#include -#include -#include -#include -#include -#include - #ifndef _RTCLOCK_H_ #define _RTCLOCK_H_ -//#define RTC_DEBUG #ifdef __cplusplus extern "C" { #endif + + +#include // for __time_t_defined +#include +#include +#include +#include +#include +#include + +//#define RTC_DEBUG + + +#if !defined(__time_t_defined) // avoid conflict with newlib or other posix libc + #warning "Using private time_t definintion" + typedef uint32_t time_t; +#endif + #ifdef RTC_DEBUG extern void dbg_printf(const char *fmt, ... ); #define rtc_debug_printf(fmt, ...) dbg_printf(fmt, ##__VA_ARGS__); #else #define rtc_debug_printf(...) #endif -#ifdef __cplusplus -} -#endif #define SECS_PER_MIN (60UL) @@ -33,7 +39,7 @@ extern "C" { #define SECS_PER_WEEK (SECS_PER_DAY * DAYS_PER_WEEK) #define SECS_PER_YEAR (SECS_PER_WEEK * 52UL) #define SECS_YR_2000 (946684800UL) // the time at the start of y2k -#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) +#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) static const unsigned char monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; // API starts months from 1, this array starts from 0 @@ -91,6 +97,28 @@ typedef enum rtc_clk_src { RTCSEL_HSE = 0x13, } rtc_clk_src; +// Time register +#define RTC_TR_PM_BIT 22 +#define RTC_TR_HOUR_BIT 16 +#define RTC_TR_MINUTE_BIT 8 +#define RTC_TR_SECOND_BIT 0 + +#define RTC_TR_PM_MASK (0x01)//<>4)) + (b&0x0F) ); } +static inline uint8_t bin2bcd(uint8_t b) { return ( ((b/10)<<4) + (b%10) ); } class RTClock { - public: - RTClock(); - RTClock(rtc_clk_src src ); + public: + RTClock() { RTClock(RTCSEL_LSE, 0, 0); } + RTClock(rtc_clk_src src ) { RTClock(src, 0, 0); } RTClock(rtc_clk_src src, uint16 sync_prescaler, uint16 async_prescaler); //~RTClock(); //to implement + + void breakTime(time_t epoch_time, tm_t & tm); + time_t makeTime(tm_t & tm); void setTime (time_t time_stamp); - void setTime (struct tm * tm_ptr); + void setTime (tm_t & tm); - struct tm* getTime(struct tm* tm_ptr); time_t getTime(); + void getTime(tm_t & tm); + #define now getTime + + uint8_t year(void) { getTime(tm); return tm.year; } + uint8_t month(void) { getTime(tm); return tm.month; } + uint8_t day(void) { getTime(tm); return tm.day; } + uint8_t weekday(void) { getTime(tm); return tm.weekday; } + uint8_t hour(void) { getTime(tm); return tm.hour; } + uint8_t minute(void) { getTime(tm); return tm.minute; } + uint8_t second(void) { getTime(tm); return tm.second; } + //uint8_t pm(void) { return _pm(RTC_BASE->TR); } + uint8_t isPM(void) { return ( hour()>=12 ); } - void setAlarmATime (tm * tm_ptr, bool hours_match = true, bool mins_match = true, bool secs_match = true, bool date_match = false); + uint8_t year(time_t t) { breakTime(t, tm); return tm.year; } + uint8_t month(time_t t) { breakTime(t, tm); return tm.month; } + uint8_t day(time_t t) { breakTime(t, tm); return tm.day; } + uint8_t weekday(time_t t) { breakTime(t, tm); return tm.weekday; } + uint8_t hour(time_t t) { breakTime(t, tm); return tm.hour; } + uint8_t minute(time_t t) { breakTime(t, tm); return tm.minute; } + uint8_t second(time_t t) { breakTime(t, tm); return tm.second; } + uint8_t isPM(time_t t) { return (hour(t)>=12); } + + void setAlarmATime (tm_t * tm_ptr, bool hours_match = true, bool mins_match = true, bool secs_match = true, bool date_match = false); void setAlarmATime (time_t alarm_time, bool hours_match = true, bool mins_match = true, bool secs_match = true, bool date_match = false); void turnOffAlarmA(); - void setAlarmBTime (tm * tm_ptr, bool hours_match = true, bool mins_match = true, bool secs_match = true, bool date_match = false); + void setAlarmBTime (tm_t * tm_ptr, bool hours_match = true, bool mins_match = true, bool secs_match = true, bool date_match = false); void setAlarmBTime (time_t alarm_time, bool hours_match = true, bool mins_match = true, bool secs_match = true, bool date_match = false); void turnOffAlarmB(); @@ -143,17 +216,29 @@ class RTClock { void attachPeriodicWakeupInterrupt(voidFuncPtr function); void detachPeriodicWakeupInterrupt(); + inline void attachSecondsInterrupt(voidFuncPtr function) { attachPeriodicWakeupInterrupt(function); } + inline void detachSecondsInterrupt() { detachPeriodicWakeupInterrupt(); } void attachAlarmAInterrupt(voidFuncPtr function); void detachAlarmAInterrupt(); void attachAlarmBInterrupt(voidFuncPtr function); void detachAlarmBInterrupt(); - //private: - -} ; + private: + inline uint8_t _year(uint32_t dr) { return bcd2bin( (dr>>RTC_DR_YEAR_BIT) & RTC_DR_YEAR_MASK ); } + inline uint8_t _month(uint32_t dr) { return bcd2bin( (dr>>RTC_DR_MONTH_BIT) & RTC_DR_MONTH_MASK ); } + inline uint8_t _day(uint32_t dr) { return bcd2bin( (dr>>RTC_DR_DAY_BIT) & RTC_DR_DAY_MASK ); } + inline uint8_t _weekday(uint32_t dr) { return bcd2bin( (dr>>RTC_DR_WEEKDAY_BIT) & RTC_DR_WEEKDAY_MASK ); } + inline uint8_t _pm(uint32_t tr) { return ( (tr>>RTC_TR_PM_BIT) & RTC_TR_PM_MASK ); } + inline uint8_t _hour(uint32_t tr) { return bcd2bin( (tr>>RTC_TR_HOUR_BIT) & RTC_TR_HOUR_MASK ); } + inline uint8_t _minute(uint32_t tr) { return bcd2bin( (tr>>RTC_TR_MINUTE_BIT) & RTC_TR_MINUTE_MASK ); } + inline uint8_t _second(uint32_t tr) { return bcd2bin( (tr>>RTC_TR_SECOND_BIT) & RTC_TR_SECOND_MASK ); } + tm_t tm; +}; +inline uint32_t getTReg(void) { return (uint32_t)(RTC_BASE->TR); } +inline uint32_t getDReg(void) { return (uint32_t)(RTC_BASE->DR); } /** * @brief Clear the register synchronized flag. The flag is then set by hardware after a write to PRL/DIV or CNT. @@ -246,7 +331,8 @@ static inline void rtc_disable_wakeup_event() { *bb_perip(&EXTI_BASE->RTSR, EXTI_RTC_WAKEUP_BIT) = 0; } - +#ifdef __cplusplus +} +#endif #endif // _RTCLOCK_H_ - \ No newline at end of file