Index: fact/FADctrl/FAD.cc
===================================================================
--- fact/FADctrl/FAD.cc	(revision 12891)
+++ fact/FADctrl/FAD.cc	(revision 14174)
@@ -617,12 +617,6 @@
 void FAD::cmd_dynrange() {
 
-  // Set number of events required for measurement
-  if (Parameter.size()==1 || !ConvertToInt(Parameter[1], &NumEventsRequested) || NumEventsRequested<=0) {
-	NumEventsRequested = DEFAULT_NUM_CALIB_EVENTS;
-  }
-
-  // Start calibration by setting mode
   Mode = dynrange;
-  Message(INFO, "Starting determination of dynamic range with %d events", NumEventsRequested);
+  Message(INFO, "Starting determination of dynamic range");
 }
 
@@ -667,5 +661,5 @@
 	else if (Mode == acalib) PrintMessage("Current mode is ACALIB (3x%d events, slowest board %d has %d events)\n", NumEventsRequested, SlowestBoard, MinCount);
 	else if (Mode == datarun) PrintMessage("Current mode is DATARUN (%d events requested, %d events taken)\n", NumEventsRequested, NumEvents);
-	else if (Mode == dynrange) PrintMessage("Current mode is DYNRANGE (%d events requested)\n", NumEventsRequested);
+	else if (Mode == dynrange) PrintMessage("Current mode is DYNRANGE\n");
 	return;
   }    
@@ -957,5 +951,5 @@
 
 	// If amplitude calibration mode, check if all boards finished procedure
-	if (Mode == acalib) {
+	if (Mode == acalib || Mode == dynrange) {
 	  bool Done = true;
 	  for (unsigned int i=0; i<Boards.size(); i++) {
@@ -965,7 +959,12 @@
 	  // Amplitude calibration finished?
 	  if (Done) {
-	    SaveAmplitudeCalibration();
+	    if (Mode == acalib) {
+		  SaveAmplitudeCalibration();
+		  Message(INFO, "Amplitude calibration done, mode set to IDLE");
+		}
+	    if (Mode == dynrange) {
+		  Message(INFO, "Dynamic range measurement done, mode set to IDLE");
+		}		
 		Mode = idle;
-		Message(INFO, "Amplitude calibration done, mode set to IDLE");
 	  }
 	}
Index: fact/FADctrl/FADBoard.cc
===================================================================
--- fact/FADctrl/FADBoard.cc	(revision 12891)
+++ fact/FADctrl/FADBoard.cc	(revision 14174)
@@ -168,13 +168,13 @@
   unsigned short DACCmd[] = {htons(CMD_Write | (BADDR_DAC + 1)), 0, htons(CMD_Write | (BADDR_DAC + 2)), 0, htons(CMD_Write | (BADDR_DAC + 3)), 0, htons(CMD_Execute) };
   string Message = string("ACALIBDONE")+Name+"\n";
-
+  
   switch (State) {
+  // *******************************************************************
+  // ******************   AMPLITUDE CALIBRATION    *********************   
+  // *******************************************************************
+
   // ====== Part A: Check if amplitude calibration should start and initialise =====
   case standbye:
-	if (m->Mode != m->acalib) break;
-
-	// Invalidate current calibration
-	ACalib.Time = -1;
-	Count = 0;
+	if (m->Mode != m->acalib && m->Mode != m->dynrange) break;
 
 	// Save initial board status, set all ROIs to 1024 and set DAC values (no triggers while setting ROI)
@@ -188,13 +188,28 @@
 	Send(&ROICmd[0], ROICmd.size()*sizeof(unsigned short));
 
-	DACCmd[1] = htons(0);
-	DACCmd[3] = htons(0);
-	DACCmd[5] = htons(0);
-	Send(DACCmd, sizeof(DACCmd));
-
-	// Clear sum vector and set state to accumulate
-	memset(Sum, 0, sizeof(Sum));
-	State = baseline;
-	SetStatus("Starting calilbration");
+	if (m->Mode == m->acalib) {
+	  // Set DAC to zero
+	  DACCmd[1] = htons(0);
+	  DACCmd[3] = htons(0);
+	  DACCmd[5] = htons(0);
+	  Send(DACCmd, sizeof(DACCmd));
+
+	  // Invalidate current calibration
+	  ACalib.Time = -1;
+	  Count = 0;
+
+	  // Clear sum vector and set state to accumulate
+	  memset(Sum, 0, sizeof(Sum));
+	  State = baseline;
+	  SetStatus("Starting calilbration");
+	}
+
+	if (m->Mode == m->dynrange) {
+	  // No amplitude calibration allowed!
+	  DAC_DR = 0;
+	  Delta_DAC = 1000;
+	  State = setdac;
+	}
+	
 	break;
 
@@ -317,31 +332,4 @@
 	for (unsigned int i=0; i<NTemp; i++) ACalib.Temp += Status.Temp[i] / NTemp;
 
-	// Inform event thread that calibration is finished for this board
-	if (write(m->Pipe[1], Message.data(), Message.size()) == -1) {
-	  m->Message(m->ERROR, "write() to Pipe[1] failed in class FADBoard::AmplitudeCalibration (%s)", strerror(errno));
-	}
-
-	SetStatus("Finished calibration");
-	State = cleanup;
-	break;
-
-  // ====== Part E: Write back original ROI and DAC settings =====
-  case cleanup:
-    // ROI values
-
-	ROICmd.clear();
-	for (unsigned int i=0; i<NChips*NChannels; i++) {
-	  ROICmd.push_back(htons(CMD_Write | (BADDR_ROI + i)));
-	  ROICmd.push_back(htons(InitialStatus.ROI[i/NChannels][i%NChannels]));
-	}
-	ROICmd.push_back(htons(CMD_Execute));
-	Send(&ROICmd[0], ROICmd.size()*sizeof(unsigned short));
-
-	// DAC values
-	DACCmd[1] = htons(InitialStatus.DAC[1]);
-	DACCmd[3] = htons(InitialStatus.DAC[2]);
-	DACCmd[5] = htons(InitialStatus.DAC[3]);
-  	Send(DACCmd, sizeof(DACCmd));
-	
 	// Update DIM service with calibration information
 	for (unsigned int i=0; i<NChips; i++) {
@@ -356,4 +344,32 @@
 	DIM_ACalData->updateService(ACalData, 3*NChips*NChannels*NBins*sizeof(float));
 
+	SetStatus("Finished calibration");
+	State = cleanup;
+	break;
+
+  // ====== Part E: Write back original ROI and DAC settings =====
+  case cleanup:
+    // ROI values
+
+	ROICmd.clear();
+	for (unsigned int i=0; i<NChips*NChannels; i++) {
+	  ROICmd.push_back(htons(CMD_Write | (BADDR_ROI + i)));
+	  ROICmd.push_back(htons(InitialStatus.ROI[i/NChannels][i%NChannels]));
+	}
+	ROICmd.push_back(htons(CMD_Execute));
+	Send(&ROICmd[0], ROICmd.size()*sizeof(unsigned short));
+
+	// DAC values
+	DACCmd[1] = htons(InitialStatus.DAC[1]);
+	DACCmd[3] = htons(InitialStatus.DAC[2]);
+	DACCmd[5] = htons(InitialStatus.DAC[3]);
+  	Send(DACCmd, sizeof(DACCmd));
+
+	// Inform event thread that calibration is finished for this board
+	if (write(m->Pipe[1], Message.data(), Message.size()) == -1) {
+	  m->Message(m->ERROR, "write() to Pipe[1] failed in class FADBoard::AmplitudeCalibration (%s)", strerror(errno));
+	}
+
+	SetStatus("Cleaning up");	
 	State = wait;
 	break;
@@ -363,6 +379,105 @@
 	if (m->Mode == m->idle) State = standbye;
 	break;
-  }
-}  
+  
+  
+  // ************************************************************************
+  // ******************   DYNAMIC RANGE DETERMINATION   *********************   
+  // ************************************************************************
+  
+  // ====== Set calibration DACs 1-3 =====
+  case setdac:
+	// Check for stopping
+	if (m->Mode != m->dynrange) {
+	  State = cleanup;
+	  break;
+	}
+
+	// Set new DAC values
+	DACCmd[1] = htons(DAC_DR);
+	DACCmd[3] = htons(DAC_DR);
+	DACCmd[5] = htons(DAC_DR);
+	Send(DACCmd, sizeof(DACCmd));
+
+	SetStatus("Dynamic range: DACs 1-3 at %u", DAC_DR);
+	State = measure;
+	break;
+
+  // ====== Determine mean and sigma =====
+  case measure:
+	// Check for stopping
+	if (m->Mode != m->dynrange) {
+	  State = cleanup;
+	  break;
+	}
+
+	// Check if current event has correct DAC values
+    if (Status.DAC[1] != DAC_DR || Status.DAC[2] != DAC_DR || Status.DAC[3] != DAC_DR) break;
+
+	// Discard first few events with correct DAC setting (can still have wrong voltage)
+	if (Count_DR++ < 2) break;
+	Count_DR = 0;
+	
+	bool Clip;
+
+	// Evaluate current event for all channels
+	for (unsigned int Chip=0; Chip<NChips; Chip++) {
+	  for (unsigned int Chan=0; Chan<NChannels; Chan++) {
+	    Clip = false;
+		Mean[Chip][Chan] = 0;
+		
+		// Determine mean value and check if CLIP_LEVEL exceeded
+		for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
+		  Mean[Chip][Chan] += Data[Chip][Chan][i] / Status.ROI[Chip][Chan];
+		  if (abs(Data[Chip][Chan][i]) >= CLIP_LEVEL) Clip = true; 
+		}
+	  }
+	}
+	
+	// If clipping occurred, continue to increase/decrease DAC until at 16-bit limit
+	if (Clip) {
+	  if (DAC_DR + Delta_DAC < 0 || DAC_DR + Delta_DAC > 65535) State = cleanup;
+	  else { 
+		DAC_DR += Delta_DAC;
+		State = setdac;
+	  }
+	  break;
+	}
+
+	// Start again from maximum DAC value downwards
+	if (Delta_DAC > 0) {
+	  for (unsigned int Chip=0; Chip<NChips; Chip++) {
+		for (unsigned int Chan=0; Chan<NChannels; Chan++) Mean_low[Chip][Chan] = Mean[Chip][Chan];
+	  }
+	  DAC_low = DAC_DR;
+	  DAC_DR = 65535;
+	  Delta_DAC = -1000;
+	  State = setdac;
+	  break;
+	}
+
+	// Procedure finished
+	double Sigma;
+	printf("Extrapolated DAC values for range with 1-sigma\nclearance to ADC count level +/-%u\n", CLIP_LEVEL);
+
+	for (unsigned int Chip=0; Chip<NChips; Chip++) {
+	  for (unsigned int Chan=0; Chan<NChannels; Chan++) {
+	  
+	    // Calculate baseline sigma for current event
+		Sigma = 0;
+	  	for (int i=0; i<Status.ROI[Chip][Chan]; i++) Sigma += pow(Data[Chip][Chan][i] - Mean[Chip][Chan], 2);
+		if (Status.ROI[Chip][Chan] > 1) Sigma = sqrt(Sigma / (Status.ROI[Chip][Chan] - 1));
+
+		// Extrapolate to find DAC values corresponding to 1-sigma clearance to CLIP_LEVEL
+		DR_low[Chip][Chan] = DAC_low - (Mean_low[Chip][Chan] + (CLIP_LEVEL-Sigma))* (DAC_DR-DAC_low) / (Mean[Chip][Chan]-Mean_low[Chip][Chan]);
+		DR_high[Chip][Chan] =  DAC_DR + (CLIP_LEVEL - Sigma - Mean[Chip][Chan]) * (DAC_DR-DAC_low) / (Mean[Chip][Chan]-Mean_low[Chip][Chan]);
+		  
+		printf("Chip %u, chan %u:  DAC Min %6d   Max %d   Range %6d\n", Chip, Chan, DR_low[Chip][Chan], DR_high[Chip][Chan], DR_high[Chip][Chan]-DR_low[Chip][Chan]);  
+	  }
+	}
+	  
+	State = cleanup;
+	break;
+  }
+}
   
 //
@@ -723,111 +838,2 @@
   }
 }
-
-
-
-//
-// Dynamic range determination
-//
-void FADBoard::DynamicRange() {
-
-  #if 0
-  vector<unsigned short> ROICmd;
-  unsigned short DACCmd[] = {htons(CMD_Write | (BADDR_DAC + 1)), 0, htons(CMD_Write | (BADDR_DAC + 2)), 0, htons(CMD_Write | (BADDR_DAC + 3)), 0, htons(CMD_Execute) };
-  string Message = string("ACALIBDONE")+Name+"\n";
-
-  switch (StateDR) {
-  // ====== Check if dynamic range measurement should start and initialise =====
-  case standbye:
-	if (m->Mode != m->dynrange) break;
-
-	// Save initial board status, and set all ROIs to 1024
-	InitialStatus = GetStatus();
-
-	for (unsigned int i=0; i<NChips*NChannels; i++) {
-	  ROICmd.push_back(htons(CMD_Write | (BADDR_ROI + i)));
-	  ROICmd.push_back(htons(NBins));
-	}
-	ROICmd.push_back(htons(CMD_Execute));
-	Send(&ROICmd[0], ROICmd.size()*sizeof(unsigned short));
-
-	// Start measurement
-	DAC_DR = 0;
-	StateDR = setdac;
-	SetStatus("Starting dynamic range measurement");
-	break;
-
-  // ====== Set calibration DAC =====
-  case setdac:
-	// Check for stopping
-	if (m->Mode != m->dynrange) {
-	  StateDR = cleanup;
-	  break;
-	}
-
-	if (DAC_DR > 66000) {
-	  StateDR = cleanup;
-	  break;
-	}
-
-	// Set new DAC values
-	DACCmd[1] = htons(DAC_DR);
-	DACCmd[3] = htons(DAC_DR);
-	DACCmd[5] = htons(DAC_DR);
-	Send(DACCmd, sizeof(DACCmd));
-
-	StateDR = measure;
-	break;
-
-  // ====== Determine mean and sigma =====
-  case measure:
-	// Check for stopping
-	if (m->Mode != m->dynrange) {
-	  StateDR = cleanup;
-	  break;
-	}
-
-	Mean = 0;
-	Sigma = 0;
-	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++) {
-		  Mean += Data[Chip][Chan][i];
-		  Sigma += Data[Chip][Chan][i]*Data[Chip][Chan][i];
-		}
-		Mean /= Status.ROI[Chip][Chan];
-		Sigma = sqrt(Status.ROI[Chip][Chan]/(Status.ROI[Chip][Chan]-1)*(Sigma/Status.ROI[Chip][Chan]-Mean*Mean));		
-	  }
-	}
-	
-	DAC_DR += 1000;
-
-	StateDR = setdac;
-	break;
-
-  // ====== Write back original ROI and DAC settings =====
-  case cleanup:
-    // ROI values
-	ROICmd.clear();
-	for (unsigned int i=0; i<NChips*NChannels; i++) {
-	  ROICmd.push_back(htons(CMD_Write | (BADDR_ROI + i)));
-	  ROICmd.push_back(htons(InitialStatus.ROI[i/NChannels][i%NChannels]));
-	}
-	ROICmd.push_back(htons(CMD_Execute));
-	Send(&ROICmd[0], ROICmd.size()*sizeof(unsigned short));
-
-	// DAC values
-	DACCmd[1] = htons(InitialStatus.DAC[1]);
-	DACCmd[3] = htons(InitialStatus.DAC[2]);
-	DACCmd[5] = htons(InitialStatus.DAC[3]);
-  	Send(DACCmd, sizeof(DACCmd));
-	
-	StateDR = wait;
-	break;
-
-  // ====== Wait for Mode not being idle =====
-  case wait:
-	if (m->Mode == m->idle) StateDR = standbye;
-	break;
-  }
-  #endif
-}  
Index: fact/FADctrl/FADBoard.h
===================================================================
--- fact/FADctrl/FADBoard.h	(revision 12891)
+++ fact/FADctrl/FADBoard.h	(revision 14174)
@@ -96,5 +96,4 @@
 	void Lock();
 	void Unlock();
-	void DynamicRange();
 
 	unsigned short Port;
@@ -110,7 +109,14 @@
 
   private:
-	enum StateType {standbye, baseline, gain, secondary, cleanup, wait};
+	enum StateType {standbye, baseline, gain, secondary, cleanup, wait, setdac, measure};
+	StateType State;
+
 	struct BoardStatus InitialStatus;
-	StateType State;
+	uint16_t DAC_DR, DAC_low;
+	int16_t Delta_DAC;
+	unsigned int Count_DR;
+    static const short CLIP_LEVEL = 2000;
+	double Mean[NChips][NChannels], Mean_low[NChips][NChannels];
+	int DR_low[NChips][NChannels], DR_high[NChips][NChannels];
 };
 
Index: fact/FADctrl/History.txt
===================================================================
--- fact/FADctrl/History.txt	(revision 12891)
+++ fact/FADctrl/History.txt	(revision 14174)
@@ -35,3 +35,4 @@
 24/6/2011	PLL lock status published as DIM service
 7/7/2011	Fixed error in setting the active boards in EventThread()
-13/7/2911   FAD board time published as DIM service
+13/7/2011   FAD board time published as DIM service
+13/6/2012   New command to determine dynamic range using the calibration DACs
