/* This program reads the WWV clock and corrects the system clock based on the WWV clock. It will wake up once an hour in order to check the clock. If the clock has lost sync, it aborts. Planned improvement: if timesync has been lost, it will call the NIST or Nautical Observatory phone line to check the time. */ #include #include #include #include #include #include #include /***************************************************/ /* Julian returns the JD given integer ID numbers. */ /***************************************************/ double juliandate( int year, int month, int day) { double y,M,B,JD; if (month > 2) { y= 1900.0 + (double) year; M = (double) month; } else { y= 1899.0 + (double) year; M = (double) month + 12; } B= floor( ( y ) / 400.0) - floor( ( y ) / 100.0); JD = floor( 365.25 * y ) + + floor(30.6001 * ( 1.0 + (double) M )) + B + day + (double) 1720996.5 ; return(JD); } /******************************************************************/ /* Setup the interupts, timezone, etc. */ /******************************************************************/ int setup() { int i; for (i=1; i<10; i++) cts10_flush(); cts10_write( (int) 0x1B); cts10_write( (int) 0x13); /* The null command - to force into command state */ cts10_flush(); cts10_write( (int) 0x1B); cts10_write( (int) 0x07); cts10_write( (int) 0x00); cts10_read(); /* Disable interupt requests */ for (i=1; i<100; i++) cts10_flush(); cts10_write( (int) 0x1B); cts10_write( (int) 0x05); cts10_write( (int) 0x00); cts10_read(); /* Set IRQ interval to zero */ for (i=1; i<100; i++) cts10_flush(); cts10_write( (int) 0x1B); cts10_write( (int) 0x0F); /* Set time zone to */ cts10_write( (int) 0X00); /* UTC */ for (i=1; i<100; i++) cts10_flush(); } /********************************************************************/ /* getcode reads in two bytes in BCD using the designated call code */ /* It interprets the resulting code as bcd and puts it in an int. */ /********************************************************************/ int bcdgetcode( code ) int code; { char c; int i,answer; for (i=1; i<100; i++) cts10_flush(); cts10_write( (int) 0x1B); /* The lead in */ cts10_write( code ); /* The actual command */ answer= 10 * (int) cts10_read(); /* Read in the appropriate code */ answer += (int) cts10_read(); return answer; } /******************************************************************/ /* The set_date command sets the computer date */ /******************************************************************/ int set_date() { struct tm tmWWV; double y,m,B,JD,M,tmp; char setstring[100],yn; cts10_write( (int) 0x1B); /* capture time in buffer on CTS10 */ cts10_write( (int) 0x01); cts10_read(); /* Read the system clock */ tmWWV.tm_sec = bcdgetcode( (int) 0x1E ); /* Set the second */ tmWWV.tm_min = bcdgetcode( (int) 0x1D ); tmWWV.tm_hour = bcdgetcode( (int) 0x1C ); tmWWV.tm_mday = bcdgetcode( (int) 0x1A ); tmWWV.tm_mon = bcdgetcode( (int) 0x19 ); tmWWV.tm_year = bcdgetcode( (int) 0x18 ); sprintf(setstring,"date -d1 %02d%02d%02d%02d%02d\n", tmWWV.tm_year, tmWWV.tm_mon, tmWWV.tm_mday, tmWWV.tm_hour, tmWWV.tm_min); /* printf( " %s %lf is the time from the WWV clock - OK to set?\n", setstring, juliandate(tmWWV.tm_year, tmWWV.tm_mon, tmWWV.tm_mday)); scanf("%c",&yn); if ( yn = 'y' ) */ system(setstring); return 0; } /********************************************************/ /* This reads the cmos clock and sets the board year. */ /********************************************************/ year_from_cmos() { struct tm *cmostime; time_t *rawtime; time(&rawtime); cmostime = (struct tm*) gmtime(&rawtime); cts10_write( (int) 0x1B); cts10_write( (int) 0x17); cts10_write( (int) cmostime->tm_year / 10); cts10_write( (int) (cmostime->tm_year % 10)); } /******************************************************************/ /* This samples the system clock, the WWV clock, and updates. */ /******************************************************************/ int set_time(arg) int arg; { struct tm tmWWV; struct timeval timeSys,timeClock; struct timezone zoneSys; int hundreths; double secClock, secSys, secError; pid_t pidOld; pidOld = getprio(getpid()); setprio( getpid(), 29); /* Lock out other processes for a sec */ cts10_write( (int) 0x1B); /* capture time in buffer on CTS10 */ cts10_write( (int) 0x01); cts10_read(); /* Read the system clock */ gettimeofday(&timeSys, &zoneSys); /* Get system time */ secSys = timeSys.tv_sec + timeSys.tv_usec / 1000000.0; setprio( getpid(), pidOld); /* Ok, back down in priority */ hundreths = bcdgetcode( (int) 0x1F ); tmWWV.tm_sec = bcdgetcode( (int) 0x1E ); /* Set the second */ tmWWV.tm_min = bcdgetcode( (int) 0x1D ); tmWWV.tm_hour = bcdgetcode( (int) 0x1C ); tmWWV.tm_mday = bcdgetcode( (int) 0x1A ); tmWWV.tm_mon = bcdgetcode( (int) 0x19 ); tmWWV.tm_year = bcdgetcode( (int) 0x18 ); if (hundreths > 97) return(1); /* To close to a second - the clock board is apt to give us an incorrect time */ secClock = 3600.0 * (double) tmWWV.tm_hour + 60.0 * (double) tmWWV.tm_min + (double) tmWWV.tm_sec + 0.01 * (double) hundreths + 24 * 3600 * (juliandate(tmWWV.tm_year, tmWWV.tm_mon, tmWWV.tm_mday) - juliandate( 70, 1, 1)); secError = secSys - secClock; if ( (( secError > 6.0) || (secError < -6.0 )) && (arg==1) ) { printf("The clock has run amok! Reset it!\n"); exit(1); } if ( ( secError > 0.005 ) || ( secError < -0.005) ) { setprio( getpid(), 29); /* Lock out other processes for a sec */ gettimeofday(&timeSys, &zoneSys); /* Get system time */ secSys = (double) timeSys.tv_sec + (double ) timeSys.tv_usec / 1000000.0; timeSys.tv_usec -= 1000000.0 * ((double) secError - floor( (double) secError )); while ( timeSys.tv_usec < 0 ) { timeSys.tv_usec += 1000000.0; timeSys.tv_sec -= 1.0; } while ( timeSys.tv_usec > 1000000.0 ) { timeSys.tv_usec -= 1000000.0; timeSys.tv_sec += 1.0; } timeSys.tv_sec -= floor( secError ); settimeofday(&timeSys, &zoneSys); setprio( getpid(), pidOld); /* Let 'em back. */ } return(0); } main() { int i,j; char c; setup(); /* Set the card as we'ld like it. */ year_from_cmos(); /* Grab year from cmos clock, set board */ set_date(); set_time(0); sleep(5); set_time(0); while(1) { sleep(5); set_time(1); fflush(stdout); } exit(1); }