/*
 *  IVCCLIB: Intel Video Capture Card Library
 *  by Jeff Norris, jnorris@alum.mit.edu
 *  
 *  File: c_ivccsetup.c
 *
 *  Description:  It's unlikely that a typical user will need to
 *  edit this file.  This file contains all of the functions needed
 *  to start an observer, and sets up the frame arrival signal.  
 *  Frame signals are actually first handled here, and then passed
 *  into the observer. 
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/fcntl.h>
#include <sys/signal.h>
#include <unistd.h>
#include <fstream.h>
extern "C"
{
#include "ioctl_meteor.h"
}
#include "grabber.h"
#include "c_ivccsetup.h"

/* device stuff */
int   grabberid[6];
char *grabberbuf[6];
int  attached[6];

/* the callbacks */
void (*grabcb[6]) (int num, char* buf);

static struct sigaction sigact = 
((struct sigaction){ sa_handler: framesig,
		     sa_mask: 0});
		     

/* geometry stuff */
static int columns = NUM_COLS,
           rows = NUM_ROWS,
	   window_size_x,
           window_size_y,
	   pixelsize = PIXELSIZE,
           noframes = NOFRAMES,
	   bufsize = PIXELSIZE*NUM_COLS*NUM_ROWS,
           fieldmode = 0x0,
           sigmode = 0x0,
	   fps = FPS;

void observersetup()
{
  int i;
  for (i=0; i< 6; i++)
    {
      grabberid[i] = 0;
      attached[i]=0;
    }
  signal(SIGINT, break_handler);
  signal(SIGQUIT, break_handler);
  signal(SIGKILL, break_handler);
  signal(SIGTERM, break_handler);
  signal(SIGSEGV, break_handler);
}

void observershutdown()
{
  int i;
  for (i=0; i < 6; i++)
    {
      if (attached[i])
	detachgrabber(i);
    }
  exit(0);  
}

void framesig(int signum)
{
  signum-=20;
  (grabcb[signum])(signum, grabberbuf[signum]);
}

/* This is the function that registers the callback with
   the capture card and starts the delivery of frames */
void attachgrabber(int grabbernum, void callback(int, char*))
{
  char DevName[12];
  int c, signum;

  signum = grabbernum+20;
  grabcb[grabbernum] = callback;

  sprintf(DevName, "/dev/bt848-%d", grabbernum);
    
  if ((grabberid[grabbernum] = open(DevName, O_RDWR)) < 0) {
    perror("open failed");
    printf("device %s\n", DevName);
    exit(1);
  }
  
  bufsize = 4*rows*columns;
    
  if ((grabberbuf[grabbernum]=(char *) mmap((caddr_t)0, bufsize,
			   PROT_READ|PROT_WRITE, 
			   MAP_FILE|MAP_SHARED, 
			   grabberid[grabbernum], (off_t)0)) == (char *)(-1)) {
    perror("mmap failed");
    exit(1);
  }
  
  if ( sigaction(signum, &sigact, NULL) ) {
    perror("sigaction failed");
    exit(1);
  }
  c = signum | sigmode;
  if (ioctl(grabberid[grabbernum], METEORSSIGNAL, &c) < 0) {
    perror("ioctl SetSignal failed");
    exit(1);
  }
  
  attached[grabbernum] = 1;
  printf("Observer online, attached to digitizer %s.\n", DevName);
  
  return;
}

void detachgrabber(int grabbernum)
{
  int c;
  c = (grabbernum+20) | sigmode;
  ioctl(grabberid[grabbernum], TASKSHUTDOWN, &c);
  attached[grabbernum] = 0;
}

/*
 * This code is a break handler.  It automatically catches kill 
 * signals and closes things down gracefully.
 */
void break_handler(int sig) 
{
  printf("Observer break detected.. calling observershutdown().\n");
  observershutdown();
  exit(0);
}

