/*
   MEX file

   x = sen_read;
   
   Provided SensiCamQE is properly connected and turned on,
   this function will return an image in the return variable x.  
   
   Artem, 6/16/04
*/

#include <stdlib.h>
#include <stdio.h>

#include <linux/vt.h>

#include "sencaml.h"
#include "sencam_def.h"
#include "typtxt.h"
#include "loglevel.h"

#include "mex.h"

#define MIRRORX 0
#define MIRRORY 1
#define EXPOSURE 0

#define SEN_CCD_X 1376
#define SEN_CCD_Y 1040
#define SEN_ROI_X 43
#define SEN_ROI_Y 33
#define SEN_TYPE M_LONG
#define SEN_TRIG 0
#define SEN_BOARD 0


extern unsigned int GetTickCount();

static int hdriver=0;
static int bufnr = -1;

void GetOut(int step, int ret_val, char *info) {
  mexPrintf("%s returned %d. abort.\n",info,ret_val);

  switch (step) {
  case 5: sen_remove_buffer_from_list(hdriver,bufnr);
  case 4: sen_stop_coc(hdriver,0);
  case 3: sen_unmap_buffer(hdriver,bufnr);
  case 2: sen_free_buffer(hdriver,bufnr);
  case 1: sen_closeboard(&hdriver);
  }
  mexErrMsgTxt("senQE aborted.\n\n");
}


void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
  int ret_val;
  struct cam_values values;

     int size,stat;
     unsigned short *picbuf;
     unsigned int zeit1,zeit2;

  int m,n;
  char delay_and_exposure[32];

#if EXPOSURE
  if(nrhs != 0)
    mexErrMsgTxt("senQE: I don't need any input arguments. Abort.");
#else
  double *exposure;

  if(nrhs != 1) {
    mexErrMsgTxt("senQE: exposure in ms input required.");
  } else if(nlhs > 1) {
    mexErrMsgTxt("Too many output arguments");
  }
  /* The input must be a noncomplex scalar double.*/
  m = mxGetM(prhs[0]);
  n = mxGetN(prhs[0]);
  if(!mxIsDouble(prhs[0]) || mxIsComplex(prhs[0]) || m != 1 || n != 1)  {
    mexErrMsgTxt("Input must be a noncomplex scalar value.");
  }
  exposure = mxGetPr(prhs[0]);
#endif
  
  hdriver=0 ;  /* bug fix ? */
  if ((ret_val=sen_initboard(SEN_BOARD,&hdriver)) < 0) GetOut(0, ret_val,"sen_initboard");

  if ((ret_val=sen_setup_camera(hdriver))<0) GetOut(1, ret_val,"sen_setup_camera");

#if EXPOSURE
  sprintf(delay_and_exposure,"0,%d,-1,-1",EXPOSURE);
#else
  sprintf(delay_and_exposure,"0,%d,-1,-1",(int)*exposure);
#endif
  if ((ret_val = sen_set_coc(hdriver,SEN_TYPE,SEN_TRIG,1,SEN_CCD_X/32,1,SEN_CCD_Y/32+1,1,1,delay_and_exposure))< 0) 
    GetOut(1,ret_val,"sen_set_coc");

  if ((ret_val = sen_get_cam_values(hdriver,&values)) < 0) GetOut(1, ret_val, "sen_get_cam_values");

  size=SEN_CCD_X*SEN_CCD_Y*2;
  bufnr = -1; /* bug fix ? */
  if ((ret_val=sen_allocate_buffer(hdriver,&bufnr,&size)) < 0) GetOut(1, ret_val, "sen_allocate_buffer");

  if ((ret_val=sen_map_buffer(hdriver,bufnr,size,0,(void *)&picbuf)) < 0) GetOut(2, ret_val, "sen_map_buffer");

  if ((ret_val=sen_run_coc(hdriver,CAM_SINGLE)) < 0) GetOut(3, ret_val, "sen_run_coc");

  if ((ret_val=sen_add_buffer_to_list(hdriver,bufnr,size,0,0)) < 0) GetOut(4, ret_val, "sen_add_buffer_to_list");


  zeit1=GetTickCount();
  /*timeout value + (delay+exposure)-time*/
  zeit1+=(int)(values.beltime)/1000;
  /*timeout value ++cameratransfer-time*/
  zeit1+=((int)values.coctime)/1000;
  /*timeout value + dmatimeout*/
  
  zeit1+=250;
  sen_get_buffer_status(hdriver,bufnr,0,&stat,sizeof(stat));
  do
    {
      zeit2=GetTickCount();
      if((zeit2%10)==0)
	sen_get_buffer_status(hdriver,bufnr,0,&stat,sizeof(stat));
    }
  while(((stat&0x0F02)==0)&&(zeit2<zeit1));
  
  if((stat&0x0F02)==0)
    mexPrintf("Timeout waiting for DMA done status %x \n",stat);
  
  if(stat&0x0F00)
    mexPrintf("Bufferstatus Error-Flags set %x \n",stat);


  if(stat&0x0002)  {
      /* looks fine, returning 8-bit tif */
      unsigned char *picb8;
      int z;
      int rgbdims[2]; 
#if MIRRORX || MIRRORY
      int row;
      unsigned short *buf;
      unsigned char *b8;
#endif

      rgbdims[0] = SEN_CCD_X ; 
      rgbdims[1] = SEN_CCD_Y ;
      plhs[0] = mxCreateNumericArray(2,rgbdims,mxUINT8_CLASS,mxREAL);
      picb8 = (unsigned char *) mxGetPr(plhs[0]);
#if MIRRORX
      // try to reverse rows while converting to 8-bit tif
      for (buf=picbuf,b8=picb8+SEN_CCD_X-1;buf<picbuf+SEN_CCD_X*SEN_CCD_Y;b8+=2*SEN_CCD_X)
	for(z=0;z<SEN_CCD_X;z++)
	  *b8--=*buf++>>4;
#elif MIRRORY
      // try to reverse cols while converting to 8-bit tif
      for (buf=picbuf,b8=picb8+SEN_CCD_X*(SEN_CCD_Y-1);buf<picbuf+SEN_CCD_X*SEN_CCD_Y;b8-=2*SEN_CCD_X)
	for (z=0;z<SEN_CCD_X;z++) 
	  *b8++=*buf++>>4;	  
#else
      // simple convertion to 8-bit tif:
      for(z=0;z<SEN_CCD_X*SEN_CCD_Y;z++)
       picb8[z]=picbuf[z]>>4;
#endif

     }
  else { 
    /*something is wrong must remove buffer*/
    GetOut(5, stat, "sen_get_buffer_status");
  }


  /* OK so far */
  if ((ret_val=sen_stop_coc(hdriver,0)) < 0) GetOut(3, stat, "sen_stop_coc");
  if ((sen_unmap_buffer(hdriver,bufnr)) < 0) GetOut(2, stat, "sen_unmap_buffer");
  if ((ret_val=sen_free_buffer(hdriver,bufnr)) < 0) GetOut(1, stat, "sen_free_buffer");
  if ((ret_val=sen_closeboard(&hdriver)) < 0) GetOut(0, stat, "sen_closeboard");

  return;
}

