Index: /fact/FADctrl/FAD.cc
===================================================================
--- /fact/FADctrl/FAD.cc	(revision 10113)
+++ /fact/FADctrl/FAD.cc	(revision 10114)
@@ -32,9 +32,10 @@
    {"address", &FAD::cmd_address, true, 2, "<range> <value>", "Set addresses in range to value"},
    {"send", &FAD::cmd_send, true, 1, "<value>", "Send arbitrary data to board"},
+   {"take", &FAD::cmd_take, true, 1, "<n> <dir>", "Start run with n events, write to directory"},
    {"acalib", &FAD::cmd_acalib, true, 0, "[n|invalidate|file]", "Perform or read amplitude calibration (n events)"},
    //{"wmode", &FAD::cmd_wmode, 0, "<run|stop>", "Domino wave running or stopped during read out"},
    //{"rmode", &FAD::cmd_rmode, 0, "<first|stop>", "Readout start at first bin or stop position (DRS4)"},
    //{"dmode", &FAD::cmd_dmode, 0, "<single|continuous>", "Domino wave single shot or continuous"},
-   {"cancel", &FAD::cmd_cancel, false, 0, "", "Cancel current operation"},
+   {"cancel", &FAD::cmd_cancel, false, 0, "", "Cancel current operation/run"},
    {"update", &FAD::cmd_update, false, 1, "<sec>", "Minimum delay between updates to DIM event service"},		  
    {"socketmode", &FAD::cmd_socketmode, true, 1, "<com|daq>", "Choose which Sockets are used for data transmission"},		  
@@ -57,4 +58,5 @@
   MainThread = pthread_self();
   Mode = idle;
+  Datafile = -1;
   EventUpdateDelay = atof(GetConfig("EventUpdateDelay", "0.5").c_str());
 
@@ -450,4 +452,31 @@
 
 //
+// Start data run
+// 
+void FAD::cmd_take() {
+
+  time_t Time = time(NULL);
+  struct tm *T = localtime(&Time);
+  char Filename[500];
+
+  // Set number of requested events
+  NumEventsRequested = atoi(Parameter[1].c_str());
+  NumEvents = 0;
+
+  //  Open file with rwx right for owner and group, never overwrite file
+  snprintf(Filename, sizeof(Filename),"%s/%d%02d%02dT%02d%02d%02d.raw", Parameter[2].c_str(), T->tm_year+1900, T->tm_mon+1, T->tm_mday, T->tm_hour, T->tm_min, T->tm_sec);
+
+  Datafile = open(Filename,O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
+  if(Datafile == -1) {
+    PrintMessage("Error: Could not open file \"%s\" (%s)\n", Filename, strerror(errno));
+    return;
+  }
+
+  // Start run
+  Mode = datarun;
+  PrintMessage("Starting run with %d events, filename '%s'\n", NumEventsRequested, Filename);
+}
+
+//
 // Amplitude calibration
 //
@@ -684,8 +713,14 @@
 void FAD::cmd_cancel() {
 
+  static char Stop[] = "stop";
+
   if (Mode == idle) PrintMessage("Nothing to cancel\n");
   else {
+	// Inform event thread to stop run in case datarun active
+	if (write(Pipe[1], Stop, strlen(Stop)+1) == -1) {
+	  Message(ERROR, "write() to Pipe[1] failed in FAD::cmd_cancel() (%s)", strerror(errno));
+	}
+    Cancel = true;
     PrintMessage("Requested cancelation of current operation\n");
-    Cancel = true;
   }
 }
@@ -915,18 +950,21 @@
 
 //
-// DIM event service update thread (publishes M0 format)
+// Event thread (publishes/writes M0 format)
 //
 void FAD::EventThread() {
 
-  struct timeval Time;
+  struct timeval Time, RunStart;
   struct timeval LastUpdate; 
   struct FADBoard::BoardStatus S;
+  vector<unsigned long> EventNumbers(Boards.size());
   double Temp;
   string IDString;
   char Buffer[100];
   int Ret;
+  unsigned long long FileSize = 0;
 
   gettimeofday(&LastUpdate, NULL);
-
+  RunStart = LastUpdate; // only to avoid 'uninitialized' warning from compiler
+  
   // Create DIM event data service
   int EventSize = sizeof(RunHeader)+ Boards.size()*sizeof(BoardStructure)+sizeof(EventHeader) + Boards.size()*(NChips*NChannels*NBins*sizeof(short) + NChips*sizeof(int));
@@ -945,6 +983,5 @@
 
   // M0 RunHeader
-  RHeader->MagicNum = 0xE0E0;
-  RHeader->DataFormat = 1;
+  RHeader->DataFormat = DATA_FORMAT;
   RHeader->RunHeaderSize = sizeof(RunHeader);
   RHeader->EventHeaderSize = sizeof(EventHeader);
@@ -954,9 +991,8 @@
 
   RHeader->Type = 0;				// Run type: 0=data, 1=pedestal, 3=test
-  RHeader->Events = 1;
 
   RHeader->RunNumber = -1;
   RHeader->FileNumber = 0;
-  snprintf(RHeader->Description, sizeof(RHeader->Description), "FADctrl_Event");       
+  snprintf(RHeader->Description, sizeof(RHeader->Description), "FADctrl");       
 
   RHeader->NBoards = Boards.size();
@@ -965,5 +1001,5 @@
   RHeader->Samples = NBins; 			// Always full pipeline
   RHeader->Offset = 0;
-  RHeader->NBytes = 2;
+  RHeader->NBytes = sizeof(short);
 
   // M0 EventHeader
@@ -977,12 +1013,40 @@
 	
 	// Update run and event header with current time
-	gettimeofday(&Time, NULL);	
+	gettimeofday(&Time, NULL);
+
+	RHeader->MagicNum = MAGICNUM_CLOSED;
+	RHeader->EndSecond = Time.tv_sec;			
+	RHeader->EndMicrosecond = Time.tv_usec;		
+
+	EHeader->Second = Time.tv_sec;
+	EHeader->Microsecond = Time.tv_usec;
+
+	// Close data file if requested or requested number of events reached
+	if((IDString.find("stop")!=string::npos || NumEvents==NumEventsRequested) && Mode==datarun) {
+
+	  // Update run header	
+	  RHeader->Events = NumEvents;
+	  RHeader->StartSecond = RunStart.tv_sec;
+	  RHeader->StartMicrosecond = RunStart.tv_usec;		
+
+	  if (lseek(Datafile, 0, SEEK_SET) == -1) {
+	    PrintMessage("Error: Could not rewind file to write updated run header (%s)\n", strerror(errno));
+	  }
+	  else if (write(Datafile, RHeader, sizeof(RunHeader)) != sizeof(RunHeader)) {
+		PrintMessage("Error: Could not write updated run header (%s)\n", strerror(errno));
+	  }
+
+	  // Close data file and terminate run
+	  if(close(Datafile) == -1) PrintMessage("Error: Could not close data file (%s)\n", strerror(errno));
+	  else PrintMessage("Data file closed (size %.1f MByte).\n", FileSize/1024.0/1024);
+
+	  Datafile = -1;
+	  Mode = idle;	  
+	}
+
+	// These values might have changed while close file
 	RHeader->StartSecond = Time.tv_sec;
 	RHeader->StartMicrosecond = Time.tv_usec;		
-	RHeader->EndSecond = Time.tv_sec;			
-	RHeader->EndMicrosecond = Time.tv_usec;		
-
-	EHeader->Second = Time.tv_sec;
-	EHeader->Microsecond = Time.tv_usec;
+    RHeader->Events = 1;
 
 	// Check all boards that have new data
@@ -1003,8 +1067,11 @@
 	  EHeader->TriggerType = S.TriggerType;
 
+	  // Register event number for data writing below
+	  EventNumbers[Brd] = S.TriggerID;
+
 	  // Write trigger cells
 	  for(unsigned int i=0; i<NChips; i++) TriggerCell[Brd*NChips+i] = (int) S.TriggerCell[i];
 
-	  // Write channel data (stored in 12 bit signed twis complement with out-of-range-bit and leading zeroes)
+	  // Write channel data (12 bit signed twis complement with out-of-range-bit and leading zeroes)
 	  int Count = 0;
 	  memset(Data, 0, Boards.size()*NChips*NChannels*NBins*sizeof(short));
@@ -1023,6 +1090,13 @@
 		Count += NBins - S.ROI[Chip][Chan];
 	  }
+
+	  // Inform TCP/IP thread that data has been processed	  
+	  Boards[Brd]->Continue = true;
 	  Boards[Brd]->Unlock();
-	}
+
+	  if ((Ret = pthread_cond_signal(&Boards[Brd]->CondVar)) != 0) {
+		Message(FATAL, "pthread_cond_signal() failed (%s)", strerror(Ret));
+	  }
+	} // Loop over boards
 
 	// Check if DIM service should be updated
@@ -1031,4 +1105,41 @@
 	  EventService->updateService(EventData, EventSize);
 	}
+	
+	// ===== Data writing ===
+	
+	if (Mode != datarun) continue;
+	
+	// Check if all event numbers are the same
+	bool Same = true;
+	for (unsigned int i=0; i<Boards.size(); i++) {
+	  if (Boards[i]->Active && EventNumbers[i] != EventNumbers[0]) Same = false;
+	}
+	if (!Same) continue;
+
+	// Write also run header if this is the first event
+	int Offset;	
+	if (NumEvents == 0) {
+	  RHeader->MagicNum = MAGICNUM_OPEN;
+	  RunStart = Time;
+	  Offset = 0;
+	  FileSize = 0;
+	}
+	else Offset = sizeof(RunHeader) + Boards.size()*sizeof(BoardStructure);
+	
+	// Write data to file
+	if(write(Datafile, EventData+Offset, EventSize-Offset) != (ssize_t) EventSize-Offset) {
+	  PrintMessage("Error: Could not write all data to file, terminating run (%s)\n", strerror(errno));
+
+	  // Close file if error
+	  if (close(Datafile) == -1) PrintMessage("Error: Could not close data file (%s)\n", strerror(errno));
+	  Datafile = -1;
+	  Mode = idle;
+	  continue;
+	}
+	
+	NumEvents++;
+	FileSize += EventSize-Offset;
+	
+	printf("Wrote event %d\n", NumEvents-1);
   }
 
Index: /fact/FADctrl/FAD.h
===================================================================
--- /fact/FADctrl/FAD.h	(revision 10113)
+++ /fact/FADctrl/FAD.h	(revision 10114)
@@ -17,4 +17,5 @@
 #include <sys/time.h>
 #include <limits>
+#include <fcntl.h>
 
 #include "FADBoard.h"
@@ -23,5 +24,5 @@
 const char CALIB_DIRECTORY[] = "~/";
 
-enum ModeType {idle, acalib, tcalib};
+enum ModeType {idle, datarun, acalib};
 
 class FAD: public EvidenceServer {
@@ -44,4 +45,7 @@
 	float EventUpdateDelay;
 
+    int Datafile;
+    int NumEvents;			// Number of event taken            
+    int NumEventsRequested;	// Number of events requested
 	int NumCalibEvents;
 	
@@ -73,4 +77,5 @@
 	void cmd_phase();		void cmd_send();
 	void cmd_cancel();		void cmd_update();
+	void cmd_take();
 
     void EnableDomino();
Index: /fact/FADctrl/FADBoard.cc
===================================================================
--- /fact/FADctrl/FADBoard.cc	(revision 10113)
+++ /fact/FADctrl/FADBoard.cc	(revision 10114)
@@ -19,4 +19,5 @@
   InitOK = false;
   Active = true;
+  Continue = true;
   CommError = false;
   ACalibTime = -1;
@@ -72,4 +73,10 @@
   }
 
+  // Initialise condition variable for synchronization
+  if ((Ret = pthread_cond_init(&CondVar, NULL)) != 0) {
+    m->Message(m->ERROR, "pthread_cond_init() failed (%s)", strerror(Ret));
+	return;
+  }
+
   // Create thread that receives data
   if ((Ret = pthread_create(&Thread, NULL, (void * (*)(void *)) LaunchThread,(void *) this)) != 0) {
@@ -93,4 +100,9 @@
 	if ((Ret = pthread_cancel(Thread)) != 0 && Ret != ESRCH) m->Message(m->ERROR, "pthread_cancel() failed in ~FADBoard() (%s)", strerror(Ret));
 	if ((Ret = pthread_join(Thread, NULL)) != 0) m->Message(m->ERROR, "pthread_join() failed in ~FADBoard (%s)", strerror(Ret));
+  }
+
+  // Delete condition variable 
+  if ((Ret = pthread_cond_destroy(&CondVar)) != 0) {
+	m->Message(m->ERROR, "pthread_cond_destroy() failed in ~FADBoard (%s)", strerror(Ret));
   }
 
@@ -187,4 +199,5 @@
   ssize_t Result;
   struct BoardStatus PrevStatus;
+  int Ret;
 
   memset(&PrevStatus, 0, sizeof(PrevStatus));
@@ -249,4 +262,11 @@
 	  // Lock to avoid concurrent access in GetStatus()
 	  Lock();
+
+	  // Wait until event thread processed the previous data
+	  while (!Continue) {
+		if ((Ret = pthread_cond_wait(&CondVar, &Mutex)) != 0) {
+		  m->Message(m->ERROR, "pthread_cond_wait() failed (%s)", strerror(Ret));
+		}
+	  }
 
 	  gettimeofday(&Status.Update, NULL);
@@ -297,4 +317,5 @@
 	  }
 
+	  Continue = false;
 	  Unlock();
 	  
Index: /fact/FADctrl/FADBoard.h
===================================================================
--- /fact/FADctrl/FADBoard.h	(revision 10113)
+++ /fact/FADctrl/FADBoard.h	(revision 10114)
@@ -75,4 +75,6 @@
 	bool CommError;
 	bool Active;
+	bool Continue;
+	pthread_cond_t CondVar;
 };
 
Index: /fact/FADctrl/History.txt
===================================================================
--- /fact/FADctrl/History.txt	(revision 10113)
+++ /fact/FADctrl/History.txt	(revision 10114)
@@ -6,2 +6,3 @@
 19/1/2011	Implemented secondary calibration.
 21/1/2011	DIM event thread now informed through pipe of new data
+23/1/2011	Data can be written to disk in M0 format
