home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PROGRAMS / UTILS / NOVELL / SETSER.ZIP / NBSCOM.ARC / NBSCOM.C next >
Encoding:
C/C++ Source or Header  |  1991-01-12  |  25.1 KB  |  673 lines

  1. /*---------------------------------------------------------------------------
  2.   NIST ACTS Access Routine -- Dials NIST & sets DOS date/time accordingly.
  3.   Copyright (c) Franklin Antonio, 1988, All Rights Reserved.
  4.  
  5.   This program (source and object) may be freely distributed and used for non-
  6.   commercial purposes only.  If you redistribute this package, you must 
  7.   distribute all the files (source, object, doc, ini), in their original, 
  8.   unmodified, form.  You may, additionally, distribute modified versions, with
  9.   the unmodified versions, but they must be clearly identified as modified, 
  10.   with the original copyright statements intact, and the name and address of
  11.   the modifier must be clearly shown.
  12.  
  13.   Compile with Microsoft C 5.1 or C 6.0a ... cl /Ox /DMAIN nbscom.c
  14.  
  15.   Edit History...
  16.   12/19/88 -fa- change abs to dabs in printf of time_change
  17.         added .ini file
  18.         put in direct i/o (to ignore modem control signals)
  19.         started hardware RTC stuff
  20.   12/20/88 -fa- replace sscanf() with atoi() in parse_a_time (AT:3.3ms-->0.3ms)
  21.         replace putc( ,stdio) with putc_screen()     (AT:1.5ms-->0.5ms)
  22.         check ftime() {1.5ms} and kbhit() {0.5ms} only every 10th char
  23.         now polled i/o won't drop chars on even the slowest machine
  24.   01/07/89 -fa- Timeout was too short for some people using pulse dialing or
  25.         using long access codes.  Changed default from 30 to 90 sec,
  26.         and made it a param settable from ini file.
  27.   01/12/89 -fa- made maxtime=0 imply no timeout.  made main loop much faster
  28.         so some machines SLOWER than 4.77MHz PCs can work!  if laptops
  29.         have garbled character problems, should try maxtime=0
  30.   04/04/89 -fa- fix the daylight savings time bug!  darn.  Now vers 1.4.
  31.   06/05/89 -pw- fix up trivial compiler warnings.
  32.   06/26/89 -fa- add COM3,COM4 addresses.  changed from \r\n to \r at end of
  33.         modem commands.  A few modems couldn't eat the \n so quickly
  34.         after the \r.  
  35.   07/30/89 -fa- chg fopen() to it_fopen() when part of InstantTrack.
  36.   09/29/89 -fa- add simple interrupt driven com i/o.  this makes us compat.
  37.         with TSRs that use significant time, very very slow machines,
  38.         multitasking things, etc.
  39.   10/29/89 -fa- Damn.  When i fixed the daylight savings time bug in april,
  40.         i got the 2am conditional backwards for the two transition
  41.         days!  Worked right except during these 2 days.  Now ver 1.6.
  42.   12/02/89 -fa- Change onscreen text from "NBS" to "NIST", because the
  43.         National Bureau of Standards changed it's name!
  44.   01/07/90 -fa- allow computer-to-modem serial link to run at any standard
  45.         speed, even tho we can only call NIST at 300 or 1200.  Some
  46.         brands of modem demand to talk to computer at a fixed speed.
  47.         Has caused complaints from owners of Everex modems.
  48.         Changed nbscom.ini to it.ini when part of IT.
  49.         Now is version 1.7
  50.   02/08/90 -fa- Put delay after hangup command, and prior to dropping DTR &
  51.         shutting down com port!  May make a difference on some modems.
  52.   01/05/91 -fa- set baud rate by writing to port directly rather than using
  53.         the BIOS.  Works better because some BIOS's don't know how to
  54.         set COM3 & COM4.  Allow user to specify port addr & irq.
  55.   01/12/91 -fa- oops.  wrote divisor to wrong port!
  56.   ----------------------------------------------------------------------------*/
  57. #include <stdio.h>
  58. #include <bios.h>            /*needed by _bios_serialcom() */
  59. #include <dos.h>            /*needed by _dos_setxxxx() */
  60. #include <conio.h>            /*needed by kbhit() */
  61. #include <sys\timeb.h>            /*needed by ftime() */
  62. #include <time.h>            /*needed by tzset() */
  63. #include <ctype.h>            /*needed by isspace() */
  64. #include <graph.h>            /*needed by _clearscreen() */
  65. #include <math.h>            /*needed by fabs() */
  66. #include <stdlib.h>            /*needed by atoi() */
  67.  
  68. /*function prototypes*/
  69. double floatime(struct timeb);
  70. double floatimenow(void);
  71. void delay(double);
  72. int parse_a_time(char *, int *, int *, int *, int *, int *, int *, int *);
  73. void Datek2(long,long *,long *,long *);
  74. long KDAY2(long,long,long);
  75. void nbs_init_and_acts(void);
  76. void nbs_init(void);
  77. void call_nbs_acts(void);
  78. void dial_the_modem(void);
  79. int nbgetc_modem(void);
  80. void putc_screen(int c);
  81. int read_hw_rtc(int *yr,int *mo,int *da,int *hr,int *mi,int *se);
  82. void hangup_the_modem(void);
  83. void control_modem(int c);
  84. void puts_modem(char *s);
  85. void putc_modem(int c);
  86. FILE *it_fopen(char *,char *);
  87. void set_mcr(int valu,int mask);
  88. void enable_com_port(void);
  89. void disable_com_port(void);
  90. static void _cdecl interrupt far com_interrupt_handler();
  91.  
  92.  
  93. #define dabs(x) fabs(x)                    /*double abs*/
  94. #define xbcd(bcd) ( 10*((bcd)>>4) + ((bcd)&0x0f) )  /*packed bcd to integer*/
  95. #define bcdx(x)   ( ((x)/10)<<4) + (x)%10 )        /*integer to packed bcd*/
  96.  
  97.  
  98. /*parameters initialized here, but set from NBSCOM.INI file if available*/
  99. int nbs_port = 0;                  /*port # for serial comm*/
  100. unsigned nbs_port_address = 0;              /*port i/o address*/
  101. unsigned nbs_port_irq = 0;              /*port irq number*/
  102. int nbs_speed = 1200;                  /*baud rate for serial comm*/
  103. int maxtime = 90;                  /*max online time (seconds*/
  104. char dial_sequence[50]   = "ATDT1-303-494-4774";  /*dial command buffer*/
  105. char hangup_sequence[50] = "ATH";          /*hangup command buffer*/
  106.  
  107.  
  108. /*items specific to standard 8250-based com ports*/
  109. unsigned port[4] ={0x3f8,0x2f8,0x3e8,0x2e8};    /*standard IBM port addresses*/
  110. unsigned interrup[4] ={4,3,4,3};        /*standard IBM port interrupts*/
  111. #define UART_DATA 0                /*data register        */
  112. #define UART_DLL  0                /*divisor latch least-sig*/
  113. #define UART_INT  1                /*interrupt enable register*/
  114. #define UART_DLM  1                /*divisor latch most-sig*/
  115. #define UART_LCR  3                /*line control register*/
  116. #define UART_MCR  4                /*modem control register*/
  117. #define UART_LSR  5                /*line status register */
  118. #define UART_MSR  6                /*modem status register*/
  119.  
  120. static void (_cdecl interrupt far * old_com_handler)(void); /*old interrupt routine*/
  121. int com_port_live=0;                /*flag that we have interrupts*/
  122. unsigned com_wp,com_rp;                /*fifo write & read ptrs*/
  123. char com_buf[32];                /*com input fifo*/
  124.  
  125.  
  126. /*-----------------------------------------------------------------------------
  127.   main  (stand alone program)
  128.   ----------------------------------------------------------------------------*/
  129. #ifdef MAIN                    
  130. main() {                    /*compile main optionally*/
  131.   nbs_init_and_acts();
  132.   }
  133. #endif
  134.  
  135. void nbs_init_and_acts(void) {
  136.   nbs_init();
  137.   printf("NBSCOM 1.9a -- Copyright (c) 1990, 1991, Franklin Antonio\n");
  138.   delay(1.0);
  139.   call_nbs_acts();
  140.   }
  141.  
  142. /*-----------------------------------------------------------------------------
  143.   call_nbs_acts -- Places a call to National Bureau of Standards  Advanced
  144.      Computer Time Service, reads date/time, & sets dos time accordingly.
  145.   ----------------------------------------------------------------------------*/
  146. void call_nbs_acts(void) {
  147. struct timeb start,now,time_before,time_after;
  148. struct dosdate_t dosdate;
  149. struct dostime_t dostime;
  150. double time_change;
  151. long lda,lmo,lyr,time;
  152. int tick,j,j1,j2,yr1,yr2,mo1,mo2,da1,da2,hr1,hr2,mi1,mi2,se1,se2,dst1,dst2;
  153. int rtc,yr,mo,da,hr,mi,se;
  154. int c;
  155. char *p,buf[80];
  156.  
  157. switch(nbs_speed) {            /*choose divisor*/
  158.   case  300: j=384; break;
  159.   case 1200: j=96;  break;
  160.   case 2400: j=48;  break;
  161.   case 4800: j=24;  break;
  162.   case 9600: j=12;  break;
  163.   case 19200: j=6;  break;
  164.   }                    /*initialize modem port*/
  165. outp(nbs_port_address+UART_LCR, 0x80);    /*divisor latch access*/
  166. outp(nbs_port_address+UART_DLM, j>>8);    /*divisor latch*/
  167. outp(nbs_port_address+UART_DLL, j&0xff);/*divisor latch*/
  168. outp(nbs_port_address+UART_LCR, 0x03);    /*8bits, no parity, no latch access*/
  169.  
  170. _clearscreen(_GCLEARSCREEN);        /*clear screen, so no scroll during*/
  171.                     /*session.  Elims scn scroll time*/
  172.  
  173. printf("Accessing National Institute of Standards & Technology\n"
  174.        "          Automated Computer Time Service...\n\n");
  175.  
  176. printf("--- Modem dialog follows --- Type any key to abort. ---\n");
  177.  
  178. enable_com_port();            /*interrupt i/o goes live here*/
  179. dial_the_modem();            /*initiate phonecall*/
  180.  
  181.  
  182. /*now sit in a loop for up to maxtime copying characters to screen, and a 
  183.   buffer.  when lf seen, attempt to parse.  two correct parses in a row which
  184.   differ by exactly 1 second causes successful termination.  Timeout or a hit
  185.   from the keyboard causes unsuccessful termination.  The most time-consuming
  186.   item in the loop (by far) is the ftime() call.  ftime() takes 6ms on a
  187.   4.77 MHz PC, which is 2/3 of a character time @ 1200 baud. ftime() is a
  188.   good example of a library routine that could have been 20 times faster
  189.   if it had been written carefully. */
  190.  
  191. fflush(stdin);                    /*flush kb, so kbhit works*/
  192. ftime(&start);                    /*begin timeout*/
  193. p=buf;                        /*init ptr to line buffer*/
  194.  
  195. for(tick=0; 1; tick = (tick>=10) ? 0 : ++tick) { /*serial port poll loop*/
  196.  
  197.   c = nbgetc_modem();                /*get a char from modem*/
  198.   if(c != 0) putc_screen(c);            /*echo to screen*/
  199.  
  200.   if(isprint(c) || isspace(c)) {        /*elim trash*/
  201.     *p++ = (char) c;                /*good char to buffer*/
  202.     if(c == '\n' || p == buf+80-1) {        /*eol?*/
  203.       *p=0; p=buf;                /*tie off & reset ptr*/
  204.       j = parse_a_time(buf,&yr1,&mo1,&da1,&hr1,&mi1,&se1,&dst1);
  205.       if(j==1) {                /*a valid time line?*/
  206.         if(yr1==yr2 && mo1==mo2 && da1==da2 && hr1==hr2 && 
  207.            mi1==mi2 && se1==se2+1 && dst1==dst2) {    /*and it's 2nd one?*/
  208.           goto goodtime;            /*zounds*/
  209.           }
  210.         else {
  211.           yr2=yr1; mo2=mo1; da2=da1;        /*then it's 1st one*/
  212.           hr2=hr1; mi2=mi1; se2=se1;        /*remember values*/
  213.       dst2=dst1;
  214.           }
  215.         }    /*end if j==1 */
  216.       }      /*end if c == */
  217.     }        /*end if isprint( */
  218.  
  219.   if(tick == 0  && maxtime != 0) {        /*occasionally check*/
  220.     ftime(&now);                /*for timeout*/
  221.     if(now.time > start.time + maxtime) break;
  222.     }
  223.   if(tick == 5) {                /*occasionally check*/
  224.     if(kbhit()) break;                /*for manual abort*/
  225.     }
  226.   }          /*end for(tick   */
  227.  
  228.  
  229. if(kbhit()) printf("--- aborted by user ---\n");
  230. else        printf("--- %d seconds elapsed.  aborted. ---\n",maxtime);
  231. time_change = 0.;                /*there was no change*/
  232.  
  233. goto hangup;                    /*attempt to hang up phone*/
  234.  
  235.  
  236.  
  237. /* ------- Here when we have read a good time.  Tell DOS. ---------*/
  238.  
  239. /*we have to adjust the UTC time we've just received by our local timezone
  240.   so we can set DOS date/time local.  Adjustment may be negative, and the lib.
  241.   routine mktime() can't handle negative arguments, so we convert using local
  242.   routines to a single time variable, adjust, then convert back.  messy.*/
  243.  
  244. goodtime:                    /*got a valid time*/
  245. tzset();                    /*make timezone valid*/
  246. time = 24L*KDAY2((long)da1,(long)mo1,(long)1900+yr1) + hr1;
  247. time -= timezone/(60L*60L);            /*adjust for timezone*/
  248. Datek2(time/24L,&lda,&lmo,&lyr);        /*get new d/m/y*/
  249. hr1 = (int) (time%24L);                /*fractional day*/
  250.  
  251. /*Now we have local *STANDARD* time.  We may need to add one hour for
  252.   daylight savings time.  Rules are complicated.  NBS gives us a day code.
  253.   Day codes 02 thru 50 are DST for sure.  Day 51 is DST if LOCAL hour >=2.
  254.   Day 01 is DST if LOCAL hour < 2.  We now have computed the local hour,
  255.   so finally can make this adjustment.                      */
  256.  
  257.   if(daylight) {            /*did user want us to consider DST?*/
  258.     if(     (dst1>=2 && dst1<=50)        /*steady state DST case*/
  259.          || (dst1==01 && hr1<2)            /*leaving DST day case*/
  260.          || (dst1==51 && hr1>=2)  ) {        /*entering DST day case*/
  261.       time += 1;                /*move us into DST*/
  262.       Datek2(time/24L,&lda,&lmo,&lyr);        /*get new d/m/y*/
  263.       hr1 = (int) (time%24L);            /*and fractional day*/
  264.       }
  265.     }
  266.  
  267. /*Now we have local time.  Do all the time-setting operations before printing
  268.   any of the results, or doing any of the calls that use floating-point 
  269.   operations, so that we get everything set before much time passes.   */
  270.  
  271. ftime(&time_before);                /*time before setting*/
  272.  
  273. dostime.hour   = (unsigned char) hr1;
  274. dostime.minute = (unsigned char) mi1;
  275. dostime.second = (unsigned char) se1;
  276. dostime.hsecond = (unsigned char) 0;
  277. j2 = _dos_settime(&dostime);            /*set dos time*/
  278.  
  279. dosdate.year  = (unsigned int) lyr;
  280. dosdate.month = (unsigned char) lmo;
  281. dosdate.day   = (unsigned char) lda;
  282. dosdate.dayofweek = (unsigned char) 0;
  283. j1 = _dos_setdate(&dosdate);            /*set dos date*/
  284.  
  285. ftime(&time_after);                /*time after setting*/
  286.  
  287. rtc = read_hw_rtc(&yr,&mo,&da,&hr,&mi,&se);    /*hardware realtime clock*/
  288.  
  289.  
  290. printf("--- Setting DOS Date & Time to local: %02d/%02d/%d %02d:%02d:%02d ---\n",
  291.        dosdate.month,dosdate.day,dosdate.year,
  292.        dostime.hour,dostime.minute,dostime.second);
  293.  
  294. if(j1 != 0) printf("--- DOS set Date failed ---\n");
  295. if(j2 != 0) printf("--- DOS set Time failed ---\n");
  296. if(j1 == 0 && j2 == 0) {
  297.   time_change = floatime(time_after) - floatime(time_before);    /*change*/
  298.   printf("--- Your DOS time was %s NIST by %.2f seconds ---\n",
  299.          time_change>0. ? "behind" : "ahead of", 
  300.          dabs(time_change)  );
  301.   }
  302. if(rtc) printf("--- Info only: Your hardware realtime clock reads: "
  303.                "%02d/%02d/%d %02d:%02d:%02d ---\n",
  304.                mo,da,yr,hr,mi,se);
  305.  
  306. goto hangup;                    /*attempt to hang up phone*/
  307.  
  308.  
  309. hangup:
  310. hangup_the_modem();                /*terminate phone call*/
  311. disable_com_port();                /*live interrupt i/o ends*/
  312.  
  313.  
  314. printf("--- Done --- Phone call duration was %.1f seconds. ---\n",
  315.        floatimenow() - floatime(start) - time_change );
  316.  
  317. }
  318.  
  319.  
  320. /*-----------------------------------------------------------------------------
  321.   dial_the_modem -- does just that.  initiates phone call.  
  322.   ----------------------------------------------------------------------------*/
  323. void dial_the_modem(void) {
  324.  
  325. control_modem(0x3);            /*turn on DTR & RTS*/
  326.  
  327. puts_modem("+++");            /*enter hayes command mode*/
  328. delay(1.25);                /* +++ guardtime*/
  329.  
  330. puts_modem(dial_sequence);        /*dial!*/
  331.  
  332. puts_modem("\r");            /*dial command terminator*/
  333. delay(0.1);                /*avoid echo last char of dial*/
  334. }
  335.  
  336.  
  337.  
  338. /*-----------------------------------------------------------------------------
  339.   hangup_the_modem -- does just that.  terminates phone call.  
  340.   ----------------------------------------------------------------------------*/
  341. void hangup_the_modem(void) {
  342.  
  343. printf    ("+++");
  344. puts_modem("+++");                /*enter hayes command mode*/
  345. delay(1.25);                    /* +++ guardtime*/
  346.  
  347. printf(    hangup_sequence);            /*hangup command*/
  348. puts_modem(hangup_sequence);
  349.  
  350. printf("\n");
  351. puts_modem("\r");
  352. delay(0.1);                    /*be sure command gets out!*/
  353.  
  354. control_modem(0x00);            /*drop DTR (hangs up some modems) */
  355. }
  356.  
  357.  
  358.  
  359. /*-----------------------------------------------------------------------------
  360.   parse_a_time -- attempt to parse a "time" line from NBS
  361.                     MJD  YR MO DA  H  M  S ST S UT1 msADV         OTM
  362.   nbs format-->    47511 88-12-16 06:03:44 00 0 -.1 045.0 UTC(NBS) *
  363.   @ 1200 baud      47511 88-12-16 06:03:45 00 0 -.1 045.0 UTC(NBS) *
  364.                     H  M  S msADV OTM
  365.   nbs format-->    06:03:44 045.0  *   <--but how do i get the date?
  366.   @ 300 baud       06:03:45 045.0  *
  367.   ----------------------------------------------------------------------------*/
  368.  
  369. parse_a_time(char *p, int *yr, int *mo, int *da,
  370.              int *hr, int *mi, int *se, int *dstflg) {
  371.  
  372. /*This scanf takes 3.3ms on my AT, but the following code that replaces it 
  373.   takes 0.3ms, so is a clear winner.
  374. int mjd;
  375.   j = sscanf(line,"%d %d-%d-%d %d:%d:%d %d",&mjd,yr,mo,da,hr,mi,se,dstflg);
  376. */
  377. while(isspace(*p)) p++;        
  378. while(isdigit(*p)) p++;            /*past mjd*/
  379. while(isspace(*p)) p++;
  380. *yr = atoi(p); p+=3;            /*date*/
  381. *mo = atoi(p); p+=3; 
  382. *da = atoi(p); p+=3; 
  383. while(isspace(*p)) p++;
  384. *hr = atoi(p); p+=3;            /*time*/
  385. *mi = atoi(p); p+=3;
  386. *se = atoi(p); p+=3;
  387. while(isspace(*p)) p++;
  388. *dstflg = atoi(p);            /*dst flag*/
  389.  
  390.  
  391. if(*yr<88 || *yr>99 || *mo<=0 || *mo>12 || *da<=0 || *da>31 || 
  392.    *hr<0  || *hr>23 || *mi<0  || *mi>59 || *se<0  || *se>59 ) return 0;
  393.                     /*and legal values everywhere?*/
  394.  
  395. return 1;                /*good, then we got it*/
  396. }
  397.  
  398.  
  399.  
  400. /*-----------------------------------------------------------------------------
  401.   delay -- spinloop delay for wait seconds.  
  402.   ----------------------------------------------------------------------------*/
  403. void delay(double wait) {
  404. struct timeb start;
  405. ftime(&start);
  406. while(floatimenow() < floatime(start) + wait);
  407. }
  408.  
  409.  
  410. /*-----------------------------------------------------------------------------
  411.   floatime -- converts a timeb structure to floating point seconds.  Used 
  412.               outside critical time sections.
  413.   ----------------------------------------------------------------------------*/
  414. double floatime(struct timeb t) {
  415. return t.time + .001*t.millitm;
  416. }
  417.  
  418. double floatimenow() {
  419. struct timeb t;
  420. ftime(&t);
  421. return floatime(t);
  422. }
  423.  
  424.  
  425. #ifndef NOINTERRUPTS
  426. /*-----------------------------------------------------------------------------
  427.   Enable COM port interrupts
  428.   ----------------------------------------------------------------------------*/
  429. void enable_com_port() {
  430. com_wp = com_rp = 0;                      /*init buffer*/
  431. old_com_handler = _dos_getvect(8+nbs_port_irq);          /*save old vect*/
  432. _dos_setvect(8+nbs_port_irq, com_interrupt_handler);      /*set new vect*/
  433. outp(0x21,inp(0x21) & ~(1<<nbs_port_irq));          /*enable PIC*/
  434. set_mcr(0xff,0x08);                      /*enable board*/
  435. outp(nbs_port_address+UART_INT,0x01);              /*enable UART*/
  436. inp(nbs_port_address+UART_LSR);                  /*dummy read*/
  437. inp(nbs_port_address+UART_DATA);              /*dummy read*/
  438. com_port_live = 1;                      /*remember*/
  439. }
  440.  
  441.  
  442. /*-----------------------------------------------------------------------------
  443.   Disable COM port interrupts
  444.     We only disable if we had previously enabled.  This allows this routine to
  445.     be called from ^C interrupt handler, or other places that don't know
  446.     whether we actually need to disable.
  447.   ----------------------------------------------------------------------------*/
  448. void disable_com_port() {
  449. if(com_port_live) {
  450.   outp(nbs_port_address+UART_INT,0x00);             /*disable UART*/
  451.   set_mcr(0x00,0x08);                     /*disable board*/
  452.   outp(0x21,inp(0x21) | (1<<nbs_port_address));         /*disable PIC*/
  453.   _dos_setvect(8+nbs_port_address, old_com_handler);     /*restore old vect*/
  454.   com_port_live = 0;                     /*remember*/
  455.   }
  456. }
  457.  
  458.  
  459. /*-----------------------------------------------------------------------------
  460.   COM input interrupt handler...
  461.   ----------------------------------------------------------------------------*/
  462. static void _cdecl interrupt far com_interrupt_handler() {
  463. int c;
  464. unsigned next_wp;
  465.  
  466. if((inp(nbs_port_address+UART_LSR) & 0x01) == 1) {    /*character ready?*/
  467.   c = inp(nbs_port_address+UART_DATA);            /*yes.  get it.*/
  468.   next_wp = (com_wp+1) & 0x1f;
  469.   if(next_wp != com_rp) {                /*space available?*/
  470.     com_buf[com_wp] = (char) c;                /*store char*/
  471.     com_wp = next_wp;                    /*advance write ptr*/
  472.     }
  473.   }
  474. outp(0x20,0x20);                    /*EOI the PIC*/
  475. }
  476.  
  477.  
  478. /*-----------------------------------------------------------------------------
  479.   nonblocking read character from serial port using interrupt i/o
  480.   ----------------------------------------------------------------------------*/
  481. int nbgetc_modem(void) {
  482. int c;
  483. if(com_wp != com_rp) {                /*if char available*/
  484.   c = com_buf[com_rp];                /*get character*/
  485.   com_rp = (com_rp+1) & 0x1f;            /*advance read ptr*/
  486.   return c;
  487.   }
  488. else {                        /*no char available*/
  489.   return 0;                    /*return nothing*/
  490.   }
  491. }
  492. #endif
  493.  
  494.  
  495. #ifdef NOINTERRUPTS
  496. /*-----------------------------------------------------------------------------
  497.   nonblocking read character from serial port using direct i/o
  498.   ----------------------------------------------------------------------------*/
  499. int nbgetc_modem(void) {
  500. if((inp(nbs_port_address+UART_LSR) & 0x01) == 0)    /*character ready?*/
  501.   return 0;                    /*no*/
  502. return inp(nbs_port_address+UART_DATA);        /*yes*/
  503. }
  504. #endif
  505.  
  506.  
  507. /*-----------------------------------------------------------------------------
  508.   write character to serial port using direct i/o
  509.   ----------------------------------------------------------------------------*/
  510. void putc_modem(int c) {
  511. while((inp(nbs_port_address+UART_LSR) & 0x20) == 0); /*wait for holding reg*/
  512. outp(nbs_port_address+UART_DATA, c);
  513. }
  514.  
  515.  
  516. /*-----------------------------------------------------------------------------
  517.   write string to serial port using direct i/o
  518.   ----------------------------------------------------------------------------*/
  519. void puts_modem(char *s) {
  520. while(*s != 0) 
  521.   putc_modem(*s++);
  522. }
  523.  
  524.  
  525. /*-----------------------------------------------------------------------------
  526.   set modem-control signals on serial port using direct i/o
  527.   ----------------------------------------------------------------------------*/
  528. void control_modem(int c) {
  529. set_mcr(c,0x03);
  530. }
  531.  
  532. void set_mcr(int valu,int mask) {
  533. outp(nbs_port_address+UART_MCR, valu&mask | inp(nbs_port_address+UART_MCR)&~mask);
  534. }
  535.  
  536.  
  537.  
  538. /*-----------------------------------------------------------------------------
  539.   put character to screen using bios.  putc(c,stdio) took 1.4 mS, this takes
  540.   0.5 mS on my AT.
  541.   ----------------------------------------------------------------------------*/
  542. void putc_screen(int c) {
  543. static union REGS reg;
  544.  
  545. reg.h.ah = 0xE;                /*write tty style*/
  546. reg.h.al = (char) c;            /*this char*/
  547. reg.h.bh = 0;                /*scn page 0*/
  548. int86(0x10,®,®);            /*do it*/
  549. }
  550.  
  551.  
  552.  
  553. /*----------------------------------------------------------------------------
  554.   ACM Algorithm 199
  555.   convert calendar date to day number
  556.   K=1 at March 1, 1900.
  557.   --------------------------------------------------------------------------*/
  558. long KDAY2(long Iday,long Month,long Iyear) {
  559. long M,IY,Kday;
  560. if(Iday < 1 || Iday > 31 || Month < 1 || Month > 12
  561.    || Iyear < 1900 || Iyear > 1999) printf("?kday: ilg param\n");
  562.  
  563. M=Month-3 ; IY=Iyear-1900;
  564. if(Month <= 2) {
  565.   M=Month+9;
  566.   IY=IY-1;
  567.   }
  568. Kday=(1461*IY)/4+(153*M+2)/5+Iday;
  569. return Kday;
  570. }
  571.  
  572.  
  573. /*----------------------------------------------------------------------------
  574.   ACM algorithm 199
  575.   day number to calendar date
  576.   Valid from 3/1/1900 thru 2/28/2000.
  577.   --------------------------------------------------------------------------*/
  578. void Datek2(long K,long *Iday,long *Month,long *Iyear) {
  579. long day,month,year;
  580.  
  581. if(K < 0 || K > 36500) printf("?datek: ilg param\n");
  582. year=(4*K-1)/1461;
  583. day=4*K-1-1461*year;
  584. day=(day+4)/4;
  585. month=(5*day-3)/153;
  586. day=5*day-3-153*month;
  587. day=(day+5)/5;
  588. month=month+3;
  589. year=year+1900;
  590. if(month >= 13) {
  591.   month=month-12;
  592.   year=year+1;
  593.   }
  594. *Iday=day; *Month=month; *Iyear=year;
  595. }
  596.  
  597.  
  598.  
  599. /*----------------------------------------------------------------------------
  600.   Parameter initialization (reads .INI file)
  601.   --------------------------------------------------------------------------*/
  602.  
  603. void nbs_init(void) {
  604. FILE *init;
  605. char buf[80];
  606.  
  607. #ifdef PARTOFIT                    /*when used in InstantTrack*/
  608. init = it_fopen("it.ini","r");            /*different way to open files*/
  609. if(init == NULL) return;            /*if no file, use defaults*/
  610. while(NULL != fgets(buf,80,init)) {        /*until end-of-file*/
  611.   sscanf(buf," nist_dial = %50s",   dial_sequence);
  612.   sscanf(buf," nist_hangup = %50s", hangup_sequence);
  613.   sscanf(buf," nist_port = %d",     &nbs_port);
  614.   if(1==sscanf(buf," nist_port = COM%d", &nbs_port)) nbs_port--;
  615.   sscanf(buf," nist_port_address = %x", &nbs_port_address);
  616.   sscanf(buf," nist_port_irq = %x", &nbs_port_irq);
  617.   sscanf(buf," nist_speed = %d",    &nbs_speed);
  618.   sscanf(buf," nist_maxtime = %d",  &maxtime);
  619.   }
  620. #else
  621. init = fopen("nbscom.ini","r");            /*open .ini file*/
  622. if(init == NULL) return;            /*if no file, use defaults*/
  623. while(NULL != fgets(buf,80,init)) {        /*until end-of-file*/
  624.   sscanf(buf," dial = %50s",   dial_sequence);
  625.   sscanf(buf," hangup = %50s", hangup_sequence);
  626.   sscanf(buf," port = %d",     &nbs_port);
  627.   if(1==sscanf(buf," port = COM%d", &nbs_port)) nbs_port--;
  628.   sscanf(buf," port_address = %x", &nbs_port_address);
  629.   sscanf(buf," port_irq = %x", &nbs_port_irq);
  630.   sscanf(buf," speed = %d",    &nbs_speed);
  631.   sscanf(buf," maxtime = %d",  &maxtime);
  632.   }
  633. #endif
  634.  
  635. if(nbs_port_address == 0) nbs_port_address = port[nbs_port];
  636. if(nbs_port_irq == 0) nbs_port_irq = interrup[nbs_port];
  637.  
  638. fclose(init);                    /*close .ini file*/
  639. }
  640.  
  641.  
  642. /*-----------------------------------------------------------------------------
  643.   Routines to diddle the hardware realtime-clock (via BIOS)
  644.   It's difficult to set the RTC accurately, because its least digit is seconds.
  645.   Furthermore, the RTC can refuse to be read (if it's propagating a carry at
  646.   the time).  I plan to write some code that overcomes these difficulties, so
  647.   that i can then set the RTC accurately.  
  648.   This only works on an IBMAT or later BIOS.  It would also work if aftermarket
  649.   RTCs came with TSRs that implemented the AT BIOS RTC functions, but none do.
  650.   **NOTFINISHED**
  651.   ----------------------------------------------------------------------------*/
  652. int read_hw_rtc(int *yr,int *mo,int *da,int *hr,int *mi,int *se) {
  653. union REGS reg;
  654.  
  655. reg.h.ah = 4;                    /*read date from RTC*/
  656. reg.h.cl = reg.h.ch = 0xff;            /*marker*/
  657. int86(0x1A,®,®);                /*BIOS call*/
  658. if(reg.h.cl==0xff || reg.h.ch==0xff) return 0;    /*if no RTC BIOS, fail return*/
  659. *yr = 100*xbcd(reg.h.ch) + xbcd(reg.h.cl);
  660. *mo = xbcd(reg.h.dh);
  661. *da = xbcd(reg.h.dl);
  662.  
  663. reg.h.ah = 2;                    /*read time from RTC*/
  664. int86(0x1A,®,®);                /*BIOS call*/
  665. *hr = xbcd(reg.h.ch);
  666. *mi = xbcd(reg.h.cl);
  667. *se = xbcd(reg.h.dh);
  668.  
  669. return 1;
  670. }
  671.  
  672.  
  673.