[comp.os.minix] get date and time from multi io card

myxm@beta.UUCP (Mike Mitchell) (05/08/87)

	After getting a copy of the program which will read the date
and time from the AST boards, I felt that modifying this utility to
read the date and time from the MCT Multi-IO card would fit quite
nicely in my system. I hope that others may be able to make use of
this as well.

	Included are two files: mioclock.c and port_io.s. These files
are fairly similar to those distributed with the astclock program.
The mioclock.c program has been modified to read the date and time
from the Multi-IO card and then set the system date.

	To compile this under Minix, you should use the command:

	cc -o mioclock mioclock.c port_io.s

	To enable automatic date and time setting upon boot, add
the following line to your /etc/rc file:

	/bin/mioclock ; date

	Thanx to tom poindexter for the original astclock code.

And now for the program:
			    mioclock.c
---/---/---/---/---/---/---/ TEAR HERE ---/---/---/---/---/---/---/---
/* mioclock.c - read the clock on the multi i/o card from mct        */
/* original code from astclock.c, tom poindexter, 4/87               */
/* modified for use with mio card, mike mitchell, 5/87               */

#include "stdio.h"

int days_per_month[] =
  { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

struct tm {
  int year, month, day, hour, min, sec;
};

/* define the current decade */
#define DECADE          80

/* ports for the mio clock */

#define MIO_SEC		0x02c2
#define MIO_MIN		0x02c3
#define MIO_HRS		0x02c4
#define MIO_DOW		0x02c5
#define MIO_DOM		0x02c6
#define MIO_MOY		0x02c7
#define MIO_YER		0x02ca

#define TRIES           10

/******************************************************************/

main()
{
  struct tm tm1;
  struct tm tm2;
  int  i;
  long t;
  long calc_sec();
  int stime();		/* stime() sets the date in minix */

  /* try several times to read the clock */

  for (i = 0; i < TRIES; i++) {

    read_clk(&tm1);			/* read the clock twice */
    read_clk(&tm2);
    
    if (tm1.year  == tm2.year  &&	/* and compare the results */
        tm1.month == tm2.month &&
        tm1.day   == tm2.day   &&
        tm1.hour  == tm2.hour  &&
        tm1.min   == tm2.min   &&
        tm1.sec   == tm2.sec) {

      t = calc_sec(&tm1);      		/* calculate the seconds */

      if (stime(&t) == -1) {		/* and set the time */
        die("mioclock: can't set stime(), are you super user?\n");
      }

      exit(0);                  /* normal termination */

    }

  }

  /* too many errors in reading the ast clock chip, give up */

  die("mioclock: can't get a consistent time from the ast clock");

}

/* calculate seconds since epoch; this code borrowed from `date.c' */

long calc_sec(tp)
struct tm *tp;
{
  int i = 0;
  long ct;
  long s_p_min;
  long s_p_hour;
  long s_p_day;
  long s_p_year;

  /* first, calculate seconds per known intervals */
  s_p_min  = 60;
  s_p_hour = 60  * s_p_min;
  s_p_day  = 24  * s_p_hour;
  s_p_year = 365 * s_p_day;

  /* calculate seconds from epoch until the start of this year */
  tp->year -= 70;			/* deal with years since 1970   */
  ct = tp->year * s_p_year;		/* seconds per year since epoch */
  ct += ((tp->year + 1) / 4) * s_p_day;	/* add in the leap years and    */
  if (((tp->year + 2) % 4) == 0) {	/* check if this year is a leap */
	days_per_month[1]++;		/* and make feb one more day    */
  }

  /* calculate seconds from january until the start of this month */
  tp->month--;
  while (i < tp->month) {
	ct += days_per_month[i++] * s_p_day;
  }
   
  /* calculate seconds of the days this month */
  ct += --tp->day * s_p_day;

  /* calculate seconds of the hour this day */
  ct += tp->hour * s_p_hour;

  /* calculate seconds of the minutes this hour */
  ct += tp->min * s_p_min;
 
  /* and finally add in the seconds so far this minute */
  ct += tp->sec;

  return (ct);
 }

/* read the mio clock and fill values into a tm structure */

read_clk(tp)
struct tm *tp;
{
  int r;

  port_in(MIO_YER, &r);
  tp->year  = DECADE + btod(r);
  port_in(MIO_MOY, &r);
  tp->month = btod(r);
  port_in(MIO_DOM, &r);
  tp->day   = btod(r);
  port_in(MIO_HRS, &r);
  tp->hour  = btod(r);
  port_in(MIO_MIN, &r);
  tp->min   = btod(r);
  port_in(MIO_SEC, &r);
  tp->sec   = btod(r);
}

/* die() - print a message on stderr and exit with false code */

die(msg)
char *msg;
{
  fprintf(stderr,msg);
  fflush(stderr);
  _cleanup();
  exit(1);

}

/* btod - bcd to decimal conversion */

int btod(num)
int num;
{
  return(((num & 0x00f0) >> 4) * 10 + (num & 0x000f));
}
---/---/---/---/---/---/---/ TEAR HERE ---/---/---/---/---/---/---/---
			     port_io.s
---/---/---/---/---/---/---/ TEAR HERE ---/---/---/---/---/---/---/---
| this file was grafted from klib88.s 

.globl _port_out, _port_in



|*===========================================================================*
|*				port_out				     *
|*===========================================================================*
| port_out(port, value) writes 'value' on the I/O port 'port'.

_port_out:
	push bx			| save bx
	mov bx,sp		| index off bx
	push ax			| save ax
	push dx			| save dx
	mov dx,4(bx)		| dx = port
	mov ax,6(bx)		| ax = value
	out			| output 1 byte
	pop dx			| restore dx
	pop ax			| restore ax
	pop bx			| restore bx
	ret			| return to caller


|*===========================================================================*
|*				port_in					     *
|*===========================================================================*
| port_in(port, &value) reads from port 'port' and puts the result in 'value'.
_port_in:
	push bx			| save bx
	mov bx,sp		| index off bx
	push ax			| save ax
	push dx			| save dx
	mov dx,4(bx)		| dx = port
	in			| input 1 byte
	xorb ah,ah		| clear ah
	mov bx,6(bx)		| fetch address where byte is to go
	mov (bx),ax		| return byte to caller in param
	pop dx			| restore dx
	pop ax			| restore ax
	pop bx			| restore bx
	ret			| return to caller
---/---/---/---/---/---/---/ TEAR HERE --- of qantepop ad to thet have