home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 September
/
Simtel20_Sept92.cdr
/
msdos
/
at
/
at_clock.arc
/
CLOCKERR.C
next >
Wrap
C/C++ Source or Header
|
1989-01-24
|
11KB
|
304 lines
/* clockerr.c
*
* This program determines the number of seconds lost or gained by the
* cmos clock on an AT computer. The program is invoked from the
* command line using one of two possible command line parameters, like
* this: clockerr s, or clockerr q.
*
* The s parameter is used the first time the program is run. The next
* time the program is run it must use the q parameter to generate the
* cmos clock statistics. The first time you run the program, (clockerr
* s), you will be prompted for the correct date and time. Your entries
* will be used to set the cmos clock. They will also be written to a
* disk file called error.log. This file is created in the current
* directory. If this file already exists then it means the cmos clock
* has already been set by this program and further action is
* inhibited. If you still want to reset the cmos clock then you have
* to erase error.log first.
*
* The q parameter is used when you run this program anytime after the
* first time. You will once again be prompted for the correct date and
* time. These values will be used to compare the time as reported by
* the cmos clock to the actual time. The difference between the cmos
* reported time and the actual time is adjusted to account for the
* length of time the cmos clock has been running since it was first
* set by this program. The resulting value, seconds/month is reported
* as a loss or gain, as appropriate.
*
* This program can be run with the q parameter anytime after the cmos
* clock has been initially set by this program. However, the cmos
* clock usually is not in error by more than a few minutes/month. This
* means you will not obtain a particularly accurate value unless at
* least several days have passed.
*/
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <dos.h>
#include <math.h>
#define RT_CLOCK 0x1A
#define SET_RT_TIME 0x03
#define SET_RT_DATE 0x05
#define GET_SYS_TIME 0x2C
#define GET_SYS_DATE 0x2A
#define GET_RT_TIME 0x02
#define GET_RT_DATE 0x04
#define DOS_FUNC_21 0x21
#define MONTH 2419200.0 /* Number of seconds in 28 days */
void main(int argc, char *argv[]);
void open_error_log(char *argv[]);
int bcd_to_bin(int bcd);
int bin_to_bcd(int bin);
void set_time(void);
void set_date(void);
time_t cmos_time(void);
FILE *fp;
void main( int argc, char *argv[] )
{
time_t start_time, elapsed_cmos, time_now, elapsed_actual, error, cmos;
struct tm *dst;
system("cls");
if(argc != 2)
{
puts("\nIncorrect usage: A command line parameter is needed.\n\n");
puts("Example: First time program is run....clockerr s\n");
puts(" Subsequent times.............clockerr q\n");
exit(0);
}
if((*argv[1] != 's') && (*argv[1] != 'q'))
{
puts("\nInvalid parameter: Must be either s or q.");
exit(0);
}
open_error_log(argv);
switch(*argv[1])
{
case 's': /*
* Program is started for the first time.
*
* Set the system date and time. Convert this time to a
* value of type time_t. Call localtime() to determine if
* daylight savings time is in effect. If dst->tm_isdst = 1
* then subtract an hour to convert to standard time. Write
* the start_time to error.log and exit.
*/
set_date();
set_time();
time(&start_time);
dst = localtime(&start_time);
if(dst->tm_isdst) start_time -= 3600;
fwrite(&start_time, sizeof(time_t), 1, fp);
puts("\nThe CMOS clock has been initialized.\n");
puts("The file, error.log has been created.\n");
exit(0);
case 'q': /*
* Clock statistics are produced.
*
* Set the sysyem time and date correctly. The program
* will get the time from the operating system later.
*/
puts("\n\nTHE UNCORRECTED TIME AND DATE ARE DISPLAYED.");
puts("ENTER THE CORRECT VALUES.\n");
system("date");
system("time");
/*
* Get the time at which the program was originally
* started. This has been stored as a value of type
* time_t in the disc file, error.log.
*/
fread(&start_time, sizeof(time_t), 1, fp);
/*
* The current time as kept by the cmos clock is obtained
* from a call to cmos_time(). The number of seconds that
* have elapsed on the cmos clock is elapsed_cmos.
*/
cmos = cmos_time();
elapsed_cmos = cmos - start_time;
/*
* The correct time, time_now, is obtained from the system.
* A call to localtime() sets dst if daylight savings time
* is in effect. If dst = 1 then the time entered by the
* user is converted to standard time, which the program
* needs.
*/
time(&time_now);
dst = localtime(&time_now);
if(dst->tm_isdst) time_now -= 3600;
/*
* elapsed_actual is the amount of time that has passed
* since this program was first run, using the s parameter.
* The number of seconds by which the cmos clock varies
* from the actual elapsed time since then is computed
* and normalized to a per month value.
*/
elapsed_actual = time_now - start_time;
error = floor((elapsed_cmos - elapsed_actual)*
MONTH/elapsed_actual +.5);
system("cls");
puts("\n\n---------------------- REAL TIME CLOCK STATISTICS ----------------------\n");
printf(" Correct time entered by user............%s\n",asctime(localtime(&time_now)));
printf(" Time reported by CMOS clock.............%s\n",asctime(localtime(&cmos)));
printf(" The CMOS clock was set on...............%s\n",asctime(localtime(&start_time)));
if(elapsed_cmos <= elapsed_actual)
printf(" The CMOS clock has lost.................%d seconds so far.\n\n", abs(elapsed_cmos - elapsed_actual));
else
printf(" The CMOS clock has gained...............%d seconds so far.\n\n", elapsed_cmos - elapsed_actual);
if(error <= 0)
printf(" The CMOS clock looses...................%d seconds/month.\n\n", abs(error));
else
printf(" The CMOS clock gains....................%d seconds/month.\n\n", error);
puts("------------------------------------------------------------------------");
exit(0);
}
}
void set_time() /* Sets the system time then puts it in the cmos clock. */
{
union REGS reg;
struct tm *dst;
time_t now;
/*
* Set the system time. Setup for DOS call then return that time in REGS.
* Current time is also stored in now and passed to localtime() to see if
* daylight savings time is in effect. If so, then dst->tm_isdst = 1 and
* structure returned by the DOS call must be corrected by subtracting
* an hour (mod 24) from the field that represents the hour.
*/
system("time");
reg.h.ah = GET_SYS_TIME;
int86(DOS_FUNC_21, ®, ®);
time(&now);
dst = localtime(&now);
if(dst->tm_isdst)
reg.h.ch = (reg.h.ch-1)<0 ? 23: reg.h.ch-1;
/*
* Convert returned values to BCD. Set daylight savings time option to 0.
* Setup for and call BIOS with converted values to set the cmos clock.
*/
reg.h.ch = bin_to_bcd(reg.h.ch);
reg.h.cl = bin_to_bcd(reg.h.cl);
reg.h.dh = bin_to_bcd(reg.h.dh);
reg.h.dl = 0;
reg.h.ah = SET_RT_TIME;
int86(RT_CLOCK, ®, ®);
}
void set_date() /* Sets the system date then puts it in the cmos clock. */
{
union REGS reg;
double year, century;
/*
* Set system date. Setup for DOS call then return that date in REGS.
*/
system("date");
reg.h.ah = GET_SYS_DATE;
int86(DOS_FUNC_21, ®, ®);
/*
* Separate century/year into century and year, (eg. 1988 to 1900, 88)
* then convert all returned values to BCD format, required by BIOS call.
*/
year = reg.x.cx - 100*floor(.01*reg.x.cx);
century = (reg.x.cx - year);
reg.h.ch = bin_to_bcd((int)(.01*century));
reg.h.cl = bin_to_bcd((int)year);
reg.h.dh = bin_to_bcd(reg.h.dh);
reg.h.dl = bin_to_bcd(reg.h.dl);
/*
* Setup for BIOS call. The date values obtained from the DOS call and
* converted to the proper format above are used to set the cmos clock.
*/
reg.h.ah = SET_RT_DATE;
int86(RT_CLOCK, ®, ®);
}
void open_error_log( char *argv[] )
{
switch(*argv[1])
{
case 's': /*
* Try to open a file with the r+ option. For this to be
* successful the file must already exist. If it does we
* probably don't want to overwrite it, hence the warning.
* If it doesn't exist, create it if possible.
*/
if((fp = fopen("error.log", "r+")) != NULL)
{
puts("\nThe CMOS clock has been set already. If you");
puts("want to start over, erase error.log first.");
exit(0);
}
else
if((fp = fopen("error.log", "w")) == NULL)
{
puts("\nCan't open the required file.");
exit(0);
}
break;
case 'q': /*
* The file error.log must exist to generate the clock
* statistics.
*/
if((fp = fopen("error.log", "r")) == NULL)
{
puts("\nCan't open the error file, or it doesn't exist.");
puts("Probably, the CMOS clock was never initialized.");
exit(0);
}
}
}
time_t cmos_time() /* Returns the elapsed time on the cmos clock. */
{
struct tm cmos;
union REGS reg;
/*
* Setup for BIOS call. First get the time from the cmos clock, convert
* the result from BCD to binary format and place in the structure, cmos.
* Then do the same for the date. Finally call mktime() with a pointer to
* the structure cmos. This converts the structure to a representation of
* the time as a value of type time_t. This is the value returned.
*/
reg.h.ah = GET_RT_TIME;
int86(RT_CLOCK, ®, ®);
cmos.tm_hour = bcd_to_bin(reg.h.ch);
cmos.tm_min = bcd_to_bin(reg.h.cl);
cmos.tm_sec = bcd_to_bin(reg.h.dh);
cmos.tm_isdst =0;
reg.h.ah = GET_RT_DATE;
int86(RT_CLOCK, ®, ®);
cmos.tm_year = bcd_to_bin(reg.h.ch)*100 + bcd_to_bin(reg.h.cl) - 1900;
cmos.tm_mon = bcd_to_bin(reg.h.dh) - 1;
cmos.tm_mday = bcd_to_bin(reg.h.dl);
return mktime(&cmos);
}
int bcd_to_bin( int bcd ) /* Convert from BCD format to binary. */
{
return bcd - (bcd/16)*6;
}
int bin_to_bcd( int bin ) /* Convert from binary format to BCD. */
{
return bin + (bin/10)*6;
}