#ifdef SGI_CFG

#include <stdio.h>
#include <sys/types.h>
#include <sys/prctl.h>
#include <sys/schedctl.h>
#include <sys/time.h>
#include <sys/lock.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <signal.h>

#include "../sys/rciext/rci.h"
#include "../sys/rciext/rciioctl.h"

typedef struct xyd {
  unsigned char id[0x40];
  unsigned char unused1[0x40];
  unsigned char intin;
  unsigned char csr;
#define XYD_RED       0x01
#define XYD_RED_ON    0x00
#define XYD_RED_OFF   0x01
#define XYD_GREEN     0x02
#define XYD_GREEN_ON  0x02
#define XYD_GREEN_OFF 0x00
#define XYD_INTPEND   0x04
#define XYD_INTENB    0x08
#define XYD_RESET     0x10
#define XYD_USER      0xe0
  unsigned char intpend;
  unsigned char intmask;
  unsigned char intclear;
  unsigned char vector;
  unsigned char out;
  unsigned char dirs;
  unsigned char ports[8];
  unsigned char unused2[0x370];
  } XYD;

XYD *xyd;

char *memdev = "/dev/mmem";
#define XYDBASE 0x9000

int gfd;

int count;

beat()
{
	/* set a bit indicating that we are here. */

	/* SET BIT */

	xyd->ports[5] ^= 0x1;
}

void setalarm(n)
int n;
{
 printf("set\n");
 if (ioctl(gfd,RCIIOC_ALARM_REQ,(n+1)*100) < 0)
  { perror("RCIIOC_ALARM_REQ");
    exit(1);
  }
}

void alarmtick(ev)
RciTimerEvent *ev;
{
 if (ev->req != RCI_ALARM_READY)
  { printf("wrong ready value (%d, wanted %d)\n",ev->req,RCI_ALARM_READY);
    exit(1);
  }
 printf("tick %d\n",ev->tick);
}

void sethb(n)
int n;
{
 if (n == 0)
  { printf("Now using heartbeat\n");
    printf("set\n");
    if (ioctl(gfd,RCIIOC_BEAT_REQ,100) < 0)
     { perror("RCIIOC_BEAT_REQ(100)");
       exit(1);
     }
    sleep(3);
  }
}

void hbtick(ev)
RciTimerEvent *ev;
{
 if (ev->req != RCI_BEAT_READY)
  { printf("wrong ready value (%d, wanted %d)\n",ev->req,RCI_BEAT_READY);
    exit(1);
  }
 printf("tick %d\n",ev->tick);
}

void clearhb()
{
 if (ioctl(gfd,RCIIOC_BEAT_REQ,0) < 0)
  { perror("RCIIOC_BEAT_REQ(0)");
    exit(1);
  }
}

dotest(pretick,ontick,post)
void (*pretick)();
void (*ontick)();
void (*post)();
{
 int i;
 struct timeval tv;
 fd_set rfds;
 RciTimerEvent tev;
 int n;

 for (i=0;i<count;i++)
  { if (pretick) (*pretick)(i);
    tv.tv_sec = 5;
    tv.tv_usec = 0;
    FD_ZERO(&rfds);
    FD_SET(gfd,&rfds);
    n = select(FD_SETSIZE,&rfds,(fd_set *)0,(fd_set *)0,&tv);
    if (n < 0)
     { perror("select:");
       exit(1);
     }
    else if (n == 0)
     { fprintf(stderr,"select timed out\n");
       exit(1);
     }
    n = read(gfd,(char*)&tev,sizeof(tev));
    if (n < 0)
     { perror("read:");
       exit(1);
     }
    else if (n != sizeof(tev))
     { fprintf(stderr,"read returned %d not %d\n",n,sizeof(tev));
       exit(1);
     }
    else
     { (*ontick)(&tev);
     }
  }
 if (post) (*post)();
}

main()
{
	/* Create a sub-task, lock it into memory, give it a high
	   priority, and then have it do something every few clock ticks */

	int sid;
	int k, i;
	sigset_t set, oset;
	int cnt = 0;
	char ack;
	char *addr;
	int fd;

	fd = open(memdev,O_RDWR,0);
	if (fd < 0)
	 { perror(memdev);
	   exit(1);
	 }
	addr = (char*)mmap(0,0x10000,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0xbd000000);
	if (addr == (void *)-1)
	 { perror("mmap");
	   exit(1);
	 }
	xyd = (XYD *)(addr+XYDBASE);
	xyd->dirs = 0xf2;

	if ((gfd = open("/dev/genrci0", O_RDWR, 0)) < 0)
	 { perror ("/dev/genrci0:");
	   exit(1);
	 }
	if (ioctl(gfd, RCIIOC_CONFIRM, 0) < 0)
	 { perror ("CONFIRM ioctl:");
	   exit (1);
	 }
	if (ioctl(gfd, RCIIOC_TIMER_ENABLE, 1) < 0)
	 { perror ("TIMER ENABLE ioctl:");
	   exit (1);
	 }
	if (ioctl(gfd, RCIIOC_SET_TIMERQ, 5) < 0)
	 { perror ("TIMER Qsize ioctl:");
	   exit (1);
	 }
#if 0
	count = 5;
	dotest(setalarm,alarmtick,(void (*)())0);
	dotest(sethb,hbtick,clearhb);
	if (ioctl(gfd, RCIIOC_SET_TIMERQ, 2) < 0)
	 { perror ("TIMER Qsize ioctl:");
	   exit (1);
	 }
	dotest(sethb,hbtick,clearhb);
#else
	timerwatch();
#endif
}

timerwatch()
{
	struct timeval tv0;
	int rcitime0;
	struct timeval tv;
	int rcitime;
	struct timeval dtv;
	int drcitime;
	int dtvms;

	ioctl(gfd,RCIIOC_TIMER_GET,&rcitime0);
	rcitime0 *= 10;
	gettimeofday(&tv0,(struct timezone *)0);
	while (1)
	 { ioctl(gfd,RCIIOC_TIMER_GET,&rcitime);
	   rcitime *= 10;
	   gettimeofday(&tv,(struct timezone *)0);
	   drcitime = rcitime - rcitime0;
	   dtv.tv_sec = tv.tv_sec - tv0.tv_sec;
	   dtv.tv_usec = tv.tv_usec - tv0.tv_usec;
/*
	   if (dtv.tv_usec < 0)
	    { dtv.tv_usec += 1000000;
	      dtv.tv_sec --;
	    }
*/
	   dtvms = (dtv.tv_usec / 1000) + (dtv.tv_sec * 1000);
	   if (abs(dtvms-drcitime) > 20)
	    { fprintf(stderr,"rci0 %d tv0 %ld.%06ld  rci %d tv %ld.%06ld  drci %d dtvms %d  d %d\n",rcitime0,tv0.tv_sec,tv0.tv_usec,rcitime,tv.tv_sec,tv.tv_usec,drcitime,dtvms,dtvms-drcitime);
	    }
	 }
}

#endif
