[comp.sources.misc] v15i009: Heathkit GC-1000 reader for unix, v1.4

mrapple@quack.sac.ca.us (Nick Sayer) (10/06/90)

Posting-number: Volume 15, Issue 9
Submitted-by: mrapple@quack.sac.ca.us (Nick Sayer)
Archive-name: gc1000/part01

#! /bin/sh
# This file was wrapped with "dummyshar".  "sh" this file to extract.
# Contents:  gc1000.c
echo extracting 'gc1000.c'
if test -f 'gc1000.c' -a -z "$1"; then echo Not overwriting 'gc1000.c'; else
sed 's/^X//' << \EOF > 'gc1000.c'
X/*
X
Xsetclock.c - get time from the Heathkit GC-1000
X
XCopyright 1990, Nick Sayer
XPermission to distribute granted as long as no fee is charged and
Xthose to whom you distribute are also free to do so. All other
Xrights reserved. No warrantees are extended regarding this software's
Xcorrectness or applicability to any specific purpose.
X
Xrevision history:
X
Xv1.4  10/01/90 - minor bug fixes. -d flag now ignores -l. -l 0 disables -l.
Xv1.3  09/22/90 - added limitation on time "displacement" -l option
Xv1.2  03/31/90 - added command line option -d (debug)
Xv1.1  02/01/90 - added configuration section & changed to settimeofday()
Xv1.0 the epoch - created
X
XBUGS -	adjtime() would be preferable to settimeofday().
X
X				USAGE
X
X% setclock [-d] [-l minutes]
X
XHave cron run this program as often as necessary to maintain system
Xclock accuracy. If the clock is not set, or if the tenth-of-a-second digit
Xis dimmed, the system time will not be changed.
X
XIf -d is specified, the system will print out what time it is according
Xto the clock. It will not try to set the system time. Use this to debug
Xthe switch and/or options settings (see below).
X
XIf the time is off by more than a certain number of minutes (specified
Xby -l, default 5), the time will not be changed and an error message
Xgenerated instead. The WWV signal has no check-bits and some computers
Xdon't have the best shielding in the world. The result is that despite
Xthe clock's heuristics it can occasionally get the wrong idea of what
Xtime it is. Having the system time suddenly change by a large amount
Xcan cause great confusion, and that confusion is complicated when the
Xtime has to be changed back again. For small numbers of minutes though
Xthis isn't such a big problem. If you know the clock is right and the
Xsystem is wrong, you can use "-l 0" to turn this checking off.
X
X			   CONFIGURATION
X
XYour clock should be set to constantly give the time every second or
Xso. I.e. the handshaking option should be off, and the continuous
Xoption should be on. On my clock, using this configuration, the
Xtime reported is exactly one second slow, so this second is added back
Xlater. To remove this, simply find the line that says
X"convert.tm_sec=....." and remove the "+1".
X
XThe time sent to the RS-232 reads exactly the same way as it does on
Xthe display, so if your clock displays UT1, so will your unix box.
XIf the section below is not right, all hell will break loose. :-)
X
XSet DEVICE to the full path of the entry in /dev (or a link to it)
Xthat talks to the clock
X*/
X#define DEVICE "/dev/clock" /* file for clock device */
X
X/*
XSet baud rate for clock (like in sgtty.h)
X*/
X#define BAUD B2400 /* baud rate for clock */
X
X/*
XSet the default minute limit here
X*/
X#define DEFAULT_MINUS_L 5
X
X/*
XIf your clock displays AM/PM, define this.
X*/
X#define AMPM                /* define if clock shows AM/PM */
X
X/*
XIf you've set the clock up to display local time rather than GMT, then
Xthe clock must also be set properly for your local interpretation of
Xdaylight savings time. If your area has DST, it is NOT a good idea to
Xrun this program less than 24 hours before DST kicks in or turns off.
XYou may find your clock changing DST status early. Unix will figure out
XDST by itself. For no-hassle results, use GMT and undef LOCAL. For
Xhuman-readibility of the clock, grin and bear it. :-)
X*/
X#define LOCAL               /* undef this if your clock displays GMT */
X
X/*
XSince the BCD time code doesn't include any indication of what year it
Xis, heath used internal dipswitches to set the year. Since it's a pain
Xto get in there on December 31 every year, two options have been
Xincluded to get around this. If you define CLOCKYEAR, the clock's idea
Xof what year it is will be used. If you define YEARFILE, and set it
Xto a filename, that file is assumed to have two digits and a newline
Xin it, and those two digits will be used as the year. If you don't
Xdefine either, the system's current notion of what year it is will
Xbe retained. If you do it this way, it is NOT a good idea to run
Xthis program close to 23:59:59 on December 31.
X*/
X/* #define CLOCKYEAR        /* define this to use the clock's year */
X/* #define YEARFILE "/usr/local/lib/year" /* define this for file */
X
X/*
XFor best results, define NICE and set to the priority level desired. -20
Xis highly recommended. This program doesn't load the CPU much, but
Xaccuracy will suffer if it gets swapped.
X*/
X#define NICE -20
X
X/*
X                        END OF CONFIGURATION
X*/
X
X/* spoof 'em for gmtime if necessary */
X
X#ifdef LOCAL
X#define LOCALTIME localtime
X#define TIMELOCAL timelocal
X#else
X#define LOCALTIME gmtime
X#define TIMELOCAL timegm
X#endif
X
X#include <stdio.h>
X#include <sgtty.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/time.h>
Xextern int errno;               /* perror(3) */
Xextern char *sys_errlist[];
Xextern int optind,opterr;       /* getopt(3) */
Xextern char *optarg;
X
X/* We'll set a timer later. If it goes off, something's messed up. */
Xbomb()
X{
X
X  printf("Timeout. Check clock.\n");
X  exit(1);
X
X}
X
X/* A hack. getc() didn't work for some reason. */
Xchar get_c(fildes)
Xint fildes;
X{
X  char c;
X  read(fildes,&c,1);
X  return c;
X}
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X
X  int clkfil,dbg_flag=0,usec,hr,timedif=DEFAULT_MINUS_L,errflag=0;
X  char a[255],*b,optchar;
X  time_t hydrant;
X
X  struct timeval tv;
X  struct timezone tz;
X  struct tm convert;
X
X  struct sgttyb ttystuff;
X
X#ifdef YEARFILE
X  FILE *yf;
X  int yf_yr;
X#endif
X
X  opterr=0;
X
X  while((optchar=getopt(argc,argv,"dl:"))!=-1)
X  {
X    switch(optchar)
X    {
X      case 'd':dbg_flag++; break;
X      case 'l':timedif=atoi(optarg); break;
X      default:errflag++;
X    }
X  }
X  if (errflag)
X  {
X    printf("Usage: %s [-d] [-l min]\n",*argv);
X    exit(1);
X  }
X
X/* if YEARFILE, we'd better read it now so it won't interfere with the
Xtight timing section later */
X#ifdef YEARFILE
X  yf=fopen(YEARFILE,"r");
X  scanf("%d\n",&yf_yr);
X  fclose(yf);
X#endif
X
X#ifdef NICE
X  nice(NICE);
X#endif
X
X  alarm(15);
X  signal(SIGALRM,bomb);
X
X  if ((clkfil=open(DEVICE,2))==NULL)
X  {
X    printf("Error opening %s.\n",DEVICE);
X    exit(1);
X  }
X
X/* set for baud rate and RAW */
X  ttystuff.sg_ispeed=BAUD;
X  ttystuff.sg_ospeed=BAUD;
X  ttystuff.sg_kill=' ';
X  ttystuff.sg_erase=' ';
X  ttystuff.sg_flags=RAW;
X  if (ioctl(clkfil,TIOCSETP,&ttystuff)==-1)
X  {
X    printf("Error setting up %s.\n",DEVICE);
X    exit(1);
X  }
X/*
XWait for end of line, then read until another. If seconds>50,
Xwait for it to go to 0. We have to add 1 to the seconds, and if it's
X:59..... Also, if the line's too short, read it again.
X*/
X  while((get_c(clkfil) & '')!='\r');
X  do {
X    b=a;
X    while((*b=get_c(clkfil) & '')!='\r') b++;
X    *b='\0';
X  } while (a[6]=='5' || strlen(a)!=23);
X/*
X
X     START OF TIME CRITICAL SECTION
X
XFrom here to end of critical section must be executed as quickly as
Xpossible to (try to) insure accuracy
X
Xa[9] is the tenth of a second digit. The clock outputs a ? here if
Xeither the clock is not set, or if it hasn't been updated in 24
Xhours and therefore isn't sure of itself.
X*/
X  if (a[9]=='?')
X  {
X    printf("Clock not set.\n");
X    exit(1);
X  }
X
X  usec=atoi(a+9)*100;
X  hr=atoi(a);
X
X#ifdef AMPM
X  if (a[11]=='P') 
X  {
X    if (hr!=12) hr+=12;
X  }
X  if (a[11]=='A')
X  {
X    if (hr==12) hr=0;
X  }
X#endif
X
X  time(&hydrant);
X  convert=*LOCALTIME(&hydrant);
X  convert.tm_min=atoi(a+3);
X  convert.tm_sec=atoi(a+6)+1;
X  convert.tm_hour=hr;
X  convert.tm_mon=atoi(a+15)-1;
X  convert.tm_mday=atoi(a+18);
X
X#ifdef CLOCKYEAR
X  convert.tm_year=atoi(a+21);
X#endif
X
X#ifdef YEARFILE
X  convert.tm_year=yf_yr;
X#endif
X
X  hydrant=TIMELOCAL(&convert);
X
X  if (dbg_flag)
X  {
X    printf("%s",ctime(&hydrant));
X    exit(0);
X  }
X
X  if ( (abs(time(0L)-hydrant)>(timedif*60)) && (timedif) )
X  {
X    printf("Clock shows substantially different time. Check clock.\n");
X    exit(1);
X  }
X
X/*
XNow hydrant is the current ctime (num of secs since epoch)
X*/
X
X  gettimeofday(&tv,&tz);
X  tv.tv_sec=hydrant;
X  tv.tv_usec=usec;
X  if (!dbg_flag)
X    if (settimeofday(&tv,&tz)!=0)
X    {
X      printf("settimeofday(): %s\n",sys_errlist[errno]);
X      exit(1);
X    }
X
X/*
X
XEND OF TIME CRITICAL SECTION
X
X*/
X
Xexit(0);
X
X}
EOF
chars=`wc -c < 'gc1000.c'`
if test $chars !=     8123; then echo 'gc1000.c' is $chars characters, should be     8123 characters!; fi
fi
exit 0
-- 
Nick Sayer               |  Disclaimer:
N6QQQ [44.2.1.17 soon]   |    "Just because you're reading my post doesn't
mrapple@quack.sac.ca.us  |     mean we're gonna take long showers together."
209-952-5347 (Telebit)   |                      -- Gunnery Sgt. Thomas Highway