Index: /fact/FADctrl/FAD.cc
===================================================================
--- /fact/FADctrl/FAD.cc	(revision 10112)
+++ /fact/FADctrl/FAD.cc	(revision 10113)
@@ -59,4 +59,7 @@
   EventUpdateDelay = atof(GetConfig("EventUpdateDelay", "0.5").c_str());
 
+  // Create pipe for data exchange
+  if (pipe(Pipe) == -1) Message(FATAL, "pipe() failed in FAD::FAD() (%s)", strerror(errno));
+
   // DIM console service used in PrintMessage()
   ConsoleOut = new DimService(SERVER_NAME"/ConsoleOut", (char *) "");
@@ -95,4 +98,8 @@
   int Ret;
 
+  // Close pipe (will make read() on pipe in DIM service thread return)
+  if (close(Pipe[0]) == -1) Message(ERROR, "close() on Pipe[0] failed in FAD::~FAD() (%s)", strerror(errno));;
+  if (close(Pipe[1]) == -1) Message(ERROR, "close() on Pipe[1] failed in FAD::~FAD() (%s)", strerror(errno));;
+
   // Wait for DIM service thread to quit
   if (pthread_equal(Thread, pthread_self()) == 0) {
@@ -105,5 +112,5 @@
   delete Command;
   delete ConsoleOut;
-  free(ConsoleText);
+  free(ConsoleText);  
 }
 
@@ -186,11 +193,9 @@
 
 //
-// Switch which sockets are used to send data away
-// case parameter is: "com" - command mode is enabled.
-// 	thus only socket 0 is used
-// case parameter is: "daq" - daq mode is enabled
-//	thus only sockets 1 - 7 are used.
+// Switch socket mode
+// "com" - command mode (only socket 0 is used)
+// "daq" - daq mode (only sockets 1 - 7 are used)
 // 
-//	note: socket 0 is always used to issue commands
+//	Note that socket 0 is always used to issue commands
 //
 void FAD::cmd_socketmode() {
@@ -275,5 +280,6 @@
 	}
   }
-    if (Match(Parameter[1],"enable")) PrintMessage("all active boards accept now incoming triggers\n");
+
+  if (Match(Parameter[1],"enable")) PrintMessage("all active boards accept now incoming triggers\n");
   else if (Match(Parameter[1],"disable")) PrintMessage("no active board accepts any incoming trigger anymore.\n");
  // else PrintUsage();
@@ -485,5 +491,5 @@
 		
 		// Check if correct number of items
-		if (Items.size() != NChips*NChannels*NBins*2 + 3) {
+		if (Items.size() != NChips*NChannels*NBins*3 + 3) {
 		  PrintMessage("Error, data format invalid\n", Parameter[1].c_str());
 		  return;
@@ -500,4 +506,5 @@
 			  Boards[Brd]->Baseline[i][j][k] = atoi(Items[Count++].c_str());
 			  Boards[Brd]->Gain[i][j][k] = atof(Items[Count++].c_str());
+			  Boards[Brd]->SecondaryBaseline[i][j][k] = atof(Items[Count++].c_str());
 			}
 		  }
@@ -571,4 +578,5 @@
 
 	PrintMessage("Board #%d - %s (%sactive)    Communication %s\n", i, Boards[i]->Name, Boards[i]->Active ? "":"in", Boards[i]->CommError ? "ERROR":"OK");
+	PrintMessage("Board ID %d		Firmware revision %d\n", S.BoardID, S.FirmwareRevision);
 	PrintMessage("DAC %d %d %d %d   %d %d %d %d\n", S.DAC[0], S.DAC[1], S.DAC[2], S.DAC[3], S.DAC[4], S.DAC[5], S.DAC[6], S.DAC[7] );
 	PrintMessage("Temperature %.2f %.2f %.2f %.2f", S.Temp[0], S.Temp[1], S.Temp[2], S.Temp[3]);
@@ -585,5 +593,4 @@
 		    GetBoard(i)->GetBoardSerialNumber(),
 		    GetBoard(i)->GetFirmwareVersion(),
-		    GetBoard(i)->GetTemperature(),
 		    ACalibTemp[i]);
 
@@ -660,5 +667,8 @@
 	  break;
 	}
-    else PrintMessage("%-28s%s\n", Buffer, CommandList[i].Help);
+    else {
+	if (strlen(Buffer) < 25) PrintMessage("%-25s%s\n", Buffer, CommandList[i].Help);
+	else PrintMessage("%s\n%-25s%s\n", Buffer, "", CommandList[i].Help);
+	}
 	free(Buffer);
   }
@@ -704,11 +714,4 @@
   unsigned short DACCmd[] = {htons(CMD_Write | (BADDR_DAC + 1)), 0, htons(CMD_Write | (BADDR_DAC + 2)), 0, htons(CMD_Write | (BADDR_DAC + 3)), 0};
 
-  /* Procedure
-
-  5. Issue single trigger and verify settings
-  ...
-  11. Secondary calibration
-*/
-
   PrintMessage("Staring amplitude calibration of all active boards (%d events)\n"
 			   "   Note: No input signals must be connected\n", NumCalibEvents);
@@ -720,5 +723,7 @@
   }
 
-  // Initialise settings for calibration
+  // ====== Part A: Baseline measurement =====
+
+  // Initialise settings for baseline measurement
   for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
 
@@ -729,11 +734,8 @@
 	Status.push_back(Boards[Brd]->GetStatus());
 	
-	// Disarm first, in order to change ROI & DAC settings
-	//Boards[Brd]->Send(CMD_TRIGGERS_OFF);
-
     // Set all ROI to 1024
 	Boards[Brd]->Send(&ROICmd[0], ROICmd.size()*sizeof(unsigned short));
 
-    // Set first DAC value
+    // Set DAC values and start accumulation
     DACCmd[1] = htons(0);
     DACCmd[3] = htons(0);
@@ -741,13 +743,5 @@
 	Boards[Brd]->Send(DACCmd, sizeof(DACCmd));
 
-	// Switch off SCLK
-	//Boards[Brd]->Send(CMD_SCLK_OFF);
-
-	// Arm again, in order to take data
-	//Boards[Brd]->Send(CMD_TRIGGERS_ON);
-
-
-	// Start accumulation
-    Boards[Brd]->AccumulateSum(NumCalibEvents);	
+    Boards[Brd]->AccumulateSum(NumCalibEvents, true);	
   }
 
@@ -762,6 +756,6 @@
   }
 
+  // Determine baseline
   for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
-	// Determine baseline
 	for (unsigned int i=0; i<NChips; i++) for (unsigned int j=0; j<NChannels; j++) {
 	  for (unsigned int k=0; k<NBins; k++) {
@@ -769,12 +763,11 @@
 	  }
 	}
-
-	// Switch on SCLK
-	Boards[Brd]->Send(CMD_SCLK_ON);
-
-	// Disarm first, in order to change ROI & DAC settings
-	//Boards[Brd]->Send(CMD_TRIGGERS_OFF);
-
-	// Set second DAC value
+  }
+  PrintMessage("Baseline measurement finished, next is gain measurement\n");
+
+  // ====== Part B: Gain measurement =====
+
+  // Set new DAC values and start accumulation
+  for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
 	DACCmd[1] = htons(50000);
 	DACCmd[3] = htons(50000);
@@ -782,12 +775,5 @@
 	Boards[Brd]->Send(DACCmd, sizeof(DACCmd));
 
-	// Switch off SCLK
-	//Boards[Brd]->Send(CMD_SCLK_OFF);
-
-	// Arm again
-	//Boards[Brd]->Send(CMD_TRIGGERS_ON);
-
-	// Start accumulation
-    Boards[Brd]->AccumulateSum(NumCalibEvents);	
+    Boards[Brd]->AccumulateSum(NumCalibEvents, true);	
   }
 
@@ -801,9 +787,50 @@
 	}
   }
-
-  // Stop triggering, write back original ROI and DAC settings
+  
+  // Determine gain
   for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
-	// Switch on SCLK
-	Boards[Brd]->Send(CMD_SCLK_ON);
+	for (unsigned int i=0; i<NChips; i++) for (unsigned int j=0; j<NChannels; j++) {
+	  for (unsigned int k=0; k<NBins; k++) {
+		Boards[Brd]->Gain[i][j][k] = (Boards[Brd]->Sum[i][j][k] / NumCalibEvents)-Boards[Brd]->Baseline[i][j][k];
+	  }
+	}
+  }
+  PrintMessage("Gain measurement finished, next is secondary calibration\n");
+
+  // ====== Part C: Secondary calibration =====
+
+  // Initialise settings for secondary calibration and start accumulation
+  for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
+    DACCmd[1] = htons(0);
+    DACCmd[3] = htons(0);
+    DACCmd[5] = htons(0);
+	Boards[Brd]->Send(DACCmd, sizeof(DACCmd));
+
+    Boards[Brd]->AccumulateSum(NumCalibEvents, false);	
+  }
+
+  // Wait until data for all boards taken
+  Done = false;
+  while (!Done && !Cancel) {
+    usleep(300000);
+	for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
+	  Done = true;
+	  if (Boards[Brd]->Active && Boards[Brd]->DoSum) Done = false;
+	}
+  }
+
+  // Determine secondary calibration
+  for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
+	for (unsigned int i=0; i<NChips; i++) for (unsigned int j=0; j<NChannels; j++) {
+	  for (unsigned int k=0; k<NBins; k++) {
+		Boards[Brd]->SecondaryBaseline[i][j][k] = Boards[Brd]->Sum[i][j][k] / (double) NumCalibEvents;
+	  }
+	}
+  }
+
+  // ===== Part D: Finish calibration =====
+ 
+  // Write back original ROI and DAC settings
+  for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
 
 	// Determine gain
@@ -866,5 +893,5 @@
 	  for (unsigned int j=0; j<NChannels; j++) {
 		for (unsigned int k=0; k<NBins; k++) {
-		  fprintf(File, "%d %lf ", Boards[Brd]->Baseline[i][j][k], Boards[Brd]->Gain[i][j][k]);
+		  fprintf(File, "%d %lf %lf ", Boards[Brd]->Baseline[i][j][k], Boards[Brd]->Gain[i][j][k], Boards[Brd]->SecondaryBaseline[i][j][k]);
 		}
 	  }
@@ -894,7 +921,9 @@
   struct timeval Time;
   struct timeval LastUpdate; 
-  bool Update;
   struct FADBoard::BoardStatus S;
   double Temp;
+  string IDString;
+  char Buffer[100];
+  int Ret;
 
   gettimeofday(&LastUpdate, NULL);
@@ -943,6 +972,8 @@
   // Update loop
   while (!ExitRequest) {
-    usleep(EventUpdateDelay*1e6);
-
+    // Wait for data from TCP/IP reading threads
+    if ((Ret=read(Pipe[0], Buffer, sizeof(Buffer))) == -1) Message(FATAL, "read() from Pipe[0] failed in FAD::EventThread() (%s)", strerror(errno));
+	IDString = string(Buffer, Ret);
+	
 	// Update run and event header with current time
 	gettimeofday(&Time, NULL);	
@@ -955,47 +986,46 @@
 	EHeader->Microsecond = Time.tv_usec;
 
-	// Check boards for new data since last update
-	Update = false;
+	// Check all boards that have new data
 	for (unsigned int Brd=0; Brd<Boards.size(); Brd++) {
+	  // Identify board
+	  if (IDString.find(Boards[Brd]->Name) == string::npos) continue;
+
+	  // Fill M0 BoardStructure		
 	  S = Boards[Brd]->GetStatus();
-	  if (S.Update.tv_sec>LastUpdate.tv_sec || ((S.Update.tv_sec==LastUpdate.tv_sec) && (S.Update.tv_usec>LastUpdate.tv_usec))) {
-
-		Update = true;
-
-		// Fill M0 BoardStructure		
-		BStruct[Brd]->SerialNo = S.BoardID;
-		BStruct[Brd]->NomFreq = 2;
-		BStruct[Brd]->BoardTemp = 0;        
-		for (unsigned int i=0; i<NTemp; i++) BStruct[Brd]->BoardTemp += S.Temp[i]/NTemp;
-		BStruct[Brd]->ScaleFactor = 1/2.048;     
-
-		// Update event header with ID and Type of current board
-		EHeader->EventNumber = S.TriggerID;
-		EHeader->TriggerType = S.TriggerType;
-
-		// 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)
-		int Count = 0;
-		memset(Data, 0, Boards.size()*NChips*NChannels*NBins*sizeof(short));
-
-		Boards[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]->ACalibTime == -1) Data[Count++] = Boards[Brd]->Data[Chip][Chan][i];
-			else {
-		      Temp = (Boards[Brd]->Data[Chip][Chan][i] - Boards[Brd]->Baseline[Chip][Chan][(i+S.TriggerCell[Chip])%NBins]);
-			  Temp *= Boards[Brd]->Gain[Chip][Chan][0]/Boards[Brd]->Gain[Chip][Chan][(i+S.TriggerCell[Chip])%NBins];
-			  Data[Count++] = (short) Temp;
-			}
+	  BStruct[Brd]->SerialNo = S.BoardID;
+	  BStruct[Brd]->NomFreq = 2;
+	  BStruct[Brd]->BoardTemp = 0;        
+	  for (unsigned int i=0; i<NTemp; i++) BStruct[Brd]->BoardTemp += S.Temp[i]/NTemp;
+	  BStruct[Brd]->ScaleFactor = 1/2.048;     
+
+	  // Update event header with ID and Type of current board
+	  EHeader->EventNumber = S.TriggerID;
+	  EHeader->TriggerType = S.TriggerType;
+
+	  // 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)
+	  int Count = 0;
+	  memset(Data, 0, Boards.size()*NChips*NChannels*NBins*sizeof(short));
+
+	  Boards[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]->ACalibTime == -1) Data[Count++] = Boards[Brd]->Data[Chip][Chan][i];
+		  else {
+		    Temp = (Boards[Brd]->Data[Chip][Chan][i] - Boards[Brd]->Baseline[Chip][Chan][(i+S.TriggerCell[Chip])%NBins]);
+			Temp *= Boards[Brd]->Gain[Chip][Chan][0]/Boards[Brd]->Gain[Chip][Chan][(i+S.TriggerCell[Chip])%NBins];
+			//Temp -= Boards[Brd]->SecondaryBaseline[Chip][Chan][i];
+			Data[Count++] = (short) Temp;
 		  }
-		  Count += NBins - S.ROI[Chip][Chan];
 		}
-		Boards[Brd]->Unlock();
+		Count += NBins - S.ROI[Chip][Chan];
 	  }
-	}
-
-	if (Update) {
+	  Boards[Brd]->Unlock();
+	}
+
+	// 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);
Index: /fact/FADctrl/FAD.h
===================================================================
--- /fact/FADctrl/FAD.h	(revision 10112)
+++ /fact/FADctrl/FAD.h	(revision 10113)
@@ -62,15 +62,15 @@
     ~FAD();
 
-		void cmd_exit();			void cmd_help();
-		void cmd_board();			void cmd_status();
-		void cmd_acalib();		void cmd_serial();
-		void cmd_trigger(); 	void cmd_socketmode();
-		void cmd_srclk();			void cmd_sclk();
-		void cmd_dwrite();		void cmd_domino();
-		void cmd_wmode();			void cmd_rmode();
-		void cmd_dmode();			void cmd_dac();
-		void cmd_roi();				void cmd_address();
-		void cmd_phase();			void cmd_send();
-		void cmd_cancel();		void cmd_update();
+	void cmd_exit();		void cmd_help();
+	void cmd_board();		void cmd_status();
+	void cmd_acalib();		void cmd_serial();
+	void cmd_trigger(); 	void cmd_socketmode();
+	void cmd_srclk();		void cmd_sclk();
+	void cmd_dwrite();		void cmd_domino();
+	void cmd_wmode();		void cmd_rmode();
+	void cmd_dmode();		void cmd_dac();
+	void cmd_roi();			void cmd_address();
+	void cmd_phase();		void cmd_send();
+	void cmd_cancel();		void cmd_update();
 
     void EnableDomino();
@@ -82,4 +82,6 @@
     bool ReadCalibration();
     void PrintMessage(const char*, ...);
+	
+	int Pipe[2];
 };
 
Index: /fact/FADctrl/FADBoard.cc
===================================================================
--- /fact/FADctrl/FADBoard.cc	(revision 10112)
+++ /fact/FADctrl/FADBoard.cc	(revision 10113)
@@ -89,7 +89,7 @@
   int Ret;
 
-  // Cancel thread and wait for it to quit
+  // Cancel thread (if it did not quit already) and wait for it to quit
   if (pthread_equal(Thread, pthread_self()) == 0) {
-	if ((Ret = pthread_cancel(Thread)) != 0) m->Message(m->ERROR, "pthread_cancel() failed in ~FADBoard() (%s)", strerror(Ret));
+	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));
   }
@@ -164,9 +164,10 @@
 // Initiate average
 //
-void FADBoard::AccumulateSum(unsigned int n) {
+void FADBoard::AccumulateSum(unsigned int n, bool Rotate) {
 
   if (!Active) return;
   
   Lock();
+  SumPhysPipeline = Rotate;
   memset(Sum, 0, sizeof(Sum));
   NumForSum = n;
@@ -253,4 +254,5 @@
 	  // Extract ID and type information
 	  Status.BoardID = ntohl(Header->board_id);
+	  Status.FirmwareRevision = ntohl(Header->version_no);
 	  Status.TriggerID = ntohl(Header->local_trigger_id);
 	  Status.TriggerType = ntohs(Header->local_trigger_type);
@@ -287,5 +289,6 @@
 		for (unsigned int Chip=0; Chip<NChips; Chip++) for (unsigned int Chan=0; Chan<NChannels; Chan++) {
 		  for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
-			Sum[Chip][Chan][(i+Status.TriggerCell[Chip]) % NBins] += Data[Chip][Chan][i];
+			if (SumPhysPipeline) Sum[Chip][Chan][(i+Status.TriggerCell[Chip]) % NBins] += Data[Chip][Chan][i];
+			else Sum[Chip][Chan][i] = Data[Chip][Chan][i]-Baseline[Chip][Chan][(i-Status.TriggerCell[Chip]) % NBins];
 		  }
 		}
@@ -312,4 +315,10 @@
 	else printf("End package flag incorrect, removing corrupt event\n");
 
+	// Inform event thread of new data
+	if (write(m->Pipe[1], Name, strlen(Name)+1) == -1) {
+	  m->Message(m->ERROR, "write() to Pipe[1] failed in class FADBoard (%s)", strerror(errno));
+	  m->ExitRequest = true;
+	}
+
 	// Remove event data from internal buffer
 	memmove(Buffer, Buffer+Length, Pos-Length);
Index: /fact/FADctrl/FADBoard.h
===================================================================
--- /fact/FADctrl/FADBoard.h	(revision 10112)
+++ /fact/FADctrl/FADBoard.h	(revision 10113)
@@ -42,4 +42,5 @@
 	struct BoardStatus {
 	  unsigned short BoardID;
+	  unsigned short FirmwareRevision;
 	  unsigned long TriggerID;
 	  unsigned char TriggerType;
@@ -54,4 +55,5 @@
 	short Baseline[NChips][NChannels][NBins];
 	double Gain[NChips][NChannels][NBins];
+	double SecondaryBaseline[NChips][NChannels][NBins];
 	float ACalibTemp;
 	time_t ACalibTime;
@@ -60,9 +62,10 @@
 	unsigned int NumForSum;
 	bool DoSum;
+	bool SumPhysPipeline;
 
 	void Send(const void *, size_t);
 	void Send(unsigned short);
 	struct BoardStatus GetStatus();
-	void AccumulateSum(unsigned int);
+	void AccumulateSum(unsigned int, bool);
 	void Lock();
 	void Unlock();
Index: /fact/FADctrl/History.txt
===================================================================
--- /fact/FADctrl/History.txt	(revision 10112)
+++ /fact/FADctrl/History.txt	(revision 10113)
@@ -4,2 +4,4 @@
 5/1/2011	First version of amplitude calibration (no secondary calibration, yet). New 'socketmode' command.
 13/1/2011	Amplitude calibration data is written to text file.
+19/1/2011	Implemented secondary calibration.
+21/1/2011	DIM event thread now informed through pipe of new data
