Nut/OS  4.10.3
API Reference
caltime.c
Go to the documentation of this file.
00001 
00040 #include <dev/board.h>
00041 #include <dev/debug.h>
00042 
00043 #include <sys/version.h>
00044 #include <sys/timer.h>
00045 
00046 #include <stdlib.h>
00047 #include <stdio.h>
00048 #include <io.h>
00049 #include <string.h>
00050 #include <time.h>
00051 #ifdef USE_BUILD_TIME
00052 #include <pro/rfctime.h>
00053 #endif
00054 
00055 #ifdef USE_LINE_EDITOR
00056 #include <gorp/edline.h>
00057 #define LINE_MAXLENGTH  80
00058 static char edbuff[LINE_MAXLENGTH];
00059 static EDLINE *edline;
00060 #endif
00061 
00070 static char *version = "2.1";
00071 
00072 
00073 /* Used for ASCII Art Animation. */
00074 static char *rotor = "|/-\\";
00075 
00076 static char *weekday_name[7] = {
00077     "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
00078 };
00079 
00080 /*
00081  * Print content of tm structure.
00082  */
00083 static void PrintDateTime(CONST struct _tm *stm)
00084 {
00085     printf("%s, %04d/%02d/%02d, %02d:%02d:%02d%s"
00086            , weekday_name[stm->tm_wday]
00087            , stm->tm_year + 1900, stm->tm_mon + 1, stm->tm_mday
00088            , stm->tm_hour, stm->tm_min, stm->tm_sec
00089            , stm->tm_isdst ? " DST" : ""
00090            );
00091 }
00092 
00093 /*
00094  * Query calendar date from user.
00095  *
00096  * Returns 0 on success, -1 otherwise.
00097  */
00098 static int EnterDate(struct _tm *stm)
00099 {
00100     int year = stm->tm_year + 1900;
00101     int month = stm->tm_mon + 1;
00102     int day = stm->tm_mday;
00103 
00104     printf("Enter date, use format YYYY/MM/DD");
00105 #ifdef USE_LINE_EDITOR
00106     printf("  : ");
00107     sprintf(edbuff, "%04d/%02d/%02d", year, month, day);
00108     EdLineRead(edline, edbuff, LINE_MAXLENGTH);
00109     sscanf(edbuff, "%d/%d/%d", &year, &month, &day);
00110 #else
00111     printf(" (%04d/%02d/%02d): ", year, month, day);
00112     scanf("%d/%d/%d", &year, &month, &day);
00113     putchar('\n');
00114 #endif
00115 
00116     if (year < 1970 || year > 2038) {
00117         printf("Bad year: %d is not within range 1970..2038\n", year);
00118         return -1;
00119     }
00120     if (month < 1 || month > 12) {
00121         printf("Bad month: %d is not within range 1..12\n", month);
00122         return -1;
00123     }
00124     if (day < 1 || day > 31) {
00125         printf("Bad day: %d is not within range 1..31\n", day);
00126         return -1;
00127     }
00128     stm->tm_year = year - 1900;
00129     stm->tm_mon = month - 1;
00130     stm->tm_mday = day;
00131 
00132     return 0;
00133 }
00134 
00135 /*
00136  * Query time of day from user.
00137  *
00138  * Returns 0 on success, -1 otherwise.
00139  */
00140 static int EnterTime(struct _tm *stm)
00141 {
00142     int hour = stm->tm_hour;
00143     int minute = stm->tm_min;
00144     int second = stm->tm_sec;
00145 
00146     printf("Enter time, use 24h format HH:MM:SS");
00147 #ifdef USE_LINE_EDITOR
00148     printf(": ");
00149     sprintf(edbuff, "%02d:%02d:%02d", hour, minute, second);
00150     EdLineRead(edline, edbuff, LINE_MAXLENGTH);
00151     sscanf(edbuff, "%d:%d:%d", &hour, &minute, &second);
00152 #else
00153     printf(" (%02d:%02d:%02d): ", hour, minute, second);
00154     scanf("%d:%d:%d", &hour, &minute, &second);
00155     putchar('\n');
00156 #endif
00157 
00158     if (hour < 0 || hour > 23) {
00159         printf("Bad hour: %d is not within range 0..23\n", hour);
00160         return -1;
00161     }
00162     if (minute < 0 || minute > 59) {
00163         printf("Bad minute: %d is not within range 0..59\n", minute);
00164         return -1;
00165     }
00166     if (second < 0 || second > 59) {
00167         printf("Bad second: %d is not within range 0..59\n", second);
00168         return -1;
00169     }
00170     stm->tm_hour = hour;
00171     stm->tm_min = minute;
00172     stm->tm_sec = second;
00173 
00174     return 0;
00175 }
00176 
00177 /*
00178  * Query time difference from user, specified in hours and minutes.
00179  *
00180  * 'init' specifies the default number of seconds.
00181  *
00182  * Returns the number of seconds.
00183  */
00184 static long EnterTimeDiff(long init)
00185 {
00186     long hours;
00187     long minutes;
00188     long seconds;
00189 
00190     seconds = init;
00191     minutes = seconds / 60L;
00192     hours = minutes / 60L;
00193     minutes = abs(minutes % 60L);
00194 
00195     printf("Enter time difference in format HH:MM");
00196 #ifdef USE_LINE_EDITOR
00197     printf(": ");
00198     sprintf(edbuff, "%+03ld:%02ld", hours, minutes);
00199     EdLineRead(edline, edbuff, LINE_MAXLENGTH);
00200     sscanf(edbuff, "%ld:%ld", &hours, &minutes);
00201 #else
00202     printf(" (%+03ld:%02ld): ", hours, minutes);
00203     scanf("%ld:%ld", &hours, &minutes);
00204     putchar('\n');
00205 #endif
00206 
00207     if (hours < -12 || hours > 12) {
00208         printf("\nBad hours: %ld is not within range -12..+12\n", hours);
00209         return init;
00210     }
00211     if (minutes < 0 || minutes > 59) {
00212         printf("\nBad minutes: %ld is not within range 0..59\n", minutes);
00213         return init;
00214     }
00215     return (hours * 60L + minutes) * 60L;
00216 }
00217 
00218 /*
00219  * Display the elapsed seconds of the epoch.
00220  *
00221  * The value is constantly updated until the user presses a key.
00222  */
00223 static void DisplaySeconds(void)
00224 {
00225     uint_fast8_t i = 0;
00226 
00227     while (!kbhit()) {
00228         printf(" [%c] Seconds since epoch: %ld\r"
00229                , rotor[++i & 3]
00230                , (long) time(NULL));
00231         NutSleep(200);
00232     }
00233     putchar('\n');
00234 }
00235 
00236 /*
00237  * Display the coordinated universal time.
00238  *
00239  * The value is constantly updated until the user presses a key.
00240  */
00241 static void DisplayZuluTime(void)
00242 {
00243     time_t secs;
00244     struct _tm *gmt;
00245     uint_fast8_t i = 0;
00246 
00247     while (!kbhit()) {
00248         secs = time(NULL);
00249         gmt = gmtime(&secs);
00250         printf(" [%c] Universal time: ", rotor[++i & 3]);
00251         PrintDateTime(gmt);
00252         printf("    \r");
00253         NutSleep(500);
00254     }
00255     putchar('\n');
00256 }
00257 
00258 /*
00259  * Display the local time.
00260  *
00261  * The value is constantly updated until the user presses a key.
00262  */
00263 static void DisplayLocalTime(void)
00264 {
00265     time_t tt;
00266     struct _tm *ltm;
00267     uint_fast8_t i = 0;
00268 
00269     while (!kbhit()) {
00270         /* Get local time and print it. */
00271         tt = time(NULL);
00272         ltm = localtime(&tt);
00273         printf(" [%c] Local time: ", rotor[++i & 3]);
00274         PrintDateTime(ltm);
00275 
00276         /* Calculate the offset from UTC in minutes. */
00277         tt = _timezone;
00278         if (ltm->tm_isdst > 0) {
00279             tt += _dstbias;
00280         }
00281         tt /= -60L;
00282 
00283         /* Print UTC offset in format HH:MM. */
00284         printf(" UTC%+03ld:%02ld   \r", tt / 60L, abs(tt) % 60L);
00285         NutSleep(200);
00286     }
00287     putchar('\n');
00288 }
00289 
00290 /*
00291  * Display system up time.
00292  *
00293  * The value is constantly updated until the user presses a key.
00294  */
00295 static void DisplayUpTime(void)
00296 {
00297     uint32_t hours;
00298     uint32_t minutes;
00299     uint32_t seconds;
00300     uint_fast8_t i = 0;
00301 
00302     while (!kbhit()) {
00303         seconds = NutGetSeconds();
00304         minutes = seconds / 60UL;
00305         hours = minutes / 60UL;
00306         minutes %= 60UL;
00307         seconds %= 60UL;
00308         printf(" [%c] System is running %lu hours"
00309                ", %lu minutes and %lu seconds   \r"
00310                , rotor[++i & 3], hours, minutes, seconds);
00311         NutSleep(500);
00312     }
00313     putchar('\n');
00314 }
00315 
00316 /*
00317  * Display the week day of a queried calendar date.
00318  *
00319  * mktime() updates the structure members tm_yday and tm_wday.
00320  * This can be used to determine the week day name of any given
00321  * date.
00322  */
00323 static void CalcWeekDay(void)
00324 {
00325     struct _tm date;
00326     time_t secs;
00327 
00328     /* Use current local time as default. */
00329     time(&secs);
00330     memcpy(&date, localtime(&secs), sizeof(date));
00331     /* Query date and print week day name if we got a valid entry. */
00332     if (EnterDate(&date) == 0) {
00333         mktime(&date);
00334         puts(weekday_name[date.tm_wday]);
00335     }
00336 }
00337 
00338 /*
00339  * Query user for a new time zone offset.
00340  */
00341 static void SetTimeZone(void)
00342 {
00343     /* Nut/OS uses a global variable to store the current TZ offset. */
00344     _timezone = EnterTimeDiff(_timezone);
00345 }
00346 
00347 /*
00348  * Query user for a new system time.
00349  */
00350 static void SetLocalTime(void)
00351 {
00352     struct _tm ltm;
00353     time_t now;
00354 
00355     /* Use current local time as default. */
00356     time(&now);
00357     memcpy(&ltm, localtime(&now), sizeof(ltm));
00358 
00359     /* Query date and time. */
00360     if (EnterDate(&ltm) == 0 && EnterTime(&ltm) == 0) {
00361         /* Let mktime determine whether DST is in effect. */
00362         ltm.tm_isdst = -1;
00363         /* mktime expects local time and returns seconds since the epoch. */
00364         now = mktime(&ltm);
00365         /* stime expects seconds since the epoch. */
00366         stime(&now);
00367     }
00368 }
00369 
00370 /*
00371  * Application entry.
00372  */
00373 int main(void)
00374 {
00375     uint32_t baud = 115200;
00376     int cmd;
00377 
00378     /* Use UART device for stdin and stdout. */
00379     NutRegisterDevice(&DEV_CONSOLE, 0, 0);
00380     freopen(DEV_CONSOLE_NAME, "w", stdout);
00381     freopen(DEV_CONSOLE_NAME, "r", stdin);
00382     _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
00383     printf("\n\nCalendar Time %s running on Nut/OS %s\n"
00384            , version, NutVersionString());
00385 
00386 #ifdef USE_LINE_EDITOR
00387     /* Open line editor, if configured. */
00388     printf("Opening line editor...");
00389     edline = EdLineOpen(EDIT_MODE_ECHO);
00390     if (edline) {
00391         puts("OK");
00392     } else {
00393         puts("failed");
00394     }
00395 #else
00396     puts("Note: Enable local echo!");
00397 #endif
00398 
00399 #if USE_TIME_ZONE
00400     _timezone = USE_TIME_ZONE;
00401 #endif
00402 
00403 #ifdef RTC_CHIP
00404     /* Register and query hardware RTC, if available. */
00405     printf("Registering RTC hardware...");
00406     if (NutRegisterRtc(&RTC_CHIP)) {
00407         puts("failed");
00408     } else {
00409         uint32_t rtc_stat;
00410 
00411         NutRtcGetStatus(&rtc_stat);
00412         if (rtc_stat & RTC_STATUS_PF) {
00413             puts("power failure");
00414         } else {
00415             puts("OK");
00416         }
00417     }
00418 #elif USE_BUILD_TIME
00419     {
00420         /* Initially use the compile date and time. */
00421         time_t now = RfcTimeParse("Unk, " __DATE__ " " __TIME__);
00422         stime(&now);
00423         puts("Built " __DATE__ " " __TIME__);
00424     }
00425 #endif
00426 
00427     for (;;) {
00428         /* Print command menu. */
00429         puts("\n  0 - Display seconds counter");
00430         puts("  1 - Display universal time");
00431         puts("  2 - Display local time");
00432         puts("  3 - Display system uptime");
00433         puts("  C - Calculate weekday");
00434         puts("  S - Set local time");
00435         puts("  Y - Toggle DST calculation");
00436         puts("  Z - Set timezone");
00437 
00438         printf("What is thy bidding, my master? ");
00439 
00440         /* Flush input buffer. */
00441         while (kbhit()) {
00442             cmd = getchar();
00443         }
00444 
00445         /* Get the next command. */
00446         cmd = getchar();
00447         putchar('\n');
00448 
00449         /* Process the command. */
00450         switch (cmd) {
00451         case '0':
00452             DisplaySeconds();
00453             break;
00454         case '1':
00455             DisplayZuluTime();
00456             break;
00457         case '2':
00458             DisplayLocalTime();
00459             break;
00460         case '3':
00461             DisplayUpTime();
00462             break;
00463         case 'C':
00464         case 'c':
00465             CalcWeekDay();
00466             break;
00467         case 'S':
00468         case 's':
00469             SetLocalTime();
00470             break;
00471         case 'Y':
00472         case 'y':
00473             /* Nut/OS uses a global variable to enable/disable DST. 
00474                Toggle the current status and display the result. */
00475             _daylight = _daylight == 0;
00476             printf("DST calculation %sabled\n", _daylight ? "en" : "dis");
00477             break;
00478         case 'Z':
00479         case 'z':
00480             SetTimeZone();
00481             break;
00482         }
00483     }
00484     return 0;
00485 }