home *** CD-ROM | disk | FTP | other *** search
- /*-----------------------------------------------------------------------------
- NBS ACTS Access Routine -- Dials NBS & sets DOS date/time accordingly.
- Copyright (c) Franklin Antonio, 1988, All Rights Reserved.
-
- This program (source and object) may be freely distributed and used for non-
- commercial purposes only. If you redistribute this package, you must
- distribute all the files (source, object, doc, ini), in their original,
- unmodified, form. You may, additionally, distribute modified versions, with
- the modified versions, but they must be clearly identified as modified, with
- the original copyright statements intact, and the name and address of the
- modifier must be clearly shown.
-
- Compile with Microsoft C 5.1 ... cl /Ox /DMAIN nbscom.c
-
- Edit History...
- 12/19/88 -fa- change abs to dabs in printf of time_change
- added .ini file
- put in direct i/o (to ignore modem control signals)
- started hardware RTC stuff
- 12/20/88 -fa- replace sscanf() with atoi() in parse_a_time (AT:3.3ms-->0.3ms)
- replace putc( ,stdio) with putc_screen() (AT:1.5ms-->0.5ms)
- check ftime() {1.5ms} and kbhit() {0.5ms} only every 10th char
- now polled i/o won't drop chars on even the slowest machine
- 01/07/89 -fa- Timeout was too short for some people using pulse dialing or
- using long access codes. Changed default from 30 to 90 sec,
- and made it a param settable from ini file.
- ----------------------------------------------------------------------------*/
- #include <stdio.h>
- #include <bios.h> /*needed by _bios_serialcom() */
- #include <dos.h> /*needed by _dos_setxxxx() */
- #include <conio.h> /*needed by kbhit() */
- #include <sys\timeb.h> /*needed by ftime() */
- #include <time.h> /*needed by tzset() */
- #include <ctype.h> /*needed by isspace() */
- #include <graph.h> /*needed by _clearscreen() */
- #include <math.h> /*needed by fabs() */
-
- /*function prototypes*/
- double floatime(struct timeb);
- double floatimenow(void);
- void delay(double);
- int parse_a_time(char *, int *, int *, int *, int *, int *, int *);
- void Datek2(long,long *,long *,long *);
- long KDAY2(long,long,long);
-
-
- #define dabs(x) fabs(x) /*double abs*/
- #define xbcd(bcd) ( 10*((bcd)>>4) + ((bcd)&0x0f) ) /*packed bcd to integer*/
- #define bcdx(x) ( ((x)/10)<<4) + (x)%10 ) /*integer to packed bcd*/
-
-
- /*parameters initialized here, but set from NBSCOM.INI file if available*/
- int nbs_port = 0; /*port # for serial comm*/
- int nbs_speed = 1200; /*baud rate for serial comm*/
- int maxtime = 90; /*max online time (seconds*/
- char dial_sequence[50] = "ATDT1-303-494-4774"; /*dial command buffer*/
- char hangup_sequence[50] = "ATH"; /*hangup command buffer*/
-
-
- /*items specific to standard 8250-based com ports*/
- unsigned port[4] ={0x3f8,0x2f8,0,0}; /*standard IBM port addresses*/
- #define UART_DATA 0 /*data register */
- #define UART_MCR 4 /*modem control register*/
- #define UART_LSR 5 /*line status register */
- #define UART_MSR 6 /*modem status register*/
-
-
-
- /*-----------------------------------------------------------------------------
- main (stand alone program)
- ----------------------------------------------------------------------------*/
- #ifdef MAIN
- main() { /*compile main optionally*/
- nbs_init_and_acts();
- }
- #endif
-
- nbs_init_and_acts() {
- nbs_init();
- printf("NBSCOM 1.2 -- Copyright(c) Franklin Antonio, 1988\n");
- delay(1.0);
- call_nbs_acts();
- }
-
- /*-----------------------------------------------------------------------------
- call_nbs_acts -- Places a call to National Bureau of Standards Advanced
- Computer Time Service, reads date/time, & sets dos time accordingly.
- ----------------------------------------------------------------------------*/
- call_nbs_acts() {
- struct timeb start,now,time_before,time_after;
- struct dosdate_t dosdate;
- struct dostime_t dostime;
- double time_change;
- long lda,lmo,lyr,time;
- int tick,j,j1,j2,yr1,yr2,mo1,mo2,da1,da2,hr1,hr2,mi1,mi2,se1,se2;
- int rtc,yr,mo,da,hr,mi,se;
- char *p,c,buf[80];
-
-
- j = _COM_CHR8 | _COM_NOPARITY;
- if(nbs_speed == 300) /*user want low speed?*/
- j |= _COM_300; /*ok*/
- else
- j |= _COM_1200; /*only other speed NBS allows*/
- _bios_serialcom(_COM_INIT,nbs_port,j); /*initialize modem port*/
-
- _clearscreen(_GCLEARSCREEN); /*clear screen, so no scroll during*/
- /*session. Elims scn scroll time*/
-
- printf("Accessing National Bureau of Standards \n"
- " Advanced Computer Time Service...\n\n");
-
- printf("--- Modem dialog follows --- Type any key to abort. ---\n");
-
- dial_the_modem(); /*initiate phonecall*/
-
-
- /*now sit in a loop for up to maxtime copying characters to screen, and a
- buffer. when lf seen, attempt to parse. two correct parses in a row which
- differ by exactly 1 second causes successful termination. Timeout or a hit
- from the keyboard causes unsuccessful termination. The most time-consuming
- item in the loop (by far) is the ftime() call. ftime() takes 6ms on a
- 4.77 MHz PC, which is 2/3 of a character time @ 1200 baud. ftime() is a
- good example of a library routine that could have been 20 times faster
- if it had been written carefully. */
-
- fflush(stdin); /*flush kb, so kbhit works*/
- ftime(&start); /*begin timeout*/
- p=buf; /*init ptr to line buffer*/
-
- for(tick=0; 1; tick = (tick>=10) ? 0 : ++tick) { /*serial port poll loop*/
-
- c = nbgetc_modem(); /*get a char from modem*/
- if(c != 0) putc_screen(c); /*echo to screen*/
-
- if(isprint(c) || isspace(c)) { /*elim trash*/
- *p++ = c; /*good char to buffer*/
- if(c == '\n' || p == buf+80-1) { /*eol?*/
- *p=0; p=buf; /*tie off & reset ptr*/
- j = parse_a_time(buf,&yr1,&mo1,&da1,&hr1,&mi1,&se1);
- if(j==1) { /*a valid time line?*/
- if(yr1==yr2 && mo1==mo2 && da1==da2 && hr1==hr2 &&
- mi1==mi2 && se1==se2+1) { /*and it's 2nd one?*/
- goto goodtime; /*zounds*/
- }
- else {
- yr2=yr1; mo2=mo1; da2=da1; /*then it's 1st one*/
- hr2=hr1; mi2=mi1; se2=se1; /*remember values*/
- }
- } /*end if j==1 */
- } /*end if c == */
- } /*end if isprint( */
-
- if(tick == 0) { /*occasionally check*/
- ftime(&now); /*for timeout*/
- if(now.time > start.time + maxtime) break;
- }
- if(tick == 5) { /*occasionally check*/
- if(kbhit()) break; /*for manual abort*/
- }
- } /*end for(tick */
-
-
- if(kbhit()) printf("--- aborted by user ---\n");
- else printf("--- %d seconds elapsed. aborted. ---\n",maxtime);
- time_change = 0.; /*there was no change*/
-
- goto hangup; /*attempt to hang up phone*/
-
-
-
- /* ------- Here when we have read a good time. Tell DOS. ---------*/
-
- /*we have to adjust the UTC time we've just received by our local timezone
- so we can set DOS date/time local. Adjustment may be negative, and the lib.
- routine mktime() can't handle negative arguments, so we convert using local
- routines to a single time variable, adjust, then convert back. messy.*/
-
- goodtime: /*got a valid time*/
- tzset(); /*make timezone valid*/
- time = 24L*KDAY2((long)da1,(long)mo1,(long)1900+yr1) + hr1;
- time -= timezone/(60L*60L); /*adjust for timezone*/
- Datek2(time/24L,&lda,&lmo,&lyr); /*get new d/m/y*/
- hr1 = time%24L; /*fractional day*/
-
- /*Now we have local time. Do all the time-setting operations before printing
- any of the results, or doing any of the calls that use floating-point
- operations, so that we get everything set before much time passes. */
-
- ftime(&time_before); /*time before setting*/
-
- dostime.hour = hr1;
- dostime.minute = mi1;
- dostime.second = se1;
- dostime.hsecond = 0;
- j2 = _dos_settime(&dostime); /*set dos time*/
-
- dosdate.year = lyr;
- dosdate.month = lmo;
- dosdate.day = lda;
- dosdate.dayofweek = 0;
- j1 = _dos_setdate(&dosdate); /*set dos date*/
-
- ftime(&time_after); /*time after setting*/
-
- rtc = read_hw_rtc(&yr,&mo,&da,&hr,&mi,&se); /*hardware realtime clock*/
-
-
- printf("--- Setting DOS Date & Time to local: %02d/%02d/%d %02d:%02d:%02d ---\n",
- dosdate.month,dosdate.day,dosdate.year,
- dostime.hour,dostime.minute,dostime.second);
-
- if(j1 != 0) printf("--- DOS set Date failed ---\n");
- if(j2 != 0) printf("--- DOS set Time failed ---\n");
- if(j1 == 0 && j2 == 0) {
- time_change = floatime(time_after) - floatime(time_before); /*change*/
- printf("--- Your DOS time was %s NBS by %.2f seconds ---\n",
- time_change>0 ? "behind" : "ahead of",
- dabs(time_change) );
- }
- if(rtc) printf("--- Info only: Your hardware realtime clock reads: "
- "%02d/%02d/%d %02d:%02d:%02d ---\n",
- mo,da,yr,hr,mi,se);
-
- goto hangup; /*attempt to hang up phone*/
-
-
- hangup:
- hangup_the_modem(); /*terminate phone call*/
-
- printf("--- Done --- Phone call duration was %.1f seconds. ---\n",
- floatimenow() - floatime(start) - time_change );
-
- return 0;
-
- }
-
-
- /*-----------------------------------------------------------------------------
- dial_the_modem -- does just that. initiates phone call.
- ----------------------------------------------------------------------------*/
- dial_the_modem() {
-
- control_modem(0x3); /*turn on DTR & RTS*/
-
- printf ("+++");
- puts_modem("+++"); /*enter hayes command mode*/
- delay(1.25); /* +++ guardtime*/
-
- printf( dial_sequence); /*dial!*/
- puts_modem(dial_sequence);
-
- printf("\n"); /*dial command terminator*/
- puts_modem("\r\n");
- delay(0.1); /*avoid echo last char of dial*/
- }
-
-
-
- /*-----------------------------------------------------------------------------
- hangup_the_modem -- does just that. terminates phone call.
- ----------------------------------------------------------------------------*/
- hangup_the_modem() {
-
- printf ("+++");
- puts_modem("+++"); /*enter hayes command mode*/
- delay(1.25); /* +++ guardtime*/
-
- printf( hangup_sequence); /*hangup command*/
- puts_modem(hangup_sequence);
-
- printf("\n");
- puts_modem("\r\n");
-
- control_modem(0x00); /*drop DTR (hangs up some modems) */
- }
-
-
-
- /*-----------------------------------------------------------------------------
- parse_a_time -- attempt to parse a "time" line from NBS
- MJD YR MO DA H M S ST S UT1 msADV OTM
- nbs format--> 47511 88-12-16 06:03:44 00 0 -.1 045.0 UTC(NBS) *
- @ 1200 baud 47511 88-12-16 06:03:45 00 0 -.1 045.0 UTC(NBS) *
- H M S msADV OTM
- nbs format--> 06:03:44 045.0 * <--but how do i get the date?
- @ 300 baud 06:03:45 045.0 *
- ----------------------------------------------------------------------------*/
-
- parse_a_time(char *p, int *yr, int *mo, int *da,
- int *hr, int *mi, int *se) {
- int mjd;
-
- /*This scanf takes 3.3ms on my AT, but the following code that replaces it
- takes 0.3ms, so is a clear winner.
- j = sscanf(line,"%d %d-%d-%d %d:%d:%d",&mjd,yr,mo,da,hr,mi,se);
- */
- while(isspace(*p)) p++;
- while(isdigit(*p)) p++; /*past mjd*/
- while(isspace(*p)) p++;
- *yr = atoi(p); p+=3; /*date*/
- *mo = atoi(p); p+=3;
- *da = atoi(p); p+=3;
- while(isspace(*p)) p++;
- *hr = atoi(p); p+=3; /*time*/
- *mi = atoi(p); p+=3;
- *se = atoi(p); p+=3;
-
- if(*yr<88 || *yr>99 || *mo<=0 || *mo>12 || *da<=0 || *da>31 ||
- *hr<0 || *hr>23 || *mi<0 || *mi>59 || *se<0 || *se>59 ) return 0;
- /*and legal values everywhere?*/
-
- return 1; /*good, then we got it*/
- }
-
-
-
- /*-----------------------------------------------------------------------------
- delay -- spinloop delay for wait seconds.
- ----------------------------------------------------------------------------*/
- void delay(double wait) {
- struct timeb start;
- ftime(&start);
- while(floatimenow() < floatime(start) + wait);
- }
-
-
- /*-----------------------------------------------------------------------------
- floatime -- converts a timeb structure to floating point seconds. Used
- outside critical time sections.
- ----------------------------------------------------------------------------*/
- double floatime(struct timeb t) {
- return t.time + .001*t.millitm;
- }
-
- double floatimenow() {
- struct timeb t;
- ftime(&t);
- return floatime(t);
- }
-
-
-
- /*-----------------------------------------------------------------------------
- nonblocking read character from serial port using direct i/o
- ----------------------------------------------------------------------------*/
- nbgetc_modem() {
- if((inp(port[nbs_port]+UART_LSR) & 0x01) == 0) /*character ready?*/
- return 0; /*no*/
- return inp(port[nbs_port]+UART_DATA); /*yes*/
- }
-
-
- /*-----------------------------------------------------------------------------
- write character to serial port using direct i/o
- ----------------------------------------------------------------------------*/
- putc_modem(char c) {
- while((inp(port[nbs_port]+UART_LSR) & 0x20) == 0); /*wait for holding reg*/
- outp(port[nbs_port]+UART_DATA, c);
- }
-
-
- /*-----------------------------------------------------------------------------
- write string to serial port using direct i/o
- ----------------------------------------------------------------------------*/
- puts_modem(char *s) {
- while(*s != 0)
- putc_modem(*s++);
- }
-
-
- /*-----------------------------------------------------------------------------
- set modem-control signals on serial port using direct i/o
- ----------------------------------------------------------------------------*/
- control_modem(char c) {
- outp(port[nbs_port]+UART_MCR,c);
- }
-
-
-
- /*-----------------------------------------------------------------------------
- put character to screen using bios. putc(c,stdio) took 1.4 mS, this takes
- 0.5 mS on my AT.
- ----------------------------------------------------------------------------*/
- putc_screen(char c) {
- static union REGS reg;
-
- reg.h.ah = 0xE; /*write tty style*/
- reg.h.al = c; /*this char*/
- reg.h.bh = 0; /*scn page 0*/
- int86(0x10,®,®); /*do it*/
- }
-
-
-
- /*----------------------------------------------------------------------------
- ACM Algorithm 199
- convert calendar date to day number
- K=1 at March 1, 1900.
- --------------------------------------------------------------------------*/
- long KDAY2(long Iday,long Month,long Iyear) {
- long M,IY,Kday;
- if(Iday < 1 || Iday > 31 || Month < 1 || Month > 12
- || Iyear < 1900 || Iyear > 1999) printf("?kday: ilg param\n");
-
- M=Month-3 ; IY=Iyear-1900;
- if(Month <= 2) {
- M=Month+9;
- IY=IY-1;
- }
- Kday=(1461*IY)/4+(153*M+2)/5+Iday;
- return Kday;
- }
-
-
-
- /*----------------------------------------------------------------------------
- ACM algorithm 199
- day number to calendar date
- Valid from 3/1/1900 thru 2/28/2000.
- --------------------------------------------------------------------------*/
- void Datek2(long K,long *Iday,long *Month,long *Iyear) {
- long day,month,year;
-
- if(K < 0 || K > 36500) printf("?datek: ilg param\n");
- year=(4*K-1)/1461;
- day=4*K-1-1461*year;
- day=(day+4)/4;
- month=(5*day-3)/153;
- day=5*day-3-153*month;
- day=(day+5)/5;
- month=month+3;
- year=year+1900;
- if(month >= 13) {
- month=month-12;
- year=year+1;
- }
- *Iday=day; *Month=month; *Iyear=year;
- }
-
-
-
- /*----------------------------------------------------------------------------
- Parameter initialization (reads .INI file)
- --------------------------------------------------------------------------*/
-
- nbs_init() {
- FILE *init;
- char buf[80],*p;
-
- init = fopen("nbscom.ini","r"); /*open .ini file*/
- if(init == NULL) return 0; /*if no file, use defaults*/
-
- while(NULL != fgets(buf,80,init)) { /*until end-of-file*/
- sscanf(buf," dial = %50s", dial_sequence);
- sscanf(buf," hangup = %50s",hangup_sequence);
- sscanf(buf," port = %d", &nbs_port);
- sscanf(buf," speed = %d", &nbs_speed);
- sscanf(buf," maxtime = %d", &maxtime);
- }
-
- fclose(init); /*close .ini file*/
- }
-
-
- /*-----------------------------------------------------------------------------
- Routines to diddle the hardware realtime-clock (via BIOS)
- It's difficult to set the RTC accurately, because its least digit is seconds.
- Furthermore, the RTC can refuse to be read (if it's propagating a carry at
- the time). I plan to write some code that overcomes these difficulties, so
- that i can then set the RTC accurately.
- This only works on an IBMAT or later BIOS. It would also work if aftermarket
- RTCs came with TSRs that implemented the AT BIOS RTC functions, but none do.
- **NOTFINISHED**
- ----------------------------------------------------------------------------*/
- read_hw_rtc(int *yr,int *mo,int *da,int *hr,int *mi,int *se) {
- union REGS reg;
-
- reg.h.ah = 4; /*read date from RTC*/
- reg.h.cl = reg.h.ch = 0xff; /*marker*/
- int86(0x1A,®,®); /*BIOS call*/
- if(reg.h.cl==0xff || reg.h.ch==0xff) return 0; /*if no RTC BIOS, fail return*/
- *yr = 100*xbcd(reg.h.ch) + xbcd(reg.h.cl);
- *mo = xbcd(reg.h.dh);
- *da = xbcd(reg.h.dl);
-
- reg.h.ah = 2; /*read time from RTC*/
- int86(0x1A,®,®); /*BIOS call*/
- *hr = xbcd(reg.h.ch);
- *mi = xbcd(reg.h.cl);
- *se = xbcd(reg.h.dh);
- }
-
-