/* Acquisition Loop with  TDC V1190 - MG xx/xx/2005 @ LIXAM-CNRS*/
/* 8-2006: First fix of crashes due to dynamical memory with glibc, the acquisition restart itself...*/
/* 10-2006: Improvement of the algorithm to avoid crash when there are to many  multi-hits: no more dynamical memory */
/* 11-2006: Add remote acquisition with files controled form outside: file start, stop */

/* ============================================================================================================================ */
/* INCLUDES */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>

#include "tdc1190_driver_high.h"
#include "console.h"

#include "keyboard.h"
#include "tdc_acq.h"


/* ============================================================================================================================ */
/* DEFINE */

/* ============================================================================================================================ */
/* STRUCTURE */

/* ============================================================================================================================ */
/* LOCAL PROTOTYPE*/
static int treatData(tdc1190 *aTdc, long *out, long *isEvent);
static int readData(tdc1190 *aTdc);
static int saveData(FILE *fp,tdcList *aList);
static int loopLocal(tdcList *aList, FILE *fp);
static int loopRemote(tdcList *aList, FILE *fp);

/* ============================================================================================================================ */
static int treatData(tdc1190 *aTdc, long *out, long *isEvent)
{
  unsigned long *dataCount,*data;
  Tevent *currentEvent;
  
  currentEvent=&aTdc->DataList[aTdc->counterTrig];
  dataCount=&currentEvent->dataCount;
  data=currentEvent->data;
  if (*(isEvent)) { 
    if (out[0]==0) { /*data*/
      if ((out[2]!=95)&&(out[2]!=127)) currentEvent->anodeEvent=1;
      if ((out[2]==95)) currentEvent->timerEvent=1; /* Add ||(out[2]==95) */
      data[*(dataCount)]=aTdc->GeoAddress<<30;
      data[*(dataCount)]+=out[2]<<22;
      data[*(dataCount)]+=out[3];
      /*printf("RR=> TC :%li, DC :%li, D:%li -- %li %x\n",aTdc->counterTrig, 
       *dataCount, out[2], out[3], ((out[2]<<22)+out[3]) );*/
      if ((*(dataCount)>=aTdc->Event_MaxHit)||(*(dataCount)>=128)) {
	currentEvent->goodEvent=0;
	currentEvent->toolongEvent=1;
      }
      else {
	currentEvent->goodEvent=(currentEvent->anodeEvent)&&(currentEvent->timerEvent);
	*(dataCount)+=1;	
      }
    };
    if(out[0]==16) {/* End Event*/      
      if (currentEvent->anodeEvent) aTdc->totalAnode+=1;
      if (currentEvent->timerEvent) aTdc->totalTimer+=1;
      if (currentEvent->toolongEvent) aTdc->Hit_Error+=1;
      aTdc->counterTrig+=1;
      *(isEvent)=0; 
    };    
  }
  else {
    if ((out[0]==8)&&(aTdc->counterTrig<DATAFIFO_SIZE)) { /* Start Event */
      *(isEvent)=1;
      *(dataCount)=0;
      aTdc->GeoAddress=out[2]<<30;
      currentEvent->eventNumber=out[1];
      currentEvent->toolongEvent=0;
    }
  };
  
  if (out[0]==4) { /* Error */
    aTdc->Tdc_Error+=1;
  }
  
  
  return *(isEvent);
}
/* ============================================================================================================================ */
static int readData(tdc1190 *aTdc)
{
  long isEvent=0, out[5];
  int i;

  aTdc->counterTrig=0;
  
  if (readTdc_rtai(aTdc,0)) {  /* read a block of data from RTAI FIFO*/ 
    i=0;
    isEvent=0;
    do {
      convert_output(((unsigned int)aTdc->RTAIdata_fifo[i]), out);
      treatData(aTdc, out, &isEvent);
      i++;
    } while (i<aTdc->RTAIcounter);
  }
  if (isEvent) {/*read the end of the event*/
    do {
      if (readTdc_rtai(aTdc,1)) /*Is there 1 data in the RTAI fifo*/ 
	convert_output(((unsigned int)aTdc->RTAIdata_fifo[0]), out); /*yes -> convert data*/
      else
	read_MMAPoutput(&aTdc->tdc_access, out); /* no -> read tdc directly !*/
   
      /*Cas ou le temps de lecture sur fifo a permis de faire une trig ?? Faut-il une pause RTAI ??*/
	
      treatData(aTdc, out, &isEvent);
    } while (isEvent);
  }
  return 0; 
}
/* ============================================================================================================================ */
static int saveData(FILE *fp, tdcList *aList)
{
  Tevent *currentEvent;
  tdc1190 *aTdc;
  unsigned long dataCount,*data;
  unsigned char bytes, marker=0xFF;
  int i,j,k;
  

  for (i=0; i<aList->numberOfTdc; i++) {
    aTdc=&aList->listOfTdc[i];
  
    for (j=0; j<aTdc->counterTrig; j++) {
      currentEvent=&aTdc->DataList[j];     
      dataCount=currentEvent->dataCount;
      bytes=(unsigned char)dataCount;
      data=currentEvent->data; 
      if ((bytes)&&(currentEvent->goodEvent)){
	/*for (k=0; k< dataCount; k++) 
	  printf("SS=> TC :%i, DC :%i, D:%x \n",j, k, data[k]);*/
	aTdc->totalEvent+=1;
	fwrite(&bytes,sizeof(unsigned char),1,fp);
	fwrite(data,sizeof(unsigned long),(int)(dataCount),fp);
	fwrite(&marker,sizeof(unsigned char),1,fp);
      }
    }    
    aTdc->totalTrig+=aTdc->counterTrig;  
 }
  return 0;
}

/* ============================================================================================================================ */
static int loopLocal(tdcList *aList, FILE *fp)
{
  int i, died, status, error;
  
  switch(fork()) 
    {
    case -1:
      printf("Cannot start acquisition !! no fork...\n");
      exit(1);

    case 0:  /*Son : Acquisition loop */     
      do {
	for (i=0; i<aList->numberOfTdc; i++) {
	  readData(&aList->listOfTdc[i]); /* Add data to event list */
	};
	saveData(fp,aList);
      } while (!Keypressed());
      /* End */
      for (i=0; i<aList->numberOfTdc; i++) {
	stopTdc_rtai(&aList->listOfTdc[i]); 
      }
      fclose(fp);
      exit(1);

    default: /* Father : wait for the end of the acquisition loop*/
      died=wait(&status);	 
      error=WEXITSTATUS(status);
      if (error==0) {  /*system crashed !!!! Warning then restart*/
	printf("\a\n***** SYSTEM IS RE-STARTED *****\n");
	for (i=0; i<aList->numberOfTdc; i++) stopTdc_rtai(&aList->listOfTdc[i]); 
      }
    }
  return error;
}

/* ============================================================================================================================ */
void acquireLocal(tdcList *aList)
{
  FILE *fp;
  int i;
  
  /*Init Real Time acquisition */
  fp=fopen("tmp.dat","wb");

  printf("Acquisition ON ...Press any key to stop....\n");
  do {
    for (i=0; i<aList->numberOfTdc; i++) {
      if (startTdc_rtai(&aList->listOfTdc[i],i,aList->rate)) return;
      SetTdc_ClearRegister(&aList->listOfTdc[i]);
    }  
  } while (loopLocal(aList,fp)!=1);
  
  

  return;
}

/* ============================================================================================================================ */
static int loopRemote(tdcList *aList, FILE *fp)
{
  int i, died, status, error;

  switch(fork()) 
    {
    case -1:
      printf("Cannot start acquisition !! no fork...\n");
      exit(1);

    case 0:  /*Son : Acquisition loop */     
      printf("The system is acquiring...\n");
      do {
	for (i=0; i<aList->numberOfTdc; i++) {
	  readData(&aList->listOfTdc[i]); /* Add data to event list */
	};
	saveData(fp,aList);
        if (fopen("refresh.acq","r")) {
	  system("rm refresh.acq");
	  fflush(fp);
	  for (i=0; i<aList->numberOfTdc; i++) {
	    status_rtai(&aList->listOfTdc[i]);
	  };
	}
      } while (fopen("stop.acq","r")==NULL);
      
     /* End */
      for (i=0; i<aList->numberOfTdc; i++) {
	stopTdc_rtai(&aList->listOfTdc[i]); 
      }
      system("rm start.acq");


      exit(1);

    default: /* Father : wait for the end of the acquisition loop*/
      died=wait(&status);	 
      error=WEXITSTATUS(status);
      if (error==0) {  /*system crashed !!!! Warning then restart*/
	printf("\a\n***** CRASH ! System re-started ....*****\n");
	for (i=0; i<aList->numberOfTdc; i++) stopTdc_rtai(&aList->listOfTdc[i]); 
      }
    }
  return error;
}

/* ============================================================================================================================ */
void acquireRemote(tdcList *aList)
{
  FILE *fp=NULL;
  int i;
  
  /*Init Real Time acquisition */


  printf("Remote acquisition ... Wait for a client to connect or press any key to stop....\n");
  do {
    if (fopen("stop.acq","r")!=NULL) {
      system("rm stop.acq");
      if (fp!=NULL) {
	printf("The system is waiting for a client to connect or press any key to stop....\n");
	fclose(fp);
	fp=NULL;
      }
    }
    if (fopen("start.acq","r")!=NULL) {
      if (fp==NULL) { 
	printf("\nCreate a new acquisition file...\n");
	fp=fopen("tmp.dat","wb");
	}
      for (i=0; i<aList->numberOfTdc; i++) {
	if (startTdc_rtai(&aList->listOfTdc[i],i,aList->rate)) return;
	SetTdc_ClearRegister(&aList->listOfTdc[i]);
      } 
      loopRemote(aList, fp);
    }
  } while (!Keypressed());
  
  

  return;
}
