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.
TimeUtilities.cpp@2:cbcdd97f3a6d, 2011-06-08 (annotated)
- Committer:
- WiredHome
- Date:
- Wed Jun 08 11:36:11 2011 +0000
- Revision:
- 2:cbcdd97f3a6d
- Parent:
- 1:6d3d16f4b27c
- Child:
- 3:524ad47afdc7
v1.01 added methods for working with the calibration register
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 | 2:cbcdd97f3a6d | 18 | /// Version History |
WiredHome | 2:cbcdd97f3a6d | 19 | /// 20110601 |
WiredHome | 2:cbcdd97f3a6d | 20 | /// \li discovered the CCALEN flag to enable calibration |
WiredHome | 2:cbcdd97f3a6d | 21 | /// 20110529 |
WiredHome | 2:cbcdd97f3a6d | 22 | /// \li original version |
WiredHome | 2:cbcdd97f3a6d | 23 | /// |
WiredHome | 0:108436d3cea9 | 24 | #ifndef WIN32 |
WiredHome | 0:108436d3cea9 | 25 | // embedded build |
WiredHome | 0:108436d3cea9 | 26 | #include "mbed.h" |
WiredHome | 0:108436d3cea9 | 27 | #endif |
WiredHome | 0:108436d3cea9 | 28 | |
WiredHome | 0:108436d3cea9 | 29 | #include "TimeUtilities.h" |
WiredHome | 0:108436d3cea9 | 30 | #include <time.h> |
WiredHome | 0:108436d3cea9 | 31 | #include <string.h> |
WiredHome | 0:108436d3cea9 | 32 | #include <stdio.h> |
WiredHome | 0:108436d3cea9 | 33 | #include <stdlib.h> |
WiredHome | 0:108436d3cea9 | 34 | |
WiredHome | 0:108436d3cea9 | 35 | #ifdef WIN32 |
WiredHome | 0:108436d3cea9 | 36 | // Fake it out for Win32 |
WiredHome | 0:108436d3cea9 | 37 | struct LPC { |
WiredHome | 2:cbcdd97f3a6d | 38 | unsigned long CCR; // Clock Control register |
WiredHome | 2:cbcdd97f3a6d | 39 | unsigned long GPREG0; // General Purpose Register - Battery backed |
WiredHome | 2:cbcdd97f3a6d | 40 | unsigned long CALIBRATION; // Calibration Register |
WiredHome | 0:108436d3cea9 | 41 | }; |
WiredHome | 0:108436d3cea9 | 42 | struct LPC X; |
WiredHome | 0:108436d3cea9 | 43 | struct LPC * LPC_RTC = &X; |
WiredHome | 0:108436d3cea9 | 44 | #define set_time(x) (void)x |
WiredHome | 0:108436d3cea9 | 45 | #endif |
WiredHome | 0:108436d3cea9 | 46 | |
WiredHome | 0:108436d3cea9 | 47 | static int tzOffsetHr = 0; ///!< time zone offset hours to print time in local time |
WiredHome | 0:108436d3cea9 | 48 | static int tzOffsetMin = 0; ///!< time zone offset minutes to print time in local time |
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 | 2:cbcdd97f3a6d | 63 | |
WiredHome | 0:108436d3cea9 | 64 | void RealTimeClock::GetTimeString(char *buf, time_t tValue) { |
WiredHome | 0:108436d3cea9 | 65 | GetTimeOffsetStore(); // Load the time zone offset values from the battery ram |
WiredHome | 0:108436d3cea9 | 66 | GetTimeString(buf, tValue, tzOffsetHr, tzOffsetMin); |
WiredHome | 0:108436d3cea9 | 67 | } |
WiredHome | 0:108436d3cea9 | 68 | |
WiredHome | 2:cbcdd97f3a6d | 69 | |
WiredHome | 0:108436d3cea9 | 70 | void RealTimeClock::GetTimeString(char *buf, int hOffset, int mOffset) { |
WiredHome | 0:108436d3cea9 | 71 | GetTimeString(buf, 0, hOffset, mOffset); |
WiredHome | 0:108436d3cea9 | 72 | } |
WiredHome | 0:108436d3cea9 | 73 | |
WiredHome | 2:cbcdd97f3a6d | 74 | |
WiredHome | 0:108436d3cea9 | 75 | void RealTimeClock::GetTimeString(char *buf, time_t tValue, int hOffset, int mOffset) { |
WiredHome | 0:108436d3cea9 | 76 | time_t ctTime; |
WiredHome | 0:108436d3cea9 | 77 | |
WiredHome | 0:108436d3cea9 | 78 | if (tValue == 0) |
WiredHome | 0:108436d3cea9 | 79 | tValue = time(NULL); |
WiredHome | 0:108436d3cea9 | 80 | ctTime = tValue + hOffset * 3600 + SignOf(hOffset) * mOffset * 60; |
WiredHome | 0:108436d3cea9 | 81 | strcpy(buf, ctime(&ctTime)); |
WiredHome | 0:108436d3cea9 | 82 | buf[strlen(buf)-1] = '\0'; // remove the \n |
WiredHome | 0:108436d3cea9 | 83 | sprintf(buf + strlen(buf), " (tzo: %2i:%02i)", hOffset, mOffset); |
WiredHome | 0:108436d3cea9 | 84 | } |
WiredHome | 0:108436d3cea9 | 85 | |
WiredHome | 2:cbcdd97f3a6d | 86 | |
WiredHome | 0:108436d3cea9 | 87 | int32_t RealTimeClock::GetTimeCalibration() { |
WiredHome | 0:108436d3cea9 | 88 | int32_t calvalue = LPC_RTC->CALIBRATION & 0x3FFFF; |
WiredHome | 0:108436d3cea9 | 89 | |
WiredHome | 0:108436d3cea9 | 90 | if (calvalue & 0x20000) { |
WiredHome | 0:108436d3cea9 | 91 | calvalue = -(calvalue & 0x1FFFF); |
WiredHome | 0:108436d3cea9 | 92 | } |
WiredHome | 0:108436d3cea9 | 93 | return calvalue; |
WiredHome | 0:108436d3cea9 | 94 | } |
WiredHome | 0:108436d3cea9 | 95 | |
WiredHome | 2:cbcdd97f3a6d | 96 | |
WiredHome | 0:108436d3cea9 | 97 | void RealTimeClock::SetTimeCalibration(int32_t calibration) { |
WiredHome | 2:cbcdd97f3a6d | 98 | if (calibration) { |
WiredHome | 2:cbcdd97f3a6d | 99 | if (calibration < 0) { |
WiredHome | 2:cbcdd97f3a6d | 100 | calibration = (-calibration & 0x1FFFF) | 0x20000; |
WiredHome | 2:cbcdd97f3a6d | 101 | } |
WiredHome | 2:cbcdd97f3a6d | 102 | LPC_RTC->CCR = 0x000001; //(LPC_RTC->CCR & 0x0003); // Clear CCALEN to enable it |
WiredHome | 2:cbcdd97f3a6d | 103 | } else { |
WiredHome | 2:cbcdd97f3a6d | 104 | LPC_RTC->CCR = 0x000011; //(LPC_RTC->CCR & 0x0003) | 0x0010; // Set CCALEN to disable it |
WiredHome | 0:108436d3cea9 | 105 | } |
WiredHome | 0:108436d3cea9 | 106 | LPC_RTC->CALIBRATION = calibration; |
WiredHome | 0:108436d3cea9 | 107 | } |
WiredHome | 0:108436d3cea9 | 108 | |
WiredHome | 2:cbcdd97f3a6d | 109 | |
WiredHome | 0:108436d3cea9 | 110 | void RealTimeClock::SetTimeOffset(int offsetHour, int offsetMinute) { |
WiredHome | 0:108436d3cea9 | 111 | tzOffsetHr = offsetHour; |
WiredHome | 0:108436d3cea9 | 112 | tzOffsetMin = offsetMinute; |
WiredHome | 0:108436d3cea9 | 113 | SetTimeOffsetStore(); |
WiredHome | 0:108436d3cea9 | 114 | } |
WiredHome | 0:108436d3cea9 | 115 | |
WiredHome | 2:cbcdd97f3a6d | 116 | |
WiredHome | 0:108436d3cea9 | 117 | void RealTimeClock::SetTimeOffsetStore() { |
WiredHome | 0:108436d3cea9 | 118 | LPC_RTC->GPREG0 = tzOffsetHr * 256 + tzOffsetMin; |
WiredHome | 0:108436d3cea9 | 119 | } |
WiredHome | 0:108436d3cea9 | 120 | |
WiredHome | 2:cbcdd97f3a6d | 121 | |
WiredHome | 0:108436d3cea9 | 122 | void RealTimeClock::GetTimeOffsetStore() { |
WiredHome | 0:108436d3cea9 | 123 | tzOffsetHr = (int32_t)LPC_RTC->GPREG0 / 256; |
WiredHome | 0:108436d3cea9 | 124 | tzOffsetMin = (LPC_RTC->GPREG0 & 0xFF); |
WiredHome | 0:108436d3cea9 | 125 | } |
WiredHome | 0:108436d3cea9 | 126 | |
WiredHome | 2:cbcdd97f3a6d | 127 | |
WiredHome | 0:108436d3cea9 | 128 | // MM/DD/YYYY HH:MM:SS [(+/-hh:mm)] |
WiredHome | 0:108436d3cea9 | 129 | bool RealTimeClock::SetTime(char * timestring) { |
WiredHome | 0:108436d3cea9 | 130 | bool success = false; |
WiredHome | 0:108436d3cea9 | 131 | char * p; |
WiredHome | 0:108436d3cea9 | 132 | time_t seconds = time(NULL); |
WiredHome | 0:108436d3cea9 | 133 | struct tm *t = localtime(&seconds); |
WiredHome | 0:108436d3cea9 | 134 | int _oH, _oM; |
WiredHome | 0:108436d3cea9 | 135 | |
WiredHome | 0:108436d3cea9 | 136 | p = strtok(timestring," /"); |
WiredHome | 0:108436d3cea9 | 137 | if (p != NULL) { |
WiredHome | 0:108436d3cea9 | 138 | t->tm_mon = atoi(p) - 1; |
WiredHome | 0:108436d3cea9 | 139 | p = strtok(NULL, " /"); |
WiredHome | 0:108436d3cea9 | 140 | if (p != NULL) { |
WiredHome | 0:108436d3cea9 | 141 | t->tm_mday = atoi(p); |
WiredHome | 0:108436d3cea9 | 142 | p = strtok(NULL, " /"); |
WiredHome | 0:108436d3cea9 | 143 | if (p != NULL) { |
WiredHome | 0:108436d3cea9 | 144 | t->tm_year = atoi(p) - 1900; |
WiredHome | 0:108436d3cea9 | 145 | p = strtok(NULL, " :"); |
WiredHome | 0:108436d3cea9 | 146 | if (p != NULL) { |
WiredHome | 0:108436d3cea9 | 147 | t->tm_hour = atoi(p); |
WiredHome | 0:108436d3cea9 | 148 | p = strtok(NULL, " :"); |
WiredHome | 0:108436d3cea9 | 149 | if (p != NULL) { |
WiredHome | 1:6d3d16f4b27c | 150 | t->tm_min = atoi(p); |
WiredHome | 1:6d3d16f4b27c | 151 | p = strtok(NULL, " (:"); |
WiredHome | 1:6d3d16f4b27c | 152 | if (p != NULL) { |
WiredHome | 1:6d3d16f4b27c | 153 | t->tm_sec = atoi(p); |
WiredHome | 1:6d3d16f4b27c | 154 | success = true; // if we get to here, we're good |
WiredHome | 1:6d3d16f4b27c | 155 | p = strtok(NULL, " (:"); |
WiredHome | 1:6d3d16f4b27c | 156 | if (p != NULL) { |
WiredHome | 1:6d3d16f4b27c | 157 | success = false; // but can't accept a partial tzo |
WiredHome | 1:6d3d16f4b27c | 158 | _oH = atoi(p); |
WiredHome | 1:6d3d16f4b27c | 159 | p = strtok(NULL, " (:)"); |
WiredHome | 1:6d3d16f4b27c | 160 | if (p != NULL) { |
WiredHome | 1:6d3d16f4b27c | 161 | _oM = atoi(p); |
WiredHome | 1:6d3d16f4b27c | 162 | success = true; // but a whole tzo is ok |
WiredHome | 1:6d3d16f4b27c | 163 | SetTimeOffset(_oH, _oM); |
WiredHome | 1:6d3d16f4b27c | 164 | } |
WiredHome | 1:6d3d16f4b27c | 165 | } |
WiredHome | 1:6d3d16f4b27c | 166 | seconds = mktime(t); |
WiredHome | 1:6d3d16f4b27c | 167 | seconds = seconds - (time_t)(tzOffsetHr * 3600 + tzOffsetMin * 60); |
WiredHome | 1:6d3d16f4b27c | 168 | set_time(seconds); |
WiredHome | 1:6d3d16f4b27c | 169 | } |
WiredHome | 1:6d3d16f4b27c | 170 | } |
WiredHome | 0:108436d3cea9 | 171 | } |
WiredHome | 0:108436d3cea9 | 172 | } |
WiredHome | 0:108436d3cea9 | 173 | } |
WiredHome | 0:108436d3cea9 | 174 | } |
WiredHome | 0:108436d3cea9 | 175 | return success; |
WiredHome | 0:108436d3cea9 | 176 | } |
WiredHome | 0:108436d3cea9 | 177 | |
WiredHome | 0:108436d3cea9 | 178 | #if 0 |
WiredHome | 0:108436d3cea9 | 179 | // GetNumber will get from the user a number using the |
WiredHome | 0:108436d3cea9 | 180 | /// specified number of digits. |
WiredHome | 0:108436d3cea9 | 181 | /// |
WiredHome | 0:108436d3cea9 | 182 | /// They can enter a number from 0 to 10^(digits-1) |
WiredHome | 0:108436d3cea9 | 183 | /// |
WiredHome | 0:108436d3cea9 | 184 | /// @param digits is the number of digits to enter |
WiredHome | 0:108436d3cea9 | 185 | /// @param pValue is a pointer to where to store the result |
WiredHome | 0:108436d3cea9 | 186 | /// @returns true if a number was entered |
WiredHome | 0:108436d3cea9 | 187 | /// @returns false if they entered a non-digit |
WiredHome | 0:108436d3cea9 | 188 | /// |
WiredHome | 0:108436d3cea9 | 189 | int GetNumber(int digits, int * pValue) { |
WiredHome | 0:108436d3cea9 | 190 | int tempValue = 0; |
WiredHome | 0:108436d3cea9 | 191 | int i; |
WiredHome | 0:108436d3cea9 | 192 | |
WiredHome | 0:108436d3cea9 | 193 | while (digits--) { |
WiredHome | 0:108436d3cea9 | 194 | while (!pc.readable()) |
WiredHome | 0:108436d3cea9 | 195 | wdt.Service(); |
WiredHome | 0:108436d3cea9 | 196 | i = pc.getc(); |
WiredHome | 0:108436d3cea9 | 197 | if (i == ' ') i = '0'; // special case for leading blank |
WiredHome | 0:108436d3cea9 | 198 | if (i >= '0' && i <= '9') { |
WiredHome | 0:108436d3cea9 | 199 | pc.putc(i); |
WiredHome | 0:108436d3cea9 | 200 | tempValue = tempValue * 10 + (i - '0'); |
WiredHome | 0:108436d3cea9 | 201 | } else |
WiredHome | 0:108436d3cea9 | 202 | return false; |
WiredHome | 0:108436d3cea9 | 203 | } |
WiredHome | 0:108436d3cea9 | 204 | *pValue = tempValue; |
WiredHome | 0:108436d3cea9 | 205 | return true; |
WiredHome | 0:108436d3cea9 | 206 | } |
WiredHome | 0:108436d3cea9 | 207 | |
WiredHome | 0:108436d3cea9 | 208 | /// RTC_Set will interactively set the Real Time Clock |
WiredHome | 0:108436d3cea9 | 209 | /// |
WiredHome | 0:108436d3cea9 | 210 | /// It will allow you to enter the date and time information |
WiredHome | 0:108436d3cea9 | 211 | /// and then create a timestamp. After this, it will set |
WiredHome | 0:108436d3cea9 | 212 | /// the RTC to that timestamp. |
WiredHome | 0:108436d3cea9 | 213 | /// |
WiredHome | 0:108436d3cea9 | 214 | void RTC_Set(void) { |
WiredHome | 0:108436d3cea9 | 215 | time_t seconds = time(NULL); |
WiredHome | 0:108436d3cea9 | 216 | struct tm *t = localtime(&seconds); |
WiredHome | 0:108436d3cea9 | 217 | |
WiredHome | 0:108436d3cea9 | 218 | pc.printf("RTC Set:\r\n"); |
WiredHome | 0:108436d3cea9 | 219 | GetTimeString(seconds, tzOffsetHr, tzOffsetMin); |
WiredHome | 0:108436d3cea9 | 220 | pc.printf(" Enter the time MM/DD/YYYY HH:MM:SS\r\n"); |
WiredHome | 0:108436d3cea9 | 221 | while (1) { |
WiredHome | 0:108436d3cea9 | 222 | int _m, _d, _y, _H, _M, _S; |
WiredHome | 0:108436d3cea9 | 223 | printf(" > "); |
WiredHome | 0:108436d3cea9 | 224 | if (GetNumber(2, &_m)) { |
WiredHome | 0:108436d3cea9 | 225 | pc.putc('/'); |
WiredHome | 0:108436d3cea9 | 226 | if (!GetNumber(2, &_d)) |
WiredHome | 0:108436d3cea9 | 227 | continue; |
WiredHome | 0:108436d3cea9 | 228 | pc.putc('/'); |
WiredHome | 0:108436d3cea9 | 229 | if (!GetNumber(4, &_y)) |
WiredHome | 0:108436d3cea9 | 230 | continue; |
WiredHome | 0:108436d3cea9 | 231 | t->tm_mon = _m - 1; |
WiredHome | 0:108436d3cea9 | 232 | t->tm_mday = _d; |
WiredHome | 0:108436d3cea9 | 233 | t->tm_year = _y - 1900; |
WiredHome | 0:108436d3cea9 | 234 | } else { |
WiredHome | 0:108436d3cea9 | 235 | pc.printf("%02d/%02d/%04d", t->tm_mon+1, t->tm_mday, t->tm_year+1900); |
WiredHome | 0:108436d3cea9 | 236 | } |
WiredHome | 0:108436d3cea9 | 237 | pc.putc(' '); |
WiredHome | 0:108436d3cea9 | 238 | if (GetNumber(2, &_H)) { |
WiredHome | 0:108436d3cea9 | 239 | pc.putc(':'); |
WiredHome | 0:108436d3cea9 | 240 | if (!GetNumber(2, &_M)) |
WiredHome | 0:108436d3cea9 | 241 | continue; |
WiredHome | 0:108436d3cea9 | 242 | pc.putc(':'); |
WiredHome | 0:108436d3cea9 | 243 | if (!GetNumber(2, &_S)) |
WiredHome | 0:108436d3cea9 | 244 | continue; |
WiredHome | 0:108436d3cea9 | 245 | t->tm_hour = _H; |
WiredHome | 0:108436d3cea9 | 246 | t->tm_min = _M; |
WiredHome | 0:108436d3cea9 | 247 | t->tm_sec = _S; |
WiredHome | 0:108436d3cea9 | 248 | pc.printf("\r\n"); |
WiredHome | 0:108436d3cea9 | 249 | pc.printf("%02d/%02d/%04d ", t->tm_mon+1, t->tm_mday, t->tm_year+1900); |
WiredHome | 0:108436d3cea9 | 250 | pc.printf("%02d:%02d:%02d\r\n", t->tm_hour, t->tm_min, t->tm_sec); |
WiredHome | 0:108436d3cea9 | 251 | // convert to timestamp and display (1256729737) |
WiredHome | 0:108436d3cea9 | 252 | time_t seconds = mktime(t); |
WiredHome | 0:108436d3cea9 | 253 | seconds = seconds - (time_t)(tzOffsetHr * 3600 + tzOffsetMin * 60); |
WiredHome | 0:108436d3cea9 | 254 | set_time(seconds); |
WiredHome | 0:108436d3cea9 | 255 | break; |
WiredHome | 0:108436d3cea9 | 256 | } else { |
WiredHome | 0:108436d3cea9 | 257 | pc.printf("%02d:%02d:%02d\r\n", t->tm_hour, t->tm_min, t->tm_sec); |
WiredHome | 0:108436d3cea9 | 258 | break; // they can bail here |
WiredHome | 0:108436d3cea9 | 259 | } |
WiredHome | 0:108436d3cea9 | 260 | } |
WiredHome | 0:108436d3cea9 | 261 | } |
WiredHome | 0:108436d3cea9 | 262 | #endif |