[comp.os.minix] ST MINIX -- set MINIX time from a Dallas Clock Chip

hcj@lzaz.ATT.COM (HC Johnson) (05/12/89)

The clock setting routines for ST minix with RS232 have been
extended to support the Dallas Semiconductor Clock.  This is 
the one that is in a socket that is inserted under a TOS ROM.

The Dallas Chip code is from work done by Bill Penner, and was
ported to this program by Bruce Szablak.

These routines can still be used with the BMS/SUPRA/ICD disk
based clocks.

	diskrtc rtc 	will set the Minix clock from Dallas
	diskset rtc	will set the Dallas clock from Minix time.

Howard C. Johnson
ATT Bell Labs
att!lzaz!hcj
hcj@lzaz.att.com

================================cut here========================
/* DISKRTC.C */
#include <sgtty.h>
#define	DEBUG

#define	AD_RTC	0xFFFC20

#define	SECL	0
#define	SECH	1
#define	MINL	2
#define	MINH	3
#define	HOURL	4
#define	HOURH	5

#define	DAYL	7
#define	DAYH	8
#define	MONL	9
#define	MONH	10
#define	YEARL	11
#define	YEARH	12

#define	N	13

int	fd;
unsigned char	a[N];
int	m[12] = {31,28,31,30,31,30,31,31,30,31,30,31};

long	time();
char	*ctime();

main(argc, argv)
char **argv;
{
	register i, n, d, ok;
	int x;
	long ot, nt;
#ifdef DEBUG
	int debug = argc != 2;
#endif
	if(argc == 1) {
usage:
		fatal("Usage: %s [bms1|bms2|supra|icd|rtc]\n",argv[0]);
		exit(1);
	}
	if(strcmp(argv[1],"bms1") == 0)
		x = DC_RBMS100;
	else if(strcmp(argv[1],"bms2") == 0)
		x =  DC_RBMS200;
	else if(strcmp(argv[1],"supra") == 0)
		x =  DC_RSUPRA;
	else if(strcmp(argv[1],"icd") == 0)
		x =  DC_RICD;
	else if(strcmp(argv[1],"rtc") == 0) {
		bootclk();
		goto dotime;
	} else
		goto usage;

	fd = open("/dev/rhd0", 0);
	if (fd < 0)
		fatal("cannot open /dev/hd0 ");
	for(n=0;n<3;n++) {
		i = ioctl(fd,x,a);
		if(i <0) {
			perror("read");
			printf("read (ioctl) returned %d\n",i);
			exit(1);
		}
		if (a[SECL] == 15)
			fatal("no RTC present");
		break;
	}
dotime:
if(debug)
	printf("bms: %x %x %x %x  %x %x %x %x  %x %x %x %x %x\n",
	  a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9],a[10],a[11],a[12]);
	a[HOURH] &= 3;
	nt = 0;
	i = dd(YEARL, 0, 99);
	if ((i & 3) == 0)
		m[1]++;
	i += 80;
	while (--i >= 70) {
		nt += 365;
		if ((i & 3) == 0)
			nt++;
	}
	i = dd(MONL, 1, 12)-1;
	while (--i >= 0)
		nt += m[i];
	nt += dd(DAYL, 1, 31) - 1;
	nt *= 24;
	nt += dd(HOURL, 0, 23);
	nt *= 60;
	nt += dd(MINL, 0, 59);
	nt *= 60;
	nt += dd(SECL, 0, 59);
	time(&ot);
#ifdef DEBUG
	if (debug) {
		printf("old time = (%ld) %s\n", ot, ctime(&ot));
		printf("new time = (%ld) %s\n", nt, ctime(&nt));
	}
#endif
	if (ot > nt)
		fatal("cannot set time back\n");
	if (stime(&nt) < 0)
		fatal("stime() failed");
	exit(0);
}

dd(i, min, max)
{
	register n;

	n = a[i] + 10 * a[i+1];
	if (n < min || n > max)
		fatal("ASSERT(idx=%d %d >= %d && %d <= %d)", i, n, min, n, max);
	return(n);
}


fatal(s, a1, a2, a3, a4, a5)
char *s;
{
	printf("bmsrtc: ");
	printf(s, a1, a2, a3, a4, a5);
	printf(" (fatal)\n");
	exit(1);
}

/******************************************************/
/*                      BOOTCLK                       */
/*----------------------------------------------------*/
/* Time Load Program                                  */
/*                          by                        */
/*                               Bill Penner          */
/*                               3235 Wright Avenue   */
/*                               Bremerton, WA  98310 */
/*----------------------------------------------------*/
/* Written 31 January 1987 for use with the Dallas    */
/* semiconductor DS1216E real time clock module.      */
/*----------------------------------------------------*/
/* This program is entered into the public domain for */
/* use and distribution.                              */
/* Modified for MINIX ST by Bruce Szablak             */
/******************************************************/

bootclk()
{
	int     *cwrite  = 0xFE0000L; /* Location of clock write      */
	int     *cread   = 0xFE0008L; /* Location of clock read       */
	
	long    code    = 0x5CA33AC5L;/* Code to activate the DS1216E */
	
	unsigned data[8];             /* Hold the read information    */
	unsigned temp;                /* Temporary use integer        */
	
	int i,j;

	temp = *cread;              /* Send out enable sequence     */
	for(i=0;i<2;i++)
	{
		for(j=0;j<32;j++) temp = cwrite[(int)((code >> j) & 1)];
	}

	for(i=0;i<8;i++)            /* Read the clock chip          */
	{ 
		data[i] = 0;
		for(j=0;j<8;j++)
			data[i] = data[i] | ((*cread & 0x100) >> (8-j));
	}

	a[SECL] = data[1] & 0xF;
	a[SECH] = (data[1] >> 4) & 0xF;
	a[MINL] = data[2] & 0xF;
	a[MINH] = (data[2] >> 4) & 0xF;
	a[HOURL] = data[3] & 0xF;
	a[HOURH] = (data[3] >> 4) & 0xF;

	a[DAYL] = data[5] & 0xF;
	a[DAYH] = (data[5] >> 4) & 0xF;
	a[MONL] = data[6] & 0xF;
	a[MONH] = (data[6] >> 4) & 0xF;
	a[YEARL] = data[7] & 0xF;
	a[YEARH] = ((data[7] >> 4) & 0xF) - 8;
}
================================cut here========================
/* DISKSET.C */
#include <sgtty.h>
/* bmsset - r set the date	in bms	Author: Howard Johnson
 * taken from minix date, Author: Adri Koppes
 */


#define	SECL	0
#define	SECH	1
#define	MINL	2
#define	MINH	3
#define	HOURL	4
#define	HOURH	5

#define DAYW	6

#define	DAYL	7
#define	DAYH	8
#define	MONL	9
#define	MONH	10
#define	YEARL	11
#define	YEARH	12

#define	N	13

int	fd;
unsigned char	a[N];

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

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

long s_p_min;
long s_p_hour;
long s_p_day;
long s_p_year;
int leap = 0;

main(argc, argv)
int argc;
char **argv;
{
  long t, time();
  int x;
  int n,i;

	if(argc == 1) {
usage:
		fatal("Usage: %s [bms1|bms2|supra|icd|rtc]\n",argv[0]);
		exit(1);
	}
  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;

	if(strcmp(argv[1],"bms1") == 0)
		x = DC_WBMS100;
	else if(strcmp(argv[1],"bms2") == 0)
		x =  DC_WBMS200;
	else if(strcmp(argv[1],"rtc") == 0)
		setareal();
	else
		goto usage;

	time(&t);
	cv_time(t);
/* expected fmt
Thu Nov 10 13:59:34 EST 1988
.month 0-11
.day 1-31
.hour 0-23
.minute 0-59
.second 0-59
.year 1970 - 
*/
	tm.year -= 1980;
	tm.month += 1;

	
	a[SECL] = (tm.sec % 10) & 0xf;
	a[SECH] = (tm.sec / 10) & 0xf;
	a[SECL] = 0;
	a[SECH] = 0;
	a[MINL] = (tm.min % 10) & 0xf;
	a[MINH] = (tm.min / 10) & 0xf;
	a[HOURL] = (tm.hour % 10) & 0xf;
	a[HOURH] = ((tm.hour / 10) & 0xf) | 0x8; /* 24 hr format */

	a[DAYL] = (tm.day % 10) & 0xf;
	a[DAYH] = ((tm.day / 10) & 0xf) | (leap?4:0);
	a[MONL] = (tm.month % 10) & 0xf;
	a[MONH] = (tm.month / 10) & 0xf;
	a[YEARL] = (tm.year % 10) & 0xf;
	a[YEARH] = (tm.year / 10) & 0xf;
  	
	a[DAYW] = 0;
	
	fd = open("/dev/rhd0", 1);
	if (fd < 0)
		fatal("cannot open /dev/rhd0 ");
	for(n=0;n<3;n++) {
		i = ioctl(fd,x,a);
		if(i == 0)
			exit(0);
	}
	perror("write");

	exit(1);
}

cv_time(t)
long t;
{
  tm.year = 0;
  tm.month = 0;
  tm.day = 1;
  tm.hour = 0;
  tm.min = 0;
  tm.sec = 0;
  while (t >= s_p_year) {
	if (((tm.year + 2) % 4) == 0)
		t -= s_p_day;
	tm.year += 1;
	t -= s_p_year;
  }
  if (((tm.year + 2) % 4) == 0) {
	days_per_month[1]++;
	leap = 1;
  }
  tm.year += 1970;
  while ( t >= (days_per_month[tm.month] * s_p_day))
	t -= days_per_month[tm.month++] * s_p_day;
  while (t >= s_p_day) {
	t -= s_p_day;
	tm.day++;
  }
  while (t >= s_p_hour) {
	t -= s_p_hour;
	tm.hour++;
  }
  while (t >= s_p_min) {
	t -= s_p_min;
	tm.min++;
  }
  tm.sec = (int) t;
}

fatal(s, a1, a2, a3, a4, a5)
char *s;
{
	printf("bmsrtc: ");
	printf(s, a1, a2, a3, a4, a5);
	printf(" (fatal)\n");
	exit(1);
}

/******************************************************/
/*                     SETAREAL                       */
/*----------------------------------------------------*/
/* Set Module Time Program                            */
/*                          by                        */
/*                               Bill Penner          */
/*                               3235 Wright Avenue   */
/*                               Bremerton, WA  98310 */
/*----------------------------------------------------*/
/* Written 31 January 1987 for use with the Dallas    */
/* semiconductor DS1216E real time clock module.      */
/* Modified for MINIX ST by Bruce Szablak             */
/*----------------------------------------------------*/
/* This program is entered into the public domain for */
/* use and distribution.                              */
/******************************************************/

setareal()
{
	int     *cwrite   = 0xFE0000L;/* Location of clock write      */
	int     *cread    = 0xFE0008L;/* Location of clock read       */
	
	long    code    = 0x5CA33AC5L;/* Code to activate the DS1216E */
	long    datetime;             /* Hold the date and time       */
	
	int     data[8];              /* Hold the read information    */
	
	int i,j, temp;

	time(&datetime);                /* Go get the present t and d */
	cv_time(datetime);

	tm.month++;
	tm.year -= 1900;
	data[0] = 0;
	data[1] = (tm.sec   % 10) | ((tm.sec   / 10) << 4);
	data[2] = (tm.min   % 10) | ((tm.min   / 10) << 4);
	data[3] = (tm.hour  % 10) | ((tm.hour  / 10) << 4);
	data[4] = 0;
	data[5] = (tm.day   % 10) | ((tm.day   / 10) << 4);
	data[6] = (tm.month % 10) | ((tm.month / 10) << 4);
	data[7] = (tm.year  % 10) | ((tm.year  / 10) << 4);

	temp = *cread;              /* Send out enable sequence     */
	for(i=0;i<2;i++)
	{
		for(j=0;j<32;j++) temp = cwrite[(int)((code >> j) & 1)];
	}

	for(i=0;i<8;i++)            /* Write the clock chip         */
	{ 
		for(j=0;j<8;j++) temp = cwrite[((data[i] >> j) & 1)];
	}
	exit(0);
}