Category : Utilities for DOS and Windows Machines
Archive   : AT-CLOCK.ZIP
Filename : CLOCKERR.C

 
Output of file : CLOCKERR.C contained in archive : AT-CLOCK.ZIP

/* 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
#include
#include
#include
#include

#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;
}


  3 Responses to “Category : Utilities for DOS and Windows Machines
Archive   : AT-CLOCK.ZIP
Filename : CLOCKERR.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/