Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
TimeUtilities.cpp@6:a517fee06e2e, 2011-11-02 (annotated)
- Committer:
- WiredHome
- Date:
- Wed Nov 02 01:32:07 2011 +0000
- Revision:
- 6:a517fee06e2e
- Parent:
- 5:fbbdf57675c3
- Child:
- 7:812452a275fa
v1.04 Minor changes to the adjustment logic for complexity reduction
Who changed what in which revision?
User | Revision | Line number | New 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 | 6:a517fee06e2e | 23 | #define VERSION "1.04" |
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 | |
WiredHome | 5:fbbdf57675c3 | 47 | |
WiredHome | 5:fbbdf57675c3 | 48 | static const char ver[] = VERSION; |
WiredHome | 0:108436d3cea9 | 49 | |
WiredHome | 0:108436d3cea9 | 50 | static int SignOf(const int i) { |
WiredHome | 0:108436d3cea9 | 51 | return (i >= 0) ? 1 : -1; |
WiredHome | 0:108436d3cea9 | 52 | } |
WiredHome | 0:108436d3cea9 | 53 | |
WiredHome | 2:cbcdd97f3a6d | 54 | |
WiredHome | 0:108436d3cea9 | 55 | RealTimeClock::RealTimeClock() { |
WiredHome | 1:6d3d16f4b27c | 56 | GetTimeOffsetStore(); |
WiredHome | 0:108436d3cea9 | 57 | } |
WiredHome | 0:108436d3cea9 | 58 | |
WiredHome | 2:cbcdd97f3a6d | 59 | |
WiredHome | 0:108436d3cea9 | 60 | RealTimeClock::~RealTimeClock() { |
WiredHome | 0:108436d3cea9 | 61 | } |
WiredHome | 0:108436d3cea9 | 62 | |
WiredHome | 5:fbbdf57675c3 | 63 | const char * RealTimeClock::GetVersion() { |
WiredHome | 5:fbbdf57675c3 | 64 | return ver; |
WiredHome | 5:fbbdf57675c3 | 65 | } |
WiredHome | 5:fbbdf57675c3 | 66 | |
WiredHome | 5:fbbdf57675c3 | 67 | time_t RealTimeClock::GetTimeValue() { |
WiredHome | 5:fbbdf57675c3 | 68 | return time(NULL); |
WiredHome | 5:fbbdf57675c3 | 69 | } |
WiredHome | 5:fbbdf57675c3 | 70 | |
WiredHome | 2:cbcdd97f3a6d | 71 | |
WiredHome | 0:108436d3cea9 | 72 | void RealTimeClock::GetTimeString(char *buf, time_t tValue) { |
WiredHome | 0:108436d3cea9 | 73 | GetTimeOffsetStore(); // Load the time zone offset values from the battery ram |
WiredHome | 0:108436d3cea9 | 74 | GetTimeString(buf, tValue, tzOffsetHr, tzOffsetMin); |
WiredHome | 0:108436d3cea9 | 75 | } |
WiredHome | 0:108436d3cea9 | 76 | |
WiredHome | 2:cbcdd97f3a6d | 77 | |
WiredHome | 0:108436d3cea9 | 78 | void RealTimeClock::GetTimeString(char *buf, int hOffset, int mOffset) { |
WiredHome | 0:108436d3cea9 | 79 | GetTimeString(buf, 0, hOffset, mOffset); |
WiredHome | 0:108436d3cea9 | 80 | } |
WiredHome | 0:108436d3cea9 | 81 | |
WiredHome | 2:cbcdd97f3a6d | 82 | |
WiredHome | 0:108436d3cea9 | 83 | void RealTimeClock::GetTimeString(char *buf, time_t tValue, int hOffset, int mOffset) { |
WiredHome | 0:108436d3cea9 | 84 | time_t ctTime; |
WiredHome | 0:108436d3cea9 | 85 | |
WiredHome | 0:108436d3cea9 | 86 | if (tValue == 0) |
WiredHome | 0:108436d3cea9 | 87 | tValue = time(NULL); |
WiredHome | 0:108436d3cea9 | 88 | ctTime = tValue + hOffset * 3600 + SignOf(hOffset) * mOffset * 60; |
WiredHome | 0:108436d3cea9 | 89 | strcpy(buf, ctime(&ctTime)); |
WiredHome | 0:108436d3cea9 | 90 | buf[strlen(buf)-1] = '\0'; // remove the \n |
WiredHome | 0:108436d3cea9 | 91 | sprintf(buf + strlen(buf), " (tzo: %2i:%02i)", hOffset, mOffset); |
WiredHome | 0:108436d3cea9 | 92 | } |
WiredHome | 0:108436d3cea9 | 93 | |
WiredHome | 2:cbcdd97f3a6d | 94 | |
WiredHome | 0:108436d3cea9 | 95 | int32_t RealTimeClock::GetTimeCalibration() { |
WiredHome | 0:108436d3cea9 | 96 | int32_t calvalue = LPC_RTC->CALIBRATION & 0x3FFFF; |
WiredHome | 0:108436d3cea9 | 97 | |
WiredHome | 0:108436d3cea9 | 98 | if (calvalue & 0x20000) { |
WiredHome | 0:108436d3cea9 | 99 | calvalue = -(calvalue & 0x1FFFF); |
WiredHome | 0:108436d3cea9 | 100 | } |
WiredHome | 0:108436d3cea9 | 101 | return calvalue; |
WiredHome | 0:108436d3cea9 | 102 | } |
WiredHome | 0:108436d3cea9 | 103 | |
WiredHome | 2:cbcdd97f3a6d | 104 | |
WiredHome | 0:108436d3cea9 | 105 | void RealTimeClock::SetTimeCalibration(int32_t calibration) { |
WiredHome | 2:cbcdd97f3a6d | 106 | if (calibration) { |
WiredHome | 2:cbcdd97f3a6d | 107 | if (calibration < 0) { |
WiredHome | 2:cbcdd97f3a6d | 108 | calibration = (-calibration & 0x1FFFF) | 0x20000; |
WiredHome | 2:cbcdd97f3a6d | 109 | } |
WiredHome | 2:cbcdd97f3a6d | 110 | LPC_RTC->CCR = 0x000001; //(LPC_RTC->CCR & 0x0003); // Clear CCALEN to enable it |
WiredHome | 2:cbcdd97f3a6d | 111 | } else { |
WiredHome | 2:cbcdd97f3a6d | 112 | LPC_RTC->CCR = 0x000011; //(LPC_RTC->CCR & 0x0003) | 0x0010; // Set CCALEN to disable it |
WiredHome | 0:108436d3cea9 | 113 | } |
WiredHome | 0:108436d3cea9 | 114 | LPC_RTC->CALIBRATION = calibration; |
WiredHome | 0:108436d3cea9 | 115 | } |
WiredHome | 0:108436d3cea9 | 116 | |
WiredHome | 2:cbcdd97f3a6d | 117 | |
WiredHome | 0:108436d3cea9 | 118 | void RealTimeClock::SetTimeOffset(int offsetHour, int offsetMinute) { |
WiredHome | 0:108436d3cea9 | 119 | tzOffsetHr = offsetHour; |
WiredHome | 0:108436d3cea9 | 120 | tzOffsetMin = offsetMinute; |
WiredHome | 0:108436d3cea9 | 121 | SetTimeOffsetStore(); |
WiredHome | 0:108436d3cea9 | 122 | } |
WiredHome | 0:108436d3cea9 | 123 | |
WiredHome | 2:cbcdd97f3a6d | 124 | |
WiredHome | 0:108436d3cea9 | 125 | void RealTimeClock::SetTimeOffsetStore() { |
WiredHome | 0:108436d3cea9 | 126 | LPC_RTC->GPREG0 = tzOffsetHr * 256 + tzOffsetMin; |
WiredHome | 0:108436d3cea9 | 127 | } |
WiredHome | 0:108436d3cea9 | 128 | |
WiredHome | 2:cbcdd97f3a6d | 129 | |
WiredHome | 0:108436d3cea9 | 130 | void RealTimeClock::GetTimeOffsetStore() { |
WiredHome | 0:108436d3cea9 | 131 | tzOffsetHr = (int32_t)LPC_RTC->GPREG0 / 256; |
WiredHome | 0:108436d3cea9 | 132 | tzOffsetMin = (LPC_RTC->GPREG0 & 0xFF); |
WiredHome | 0:108436d3cea9 | 133 | } |
WiredHome | 0:108436d3cea9 | 134 | |
WiredHome | 6:a517fee06e2e | 135 | void RealTimeClock::SetTimeLastSet(time_t t) { |
WiredHome | 6:a517fee06e2e | 136 | LPC_RTC->GPREG1 = t; |
WiredHome | 5:fbbdf57675c3 | 137 | } |
WiredHome | 5:fbbdf57675c3 | 138 | |
WiredHome | 6:a517fee06e2e | 139 | time_t RealTimeClock::GetTimeLastSet() { |
WiredHome | 6:a517fee06e2e | 140 | return LPC_RTC->GPREG1; |
WiredHome | 5:fbbdf57675c3 | 141 | } |
WiredHome | 2:cbcdd97f3a6d | 142 | |
WiredHome | 0:108436d3cea9 | 143 | // MM/DD/YYYY HH:MM:SS [(+/-hh:mm)] |
WiredHome | 0:108436d3cea9 | 144 | bool RealTimeClock::SetTime(char * timestring) { |
WiredHome | 0:108436d3cea9 | 145 | bool success = false; |
WiredHome | 0:108436d3cea9 | 146 | char * p; |
WiredHome | 0:108436d3cea9 | 147 | time_t seconds = time(NULL); |
WiredHome | 0:108436d3cea9 | 148 | struct tm *t = localtime(&seconds); |
WiredHome | 0:108436d3cea9 | 149 | int _oH, _oM; |
WiredHome | 0:108436d3cea9 | 150 | |
WiredHome | 0:108436d3cea9 | 151 | p = strtok(timestring," /"); |
WiredHome | 0:108436d3cea9 | 152 | if (p != NULL) { |
WiredHome | 0:108436d3cea9 | 153 | t->tm_mon = atoi(p) - 1; |
WiredHome | 0:108436d3cea9 | 154 | p = strtok(NULL, " /"); |
WiredHome | 0:108436d3cea9 | 155 | if (p != NULL) { |
WiredHome | 0:108436d3cea9 | 156 | t->tm_mday = atoi(p); |
WiredHome | 0:108436d3cea9 | 157 | p = strtok(NULL, " /"); |
WiredHome | 0:108436d3cea9 | 158 | if (p != NULL) { |
WiredHome | 0:108436d3cea9 | 159 | t->tm_year = atoi(p) - 1900; |
WiredHome | 0:108436d3cea9 | 160 | p = strtok(NULL, " :"); |
WiredHome | 0:108436d3cea9 | 161 | if (p != NULL) { |
WiredHome | 0:108436d3cea9 | 162 | t->tm_hour = atoi(p); |
WiredHome | 0:108436d3cea9 | 163 | p = strtok(NULL, " :"); |
WiredHome | 0:108436d3cea9 | 164 | if (p != NULL) { |
WiredHome | 1:6d3d16f4b27c | 165 | t->tm_min = atoi(p); |
WiredHome | 1:6d3d16f4b27c | 166 | p = strtok(NULL, " (:"); |
WiredHome | 1:6d3d16f4b27c | 167 | if (p != NULL) { |
WiredHome | 1:6d3d16f4b27c | 168 | t->tm_sec = atoi(p); |
WiredHome | 1:6d3d16f4b27c | 169 | success = true; // if we get to here, we're good |
WiredHome | 1:6d3d16f4b27c | 170 | p = strtok(NULL, " (:"); |
WiredHome | 1:6d3d16f4b27c | 171 | if (p != NULL) { |
WiredHome | 1:6d3d16f4b27c | 172 | success = false; // but can't accept a partial tzo |
WiredHome | 1:6d3d16f4b27c | 173 | _oH = atoi(p); |
WiredHome | 1:6d3d16f4b27c | 174 | p = strtok(NULL, " (:)"); |
WiredHome | 1:6d3d16f4b27c | 175 | if (p != NULL) { |
WiredHome | 1:6d3d16f4b27c | 176 | _oM = atoi(p); |
WiredHome | 1:6d3d16f4b27c | 177 | success = true; // but a whole tzo is ok |
WiredHome | 1:6d3d16f4b27c | 178 | SetTimeOffset(_oH, _oM); |
WiredHome | 1:6d3d16f4b27c | 179 | } |
WiredHome | 1:6d3d16f4b27c | 180 | } |
WiredHome | 1:6d3d16f4b27c | 181 | seconds = mktime(t); |
WiredHome | 1:6d3d16f4b27c | 182 | seconds = seconds - (time_t)(tzOffsetHr * 3600 + tzOffsetMin * 60); |
WiredHome | 1:6d3d16f4b27c | 183 | set_time(seconds); |
WiredHome | 6:a517fee06e2e | 184 | SetTimeLastSet(seconds); |
WiredHome | 1:6d3d16f4b27c | 185 | } |
WiredHome | 1:6d3d16f4b27c | 186 | } |
WiredHome | 0:108436d3cea9 | 187 | } |
WiredHome | 0:108436d3cea9 | 188 | } |
WiredHome | 0:108436d3cea9 | 189 | } |
WiredHome | 0:108436d3cea9 | 190 | } |
WiredHome | 0:108436d3cea9 | 191 | return success; |
WiredHome | 0:108436d3cea9 | 192 | } |
WiredHome | 0:108436d3cea9 | 193 | |
WiredHome | 5:fbbdf57675c3 | 194 | bool RealTimeClock::AdjustBySeconds(int32_t adjustSeconds) { |
WiredHome | 6:a517fee06e2e | 195 | time_t lastSet = GetTimeLastSet(); |
WiredHome | 6:a517fee06e2e | 196 | |
WiredHome | 6:a517fee06e2e | 197 | if (lastSet != 0) { |
WiredHome | 5:fbbdf57675c3 | 198 | time_t seconds = time(NULL); // get "now" according to the rtc |
WiredHome | 6:a517fee06e2e | 199 | int32_t delta = seconds - lastSet; |
WiredHome | 5:fbbdf57675c3 | 200 | int32_t curCal = GetTimeCalibration(); |
WiredHome | 5:fbbdf57675c3 | 201 | int32_t calMAX = 131071; |
WiredHome | 5:fbbdf57675c3 | 202 | int32_t secPerDay = 86400; |
WiredHome | 5:fbbdf57675c3 | 203 | float errSecPerDay; |
WiredHome | 5:fbbdf57675c3 | 204 | |
WiredHome | 5:fbbdf57675c3 | 205 | // Convert the current calibration and the adjustment into |
WiredHome | 5:fbbdf57675c3 | 206 | // the new calibration value |
WiredHome | 5:fbbdf57675c3 | 207 | // assume it is +10sec and it has been 2days, then the adjustment |
WiredHome | 5:fbbdf57675c3 | 208 | // needs to be +5 sec per day, or one adjustment every 1/5th |
WiredHome | 5:fbbdf57675c3 | 209 | // of a day, or 1 adjustment every 86400/5 counts. |
WiredHome | 5:fbbdf57675c3 | 210 | // delta = now - then (number of elapsed seconds) |
WiredHome | 5:fbbdf57675c3 | 211 | if (adjustSeconds != 0 && delta != 0) { |
WiredHome | 5:fbbdf57675c3 | 212 | int32_t calFactor; |
WiredHome | 6:a517fee06e2e | 213 | |
WiredHome | 6:a517fee06e2e | 214 | // Make the clock correct |
WiredHome | 6:a517fee06e2e | 215 | seconds = seconds + adjustSeconds; |
WiredHome | 6:a517fee06e2e | 216 | set_time(seconds); |
WiredHome | 6:a517fee06e2e | 217 | SetTimeLastSet(seconds); |
WiredHome | 6:a517fee06e2e | 218 | // Compute the calibration factor |
WiredHome | 5:fbbdf57675c3 | 219 | errSecPerDay = (float)adjustSeconds / ((float)(delta)/secPerDay); |
WiredHome | 5:fbbdf57675c3 | 220 | calFactor = (int32_t)((float)secPerDay/errSecPerDay); |
WiredHome | 5:fbbdf57675c3 | 221 | if (abs(calFactor) < calMAX) |
WiredHome | 5:fbbdf57675c3 | 222 | SetTimeCalibration(calFactor); |
WiredHome | 5:fbbdf57675c3 | 223 | } |
WiredHome | 5:fbbdf57675c3 | 224 | return true; |
WiredHome | 5:fbbdf57675c3 | 225 | } else { |
WiredHome | 5:fbbdf57675c3 | 226 | return false; |
WiredHome | 5:fbbdf57675c3 | 227 | } |
WiredHome | 5:fbbdf57675c3 | 228 | } |