John Mitchell / lpc4088_displaymodule_GC500_2_5inch

Dependencies:   DMBasicGUI DMSupport

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers GCRealTimeClock.cpp Source File

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