Index: fact/FADctrl/FAD.cc
===================================================================
--- fact/FADctrl/FAD.cc	(revision 10813)
+++ fact/FADctrl/FAD.cc	(revision 10913)
@@ -30,10 +30,10 @@
    {"reset", &FAD::cmd_reset, true, 0, "", "Reset internal trigger counter"},
    {"runnumber", &FAD::cmd_runnumber, true, 1, "<n>", "Set runnumber"},
-   {"roi", &FAD::cmd_roi, true, 2, "<channel range> <value>", "Set region-of-interest to value"},
+   {"roi", &FAD::cmd_roi, true, 2, "<range> <value>", "Set ROI to for channel range to value"},
    {"dac", &FAD::cmd_dac, true, 2, "<range> <value>", "Set DAC numbers in range to value"},
    {"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)"},
+   {"take", &FAD::cmd_take, true, 1, "<n> <dir>", "Start run with n events (n=0 -> unlimited)"},
+   {"acalib", &FAD::cmd_acalib, true, 0, "[n|inval|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)"},
@@ -827,30 +827,31 @@
 void FAD::EventThread() {
 
-  struct timeval Time, RunStart;
+  struct timeval Time;
   struct timeval LastUpdate; 
   struct FADBoard::BoardStatus S;
   vector<unsigned long> EventNumbers(Boards.size());
   vector<bool> AcalibDone(Boards.size());
+  map<unsigned int, class FADBoard *> ActiveBoards;
   double Temp;
   string IDString;
   char Buffer[100];
   int Ret;
-  unsigned long long FileSize = 0;
+  struct stat FileStat;
+  float FileSizeMB = 0;
+  RunHeader FileRHeader;
 
   gettimeofday(&LastUpdate, NULL);
-  RunStart = LastUpdate; // only to avoid 'uninitialized' warning from compiler
   
   // Create DIM event data and number services
-  int EventSize = sizeof(RunHeader)+ Boards.size()*sizeof(BoardStructure)+sizeof(EventHeader) + Boards.size()*(NChips*NChannels*NBins*sizeof(short) + NChips*sizeof(int));
-  char *EventData = new char [EventSize];
-
-  memset(EventData, 0, EventSize);
+  char *EventData = new char [sizeof(RunHeader)+ Boards.size()*sizeof(BoardStructure)+sizeof(EventHeader) + Boards.size()*(NChips*NChannels*NBins*sizeof(short) + NChips*sizeof(int))];
 
   DimService EventService(SERVER_NAME"/EventData", (char *) "C", NULL, 0);
   DimService EventNumService(SERVER_NAME"/EventNumber", NumEvents);
-
-  // Calculate pointers to EventData array
+  DimService FileSizeService(SERVER_NAME"/FileSizeMB", FileSizeMB);
+
+  // Calculate pointers to EventData array (will be updated when active number of boards changes)
   RunHeader *RHeader = (RunHeader *) EventData;
   BoardStructure **BStruct = new BoardStructure * [Boards.size()];
+
   for (unsigned int i=0; i<Boards.size(); i++) BStruct[i] = ((BoardStructure *) (RHeader + 1)) + i;
   EventHeader *EHeader = (EventHeader *) ((char *) (RHeader + 1) + Boards.size()*sizeof(BoardStructure));
@@ -858,5 +859,6 @@
   short *Data = (short *) (TriggerCell + NChips*Boards.size());
 
-  // M0 RunHeader
+  // Fill fixed entries in M0 RunHeader
+  RHeader->MagicNum = MAGICNUM_CLOSED;
   RHeader->DataFormat = DATA_FORMAT;
   RHeader->RunHeaderSize = sizeof(RunHeader);
@@ -865,12 +867,11 @@
   RHeader->SoftwareRevision = atoi(REVISION) * (strchr(REVISION, 'M')==NULL ? 1:-1);
   RHeader->Identification = 0;
-
   RHeader->Type = 0;				// Run type: 0=data, 1=pedestal, 3=test
-
   RHeader->RunNumber = -1;
   RHeader->FileNumber = 0;
   snprintf(RHeader->Description, sizeof(RHeader->Description), "FADctrl");       
-
-  RHeader->NBoards = Boards.size();
+  RHeader->Events = 1;
+  RHeader->StartSecond = LastUpdate.tv_sec;			
+  RHeader->StartMicrosecond = LastUpdate.tv_usec;		
   RHeader->NChips = NChips;
   RHeader->NChannels = NChannels;
@@ -879,7 +880,4 @@
   RHeader->NBytes = sizeof(short);
 
-  // M0 EventHeader
-  EHeader->EventSize = Boards.size()*(NChips*NChannels*NBins*sizeof(short) + NChips*sizeof(int));
-
   // Update loop
   while (!ExitRequest) {
@@ -896,5 +894,18 @@
 	IDString.append(string(Buffer, Ret));
 
-	// If amplitude calibration mode, check if board finished procedure
+	// Active boards for DIM and data taking must only change when idle
+	if (Mode == idle) {
+	  ActiveBoards.clear();
+	  for (unsigned int i=0; i<Boards.size(); i++) if (Boards[i]->Active) ActiveBoards[i] = Boards[i];
+	  RHeader->NBoards = ActiveBoards.size();
+	  
+	  // Calculate updated pointers to EventData array
+	  for (unsigned int i=0; i<ActiveBoards.size(); i++) BStruct[i] = ((BoardStructure *) (RHeader + 1)) + i;
+	  EHeader = (EventHeader *) ((char *) (RHeader + 1) + ActiveBoards.size()*sizeof(BoardStructure));
+	  TriggerCell = (int *) (EHeader + 1);
+	  Data = (short *) (TriggerCell + NChips*ActiveBoards.size());
+	}
+
+	// If amplitude calibration mode, check if all boards finished procedure
 	if (Mode == acalib) {
 	  bool Done = true;
@@ -912,50 +923,19 @@
 	else for (unsigned int i=0; i<Boards.size(); i++) AcalibDone[i] = false;
 
-	// Update run and event header with current time
+	// Update run and event header
 	gettimeofday(&Time, NULL);
-
-	RHeader->MagicNum = MAGICNUM_CLOSED;
 	RHeader->EndSecond = Time.tv_sec;			
 	RHeader->EndMicrosecond = Time.tv_usec;		
 
+    EHeader->EventSize = RHeader->NBoards * (NChips*NChannels*NBins*sizeof(short) + NChips*sizeof(int));
 	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) {
-	    Message(ERROR, "Could not rewind file to write updated run header (%s)", strerror(errno));
-	  }
-	  else if (write(Datafile, RHeader, sizeof(RunHeader)) != sizeof(RunHeader)) {
-		Message(ERROR, "Could not write updated run header (%s)", strerror(errno));
-	  }
-
-	  // Close data file and terminate run
-	  if(close(Datafile) == -1) Message(ERROR, "Could not close data file (%s)", strerror(errno));
-	  else PrintMessage("Data file closed (size %.1f MByte).\n", FileSize/1024.0/1024);
-
-	  Datafile = -1;
-	  Mode = idle;
-	  Message(INFO, "Data run ended, mode set to IDLE");	  
-	}
-
-	// These values might have changed while close file
-	RHeader->StartSecond = Time.tv_sec;
-	RHeader->StartMicrosecond = Time.tv_usec;		
-    RHeader->Events = 1;
-
 	// Check all boards that have new data
-	for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
-	  // Identify board
+	for (unsigned int Brd=0; Brd<ActiveBoards.size(); Brd++) {
 	  if (IDString.find(string("EVENT")+Boards[Brd]->Name) == string::npos) continue;
 
 	  // Fill M0 BoardStructure		
-	  S = Boards[Brd]->GetStatus();
+	  S = ActiveBoards[Brd]->GetStatus();
 	  BStruct[Brd]->SerialNo = (U32) S.DNA;
 	  BStruct[Brd]->NomFreq = S.Frequency;
@@ -978,12 +958,12 @@
 	  memset(Data+Count, 0, NChips*NChannels*NBins*sizeof(short));
 
-	  Boards[Brd]->Lock();
+	  ActiveBoards[Brd]->Lock();
 	  for (unsigned int Chip=0; Chip<NChips; Chip++) for (unsigned int Chan=0; Chan<NChannels; Chan++) {
 		for (int i=0; i<S.ROI[Chip][Chan]; i++) {
-		  if (Boards[Brd]->ACalib.Time == -1) Data[Count++] = Boards[Brd]->Data[Chip][Chan][i];
+		  if (ActiveBoards[Brd]->ACalib.Time == -1) Data[Count++] = ActiveBoards[Brd]->Data[Chip][Chan][i];
 		  else {
-		    Temp = (Boards[Brd]->Data[Chip][Chan][i] - Boards[Brd]->ACalib.Baseline[Chip][Chan][(i+S.TriggerCell[Chip])%NBins]);
-			Temp *= Boards[Brd]->ACalib.Gain[Chip][Chan][0]/Boards[Brd]->ACalib.Gain[Chip][Chan][(i+S.TriggerCell[Chip])%NBins];
-			//Temp -= Boards[Brd]->ACalib.Secondary[Chip][Chan][i];
+		    Temp = (ActiveBoards[Brd]->Data[Chip][Chan][i] - ActiveBoards[Brd]->ACalib.Baseline[Chip][Chan][(i+S.TriggerCell[Chip])%NBins]);
+			Temp *= ActiveBoards[Brd]->ACalib.Gain[Chip][Chan][0]/ActiveBoards[Brd]->ACalib.Gain[Chip][Chan][(i+S.TriggerCell[Chip])%NBins];
+			//Temp -= ActiveBoards[Brd]->ACalib.Secondary[Chip][Chan][i];
 			Data[Count++] = (short) Temp;
 		  }
@@ -991,6 +971,10 @@
 		Count += NBins - S.ROI[Chip][Chan];
 	  }
-
-	  // Inform TCP/IP thread that data has been processed	  
+  	  ActiveBoards[Brd]->Unlock();
+	}
+
+	// Inform TCP/IP thread of all boards that send data that processing is finished
+	for (unsigned int Brd=0; Brd<Boards.size(); Brd++) if (IDString.find(string("EVENT")+Boards[Brd]->Name) != string::npos) {
+	  Boards[Brd]->Lock();
 	  Boards[Brd]->Continue = true;
 	  Boards[Brd]->Unlock();
@@ -999,15 +983,15 @@
 		Message(FATAL, "pthread_cond_signal() failed (%s)", strerror(Ret));
 	  }
-	} // Loop over boards
+	}
 
 	// Check if DIM service should be updated
 	if ((Time.tv_sec-LastUpdate.tv_sec)*1e6 + Time.tv_usec-LastUpdate.tv_usec > EventUpdateDelay*1e6) {
 	  gettimeofday(&LastUpdate, NULL);
-	  EventService.updateService(EventData, EventSize);
+	  EventService.updateService(EventData, sizeof(RunHeader) + sizeof(EventHeader) + ActiveBoards.size()*(sizeof(BoardStructure) + NChips*NChannels*NBins*sizeof(short) + NChips*sizeof(int)));
 	  EventNumService.updateService();
+	  if (Mode == datarun) FileSizeService.updateService();
 	}
 	
-	// ===== Data writing ===
-	
+	// ===== Data writing ===	
 	if (Mode != datarun) continue;
 	
@@ -1024,19 +1008,54 @@
 	if (CommonEventNum == numeric_limits<unsigned long>::max()) continue;
 
-	// Write also run header if this is the first event
-	int Offset;	
+	int Error = 0;
+
+	// Initialize run
 	if (NumEvents == 0) {
-	  RHeader->MagicNum = MAGICNUM_OPEN;
-	  RunStart = Time;
-	  Offset = 0;
-	  FileSize = 0;
-	}
-	else Offset = sizeof(RunHeader) + Boards.size()*sizeof(BoardStructure);
+	  FileSizeMB = 0;
+
+	  FileRHeader = *RHeader;
+	  FileRHeader.MagicNum = MAGICNUM_OPEN;
+	  FileRHeader.StartSecond = Time.tv_sec;
+	  FileRHeader.StartMicrosecond = Time.tv_usec;		
+
+	  // Write run header and board structures
+	  if (write(Datafile, &FileRHeader, sizeof(RunHeader)) == -1) Error = errno;
+	  else if (write(Datafile, BStruct[0], FileRHeader.NBoards*sizeof(BoardStructure)) == -1) Error = errno;
+	}
+
+	// Write event header, trigger cells and ADC data to file
+	if (write(Datafile, EHeader, sizeof(EventHeader)+NChips*sizeof(int)+ActiveBoards.size()*NChips*NChannels*NBins*sizeof(short)) == -1) Error = errno;
+
+	NumEvents++;
+
+	// Write event header to file
+	//if(write(Datafile, EHeader, sizeof(EventHeader)) != sizeof(EventHeader)) Error = true;
+
+	// Write trigger cells
+	//for (unsigned int i=0; i<ActiveBoards.size(); i++) {
+	  //if(write(Datafile, TriggerCell + i*NChips, NChips*sizeof(int)) != NChips*sizeof(int)) Error = true;
+	//}
+
+	// Write ADC data
+	//unsigned int Bins = NChips*NChannels*NBins;
+	//for (unsigned int i=0; i<ActiveBoards.size(); i++) {
+	  //if(write(Datafile, Data+i*Bins, Bins*sizeof(short)) != (ssize_t) (Bins*sizeof(short))) Error = true;
+	//}
 	
-	// Write data to file
-	if(write(Datafile, EventData+Offset, EventSize-Offset) != (ssize_t) EventSize-Offset) {
-	  Message(ERROR, "Could not write all data to file, terminating run, setting mode to IDLE (%s)", strerror(errno));
-
-	  // Close file if error
+	// Update file size
+	if (fstat(Datafile, &FileStat) == -1) Error = errno;
+    else FileSizeMB = FileStat.st_size/1024.0/1024.0;
+
+	// Check for write errors and for correct file size
+	if (Error !=0) {
+	  Message(ERROR, "Error writing to data data file (%s), terminating run, setting mode to IDLE", strerror(Error));
+	}
+	else if ((size_t) FileStat.st_size != sizeof(RunHeader)+ FileRHeader.NBoards*sizeof(BoardStructure)+NumEvents*(sizeof(EventHeader) + FileRHeader.NBoards*(NChips*NChannels*NBins*sizeof(short) + NChips*sizeof(int)))) {
+	  Message(ERROR, "Could not write all data to file, terminating run, setting mode to IDLE");
+	  Error = 1;
+	}
+
+	// Close file if error
+	if (Error != 0) {
 	  if (close(Datafile) == -1) Message(ERROR, "Could not close data file (%s)", strerror(errno));
 	  Datafile = -1;
@@ -1045,11 +1064,32 @@
 	}
 	
-	NumEvents++;
-	FileSize += EventSize-Offset;
+	// Close data file if requested or requested number of events reached
+	if(IDString.find("stop")!=string::npos || (NumEvents==NumEventsRequested && NumEventsRequested!=0)) {
+
+	  // Update run header for writing	
+	  FileRHeader.MagicNum = MAGICNUM_CLOSED; 
+	  FileRHeader.Events = NumEvents;
+	  FileRHeader.EndSecond = Time.tv_sec;			
+	  FileRHeader.EndMicrosecond = Time.tv_usec;		
+
+	  if (lseek(Datafile, 0, SEEK_SET) == -1) {
+	    Message(ERROR, "Could not rewind file to write updated run header (%s)", strerror(errno));
+	  }
+	  else if (write(Datafile, &FileRHeader, sizeof(RunHeader)) != sizeof(RunHeader)) {
+		Message(ERROR, "Could not write updated run header (%s)", strerror(errno));
+	  }
+
+	  // Close data file and terminate run
+	  if(close(Datafile) == -1) Message(ERROR, "Could not close data file (%s)", strerror(errno));
+	  else PrintMessage("Data file closed (size %.1f MByte).\n", FileSizeMB);
+
+	  Datafile = -1;
+	  Mode = idle;
+	  Message(INFO, "Data run ended, mode set to IDLE");	  
+	}
   }
 
   delete[] BStruct;
   delete[] EventData;
-
 }
 
Index: fact/FADctrl/History.txt
===================================================================
--- fact/FADctrl/History.txt	(revision 10813)
+++ fact/FADctrl/History.txt	(revision 10913)
@@ -30,2 +30,3 @@
 			cancelled
 25/5/2011	dcm_lock and dcm_ready bits were incorrectly evaluated.
+3/6/2011	Raw data files will only contain boards active at the start of the run.
