/*
 *  IVCCLIB: Intel Video Capture Card Library
 *  by Jeff Norris, jnorris@alum.mit.edu
 *  
 *  File: m_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.  This file is compiled with m_observer.c to make
 *  m_observer.mexlx, which is then executed from Matlab.
 *
 *  This code also handles control-c breaks, shutting down the
 *  observer before returning the user to Matlab.
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/fcntl.h>
#include <sys/signal.h>
#include <unistd.h>
#include "ioctl_meteor.h"
#include "grabber.h"
#include "m_ivccsetup.h"

/* device stuff */
char *grabberbuf;
int  attached;

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

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

/* 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;
  grabberid = 0;
  attached=0;
  sigaction(SIGINT, &newact, &oldact);
}

void observershutdown()
{
  sigaction(SIGINT, &oldact, NULL);
  detachgrabber();
  quit = 1;
}

void framesig(int signum)
{
  (grabcb)(signum, grabberbuf);
}


void attachgrabber(int grabbernum, void callback(int, char*))
{
  char DevName[14];
  int c, signum;
  
  signum = SIGUSR2;
  grabcb = callback;

  sprintf(DevName, "/dev/bt848-%d", grabbernum);
  
  if ((grabberid = open(DevName, O_RDWR)) < 0) {
    perror("open failed");
    printf("device %s\n", DevName);
    exit(1);
  }

  bufsize = 4*rows*columns;
    
  if ((grabberbuf=(char *) mmap((caddr_t)0, bufsize,
			   PROT_READ|PROT_WRITE, 
			   MAP_FILE|MAP_SHARED, 
			   grabberid, (off_t)0)) == (char *)(-1)) {
    perror("mmap failed");
    exit(1);
  }

  printf("Observer online, attached to digitizer %s.\n", DevName);
  
  if ( sigaction(signum, &sigact, NULL) ) {
    perror("sigaction failed");
    exit(1);
  }
  c = signum | sigmode;
  if (ioctl(grabberid, METEORSSIGNAL, &c) < 0) {
    perror("ioctl SetSignal failed");
    exit(1);
  }

  attached = 1;
  
  return;
}

void detachgrabber()
{
  int c;
  c =  SIGUSR2 | sigmode;
  ioctl(grabberid, TASKSHUTDOWN, &c);
  close(grabberid);
  attached= 0;
  return;
}

/*
 * 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();
  return;  
}

