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.
Dependencies: DMBasicGUI DMSupport
GCRealTimeClock.cpp
00001 /* 00002 This class consists of static functions that handle the real time clock [RTC] on the GC. 00003 It contains only static functions, and cannot be instantiated. 00004 */ 00005 00006 #include "GCRealTimeClock.h" 00007 00008 00009 /* 00010 Gets the various time fields from the relevant GC registers 00011 using the "QRTC000r" command, where 'r' is the register number 00012 for each field. Returns the command responses, as strings, 00013 in the buffers specified. 00014 00015 Note that, to avoid rollover (see comments in function 'GetGCClockTime'), 00016 we do minimal processing between getting each response. 00017 00018 Args: a pointer to the USBHostGC instance that corresponds to the GC, 00019 a pointer to the USBDeviceConnected instance that (also) corresponds to the GC 00020 pointers to the buffers to contain the time fields - it is up to the caller 00021 to make sure these are large enough for a GC response 00022 00023 Returns true if it succeeded, false if it failed (e.g. the GC gave an error, etc) 00024 */ 00025 bool GCRealTimeClock::GetTimeFieldsFromGC(USBDeviceConnected* usbDevice, 00026 USBHostGC* usbHostGC, 00027 char *gcSecondsResponse, 00028 char *gcMinutesResponse, 00029 char *gcHoursResponse, 00030 char *gcDateResponse, 00031 char *gcMonthResponse, 00032 char *gcYearResponse) 00033 { 00034 while(usbHostGC->ExecutingSetDeviceReport()) {} 00035 usbHostGC->SetDeviceReport(usbDevice, "QRTC0000", gcSecondsResponse); 00036 if(gcSecondsResponse[0] == 'E') { 00037 // Assume "EPKT" 00038 return false; 00039 } 00040 00041 while(usbHostGC->ExecutingSetDeviceReport()) {} 00042 usbHostGC->SetDeviceReport(usbDevice, "QRTC0001", gcMinutesResponse); 00043 if(gcMinutesResponse[0] == 'E') { 00044 // Assume "EPKT" 00045 return false; 00046 } 00047 00048 while(usbHostGC->ExecutingSetDeviceReport()) {} 00049 usbHostGC->SetDeviceReport(usbDevice, "QRTC0002", gcHoursResponse); 00050 if(gcHoursResponse[0] == 'E') { 00051 // Assume "EPKT" 00052 return false; 00053 } 00054 00055 while(usbHostGC->ExecutingSetDeviceReport()) {} 00056 usbHostGC->SetDeviceReport(usbDevice, "QRTC0004", gcDateResponse); 00057 if(gcDateResponse[0] == 'E') { 00058 // Assume "EPKT" 00059 return false; 00060 } 00061 00062 while(usbHostGC->ExecutingSetDeviceReport()) {} 00063 usbHostGC->SetDeviceReport(usbDevice, "QRTC0005", gcMonthResponse); 00064 if(gcMonthResponse[0] == 'E') { 00065 // Assume "EPKT" 00066 return false; 00067 } 00068 00069 while(usbHostGC->ExecutingSetDeviceReport()) {} 00070 usbHostGC->SetDeviceReport(usbDevice, "QRTC0006", gcYearResponse); 00071 if(gcYearResponse[0] == 'E') { 00072 // Assume "EPKT" 00073 return false; 00074 } 00075 00076 // If we get here, all the above must have succeeded 00077 return true; 00078 } 00079 00080 /* 00081 Constructs a time value from the GC responses returned by 'GetTimeFieldsFromGC()'. 00082 Fills a 'tm' struct - see the <ctime> (time.h) system include file. 00083 00084 We expect the responses to look like "DRTCnnnn", where "nnnn" is the value 00085 of the relevant register, so we expect the register value to start in array element 4. 00086 00087 For a full description of the register values, see the DS1307 Real-Time Clock documentation, 00088 which can currently be found here: 00089 00090 V:\Development\500 Series GC\Main Instrument\Documentation\Electronic\DS1307 IIC RTCC Chip.pdf 00091 00092 [V: is the Ellutia File Server.] 00093 00094 *** The register values are in binary coded decimal format. *** 00095 00096 00097 Args: a pointer to a 'tm' struct to be filled with the time value 00098 pointers to the buffers that contain each of the time fields 00099 returned by the GC in our 'GetTimeFieldsFromGC()' function 00100 00101 No return code. 00102 */ 00103 void GCRealTimeClock::MakeTimeValueFromGCTimeFields(struct tm *timeValue, 00104 char *gcSecondsResponse, 00105 char *gcMinutesResponse, 00106 char *gcHoursResponse, 00107 char *gcDateResponse, 00108 char *gcMonthResponse, 00109 char *gcYearResponse) 00110 { 00111 int secondsValue; 00112 sscanf(&gcSecondsResponse[4], "%d", &secondsValue); 00113 00114 int secondsUnitsDigit = secondsValue & 0xF; 00115 int secondsTensDigit = (secondsValue & 0x70) >> 4; 00116 timeValue->tm_sec = secondsUnitsDigit + (secondsTensDigit * 10); 00117 00118 00119 int minutesValue; 00120 sscanf(&gcMinutesResponse[4], "%d", &minutesValue); 00121 00122 int minutesUnitsDigit = minutesValue & 0xF; 00123 int minutesTensDigit = (minutesValue & 0x70) >> 4; 00124 timeValue->tm_min = minutesUnitsDigit + (minutesTensDigit * 10); 00125 00126 00127 int hoursValue; 00128 sscanf(&gcHoursResponse[4], "%d", &hoursValue); 00129 00130 // Note that, while the GC real-time clock can work in 12 or 24 hour mode, 00131 // the 'tm' struct can only handle 24 hour clock values. 00132 int hoursUnitsDigit = hoursValue & 0xF; 00133 int hoursTensDigit = 0; 00134 if(hoursValue & 0x40) { 00135 // 12 hour mode - hours range is 01-12 - 00136 // but tm struct needs hours to start at zero, not one 00137 hoursTensDigit = (hoursValue & 0x10) >> 4; 00138 timeValue->tm_hour = hoursUnitsDigit + (hoursTensDigit * 10) - 1; 00139 if(hoursValue & 0x20) { 00140 // pm (else am) 00141 timeValue->tm_hour += 12; 00142 } 00143 } else { 00144 // 24 hour mode - hours range is 00-23 00145 hoursTensDigit = (hoursValue & 0x30) >> 4; 00146 timeValue->tm_hour = hoursUnitsDigit + (hoursTensDigit * 10); 00147 } 00148 00149 00150 int dateValue; 00151 sscanf(&gcDateResponse[4], "%d", &dateValue); 00152 00153 int dateUnitsDigit = dateValue & 0xF; 00154 int dateTensDigit = (dateValue & 0x30) >> 4; 00155 timeValue->tm_mday = dateUnitsDigit + (dateTensDigit * 10); 00156 00157 00158 int monthValue; 00159 sscanf(&gcMonthResponse[4], "%d", &monthValue); 00160 00161 // GC month value range is 1-12 - but 'tm' struct month range is 0-11 00162 int monthUnitsDigit = monthValue & 0xF; 00163 int monthTensDigit = (monthValue & 0x10) >> 4; 00164 timeValue->tm_mon = monthUnitsDigit + (monthTensDigit * 10) - 1; 00165 00166 00167 int yearValue; 00168 sscanf(&gcYearResponse[4], "%d", &yearValue); 00169 00170 // GC year value is 00-99 - but 'tm' struct year value 00171 // is the number of years since 1900 00172 int yearUnitsDigit = yearValue & 0xF; 00173 int yearTensDigit = (yearValue & 0xF0) >> 4; 00174 timeValue->tm_year = yearUnitsDigit + (yearTensDigit * 10) + 100; 00175 } 00176 00177 00178 /* 00179 Get the time and date from the GC's real time clock, 00180 and return it in a time_t variable provided by the caller 00181 00182 Args: a pointer to the USBHostGC instance that corresponds to the GC, 00183 a pointer to the USBDeviceConnected instance that (also) corresponds to the GC 00184 a pointer to a time_t variable, which we will set to the GC time 00185 00186 Returns true if it succeeded, false if it failed (e.g. the GC gave an error, etc) 00187 */ 00188 bool GCRealTimeClock::GetGCClockTime(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC, time_t *clockTime) 00189 { 00190 // The seconds, minutes, hours, date (i.e. day of the month), month and year are kept in separate registers 00191 // in the GC, so we get them separately. This means we must guard against 'rollover' - 00192 // e.g. the GC time when we get the minutes is 11:59, but when we get the hours 00193 // it is 12:00, so we think the time is 12:59. 00194 // 00195 // We do this in two ways: 00196 // 00197 // 1 - we do minimal processing between getting each value (see also function 'GetTimeFieldsFromGC') 00198 // 2 - we get the time twice - if the first value is greater than the second, 00199 // we assume that the first must have rolled over, so we use the second, 00200 // otherwise we use the first (they surely cannot both rollover unless 00201 // they are exactly 60 seconds apart, which is very unlikely - or 60 minutes, 00202 // 1 day, etc, which is even more unlikely). Also note that, since we get 00203 // the components in ascending order of 'size', any rollover will always 00204 // make the time value greater than it should be, not less. 00205 00206 00207 // Date and time value 1 00208 char seconds1[20]; 00209 char minutes1[20]; 00210 char hours1[20]; 00211 char date1[20]; 00212 char month1[20]; 00213 char year1[20]; 00214 if(!GetTimeFieldsFromGC(usbDevice, usbHostGC, seconds1, minutes1, hours1, date1, month1, year1)) { 00215 return false; 00216 } 00217 00218 // *** Do nothing between these two 'GetTimeFieldsFromGC' calls *** 00219 00220 // Date and time value 2 00221 char seconds2[20]; 00222 char minutes2[20]; 00223 char hours2[20]; 00224 char date2[20]; 00225 char month2[20]; 00226 char year2[20]; 00227 if(!GetTimeFieldsFromGC(usbDevice, usbHostGC, seconds2, minutes2, hours2, date2, month2, year2)) { 00228 return false; 00229 } 00230 00231 00232 struct tm time1; 00233 MakeTimeValueFromGCTimeFields(&time1, seconds1, minutes1, hours1, date1, month1, year1); 00234 00235 time_t time_t1 = mktime(&time1); 00236 00237 00238 struct tm time2; 00239 MakeTimeValueFromGCTimeFields(&time2, seconds2, minutes2, hours2, date2, month2, year2); 00240 00241 time_t time_t2 = mktime(&time2); 00242 00243 00244 // time_t1 should be less than time_t2, since we obtained the values from which we calculated it (slightly) earlier. 00245 // If so, use time_t1. If not, assume one or more of time_t1's constituent values must have been affected by rollover, 00246 // and use time_t2. (Note that if time_t2 was affected by rollover, its value will (even more) be greater than time_t1, 00247 // so we will ignore it anyway.) 00248 00249 *clockTime = (time_t1 < time_t2) ? time_t1 : time_t2; 00250 00251 return true; 00252 } 00253 00254 00255 /* 00256 Get the time and date from the GC's real time clock, 00257 and set the LPC4088 RTC to match. 00258 00259 Args: a pointer to the USBHostGC instance that corresponds to the GC, 00260 a pointer to the USBDeviceConnected instance that (also) corresponds to the GC 00261 00262 Returns true if it succeeded, false if it failed (e.g. the GC gave an error, etc) 00263 */ 00264 bool GCRealTimeClock::SetLPC4088RealTimeClockToMatchGC(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) 00265 { 00266 time_t timeToSet; 00267 00268 if(GetGCClockTime(usbDevice, usbHostGC, &timeToSet)) { 00269 00270 set_time(timeToSet); 00271 00272 return true; 00273 } 00274 00275 // 'else' ... 00276 return false; 00277 } 00278
Generated on Tue Jul 19 2022 00:31:06 by
1.7.2