Index: trunk/FACT++/src/EventBuilder.c
===================================================================
--- trunk/FACT++/src/EventBuilder.c	(revision 10773)
+++ trunk/FACT++/src/EventBuilder.c	(revision 10773)
@@ -0,0 +1,958 @@
+
+
+
+
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <time.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <math.h>
+#include <error.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h> 
+#include <sys/socket.h>
+#include <pthread.h>
+#include <sched.h>
+
+
+#include "EventBuilder.h"
+
+#define ETHTEST   0
+#define MIN_LEN  32        // min #bytes needed to interpret FADheader
+#define MAX_LEN  64*1024   // size of read-buffer per socket
+   
+int g_actTime   =  0 ;
+int g_runStat   = 40 ;
+int g_actBoards = 20 ;
+
+uint gi_SecRate[MAX_SOCK] ;
+uint gi_S10Rate[MAX_SOCK] ;
+uint gi_MinRate[MAX_SOCK] ;
+uint gi_ErrCnt[MAX_SOCK] ;
+
+uint gi_NumConnect[NBOARDS];   //4 crates * 10 boards
+
+uint gi_SecTime, gi_S10Time, gi_MinTime ;
+uint gi_EvtStart= 0 ;
+uint gi_EvtRead = 0 ;
+uint gi_EvtBad  = 0 ;
+uint gi_EvtTot  = 0 ;
+uint gw_EvtTot  = 0 ;
+uint gp_EvtTot  = 0 ;
+
+
+EVT_CTRL    evtCtrl ;       //control of events during processing
+int         evtIdx[MAX_EVT*MAX_RUN] ; //index from mBuffer to evtCtrl
+
+WRK_DATA    mBuffer[MAX_EVT*MAX_RUN]; //local working space
+
+
+
+
+RUN_HEAD    actRun ;
+
+RUN_CTRL    runCtrl[MAX_RUN] ;
+
+RUN_TAIL    runTail[MAX_RUN] ;
+
+
+/*
+*** Definition of rdBuffer to read in IP packets; keep it global !!!!
+ */
+
+
+typedef union {
+  int8_t  B[MAX_LEN/8];
+  int16_t S[MAX_LEN/4];
+  int32_t I[MAX_LEN/2];
+  int64_t L[MAX_LEN  ];
+} CNV_FACT ;
+
+typedef struct {
+  int  bufTyp ;          //what are we reading at the moment: 0=header 1=data -1=skip ...
+  int32_t  bufPos ;          //next byte to read to the buffer next
+  int32_t  bufLen ;          //number of bytes left to read
+
+  int  sockStat   ;      //-1 if socket not yet connected
+  int  socket     ;      //contains the sockets
+  struct sockaddr_in SockAddr ; //IP for each socket
+
+  int  evtID  ;          // event ID of event currently read
+  int  runID  ;          // run       "
+//int  evtPtr ;          // index into evtCtrl structure
+  uint  fadLen ;          // FADlength of event currently read
+  int  fadVers ;         // Version of FAD
+  int  board ;           // boardID (softwareID: 0..40 )
+  int  Port ;
+
+//  int8_t *rBuf;          //local buffer to be used when no event defined yet
+  CNV_FACT *rBuf ;
+
+} READ_STRUCT ;
+
+
+typedef union {
+  int8_t  B[2];
+  int16_t S  ;
+} SHORT_BYTE ;
+
+
+
+struct timespec xwait ;
+
+
+SHORT_BYTE  start, stop;
+
+READ_STRUCT rd[MAX_SOCK] ;  //buffer to read IP and afterwards store in mBuffer
+
+
+
+/*-----------------------------------------------------------------*/
+
+
+/*-----------------------------------------------------------------*/
+
+
+
+int GenSock(int flag, int crate0, int board0, int port0, READ_STRUCT *rd) {
+/*
+*** generate Address, create sockets and allocates readbuffer for it
+*** 
+*** if flag!=0 only close and redo the socket
+ */
+
+  int crate, board, port ;
+  char IPstr[100] ;
+  struct in_addr IPaddr ;
+
+  rd->sockStat = -1 ;
+
+
+  crate = crate0;
+  board = board0;
+  port  = port0 ;
+
+
+  if (flag !=0 ) {
+     close(rd->socket) ;
+     if ( (rd->socket = socket (PF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)) <= 0) {
+        error(1,errno,"Could not generate socket\n");
+        return -2 ;
+     }
+     return 0 ;
+  }
+
+
+  if (ETHTEST >0) {
+     port = port0+100*crate0+10*board0 ;
+     sprintf(IPstr,"10.0.%d.11",128+crate); // test on fact1
+//      if (board==3) sprintf(IPstr,"10.0.100.11");
+
+//     sprintf(IPstr,"10.0.131.11"); // test on fact1
+     inet_pton(PF_INET, IPstr, &IPaddr) ;
+     port = port0+100*crate0+10*board0 ;
+  } else {
+
+
+     sprintf(IPstr,"10.0.%d.%d",128+crate,128+board); // real environment
+     if ( inet_pton(PF_INET, IPstr, &IPaddr) <=0 ) {
+        error(1,errno,"Error: bad address c=%d b=%d '%s'\n", crate, board, IPstr);
+        return -1 ;
+     }
+  } 
+
+     rd->Port  = port ;
+     rd->board = crate0*10+board0 ;
+     rd->SockAddr.sin_family = PF_INET;
+     rd->SockAddr.sin_port = htons(port) ;
+     rd->SockAddr.sin_addr = IPaddr ;
+
+     if ( (rd->socket = socket (PF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)) <= 0) {
+        error(1,errno,"Could not generate socket\n");
+        return -2 ;
+     } else {
+       rd->rBuf = malloc(sizeof(CNV_FACT) ) ;
+       if ( rd->rBuf == NULL ) {
+          error(1,errno,"Could not create local buffer\n");
+          return -3 ;
+       }
+     }
+
+  return 0 ;
+
+} /*-----------------------------------------------------------------*/
+
+
+int PrintErr() {
+
+  int k,c,b,p,s ;
+
+
+       k=0 ;
+       printf("Errors:\n");
+       for (c=0; c<4; c++) {
+          for (b=0; b<10; b++) {
+             s=0 ;
+             printf("c%d b%d: ",c,b);
+             for (p=1; p<8; p++) {
+                printf("%7d",gi_ErrCnt[k]);
+                s+=gi_ErrCnt[k];
+             }
+             printf("%8d\n",s);
+          }
+       }
+
+       return 0;
+} /*-----------------------------------------------------------------*/
+
+
+int PrintRate() {
+
+  int k,c,b,p,s ;
+
+
+    if (g_actTime > gi_SecTime) {
+       gi_SecTime = g_actTime ;
+       printf("Nr Ev start %d compl %d bad %d\n",gi_EvtStart,gi_EvtRead,gi_EvtBad) ;
+
+
+       k=0 ;
+       printf("Rate/Second:\n");
+       for (c=0; c<4; c++) {
+          for (b=0; b<10; b++) {
+             s=0 ;
+             printf("c%d b%d: ",c,b);
+             for (p=1; p<8; p++) {
+                printf("%7d",gi_SecRate[k]);
+                s+=            gi_SecRate[k];
+                gi_S10Rate[k]+=gi_SecRate[k];
+                gi_SecRate[k++]=0 ;
+             }
+             printf("%8d\n",s);
+          }
+       }
+       for (b=0; b<NBOARDS; b++)
+          printf("%d ",gi_NumConnect[b]) ;
+       printf("\n");
+    }
+
+
+    if ( g_actTime%10 == 0 && g_actTime > gi_S10Time) {
+       gi_S10Time = g_actTime ;
+       k=0 ;
+       printf("Rate/10Second:\n");
+       for (c=0; c<4; c++) {
+          for (b=0; b<10; b++) {
+             s=0 ;
+             printf("c%d b%d: ",c,b);
+             for (p=1; p<8; p++) {
+                printf("%7d",gi_S10Rate[k]);
+                s+=            gi_S10Rate[k];
+                gi_MinRate[k]+=gi_S10Rate[k];
+                gi_S10Rate[k++]=0 ;
+             }
+             printf("%8d\n",s);
+          }
+       }
+    }
+
+
+    if ( g_actTime%60 == 0 && g_actTime > gi_MinTime) {
+       gi_MinTime = g_actTime ;
+       k=0 ;
+       printf("Rate/Minute:\n");
+       for (c=0; c<4; c++) {
+          for (b=0; b<10; b++) {
+             printf("c%d b%d: ",c,b);
+             s=0 ;
+             for (p=1; p<8; p++) {
+                printf("%7d",gi_MinRate[k]);
+                s+=          gi_MinRate[k];
+                gi_MinRate[k++]=0 ;
+             }
+             printf("%8d\n",s);
+          }
+       }
+    }
+  
+      return 0;
+
+} /*-----------------------------------------------------------------*/
+
+
+
+
+int mBufInit() {
+// initialize mBuffer (mark all entries as unused\empty)
+
+   int i,j,k ;
+
+   for (i=0; i<MAX_EVT*MAX_RUN; i++) {
+      mBuffer[i].evNum = mBuffer[i].runNum = -1;
+
+      evtCtrl.evtBuf[  i] = -1 ;
+      evtCtrl.evtStat[ i] = -1 ;
+      evtCtrl.pcTime[  i] = g_actTime + 50000000 ;  //initiate to far future
+   }
+
+   for (i=0; i<MAX_RUN; i++) {
+      runCtrl[i].runId = 
+      runCtrl[i].lastTime = 
+      runCtrl[i].nextEvt = 0 ;
+      runCtrl[i].fileId = -2 ;
+
+      for (k=0; k<MAX_EVT; k++) runCtrl[i].buffId[k] = 0 ;
+
+      runTail[i].nEventsOk =
+      runTail[i].nEventsRej =
+      runTail[i].nEventsBad =
+      runTail[i].PCtime0 =
+      runTail[i].PCtimeX = 0 ;
+   }
+
+
+   evtCtrl.readPtr =  0 ;
+   evtCtrl.writePtr=  0 ;
+
+   return 0 ;
+
+} /*-----------------------------------------------------------------*/
+
+
+
+
+int mBufEvt(int evID, int runID, int nRoi) {
+// generate a new Event into mBuffer:   
+// make sure only complete Event are possible, so 'free' will always work
+// returns index into mBuffer[], or negative value in case of error
+
+
+   int i, k, evFree ;
+
+   if (nRoi < 0 || nRoi > 1024) {
+      printf("illegal nRoi %d\n",nRoi) ;
+      return 99 ;
+   }
+
+   i = evID % MAX_EVT ;
+   evFree = -1 ;
+
+   for ( k=0; k<MAX_RUN; k++) {
+      if ( mBuffer[i].evNum == evID
+        && mBuffer[i].runNum== runID ) {
+         return i ;  
+      }
+      if ( evFree < 0 && mBuffer[i].evNum < 0 ) evFree = i ;
+      i += MAX_EVT ;
+   }
+
+
+   //event does not yet exist; create
+   if (evFree < 0 ) {        //no space available in ctrl
+        error(0,0, "no space left to keep event...") ;
+        return -1 ;
+   }
+
+   
+
+   i = evFree ;   //found free entry; use it ...
+
+   mBuffer[i].fEvent  = malloc( sizeof(EVENT) ) ;
+   if (mBuffer[i].fEvent  == NULL) return -12;
+
+
+   mBuffer[i].fEvent->StartPix  = malloc( NPIX * sizeof(int16_t) ) ;
+   if (mBuffer[i].fEvent->StartPix  == NULL) {
+      free(mBuffer[i].fEvent) ;
+      mBuffer[i].fEvent = NULL ;
+      mBuffer[i].nRoi = -3 ;
+      return -13;
+   }
+   for (k=0; k<NPIX; k++) mBuffer[i].fEvent->StartPix[k] = -1 ;
+
+   mBuffer[i].fEvent->StartTM   = malloc( NTMARK * sizeof(int16_t) ) ;
+   if (mBuffer[i].fEvent->StartTM  == NULL) {
+      free(mBuffer[i].fEvent->StartPix ) ;
+      free(mBuffer[i].fEvent) ;
+      mBuffer[i].fEvent = NULL ;
+      mBuffer[i].nRoi = -4 ;
+      return -14;
+   }
+   for (k=0; k<NTMARK; k++) mBuffer[i].fEvent->StartTM[k] = -1 ;
+
+   mBuffer[i].fEvent->Adc_Data = malloc( NPIX  * nRoi * sizeof(int16_t) ) ;
+   if (mBuffer[i].fEvent->Adc_Data == NULL) {
+      free(mBuffer[i].fEvent->StartTM  ) ;
+      free(mBuffer[i].fEvent->StartPix ) ;
+      free(mBuffer[i].fEvent) ;
+      mBuffer[i].fEvent = NULL ;
+      mBuffer[i].nRoi = -5 ;
+      return -15;
+   }
+
+   mBuffer[i].fEvent->Adc_Tmark= malloc( NTMARK* nRoi * sizeof(int16_t) ) ;
+   if (mBuffer[i].fEvent->Adc_Tmark== NULL) {
+      free(mBuffer[i].fEvent->Adc_Data ) ;
+      free(mBuffer[i].fEvent->StartTM  ) ;
+      free(mBuffer[i].fEvent->StartPix ) ;
+      free(mBuffer[i].fEvent) ;
+      mBuffer[i].fEvent = NULL ;
+      mBuffer[i].nRoi = -6 ;
+      return -16;
+   }
+
+   mBuffer[i].fEvent->FADhead = malloc( NBOARDS* sizeof(PEVNT_HEADER) ) ;
+   if (mBuffer[i].fEvent->FADhead== NULL) {
+      free(mBuffer[i].fEvent->Adc_Tmark ) ;
+      free(mBuffer[i].fEvent->Adc_Data ) ;
+      free(mBuffer[i].fEvent->StartTM  ) ;
+      free(mBuffer[i].fEvent->StartPix ) ;
+      free(mBuffer[i].fEvent) ;
+      mBuffer[i].fEvent = NULL ;
+      mBuffer[i].nRoi = -7 ;
+      return -17;
+   }
+
+   mBuffer[i].nBoard = 0 ;
+   for (k=0; k<NBOARDS; k++ ) {
+      mBuffer[i].board[k] = -1;
+   }
+
+   mBuffer[i].pcTime  = g_actTime ;
+   mBuffer[i].nRoi    = nRoi ;
+   mBuffer[i].evNum   = evID  ;
+   mBuffer[i].runNum  = runID ;
+
+
+   //register event in 'active list (reading)'
+
+   evtCtrl.evtBuf[  evtCtrl.readPtr] = i ;
+   evtCtrl.evtStat[ evtCtrl.readPtr] = 0 ;
+   evtCtrl.pcTime[  evtCtrl.readPtr] = g_actTime ;
+   evtIdx[i] = evtCtrl.readPtr ;
+
+   evtCtrl.readPtr++ ;
+   if (evtCtrl.readPtr == MAX_EVT*MAX_RUN ) evtCtrl.readPtr = 0;
+
+   gi_EvtStart++ ;
+
+   //check if runId already registered in runCtrl
+   evFree = -1 ;
+   for (k=0; k<MAX_RUN; k++) {
+      if (runCtrl[k].runId == runID ) return i ;//run exists already
+      else if (evFree < 0 && runCtrl[k].runId == 0 ) evFree = k ;
+   }
+   
+   if (evFree <0 ) {
+      error(0,0, "not able to register the new run %d\n",runID);
+   } else {
+      runCtrl[evFree].runId = runID ;
+   }
+
+
+   return i ;
+ 
+} /*-----------------------------------------------------------------*/
+
+
+int mBufFree(int i) {
+//delete entry [i] from mBuffer:
+//(and make sure multiple calls do no harm ....)
+
+   if ( mBuffer[i].nRoi > 0) {      //have an fEvent structure generated ...
+      free(mBuffer[i].fEvent->Adc_Tmark) ;
+      free(mBuffer[i].fEvent->Adc_Data ) ;
+      free(mBuffer[i].fEvent->StartTM  ) ;
+      free(mBuffer[i].fEvent->StartPix ) ;
+      free(mBuffer[i].fEvent ) ;
+      mBuffer[i].fEvent = NULL ;
+   }
+   mBuffer[i].evNum   = mBuffer[i].runNum = mBuffer[i].nRoi= -1;
+    
+   return 0 ;
+ 
+} /*-----------------------------------------------------------------*/
+
+
+  /*-----------------------------------------------------------------*/
+
+
+
+int initReadFAD() {
+/* *** initialize reading of FAD data */
+  int32_t i,j,k ;
+  int c,b,p ;
+
+
+  g_actTime = time(NULL) ;
+
+  k = 0 ;
+  for ( c=0; c<4; c++ )
+     for (b=0; b<10; b++ )
+        for (p=5001; p<5008; p++) {
+          j = GenSock(0,c,b,p, &rd[k]) ;
+          if ( j != 0 ) printf("problem with c%d b%d p%d\n",c,b,p);
+//        else          printf("ok socket %d = %d\n",k,rd[k].socket) ;
+          k++ ;
+        }
+
+  for (k=0; k<MAX_SOCK; k++)
+     gi_SecRate[k]=gi_S10Rate[k]=gi_MinRate[k]=gi_ErrCnt[k] = 0 ;
+
+  for (k=0; k<NBOARDS; k++)
+     gi_NumConnect[k]=0;
+
+
+  gi_SecTime= gi_S10Time= gi_MinTime= g_actTime ;
+     
+         return NULL;
+
+} /*-----------------------------------------------------------------*/
+
+
+
+void *readFAD( void *ptr ) {
+/* *** main loop reading FAD data and sorting them to complete events */
+  int head_len,frst_len,numok,numok2,evFree,dest,evID,i,j,k ;
+  int32_t jrd ;
+  int8_t FADbyte0, FADbyte1, FADbyteX0, FADbyteX1 ;
+  int32_t myRun, cleanTime ;
+  int boardId, roi,drs,px,src,pixS,pixH,pixC,pixR,tmS ;
+  int reqBoards = 40 ;
+
+  int goodevt=0;
+  int goodhed=0;
+  int nbuf=0;
+  int ret ;
+
+  int waitTime = 10 ; //maximum nr of seconds wait for delayed packets
+
+  int nokCnt[MAX_SOCK],loopCnt=0;
+  int sokCnt[MAX_SOCK];
+
+  for (k=0; k<MAX_SOCK; k++) sokCnt[k]=nokCnt[k]=0 ;
+
+
+  head_len = sizeof(PEVNT_HEADER) ;
+  frst_len = head_len + 36 * 12 ;
+  if (head_len < MIN_LEN) { printf("headLen ...\n"); exit(99);}
+
+  numok = numok2   = 0 ;
+
+  start.S=0xFB01;
+  stop.S= 0x04FE;
+
+  myRun = g_actTime ;
+  cleanTime = g_actTime ;     //once per second cleanup buffers from too old data
+
+
+
+
+  mBufInit() ;
+
+
+  while (g_runStat > 0) {           //loop until global variable g_stop is set
+
+
+    g_actTime = time(NULL) ;
+    nokCnt[numok]++;
+
+    loopCnt++ ;
+
+    numok = 0 ;                       //count number of succesfull actions
+
+    for (i=0; i<MAX_SOCK; i++) {      //check all sockets if something to read
+
+      if (rd[i].sockStat <0 ) {         //try to connect if not yet done
+        rd[i].sockStat=connect(rd[i].socket,
+            (struct sockaddr*) &rd[i].SockAddr, sizeof(rd[i].SockAddr)) ;
+        if (rd[i].sockStat >=0 ) {      //successfull ==>
+          rd[i].bufTyp = 0 ;            //  expect a header
+          rd[i].bufLen = frst_len ;     //  max size to read at begining
+          rd[i].bufPos = 0 ;            //  no byte read so far
+ gi_NumConnect[ rd[i].board ]++ ;
+ printf("+++connect %d %d\n",rd[i].board,gi_NumConnect[ rd[i].board ]);
+        }
+      }
+
+      if (rd[i].sockStat >=0) {     //we have a connection ==> try to read
+        numok++ ;
+        sokCnt[i]++;
+        jrd=recv(rd[i].socket,&rd[i].rBuf->B[ rd[i].bufPos], rd[i].bufLen, MSG_DONTWAIT);
+
+        if (jrd == 0) {                 //connection has closed ...
+           rd[i].sockStat = -1 ;        //flag (try to reopen next round)
+           error(0,errno,"Socket %d closed",i);
+           j = GenSock(1,0,0,0, &rd[i]) ;
+           gi_ErrCnt[i]++ ;
+ gi_NumConnect[ rd[i].board ]-- ;
+ printf("disconnect %d %d\n",rd[i].board,gi_NumConnect[ rd[i].board ]);
+        } else if ( jrd<0 ) {           //did not read anything
+           if (errno != EAGAIN && errno != EWOULDBLOCK ) {
+              error(1,errno,"Error Reading from %d",i);
+              gi_ErrCnt[i]++ ;
+           } else  numok-- ;            //else nothing waiting to be read
+
+        } else if ( rd[i].bufTyp >0 ) { // we are reading data ...
+//printf("received data %d %d\n", i,jrd);
+
+            if ( jrd < rd[i].bufLen ) {    //not yet all read
+             rd[i].bufPos += jrd ;        //==> prepare for continuation
+             rd[i].bufLen -= jrd ;
+           } else {                     //full dataset read
+             rd[i].bufLen  = rd[i].bufPos + j ;
+             rd[i].bufPos  = rd[i].fadLen ;
+             if ( rd[i].rBuf->B[ rd[i].bufPos-1] != stop.B[0]
+               && rd[i].rBuf->B[ rd[i].bufPos  ] != stop.B[1]) {
+                gi_ErrCnt[i]++ ;
+                printf( "wrong end of buffer found %d\n",rd[i].bufPos);
+ exit(1) ;
+                goto EndBuf ;
+
+             } 
+
+             //we have a complete buffer, copy to WORK area
+             gi_SecRate[i]++ ;
+
+             roi = ntohs(rd[i].rBuf->S[ head_len/2 + 2 ]) ; 
+             //get index into mBuffer for this event (create if needed)
+             evID = mBufEvt( rd[i].evtID, rd[i].runID, roi ) ;
+
+             if (evID < 0) {
+                printf("no space left ...%d\n",evID) ;
+ exit(2) ;
+                goto EndBuf ;
+             } 
+
+             //we have a valid entry in mBuffer[]; fill it
+
+             boardId = rd[i].board  ;
+             if ( mBuffer[evID].board[ boardId ] != -1) {   //this board already stored ...
+                printf( "board of this event already stored ...") ;
+             } else {
+
+                int iDx = evtIdx[evID] ;   //index into evtCtrl
+
+                memcpy( &mBuffer[evID].fEvent->FADhead[boardId].start_package_flag,
+                        &rd[i].rBuf->S[0], head_len) ;
+                mBuffer[evID].board[ boardId ] = boardId ;
+                roi  = mBuffer[evID].nRoi ;
+
+                pixS = boardId*36 -1 ;   //
+                tmS  = boardId*4  -1 ;   //
+                src  = head_len/2 ;
+                for ( drs=0; drs<4; drs++ ) {
+                   for ( px=0; px<9; px++ ) {
+                      pixH= ntohs(rd[i].rBuf->S[src++]) ;
+                      pixC= ntohs(rd[i].rBuf->S[src++]) ;
+                      pixR= ntohs(rd[i].rBuf->S[src++]) ;
+ 
+                      src++  ;
+                      pixS++ ; //pixS = pixH2S[pixH] ;
+                      if (pixR != roi ) {
+                         if (px == 8 && pixR == 2*roi ) {
+                         } else {
+                            printf("wrong roi %d %d %d %d\n",px,pixR,roi,src-2);
+//exit(66);
+                         }
+//                         goto EndBuf ;
+                      }
+
+                      mBuffer[evID].fEvent->StartPix[pixS] =pixC;
+                      dest= pixS * roi ;
+                      memcpy(
+                            &mBuffer[evID].fEvent->Adc_Data[dest],
+                            &rd[i].rBuf->S[src],  roi * 2) ;
+                      src+= roi ;
+
+        //            if (px==8 && roi < 512 ) {
+        //               tmS++ ;
+        //               dest= tmS * roi ;
+        //               mBuffer[evID].fEvent->StartTM[pixS] =pixC+roi;
+        //               memcpy(
+        //                     &mBuffer[evID].fEvent->Adc_Tmark[dest],
+        //                     &rd[i].rBuf.S[src],  roi * 2) ;
+// ?? not in the simulator ...                      src+= roi ;
+        //            }
+                   }
+                }
+                evtCtrl.evtStat[ iDx ]++ ;
+                evtCtrl.pcTime[ iDx ] = g_actTime ;
+
+                if (++mBuffer[evID].nBoard == 19 ) {
+                   //complete event read ---> flag for next processing
+                   evtCtrl.evtStat[ iDx ] = 99;
+                   gi_EvtRead++ ;
+                   gi_EvtTot++ ;    
+ printf("complete event --------------------------------------------------\n");
+                }
+             }// now we have stored a new board contents into Event structure
+
+EndBuf:
+             rd[i].bufTyp = 0 ;           //ready to read next header
+             rd[i].bufLen = frst_len ;
+             rd[i].bufPos = 0 ;         
+           }
+
+        } else {                        //we are reading event header
+           rd[i].bufPos += jrd ;
+           rd[i].bufLen -= jrd ;
+           if ( rd[i].bufPos > MIN_LEN ){ //sufficient data to take action
+              //check if startflag correct; else shift block ....
+              for (k=0; k<rd[i].bufPos -1 ; k++) {
+                 if (rd[i].rBuf->B[k  ] == start.B[1]
+                  && rd[i].rBuf->B[k+1] == start.B[0] ) break ;
+              }
+              if (k >= rd[i].bufPos-1 ) {   //no start of header found
+ printf("no start of header found !!!!\n");
+                 rd[i].bufPos = 0 ;
+                 rd[i].bufLen = head_len ;
+              } else if ( k>0 ) {
+                 rd[i].bufPos -= k ;
+                 rd[i].bufLen += k ;
+                 memcpy(&rd[i].rBuf->B[0], &rd[i].rBuf->B[k], rd[i].bufPos ) ;
+              }
+              if ( rd[i].bufPos > MIN_LEN ) {
+                 goodhed++;
+                 rd[i].fadLen = ntohs(rd[i].rBuf->S[1])*2 ; ///???
+                 rd[i].fadVers= ntohs(rd[i].rBuf->S[2]) ;
+                 rd[i].evtID  = ntohl(rd[i].rBuf->I[4]) ;
+                 rd[i].runID  = ntohl(rd[i].rBuf->I[11]) ;
+ printf("received event %d %d\n",rd[i].evtID,i);
+                    if (rd[i].runID ==0 ) rd[i].runID = myRun ;
+                 rd[i].bufTyp = 1 ;       //ready to read full record
+                 rd[i].bufLen = rd[i].fadLen - rd[i].bufPos ;
+                 if (rd[i].bufLen <=0 ) rd[i].bufLen = 100000 ;
+              }
+           }
+        } //end interpreting last read
+      } //end of successful read anything
+    } //finished trying to read all sockets
+
+
+    g_actTime = time(NULL) ;
+    if ( g_actTime > gi_SecTime ) {
+//       PrintRate() ;
+
+       //loop over all active events and flag those older than read-timeout
+
+       int kd = evtCtrl.readPtr - evtCtrl.writePtr ;
+       if ( kd < 0 ) kd+= (MAX_EVT*MAX_RUN) ;
+       for ( k=evtCtrl.writePtr; k<(evtCtrl.writePtr+kd); k++ ) {
+          int k0 = k % (MAX_EVT*MAX_RUN) ;
+
+          if (evtCtrl.evtStat[k0] > 0
+           && evtCtrl.evtStat[k0] < 90
+           && evtCtrl.pcTime[k0] < g_actTime-10 ) {
+             evtCtrl.evtStat[k0] = 91 ;
+             gi_EvtBad++ ;
+             gi_EvtTot++ ;    
+          }
+       }
+    }
+
+
+    if (numok > 0 ) numok2=0;
+    else if (numok2++ > 3) {
+       if (g_runStat == 1) {
+          xwait.tv_sec = 1;
+          xwait.tv_nsec= 0 ;        // hibernate for 1 sec
+       } else {
+          xwait.tv_sec = 0;
+          xwait.tv_nsec= 2000000 ;  // sleep for ~2 msec
+//          xwait.tv_nsec= 10000000 ;  // sleep for ~10 msec
+       }
+//       printf("sleeping ...\n");
+       nanosleep( &xwait , NULL ) ;
+    }
+
+
+
+
+ } //and do next loop over all sockets ...
+  
+      return NULL;
+} /*-----------------------------------------------------------------*/
+
+
+void *procEvt( void *ptr ) {
+/* *** main loop processing file, including SW-trigger */
+  int numProc ;
+  int k,k1,k2,kd ;
+
+  while (g_runStat > 0) {
+
+
+     kd = evtCtrl.readPtr - evtCtrl.writePtr ;
+     if ( kd < 0 ) kd+= (MAX_EVT*MAX_RUN) ;
+     k1=evtCtrl.writePtr;
+     k2=evtCtrl.writePtr+kd;
+
+     numProc = 0 ;
+     if (gp_EvtTot < gi_EvtTot) {
+        for ( k=k1; k<k2; k++ ) {
+           int k0 = k % (MAX_EVT*MAX_RUN) ;
+
+           if (evtCtrl.evtStat[k0] > 90 && evtCtrl.evtStat[k0] <500) {
+              //ready to be processed ...
+              int      id   = evtCtrl.evtBuf[k0] ;
+              uint32_t irun = mBuffer[id].runNum ;
+              int      ievt = mBuffer[id].evNum ;
+printf("processing %d %d %d %d\n",ievt,k,evtCtrl.evtStat[k0],evtCtrl.writePtr) ;
+              numProc++ ;
+              evtCtrl.evtStat[k0] = 501 ;
+              gp_EvtTot++ ;
+           }
+        }
+     }
+     if (numProc == 0) {
+        //seems we have nothing to do, so sleep a little
+        xwait.tv_sec = 0;
+        xwait.tv_nsec= 10000000 ;  // sleep for ~10 msec
+        nanosleep( &xwait , NULL ) ;
+     }
+
+  }
+  return NULL;
+  
+} /*-----------------------------------------------------------------*/
+
+
+void *writeEvt( void *ptr ) {
+/* *** main loop writing event (including opening and closing run-files */
+
+  int  numWrite = 0 ;
+  int j,id,irun,ievt ;
+
+  while (g_runStat > 0) {           //loop until global variable g_stop is set
+
+    //loop over buffered events and check if something to write ...
+
+    if ( gp_EvtTot == gw_EvtTot ) {
+       //there is for sure nothing to do --> sleep a little
+       xwait.tv_sec = 0;
+       xwait.tv_nsec= 10000000 ;  // sleep for ~10 msec
+       nanosleep( &xwait , NULL ) ;
+
+    } else {  //go through evtCtrl list to check if there might be something
+
+       //if run-file not yet opened==> open runfile (better to store headers in own structure ?)
+
+       //if eventid == next event for run ==> write it (or flag it)
+       //if eventid > next event exists, and nothing new for >time out ==> write it
+       //if nothing for this run for >timeout ==> close run
+
+       int kd = evtCtrl.readPtr - evtCtrl.writePtr ;
+       if ( kd < 0 ) kd+= (MAX_EVT*MAX_RUN) ;
+       int k,k1,k2 ;
+
+
+       k1=evtCtrl.writePtr;
+       k2=evtCtrl.writePtr+kd;
+
+       int evtTot=gw_EvtTot ;
+       for ( k=k1; k<k2; k++ ) {
+          int k0 = k % (MAX_EVT*MAX_RUN) ;
+
+          if (evtCtrl.evtStat[k0] > 500 ) { //ready to be written ...
+             id   = evtCtrl.evtBuf[k0] ;
+             irun = mBuffer[id].runNum ;
+             ievt = mBuffer[id].evNum ;
+
+             for ( j=0; j<MAX_RUN; j++) {
+                if ( runCtrl[j].runId == irun ) break ;
+             }
+             if ( j >= MAX_RUN ) {
+ printf("error: can not find run %d\n", irun);
+ exit(111);
+             }
+
+             if (runCtrl[j].fileId < 0 ) {
+ printf("open new run_file %d\n",irun) ;
+                runCtrl[j].fileId = 999  ; // should be a function call
+                runCtrl[j].nextEvt= 0;
+                runCtrl[j].lastTime=g_actTime ;
+             }
+
+             if (runCtrl[j].nextEvt == ievt ) {  //write this event
+ printf("write event %d (run %d %d)\n",ievt,irun,evtCtrl.evtStat[k0] ) ;
+                runCtrl[j].nextEvt= ievt+1;
+                runCtrl[j].lastTime=g_actTime ;
+                evtCtrl.evtStat[k0]= -1 ;
+                gw_EvtTot++ ;
+                numWrite++ ;
+//                evtCtrl.writePtr=k+1;
+             } else if ( ievt < runCtrl[j].nextEvt ) {
+ printf("delayed event (run %d %d %d) skipped\n",ievt,irun,evtCtrl.evtStat[k0] ) ;
+                evtCtrl.evtStat[k0]= -1 ;
+//                evtCtrl.writePtr=k+1;
+                gw_EvtTot++ ;
+                numWrite++ ;
+             } 
+          }
+
+
+
+          if ( runCtrl[j].lastTime < g_actTime-15) {
+ printf("non existing event skip %d (run %d -> %d)\n",runCtrl[j].nextEvt,irun,ievt) ;
+             runCtrl[j].nextEvt++;
+             numWrite++;
+          } 
+
+          for ( j=0; j<MAX_RUN; j++) {
+             if ( runCtrl[j].runId >0 && runCtrl[j].lastTime < g_actTime-120) {
+ printf("close run %d (timeout)\n",irun) ;
+                runCtrl[j].fileId = -2 ;
+                runCtrl[j].runId  =  0 ;
+             }
+          }
+          if (numWrite == 0 ) {
+             //nothing to do at the moment ==> sleep a little
+             xwait.tv_sec = 0;
+             xwait.tv_nsec= 10000000 ;  // sleep for ~10 msec
+             nanosleep( &xwait , NULL ) ;
+          }
+
+       }
+     }
+
+
+
+
+
+
+
+
+
+
+
+
+  return NULL;
+  }
+
+  return NULL;
+
+} /*-----------------------------------------------------------------*/
+
+
+
+/*
+int main() {
+  int i,th_ret[50] ;
+  pthread_t thread[50] ;
+
+  initReadFAD() ;
+  i=0 ;
+  th_ret[i] = pthread_create( &thread[i], NULL, readFAD,  (void*) i++ );
+  th_ret[i] = pthread_create( &thread[i], NULL, procEvt,  (void*) i++ );
+  th_ret[i] = pthread_create( &thread[i], NULL, writeEvt, (void*) i++ );
+
+  for(;;) { sleep(1); }
+
+
+}
+*/
Index: trunk/FACT++/src/EventBuilder.h
===================================================================
--- trunk/FACT++/src/EventBuilder.h	(revision 10773)
+++ trunk/FACT++/src/EventBuilder.h	(revision 10773)
@@ -0,0 +1,41 @@
+#ifndef FACT_EventBuilder
+#define FACT_EventBuilder
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "FAD.h"
+
+/* global variables; 
+   to avoid race canoditions, only one thread is allowed to write 
+   the name of the variable defines which process shall write it:
+
+   g_XXX : main control thread
+   gi_XX : input thread (reading from camera)
+   gw_XX : write thread (writing to disk)
+   qp_XX : processing thread(s) (processing data, eg. soft-trig)
+
+*/
+extern int  g_actTime   ;  //actual time, to be updated regularily
+extern int  g_runStat   ;  //main steering variable
+extern int  g_actBoards ;  //number of boards that should exist
+
+extern uint gi_SecRate[MAX_SOCK] ;    //MAX_SOCK defined in FACTEvent.h
+extern uint gi_S10Rate[MAX_SOCK] ;
+extern uint gi_MinRate[MAX_SOCK] ;
+extern uint gi_ErrCnt[MAX_SOCK] ;
+extern uint gi_NumConnect[NBOARDS];   //4 crates * 10 boards
+extern uint gi_SecTime, gi_S10Time, gi_MinTime ;
+extern uint gi_EvtStart ;
+extern uint gi_EvtRead  ;
+extern uint gi_EvtBad   ;
+extern uint gi_EvtTot   ;
+extern uint gw_EvtTot   ;
+extern uint gp_EvtTot   ;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: trunk/FACT++/src/FAD.h
===================================================================
--- trunk/FACT++/src/FAD.h	(revision 10773)
+++ trunk/FACT++/src/FAD.h	(revision 10773)
@@ -0,0 +1,219 @@
+#ifndef FACT_FAD_H
+#define FACT_FAD_H
+
+//---------------------------------------------------------------
+//
+// FAD internal structures
+//
+//---------------------------------------------------------------
+
+    //
+// Other definitions
+//
+#define MAX_ADDR 0xFF           // highest address in Config-RAM
+#define BADDR_ROI 0x00          // Baseaddress ROI-Values
+#define BADDR_DAC 0x24          // Baseaddress DAC-Values
+#define BADDR_CONT_TRIGGER_TIME 0x2C // Baseaddress for the continouus trigger timing.
+#define ADDR_RUNNUMBER 0x2D //
+#define MAX_VAL 65535
+#define MAX_ROIVAL 1024
+#define MAX_DACVAL 65535
+
+#define NChannels      9
+#define NBins       1024
+#define NChips         4
+#define NTemp          4
+#define NDAC           8
+
+//
+// Data structures
+//
+typedef struct {
+
+  uint16_t start_package_flag;
+  uint16_t package_length;
+  uint16_t version_no;
+  uint16_t PLLLCK;
+
+  uint16_t trigger_crc;
+  uint16_t trigger_type;
+  uint32_t trigger_id;
+
+  uint32_t fad_evt_counter;
+  uint32_t REFCLK_frequency;
+
+  uint16_t board_id;
+  uint8_t  zeroes;
+  int8_t   adc_clock_phase_shift;
+  uint16_t number_of_triggers_to_generate;
+  uint16_t trigger_generator_prescaler;
+
+  uint64_t DNA;
+
+  uint32_t time;
+  uint32_t runnumber;
+
+  int16_t  drs_temperature[NTemp];
+
+  uint16_t dac[NDAC];
+
+} __attribute__((__packed__)) PEVNT_HEADER;
+
+typedef struct {
+uint16_t id;
+uint16_t start_cell;
+uint16_t roi;
+uint16_t filling;
+uint16_t adc_data[];
+} __attribute__((__packed__)) PCHANNEL;
+
+
+typedef struct {
+uint16_t package_crc;
+uint16_t end_package_flag;
+} __attribute__((__packed__)) PEVNT_FOOTER;
+
+#define NBOARDS      40      // max. number of boards
+#define NPIX       1440      // max. number of pixels
+#define NTMARK      180      // max. number of timeMarker signals
+#define MAX_SOCK    280      // NBOARDS * 7
+
+
+typedef union {
+  uint8_t   B[8] ;        //8 bytes
+  uint16_t  S[4] ;        //4 short
+  uint32_t  I[2] ;        //2 int
+  uint64_t  L    ;        //1 long
+} L_WORD ;
+
+typedef union {
+  uint8_t   B[4] ;        //4 bytes
+  uint16_t  S[2] ;        //2 short
+  uint32_t  I    ;        //1 int
+} I_WORD ;
+
+
+//---------------------------------------------------------------
+//
+// Data structures
+//
+//---------------------------------------------------------------
+
+typedef struct {
+  uint32_t EventNum ;       // EventNumber as from FTM
+  uint16_t TriggerType ;    // Trigger Type from FTM
+  uint16_t Roi ;            // #slices per pixel (same for all pixels and tmarks)
+
+  uint32_t SoftTrig ;       // SoftTrigger Info (TBD)
+  uint32_t PCTime ;         // when did event start to arrive at PC
+
+   int16_t *StartPix ;      //First Channel per Pixel (Pixels sorted according Software ID)  ; -1 if not filled
+
+   int16_t *StartTM  ;      //First Channel for TimeMark (sorted Hardware ID) ; -1 if not filled
+
+  uint16_t *Adc_Data ;      // [ NPixels ] [ ROI ]  sorted softID
+
+  uint16_t *Adc_Tmark ;     // [ NTmark ] [ ROI ]   sorted hardID
+
+//this is highly redundant and should be reduced to usefull info [if any]
+  PEVNT_HEADER *FADhead;    // [ NBoards ] sorted Board Headers (according Hardware ID)
+
+} EVENT ;
+
+
+
+//---------------------------------------------------------------
+
+
+
+
+typedef struct {
+  uint32_t Version ;
+  uint32_t RunType ;
+  uint16_t NBoard  ;
+  uint16_t NPix ;
+  uint16_t NTm  ;
+  uint16_t Nroi ;
+
+//headers of all FAD-boards for first event ==> all FAD configs
+  PEVNT_HEADER *FADhead;    // [ NBoards ] sorted Board Headers (according Hardware ID)
+
+//do we also have info about FTM config we want to add here ???
+} RUN_HEAD ;
+
+
+//---------------------------------------------------------------
+
+
+typedef struct {
+  uint32_t nEventsOk ;  //how many events were written
+  uint32_t nEventsRej;  //how many events were rejected by SW-trig
+  uint32_t nEventsBad;  //how many events were rejected by Error
+
+  uint32_t PCtime0 ;    //time when first event received
+  uint32_t PCtimeX ;    //time when last  event received
+
+ 
+//probably more to come ...
+} RUN_TAIL ;
+
+
+
+//---------------------------------------------------------------
+
+#define MAX_RUN   64
+#define MAX_EVT   131072
+
+typedef struct {
+  uint32_t runId ;       //run number
+  uint32_t lastTime ;    //time when last event written so far
+  uint32_t nextEvt ;     //next event number to be written
+  uint32_t waitEvt ;     //event that would be ready to be written
+   int32_t fileId ;      //id of open file
+   int16_t ctrlId[MAX_EVT] ; //index to buffId (sorted list; -1 =end)
+  uint16_t buffId[MAX_EVT] ; //index to mBuffer(buffered raw data)
+} RUN_CTRL ;
+
+
+
+//---------------------------------------------------------------
+
+
+typedef struct {
+  int32_t evNum ;
+  int32_t runNum ;
+  int32_t fadLen ;
+  int32_t nBoard ;
+  int16_t board[ NBOARDS ];
+  int32_t nRoi   ;
+  int32_t pcTime ;
+  EVENT   *fEvent  ;
+
+} WRK_DATA ;             //internal to eventbuilder
+
+
+//---------------------------------------------------------------
+
+
+typedef struct {
+  int readPtr ;             //index of reading
+  int writePtr ;            //index of writing
+  int evtBuf[MAX_EVT*MAX_RUN] ;     //index of event in mBuffer
+  int evtStat[MAX_EVT*MAX_RUN] ;    //status of event:
+                                      // -1=empty
+                                      //  1..NBoards reading #Boards
+                                      // 90-99 : end reading
+                                      //128-255: processing
+                                      //256-
+                                      //201=start processing
+                                      //299=end processing
+                                      //901=start writing
+                                      //999=finished writing
+                                //(TO BE REVISED)
+
+  int pcTime[MAX_EVT*MAX_RUN] ;     //time when last action happened
+} EVT_CTRL ;
+
+
+
+#endif
Index: trunk/FACT++/src/fadctrl.cc
===================================================================
--- trunk/FACT++/src/fadctrl.cc	(revision 10772)
+++ trunk/FACT++/src/fadctrl.cc	(revision 10773)
@@ -314,4 +314,5 @@
 
         kCmdWriteRate       = kCmdWrite|0x2c, // Continous trigger rate
+        kCmdWriteRunNumber  = kCmdWrite|0x2d, // 
 
         /*
