This is a library for managing the mbed real time clock, including functions for setting and getting the rtc in text format, getting and setting the timezone offset, and getting and setting the calibration register, both directly, and by using an adjustment API to automatically set the calibration value.

Dependents:   LAB4WEEK1 Motor

Committer:
WiredHome
Date:
Sun Oct 30 23:42:43 2011 +0000
Revision:
5:fbbdf57675c3
Parent:
3:524ad47afdc7
Child:
6:a517fee06e2e
v1.03 Added API to adjust the calibration based on an accumulated error over a period of time (typically >= 1 day).

Who changed what in which revision?

UserRevisionLine numberNew contents of line
WiredHome 0:108436d3cea9 1 /// @file TimeUtilities.cpp contains a real time clock interface for the mbed
WiredHome 0:108436d3cea9 2 ///
WiredHome 0:108436d3cea9 3 /// APIs for showing the time from the RTC, or from a passed in value.
WiredHome 0:108436d3cea9 4 /// Also supports setting the clock, timezone offsets and calibration
WiredHome 0:108436d3cea9 5 /// of the RTC subsystem.
WiredHome 0:108436d3cea9 6 ///
WiredHome 1:6d3d16f4b27c 7 /// @note Copyright &copr; 2011 by Smartware Computing, all rights reserved.
WiredHome 1:6d3d16f4b27c 8 /// Individuals may use this application for evaluation or non-commercial
WiredHome 1:6d3d16f4b27c 9 /// purposes. Within this restriction, changes may be made to this application
WiredHome 1:6d3d16f4b27c 10 /// as long as this copyright notice is retained. The user shall make
WiredHome 1:6d3d16f4b27c 11 /// clear that their work is a derived work, and not the original.
WiredHome 1:6d3d16f4b27c 12 /// Users of this application and sources accept this application "as is" and
WiredHome 1:6d3d16f4b27c 13 /// shall hold harmless Smartware Computing, for any undesired results while
WiredHome 1:6d3d16f4b27c 14 /// using this application - whether real or imagined.
WiredHome 1:6d3d16f4b27c 15 ///
WiredHome 1:6d3d16f4b27c 16 /// @author David Smart, Smartware Computing
WiredHome 0:108436d3cea9 17 ///
WiredHome 0:108436d3cea9 18 #ifndef WIN32
WiredHome 0:108436d3cea9 19 // embedded build
WiredHome 0:108436d3cea9 20 #include "mbed.h"
WiredHome 0:108436d3cea9 21 #endif
WiredHome 0:108436d3cea9 22
WiredHome 5:fbbdf57675c3 23 #define VERSION "1.03"
WiredHome 5:fbbdf57675c3 24
WiredHome 0:108436d3cea9 25 #include "TimeUtilities.h"
WiredHome 0:108436d3cea9 26 #include <time.h>
WiredHome 0:108436d3cea9 27 #include <string.h>
WiredHome 0:108436d3cea9 28 #include <stdio.h>
WiredHome 0:108436d3cea9 29 #include <stdlib.h>
WiredHome 0:108436d3cea9 30
WiredHome 0:108436d3cea9 31 #ifdef WIN32
WiredHome 3:524ad47afdc7 32 // Fake it out for Win32 development and testing
WiredHome 0:108436d3cea9 33 struct LPC {
WiredHome 2:cbcdd97f3a6d 34 unsigned long CCR; // Clock Control register
WiredHome 5:fbbdf57675c3 35 unsigned long GPREG0; // General Purpose Register #0 - 32-bit Battery backed
WiredHome 5:fbbdf57675c3 36 unsigned long GPREG1; // General Purpose Register #1 - 32-bit Battery backed
WiredHome 2:cbcdd97f3a6d 37 unsigned long CALIBRATION; // Calibration Register
WiredHome 0:108436d3cea9 38 };
WiredHome 0:108436d3cea9 39 struct LPC X;
WiredHome 0:108436d3cea9 40 struct LPC * LPC_RTC = &X;
WiredHome 0:108436d3cea9 41 #define set_time(x) (void)x
WiredHome 0:108436d3cea9 42 #endif
WiredHome 0:108436d3cea9 43
WiredHome 0:108436d3cea9 44 static int tzOffsetHr = 0; ///!< time zone offset hours to print time in local time
WiredHome 0:108436d3cea9 45 static int tzOffsetMin = 0; ///!< time zone offset minutes to print time in local time
WiredHome 5:fbbdf57675c3 46 static time_t timeWhenLastSet = 0;
WiredHome 5:fbbdf57675c3 47
WiredHome 5:fbbdf57675c3 48
WiredHome 5:fbbdf57675c3 49 static const char ver[] = VERSION;
WiredHome 0:108436d3cea9 50
WiredHome 0:108436d3cea9 51 static int SignOf(const int i) {
WiredHome 0:108436d3cea9 52 return (i >= 0) ? 1 : -1;
WiredHome 0:108436d3cea9 53 }
WiredHome 0:108436d3cea9 54
WiredHome 2:cbcdd97f3a6d 55
WiredHome 0:108436d3cea9 56 RealTimeClock::RealTimeClock() {
WiredHome 1:6d3d16f4b27c 57 GetTimeOffsetStore();
WiredHome 5:fbbdf57675c3 58 GetTimeLastSetStore();
WiredHome 0:108436d3cea9 59 }
WiredHome 0:108436d3cea9 60
WiredHome 2:cbcdd97f3a6d 61
WiredHome 0:108436d3cea9 62 RealTimeClock::~RealTimeClock() {
WiredHome 0:108436d3cea9 63 }
WiredHome 0:108436d3cea9 64
WiredHome 5:fbbdf57675c3 65 const char * RealTimeClock::GetVersion() {
WiredHome 5:fbbdf57675c3 66 return ver;
WiredHome 5:fbbdf57675c3 67 }
WiredHome 5:fbbdf57675c3 68
WiredHome 5:fbbdf57675c3 69 time_t RealTimeClock::GetTimeValue() {
WiredHome 5:fbbdf57675c3 70 return time(NULL);
WiredHome 5:fbbdf57675c3 71 }
WiredHome 5:fbbdf57675c3 72
WiredHome 5:fbbdf57675c3 73 time_t RealTimeClock::GetTimeValueWhenSet() {
WiredHome 5:fbbdf57675c3 74 return timeWhenLastSet;
WiredHome 5:fbbdf57675c3 75 }
WiredHome 5:fbbdf57675c3 76
WiredHome 2:cbcdd97f3a6d 77
WiredHome 0:108436d3cea9 78 void RealTimeClock::GetTimeString(char *buf, time_t tValue) {
WiredHome 0:108436d3cea9 79 GetTimeOffsetStore(); // Load the time zone offset values from the battery ram
WiredHome 0:108436d3cea9 80 GetTimeString(buf, tValue, tzOffsetHr, tzOffsetMin);
WiredHome 0:108436d3cea9 81 }
WiredHome 0:108436d3cea9 82
WiredHome 2:cbcdd97f3a6d 83
WiredHome 0:108436d3cea9 84 void RealTimeClock::GetTimeString(char *buf, int hOffset, int mOffset) {
WiredHome 0:108436d3cea9 85 GetTimeString(buf, 0, hOffset, mOffset);
WiredHome 0:108436d3cea9 86 }
WiredHome 0:108436d3cea9 87
WiredHome 2:cbcdd97f3a6d 88
WiredHome 0:108436d3cea9 89 void RealTimeClock::GetTimeString(char *buf, time_t tValue, int hOffset, int mOffset) {
WiredHome 0:108436d3cea9 90 time_t ctTime;
WiredHome 0:108436d3cea9 91
WiredHome 0:108436d3cea9 92 if (tValue == 0)
WiredHome 0:108436d3cea9 93 tValue = time(NULL);
WiredHome 0:108436d3cea9 94 ctTime = tValue + hOffset * 3600 + SignOf(hOffset) * mOffset * 60;
WiredHome 0:108436d3cea9 95 strcpy(buf, ctime(&ctTime));
WiredHome 0:108436d3cea9 96 buf[strlen(buf)-1] = '\0'; // remove the \n
WiredHome 0:108436d3cea9 97 sprintf(buf + strlen(buf), " (tzo: %2i:%02i)", hOffset, mOffset);
WiredHome 0:108436d3cea9 98 }
WiredHome 0:108436d3cea9 99
WiredHome 2:cbcdd97f3a6d 100
WiredHome 0:108436d3cea9 101 int32_t RealTimeClock::GetTimeCalibration() {
WiredHome 0:108436d3cea9 102 int32_t calvalue = LPC_RTC->CALIBRATION & 0x3FFFF;
WiredHome 0:108436d3cea9 103
WiredHome 0:108436d3cea9 104 if (calvalue & 0x20000) {
WiredHome 0:108436d3cea9 105 calvalue = -(calvalue & 0x1FFFF);
WiredHome 0:108436d3cea9 106 }
WiredHome 0:108436d3cea9 107 return calvalue;
WiredHome 0:108436d3cea9 108 }
WiredHome 0:108436d3cea9 109
WiredHome 2:cbcdd97f3a6d 110
WiredHome 0:108436d3cea9 111 void RealTimeClock::SetTimeCalibration(int32_t calibration) {
WiredHome 2:cbcdd97f3a6d 112 if (calibration) {
WiredHome 2:cbcdd97f3a6d 113 if (calibration < 0) {
WiredHome 2:cbcdd97f3a6d 114 calibration = (-calibration & 0x1FFFF) | 0x20000;
WiredHome 2:cbcdd97f3a6d 115 }
WiredHome 2:cbcdd97f3a6d 116 LPC_RTC->CCR = 0x000001; //(LPC_RTC->CCR & 0x0003); // Clear CCALEN to enable it
WiredHome 2:cbcdd97f3a6d 117 } else {
WiredHome 2:cbcdd97f3a6d 118 LPC_RTC->CCR = 0x000011; //(LPC_RTC->CCR & 0x0003) | 0x0010; // Set CCALEN to disable it
WiredHome 0:108436d3cea9 119 }
WiredHome 0:108436d3cea9 120 LPC_RTC->CALIBRATION = calibration;
WiredHome 0:108436d3cea9 121 }
WiredHome 0:108436d3cea9 122
WiredHome 2:cbcdd97f3a6d 123
WiredHome 0:108436d3cea9 124 void RealTimeClock::SetTimeOffset(int offsetHour, int offsetMinute) {
WiredHome 0:108436d3cea9 125 tzOffsetHr = offsetHour;
WiredHome 0:108436d3cea9 126 tzOffsetMin = offsetMinute;
WiredHome 0:108436d3cea9 127 SetTimeOffsetStore();
WiredHome 0:108436d3cea9 128 }
WiredHome 0:108436d3cea9 129
WiredHome 2:cbcdd97f3a6d 130
WiredHome 0:108436d3cea9 131 void RealTimeClock::SetTimeOffsetStore() {
WiredHome 0:108436d3cea9 132 LPC_RTC->GPREG0 = tzOffsetHr * 256 + tzOffsetMin;
WiredHome 0:108436d3cea9 133 }
WiredHome 0:108436d3cea9 134
WiredHome 2:cbcdd97f3a6d 135
WiredHome 0:108436d3cea9 136 void RealTimeClock::GetTimeOffsetStore() {
WiredHome 0:108436d3cea9 137 tzOffsetHr = (int32_t)LPC_RTC->GPREG0 / 256;
WiredHome 0:108436d3cea9 138 tzOffsetMin = (LPC_RTC->GPREG0 & 0xFF);
WiredHome 0:108436d3cea9 139 }
WiredHome 0:108436d3cea9 140
WiredHome 5:fbbdf57675c3 141 void RealTimeClock::SetTimeLastSetStore() {
WiredHome 5:fbbdf57675c3 142 LPC_RTC->GPREG1 = timeWhenLastSet;
WiredHome 5:fbbdf57675c3 143 }
WiredHome 5:fbbdf57675c3 144
WiredHome 5:fbbdf57675c3 145 void RealTimeClock::GetTimeLastSetStore() {
WiredHome 5:fbbdf57675c3 146 timeWhenLastSet = LPC_RTC->GPREG1;
WiredHome 5:fbbdf57675c3 147 }
WiredHome 2:cbcdd97f3a6d 148
WiredHome 0:108436d3cea9 149 // MM/DD/YYYY HH:MM:SS [(+/-hh:mm)]
WiredHome 0:108436d3cea9 150 bool RealTimeClock::SetTime(char * timestring) {
WiredHome 0:108436d3cea9 151 bool success = false;
WiredHome 0:108436d3cea9 152 char * p;
WiredHome 0:108436d3cea9 153 time_t seconds = time(NULL);
WiredHome 0:108436d3cea9 154 struct tm *t = localtime(&seconds);
WiredHome 0:108436d3cea9 155 int _oH, _oM;
WiredHome 0:108436d3cea9 156
WiredHome 0:108436d3cea9 157 p = strtok(timestring," /");
WiredHome 0:108436d3cea9 158 if (p != NULL) {
WiredHome 0:108436d3cea9 159 t->tm_mon = atoi(p) - 1;
WiredHome 0:108436d3cea9 160 p = strtok(NULL, " /");
WiredHome 0:108436d3cea9 161 if (p != NULL) {
WiredHome 0:108436d3cea9 162 t->tm_mday = atoi(p);
WiredHome 0:108436d3cea9 163 p = strtok(NULL, " /");
WiredHome 0:108436d3cea9 164 if (p != NULL) {
WiredHome 0:108436d3cea9 165 t->tm_year = atoi(p) - 1900;
WiredHome 0:108436d3cea9 166 p = strtok(NULL, " :");
WiredHome 0:108436d3cea9 167 if (p != NULL) {
WiredHome 0:108436d3cea9 168 t->tm_hour = atoi(p);
WiredHome 0:108436d3cea9 169 p = strtok(NULL, " :");
WiredHome 0:108436d3cea9 170 if (p != NULL) {
WiredHome 1:6d3d16f4b27c 171 t->tm_min = atoi(p);
WiredHome 1:6d3d16f4b27c 172 p = strtok(NULL, " (:");
WiredHome 1:6d3d16f4b27c 173 if (p != NULL) {
WiredHome 1:6d3d16f4b27c 174 t->tm_sec = atoi(p);
WiredHome 1:6d3d16f4b27c 175 success = true; // if we get to here, we're good
WiredHome 1:6d3d16f4b27c 176 p = strtok(NULL, " (:");
WiredHome 1:6d3d16f4b27c 177 if (p != NULL) {
WiredHome 1:6d3d16f4b27c 178 success = false; // but can't accept a partial tzo
WiredHome 1:6d3d16f4b27c 179 _oH = atoi(p);
WiredHome 1:6d3d16f4b27c 180 p = strtok(NULL, " (:)");
WiredHome 1:6d3d16f4b27c 181 if (p != NULL) {
WiredHome 1:6d3d16f4b27c 182 _oM = atoi(p);
WiredHome 1:6d3d16f4b27c 183 success = true; // but a whole tzo is ok
WiredHome 1:6d3d16f4b27c 184 SetTimeOffset(_oH, _oM);
WiredHome 1:6d3d16f4b27c 185 }
WiredHome 1:6d3d16f4b27c 186 }
WiredHome 1:6d3d16f4b27c 187 seconds = mktime(t);
WiredHome 1:6d3d16f4b27c 188 seconds = seconds - (time_t)(tzOffsetHr * 3600 + tzOffsetMin * 60);
WiredHome 1:6d3d16f4b27c 189 set_time(seconds);
WiredHome 5:fbbdf57675c3 190 timeWhenLastSet = seconds;
WiredHome 5:fbbdf57675c3 191 SetTimeLastSetStore();
WiredHome 1:6d3d16f4b27c 192 }
WiredHome 1:6d3d16f4b27c 193 }
WiredHome 0:108436d3cea9 194 }
WiredHome 0:108436d3cea9 195 }
WiredHome 0:108436d3cea9 196 }
WiredHome 0:108436d3cea9 197 }
WiredHome 0:108436d3cea9 198 return success;
WiredHome 0:108436d3cea9 199 }
WiredHome 0:108436d3cea9 200
WiredHome 5:fbbdf57675c3 201 bool RealTimeClock::AdjustBySeconds(int32_t adjustSeconds) {
WiredHome 5:fbbdf57675c3 202 if (timeWhenLastSet != 0) {
WiredHome 5:fbbdf57675c3 203 time_t seconds = time(NULL); // get "now" according to the rtc
WiredHome 5:fbbdf57675c3 204 int32_t delta = seconds - timeWhenLastSet;
WiredHome 5:fbbdf57675c3 205 int32_t curCal = GetTimeCalibration();
WiredHome 5:fbbdf57675c3 206 int32_t calMAX = 131071;
WiredHome 5:fbbdf57675c3 207 int32_t secPerDay = 86400;
WiredHome 5:fbbdf57675c3 208 float errSecPerDay;
WiredHome 5:fbbdf57675c3 209
WiredHome 5:fbbdf57675c3 210 // Make the clock correct
WiredHome 5:fbbdf57675c3 211 seconds = seconds + adjustSeconds;
WiredHome 5:fbbdf57675c3 212 set_time(seconds);
WiredHome 5:fbbdf57675c3 213
WiredHome 5:fbbdf57675c3 214 // Convert the current calibration and the adjustment into
WiredHome 5:fbbdf57675c3 215 // the new calibration value
WiredHome 5:fbbdf57675c3 216 // assume it is +10sec and it has been 2days, then the adjustment
WiredHome 5:fbbdf57675c3 217 // needs to be +5 sec per day, or one adjustment every 1/5th
WiredHome 5:fbbdf57675c3 218 // of a day, or 1 adjustment every 86400/5 counts.
WiredHome 5:fbbdf57675c3 219 // delta = now - then (number of elapsed seconds)
WiredHome 5:fbbdf57675c3 220 if (adjustSeconds != 0 && delta != 0) {
WiredHome 5:fbbdf57675c3 221 int32_t calFactor;
WiredHome 5:fbbdf57675c3 222 errSecPerDay = (float)adjustSeconds / ((float)(delta)/secPerDay);
WiredHome 5:fbbdf57675c3 223 calFactor = (int32_t)((float)secPerDay/errSecPerDay);
WiredHome 5:fbbdf57675c3 224 if (abs(calFactor) < calMAX)
WiredHome 5:fbbdf57675c3 225 SetTimeCalibration(calFactor);
WiredHome 5:fbbdf57675c3 226 }
WiredHome 5:fbbdf57675c3 227 return true;
WiredHome 5:fbbdf57675c3 228 } else {
WiredHome 5:fbbdf57675c3 229 return false;
WiredHome 5:fbbdf57675c3 230 }
WiredHome 5:fbbdf57675c3 231 }