Index: /fact/BIASctrl/BIASctrl.cc
===================================================================
--- /fact/BIASctrl/BIASctrl.cc	(revision 11905)
+++ /fact/BIASctrl/BIASctrl.cc	(revision 11906)
@@ -14,5 +14,7 @@
 #include <readline/history.h>
 
-const char READLINE_HIST_FILE[] = "/tmp/.history.BIASctrl";
+using namespace std;
+
+const string READLINE_HIST_FILE = string(getenv("HOME"))+"/.history_BIASctrl";
 
 // Main program
@@ -24,5 +26,5 @@
   // Uses getc() for readline library (allows interruption by signal) and load history buffer
   rl_getc_function = getc;
-  read_history(READLINE_HIST_FILE);
+  read_history(READLINE_HIST_FILE.c_str());
 
   // Set signal SIGTERM to interrupt blocking system calls
@@ -38,5 +40,5 @@
   // Handle command-line input
   while (!M.ExitRequest) {        
-    Command = readline("\rBias> ");
+    Command = readline("Bias> ");
 	
 	// NULL returned if interrupted by signal
@@ -55,5 +57,5 @@
   
   // Save history buffer  
-  int Ret = write_history(READLINE_HIST_FILE);
-  if (Ret != 0 ) printf("Error writing history file to '%s' (%s)\n", READLINE_HIST_FILE, strerror(Ret));
+  int Ret = write_history(READLINE_HIST_FILE.c_str());
+  if (Ret != 0 ) printf("Error writing history file to '%s' (%s)\n", READLINE_HIST_FILE.c_str(), strerror(Ret));
 }
Index: /fact/BIASctrl/Crate.cc
===================================================================
--- /fact/BIASctrl/Crate.cc	(revision 11905)
+++ /fact/BIASctrl/Crate.cc	(revision 11906)
@@ -20,4 +20,5 @@
   // Initialize
   InitOK = false;
+  Disabled = false;
   File = NULL;
   m = PIO;
@@ -26,11 +27,10 @@
   CrateNumber = Number;
   WrapCount = -1;
-
-  for (int i=0; i<MAX_NUM_BOARDS; i++) {
-	for (int j=0; j<NUM_CHANNELS; j++) {
-	  OC[i][j] = false;
-	  Present[i][j] = false;
-	  Current[i][j] = 0;
-	}
+  LastReset = 0;
+
+  for (unsigned int i=0; i<MAX_NUM_BOARDS*NUM_CHANNELS; i++) {
+	OC[i] = false;
+	Present[i] = false;
+	Current[i] = 0;
   }
   ResetHit = false;
@@ -45,5 +45,4 @@
   NameService = new DimService ((SERVER_NAME"/NAME/ID"+ID.str()).c_str(), Name);
   BiasVolt = new DimService ((char *) (SERVER_NAME"/VOLT/ID"+ID.str()).c_str(), (char *) "D", Volt, MAX_NUM_BOARDS*NUM_CHANNELS*sizeof(double));
-  BiasDAC = new DimService ((char *) (SERVER_NAME"/DAC/ID"+ID.str()).c_str(), (char *) "I", DAC, MAX_NUM_BOARDS*NUM_CHANNELS*sizeof(int));
   BiasCurrent = new DimService ((char *) (SERVER_NAME"/MICROAMP/ID"+ID.str()).c_str(), (char *) "F", Current, MAX_NUM_BOARDS*NUM_CHANNELS*sizeof(float));
 
@@ -52,5 +51,5 @@
   // Open device
   if ((fDescriptor = open(("/dev/"+CrateName).c_str(), O_RDWR|O_NOCTTY|O_NDELAY)) == -1) {
-    if(errno != 2) m->PrintMessage("Error: Could not open device %d/%s (%s)\n", CrateNumber, Name, strerror(errno));
+    if (errno != 2) m->PrintMessage("Error: Could not open device %d/%s (%s)\n", CrateNumber, Name, strerror(errno));
     return;
   }
@@ -69,5 +68,5 @@
 
   // Set baudrate and raw mode
-  if (cfsetspeed(&tio, BAUDRATE) == -1) {
+  if (cfsetspeed(&tio, B115200) == -1) {
 	m->PrintMessage("Error: Could not set baud rate of device %s (%s)\n", Name,  strerror(errno));
 	return;
@@ -79,4 +78,10 @@
   }
   
+  // Synchronize crate
+  if (!Synch()) return;
+
+  // Set voltages and zero and reset crate
+  if (!GlobalSet(0) || !SystemReset()) return;
+
   InitOK = true;
 }
@@ -88,7 +93,6 @@
 
   if(fDescriptor != -1) {
-    GlobalSet(0);
-
-    SystemReset();
+    if (!GlobalSet(0)) m->Message(m->ERROR, "Could not global set crate %d to zero voltage", Name);
+
     if (File == NULL) {
 	  if (close(fDescriptor) == -1) m->PrintMessage("Error closing device %s (%s)\n", Name, strerror(errno));
@@ -99,5 +103,4 @@
   delete NameService;
   delete BiasVolt;
-  delete BiasDAC;
   delete BiasCurrent;
   delete[] Name;
@@ -105,27 +108,28 @@
 
 
-// Communicate: Write and read from HV Board until time-out has been reached 
-//
-// Returns: 0 error, 1 success, -1 time-out exceeded
+//
+// Communicate with crate (return empty vector in case of time-out or not a multiple of 3 bytes was returned) 
+//
 vector<unsigned char> Crate::Communicate(string Buf) {
 
   int N;
   fd_set SelectDescriptor;
-  struct timeval WaitTime = {(long) m->fTimeOut, (long) ((m->fTimeOut-(long) m->fTimeOut)*1e6)};
+  float TimeOut = atof(m->GetConfig("TimeOut").c_str());
+  struct timeval WaitTime = {(long) TimeOut, (long) ((TimeOut-(long) TimeOut)*1e6)};
   char Buffer[10000];
   vector<unsigned char> Data;
+
+  // Crate disabled because of too many errors?
+  if (Disabled) return Data;
   
   // === Lock device ===
   flockfile(File);
 
-  // Do not try to communicate if crate has too many errors
-  if (ErrorCount > MAX_ERR_COUNT) goto ExitCommunicate;
-
   // === Write data ===
   if ((N = write(fDescriptor, Buf.data(), Buf.size())) < (int) Buf.size()) {
-    if (N == -1) m->Message(m->ERROR, "Could not write data to crate (%s)", strerror(errno));
-    else m->Message(m->ERROR, "Could write only %d of %d bytes to board", N, Buf.size());
+    if (N == -1) m->Message(m->ERROR, "Could not write data to crate %s (%s)", Name, strerror(errno));
+    else m->Message(m->ERROR, "Could write only %d of %d bytes to crate %s", N, Buf.size(), Name);
     ErrorCount++;
-	
+	goto ExitCommunicate;
   }
 
@@ -145,5 +149,5 @@
 	// Read data   
 	if ((N = read(fDescriptor, Buffer, sizeof(Buffer))) == -1) {
-      m->Message(m->ERROR, "Read error (%s)", strerror(errno));
+      m->Message(m->ERROR, "Read error from crate %s (%s)", Name, strerror(errno));
       ErrorCount++;
 	  goto ExitCommunicate;
@@ -160,5 +164,5 @@
   }
 
-  // === Check/update all wrap counter ===  
+  // === Check/update wrap counter in all received data packages of three bytes ===  
   for (unsigned int i=0; i<Data.size(); i+=3) {
 	if (WrapCount != -1) {
@@ -168,4 +172,10 @@
 	WrapCount = (Data[i]>>4) & 7;
   }
+
+ // Check wrap counter
+ if (!WrapOK) {
+  	m->Message(m->WARN, "Wrap counter mismatch of crate %s", Name);
+	ErrorCount++;
+ }
  
   // === UnLock file descriptor ===
@@ -173,5 +183,5 @@
   funlockfile(File);
 
-  if (Data.empty()) Data.push_back(0);
+  if (ErrorCount > MAX_ERR_COUNT) Disabled = true;
 
   return Data;
@@ -181,14 +191,17 @@
 // System reset of bias crate
 //
-int Crate::SystemReset() {
-  
-  vector<unsigned char> Data = Communicate(string(3, 0));
-
-  if (Data.size() == 3) {
-	ResetHit = false;
-    ErrorCount = 0;
-	return 1;
-  }
-  return 0;
+bool Crate::SystemReset() {
+
+  // Check if minimum requested period elapsed since last reset  
+  if (time(NULL) - LastReset < max(atoi(m->GetConfig("MinResetPeriod").c_str()),1)) return false;
+  LastReset = time(NULL);
+
+  // Send reset and check if 3 bytes returned  
+  if (Communicate(string(3, 0)).size() != 3) return false;
+
+  ResetHit = false;
+  Disabled = false;
+  ErrorCount = 0;
+  return true;
 }
 
@@ -196,10 +209,10 @@
 // Read all channels status
 //
-int Crate::ReadAll() {
+bool Crate::ReadAll() {
 
   string Buf;
 
   // Prepare command to read all channels
-  for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
+  for (unsigned int i=0; i<MAX_NUM_BOARDS; i++) for (int unsigned j=0; j<NUM_CHANNELS; j++) {
 	Buf.push_back(1<<5 | i<<1 | (j&16)>>4);
 	Buf.push_back(j<<4);
@@ -210,24 +223,28 @@
   vector<unsigned char> Data = Communicate(Buf);
     
-  if (Data.size() != Buf.size()) return 0;
+  if (Data.size() != Buf.size()) return false;
 
   // Evaluate data returned from crate
   int Count = 0;
-  for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
-	Current[i][j] = (Data[Count+1] + (Data[Count] & 0x0f)*256) * 1.22;
-	OC[i][j] = Data[Count] & 128;
-	Present[i][j] = (Data[Count+2] & 0x70) == 0 ? true : false;
+  for (unsigned int i=0; i<MAX_NUM_BOARDS*NUM_CHANNELS; i++) {
+	Current[i] = (Data[Count+1] + (Data[Count] & 0x0f)*256) * 1.22;
+	OC[i] = Data[Count] & 128;
+	Present[i] = (Data[Count+2] & 0x70) == 0 ? true : false;
 	if (!ResetHit) ResetHit = (Data[Count+2] & 0x80) == 0 ? false : true;
 	Count += 3;
   }
-  return 1;
+  return true;
 }
 
 
 // ***** Global set *****
-int Crate::GlobalSet(double Voltage) {
-
+bool Crate::GlobalSet(double Voltage) {
+
+  // Limit voltage
+  Voltage = min(Voltage, atof(m->GetConfig("VoltageLimit").c_str()));
+
+  // Calculate DAC value
   unsigned int SetPoint = (unsigned int) (Voltage/90.0*0x0fff);
-  
+
   // Execute command
   string Buf;
@@ -235,27 +252,28 @@
   vector<unsigned char> Data = Communicate(Buf);
 
-  if (Data.size() == 3) {
-	for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
-	  DAC[i][j] = SetPoint;
-	  Volt[i][j] = Voltage;
-	  RefVolt[i][j] = Voltage;
-	}
-	return 1;
-  }
-  return 0;
+  if (Data.size() != 3) return false;
+  
+  for (unsigned int i=0; i<MAX_NUM_BOARDS*NUM_CHANNELS; i++) {
+	Volt[i] = Voltage;
+	RefVolt[i] = Voltage;
+  }
+  return true;
 }
 
 
 // ***** Set channel voltages *****
-int Crate::SetChannels(map<unsigned int, double> V) {
+bool Crate::SetChannels(map<unsigned int, double> V) {
   
   string Buf;
 
-  if (V.empty()) return 1;
+  if (V.empty()) return true;
 
   // Build and execute commands
-  for (map<unsigned int, double>::const_iterator it = V.begin(); it != V.end(); ++it) {
+  for (map<unsigned int, double>::iterator it = V.begin(); it != V.end(); ++it) {
+    // Limit maximum voltage
+	it->second = min(it->second, atof(m->GetConfig("VoltageLimit").c_str()));
+
     // If DAC value unchanged, do not send command
-	if (DAC[it->first/NUM_CHANNELS][it->first%NUM_CHANNELS] == it->second/90.0*0x0fff) continue;
+	if (GetDAC(it->first) == it->second/90.0*0x0fff) continue;
 
 	// Add command to buffer
@@ -267,13 +285,12 @@
 
   // Store new voltage values of successful
-  if (Data.size() == Buf.size()) {
-	for (map<unsigned int, double>::const_iterator it = V.begin(); it != V.end(); ++it) {
-	  DAC[it->first/NUM_CHANNELS][it->first%NUM_CHANNELS] = (unsigned int) (it->second/90.0*0x0fff);
-	  Volt[it->first/NUM_CHANNELS][it->first%NUM_CHANNELS] = it->second;
-	  RefVolt[it->first/NUM_CHANNELS][it->first%NUM_CHANNELS] = it->second;
-	}
-	return 1;
-  }
-  return 0;  
+  if (Data.size() != Buf.size()) return false;
+  
+  for (map<unsigned int, double>::const_iterator it = V.begin(); it != V.end(); ++it) {
+	Volt[it->first] = it->second;
+	RefVolt[it->first] = it->second;
+  }
+
+  return true;
 }
 
@@ -296,8 +313,7 @@
 void Crate::ClearVoltageArrays() {
 
-  for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
-	DAC[i][j] = 0;
-	Volt[i][j] = 0;  
-	RefVolt[i][j] = 0;  
+  for (unsigned int i=0; i<MAX_NUM_BOARDS*NUM_CHANNELS; i++) {
+	Volt[i] = 0;  
+	RefVolt[i] = 0;  
   }
 
@@ -310,5 +326,5 @@
 
   if (Channel >= MAX_NUM_BOARDS*NUM_CHANNELS) return 0;
-  else return Volt[Channel/NUM_CHANNELS][Channel%NUM_CHANNELS]; 
+  else return Volt[Channel]; 
 }
 
@@ -318,5 +334,5 @@
 
   if (Channel >= MAX_NUM_BOARDS*NUM_CHANNELS) return 0;
-  else return DAC[Channel/NUM_CHANNELS][Channel%NUM_CHANNELS]; 
+  else return (unsigned int) (Volt[Channel]/90.0*0x0fff);
 }
 
@@ -326,5 +342,5 @@
 
   if (Channel >= MAX_NUM_BOARDS*NUM_CHANNELS) return 0;
-  else return Current[Channel/NUM_CHANNELS][Channel%NUM_CHANNELS]; 
+  else return Current[Channel]; 
 }
 
@@ -334,5 +350,4 @@
 
   BiasVolt->updateService();
-  BiasDAC->updateService();
 }
 
@@ -341,7 +356,5 @@
 void Crate::SetRefCurrent() {
 
-  for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
-	RefCurrent[i][j] = Current[i][j];  
-  }
+  for (unsigned int i=0; i<MAX_NUM_BOARDS*NUM_CHANNELS; i++) RefCurrent[i] = Current[i];  
 }
 
@@ -354,7 +367,7 @@
   map<unsigned int, double> Voltages;
 
-  for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
-    if (RefVolt[i][j] == 0) continue;
-	Voltages[i*NUM_CHANNELS+j] = RefVolt[i][j] + (RefCurrent[i][j]-Current[i][j])*RESISTOR/1e6;  
+  for (unsigned int i=0; i<MAX_NUM_BOARDS*NUM_CHANNELS; i++) {
+    if (RefVolt[i] == 0) continue;
+	Voltages[i] = RefVolt[i] + (RefCurrent[i]-Current[i])*RESISTOR/1e6;  
   }  
   SetChannels(Voltages);
Index: /fact/BIASctrl/Crate.h
===================================================================
--- /fact/BIASctrl/Crate.h	(revision 11905)
+++ /fact/BIASctrl/Crate.h	(revision 11906)
@@ -14,8 +14,7 @@
 #include "dis.hxx"
 
-#define MAX_NUM_BOARDS 13	// Maximum number of boards per crate
-#define NUM_CHANNELS 32		// Channels per bias board
-#define BAUDRATE B115200
-const float RESISTOR = 1000;	// Resistance in Ohm for voltage correction
+const unsigned int MAX_NUM_BOARDS = 13;	// Maximum number of boards per crate
+const unsigned int NUM_CHANNELS = 32;	// Channels per bias board
+const float RESISTOR = 1000;			// Resistance in Ohm for voltage correction
 const int MAX_ERR_COUNT = 10;	// Maximum number of errors before reporting stopped
 class User;
@@ -29,11 +28,10 @@
 	DimService *NameService;
 	DimService *BiasVolt;
-	DimService *BiasDAC;
 	DimService *BiasCurrent;
 
+	double Volt[MAX_NUM_BOARDS*NUM_CHANNELS];	// Voltage
+	float Current[MAX_NUM_BOARDS*NUM_CHANNELS];
+	time_t LastReset;
 
-	int DAC[MAX_NUM_BOARDS][NUM_CHANNELS];		// Voltage in DAC units
-	double Volt[MAX_NUM_BOARDS][NUM_CHANNELS];	// Voltage in Volt
-	float Current[MAX_NUM_BOARDS][NUM_CHANNELS];
 	std::vector<unsigned char> Communicate(std::string);
 	void ClearVoltageArrays();
@@ -45,20 +43,21 @@
     char *Name;
 
-	bool OC[MAX_NUM_BOARDS][NUM_CHANNELS];
-	bool Present[MAX_NUM_BOARDS][NUM_CHANNELS];
+	bool OC[MAX_NUM_BOARDS*NUM_CHANNELS];
+	bool Present[MAX_NUM_BOARDS*NUM_CHANNELS];
 	bool ResetHit;
 	bool WrapOK;
 	int WrapCount;
 	int ErrorCount;
+	bool Disabled;
 
-	float RefCurrent[MAX_NUM_BOARDS][NUM_CHANNELS];
-	double RefVolt[MAX_NUM_BOARDS][NUM_CHANNELS];
+	float RefCurrent[MAX_NUM_BOARDS*NUM_CHANNELS];
+	double RefVolt[MAX_NUM_BOARDS*NUM_CHANNELS];
 
 	bool InitOK;
 
-	int SetChannels(std::map<unsigned int, double>);
-	int ReadAll();
-	int SystemReset();
-	int GlobalSet(double);
+	bool SetChannels(std::map<unsigned int, double>);
+	bool ReadAll();
+	bool SystemReset();
+	bool GlobalSet(double);
 	bool Synch();
 	double GetVoltage(unsigned int);
Index: /fact/BIASctrl/History.txt
===================================================================
--- /fact/BIASctrl/History.txt	(revision 11905)
+++ /fact/BIASctrl/History.txt	(revision 11906)
@@ -16,2 +16,3 @@
 4/8/2011	'pixel' and 'channel' commands accept 'info' parameter.
 5/8/2011	Default voltages now given per bias channel, not per pixel
+15/8/2011	Added global voltage limit and minimum time between system resets.
Index: /fact/BIASctrl/User.cc
===================================================================
--- /fact/BIASctrl/User.cc	(revision 11905)
+++ /fact/BIASctrl/User.cc	(revision 11906)
@@ -26,6 +26,4 @@
 	{"load", &User::cmd_load, 1, true, "<file>", "Load and set bias settings from file"},
 	{"save", &User::cmd_save, 1, true, "<file>", "Save current bias settings to file"},
-	{"rate", &User::cmd_rate, 1, false, "<rate>", "Set refresh rate in Hz"},
-	{"timeout", &User::cmd_timeout, 1, false, "<time>", "Set timeout to return from read in seconds"},
 	{"help", &User::cmd_help, 0, false, "", "Print help"},
 	{"exit", &User::cmd_exit, 0, false, "", "Exit program"},
@@ -43,11 +41,11 @@
   ConsoleOut = new DimService(SERVER_NAME"/ConsoleOut", (char *) "");
 
-  // Get configuration data
+  // Get/initialize configuration data
   vector<string> Boards = Tokenize(GetConfig("Boards", "dummy"), " \t");
-  fTimeOut = atof(GetConfig("TimeOut").c_str());
-  fStatusRefreshRate = atof(GetConfig("StatusRefreshRate").c_str());
-  fMaxDiff = atof(GetConfig("HVMaxDiffNew").c_str());
-
-  if (fStatusRefreshRate < MIN_RATE || fStatusRefreshRate > MAX_RATE)  fStatusRefreshRate = 1;
+  GetConfig("TimeOut");
+  GetConfig("VoltageLimit");
+  GetConfig("MinResetPeriod");
+  GetConfig("RampSpeed");
+  GetConfig("UpdatePeriod");
 
   vector<string> Text = Tokenize(GetConfig("DefaultVoltage", ""), " \t");
@@ -62,5 +60,5 @@
     class Crate *New = new class Crate(Boards[i], Crates.size(), this);
 
-    if (New->InitOK && New->Synch()) {
+    if (New->InitOK) {
        PrintMessage("Synchronized and reset crate %s (#%d)\n", Boards[i].c_str(), Crates.size());
        Crates.push_back(New);
@@ -94,6 +92,8 @@
   int Ret;
   
-  // Wait for thread to quit
-  if ((Ret = pthread_cancel(Thread)) != 0) Message(ERROR, "pthread_cancel() failed (%s)", strerror(Ret));
+  // Wait for thread to quit (ignore error if thread did already exit)
+  if ((Ret = pthread_cancel(Thread)) != 0) {
+	if (Ret != ESRCH) Message(ERROR, "pthread_cancel() failed (%s)", strerror(Ret));
+  }
   if ((Ret = pthread_join(Thread, NULL)) != 0) Message(ERROR, "pthread_join() failed (%s)", strerror(Ret));
 
@@ -266,7 +266,5 @@
 	  if (Match(Parameter[n+1], "info")) {
 		PrintMessage("Crate %2d, channel %3d  ", Crate, Channel);
-		if (!Crates[Crate]->Present[Channel/NUM_CHANNELS][Channel%NUM_CHANNELS]) {
-		  PrintMessage("(channel not present in crate)");
-		}
+		if (!Crates[Crate]->Present[Channel]) PrintMessage("(channel not present in crate)");
 		PrintMessage("\n  Channel is on board %d, board channel %d\n", Channel/32, Channel%32);
 
@@ -280,5 +278,5 @@
 		PrintMessage("\n  Voltage setpoint: %.2f V (DAC %u)    Current: %.2f uA ", Crates[Crate]->GetVoltage(Channel), Crates[Crate]->GetDAC(Channel), Crates[Crate]->GetCurrent(Channel));
 
-		if (Crates[Crate]->OC[Channel/NUM_CHANNELS][Channel%NUM_CHANNELS]) PrintMessage("(overcurrent)\n");
+		if (Crates[Crate]->OC[Channel]) PrintMessage("(overcurrent)\n");
 		else PrintMessage("\n");
 
@@ -327,5 +325,6 @@
 
   char Buffer[MAX_COM_SIZE];
-  int Errors = 0, Channel;
+  int Errors = 0;
+  unsigned int Channel;
   double Value;
   FILE *File;
@@ -368,27 +367,5 @@
   if (fclose(File) != 0) PrintMessage("Error: Could not close file '%s'\n", Parameter[1].c_str());
 }
-	   
-//
-// Set refresh rate
-//
-void User::cmd_rate() {
-
-  double Rate;
-
-  if (!ConvertToDouble(Parameter[1], &Rate)) {
-     PrintMessage("Error: Wrong number format\n");
-     return;   
-  }
-
-  // Check limits
-  if (Rate<MIN_RATE || Rate>MAX_RATE) {
-    PrintMessage("Refresh rate out of range (min: %.2f Hz, max: %.2f Hz)\n", MIN_RATE, MAX_RATE);
-    return;
-  }
-
-  fStatusRefreshRate = Rate;
-  PrintMessage("Refresh rate set to %.2f Hz\n", fStatusRefreshRate);
-}
-  
+	     
 //
 // Reset crates
@@ -396,5 +373,5 @@
 void User::cmd_reset() {
 
-  if (Crates[ActiveCrate]->SystemReset() == 1) PrintMessage("System reset of crate %d\n", ActiveCrate);
+  if (Crates[ActiveCrate]->SystemReset()) PrintMessage("System reset of crate %d\n", ActiveCrate);
   else PrintMessage("Error: Could not reset crate %d\n", ActiveCrate);
 }
@@ -412,5 +389,5 @@
   }
   
-  if (Crates[ActiveCrate]->GlobalSet(Voltage) != 1) {
+  if (!Crates[ActiveCrate]->GlobalSet(Voltage)) {
 	PrintMessage("Error: Could not global set crate %d\n", ActiveCrate);
   }  
@@ -435,5 +412,5 @@
     fprintf(File, "%s\n\n", Crates[i]->Name);
 
-    for (int j=0; j<MAX_NUM_BOARDS*NUM_CHANNELS; j++) fprintf(File,"%.3f ",Crates[i]->GetVoltage(j));
+    for (unsigned int j=0; j<MAX_NUM_BOARDS*NUM_CHANNELS; j++) fprintf(File,"%.3f ",Crates[i]->GetVoltage(j));
     fprintf(File, "\n");
   }
@@ -463,14 +440,23 @@
 void User::cmd_status() {
 
-  PrintMessage(" Number of crates:  %d\n", Crates.size());
-  PrintMessage(" Active crate:      %d\n", ActiveCrate);  
-  PrintMessage(" Refresh rate:      %.2f Hz\n", fStatusRefreshRate);
-  PrintMessage(" Time out:          %.2f s\n\n", fTimeOut);
-  PrintMessage(" MaxDiff :          %u\n", fMaxDiff);
-
+  PrintMessage(" Number of crates:   %d\n", Crates.size());
+  PrintMessage(" Active crate:       %d\n", ActiveCrate);  
+  PrintMessage(" Update delay:       %d sec\n", min(atoi(GetConfig("UpdatePeriod").c_str()), 1));
+  PrintMessage(" Time out:           %.2f sec\n", atof(GetConfig("TimeOut").c_str()));
+  PrintMessage(" Max ramp speed      %.2f V/10 ms\n", atof(GetConfig("RampSpeed").c_str()));
+  PrintMessage(" Voltage limit:      %.2f V\n", atof(GetConfig("VoltageLimit").c_str()));
+  PrintMessage(" Minium reset delay: %u sec\n", atoi(GetConfig("MinResetPeriod").c_str()));
+  
   for (unsigned int i=0; i<Crates.size(); i++) {
-    PrintMessage(" CRATE %d (%s)\n   Wrap counter: %s (%d)  Reset: %s  Error count: %d\n ",
+
+    PrintMessage(" CRATE %d (%s)\n   Wrap counter: %s (%d)  Reset: %s  Error count: %d %s\n ",
 		i, Crates[i]->Name,	Crates[i]->WrapOK ? "ok":"error", Crates[i]->WrapCount, 
-		Crates[i]->ResetHit ? "yes" : "no", Crates[i]->ErrorCount);
+		Crates[i]->ResetHit ? "yes" : "no", Crates[i]->ErrorCount, Crates[i]->Disabled ? "(DISABLED)":"");
+
+	// Read all channels
+	if (!Crates[i]->ReadAll()) {
+	  PrintMessage("Could not update status from crate %d\n", i);
+	  continue;
+	}
 
 	if (Parameter.size() == 1) PrintMessage("Channel voltages (in V)");
@@ -478,10 +464,10 @@
 	else PrintMessage("Channel currents (in uA)");
 
-    for (int j=0; j<MAX_NUM_BOARDS*NUM_CHANNELS; j++) {
+    for (unsigned int j=0; j<MAX_NUM_BOARDS*NUM_CHANNELS; j++) {
 	  if (j%12 == 0) PrintMessage("\n%3.1d:  ", j);
-	  if (!Crates[i]->Present[j/NUM_CHANNELS][j%NUM_CHANNELS]) PrintMessage("  -   ");
+	  if (!Crates[i]->Present[j]) PrintMessage("  -   ");
       else if (Parameter.size() == 1) PrintMessage("%#5.2f ",Crates[i]->GetVoltage(j));
 	  else if (Match(Parameter[1], "dac")) PrintMessage("%5d ", Crates[i]->GetDAC(j));
-	  else PrintMessage("%#5.2f %s ", Crates[i]->GetCurrent(j), Crates[i]->OC[j/NUM_CHANNELS][j%NUM_CHANNELS] ? "OC":"");
+	  else PrintMessage("%#5.2f %s ", Crates[i]->GetCurrent(j), Crates[i]->OC[j] ? "OC":"");
     }
 	PrintMessage("\n");
@@ -489,20 +475,4 @@
 } 
 
-//
-// Set timeout to return from read
-//
-void User::cmd_timeout() {
-
-  double Timeout;
-
-  if (!ConvertToDouble(Parameter[1], &Timeout)) {
-     PrintMessage("Error: Wrong number format\n");
-     return;   
-  }
-
-  fTimeOut = Timeout;
-  PrintMessage("Timeout set to %.2f s\n", fTimeOut);
-}
-    
 //
 // Exit program (Signal makes readline return and sets ExitRequest)
@@ -535,9 +505,11 @@
   if (vasprintf(&Text, Format, ArgumentPointer) == -1) Text = Error;
   va_end(ArgumentPointer);
+
+  if (strlen(Text) == 0) return;
  
   // Print to console
-  printf("%s", Text); // New prompt
+  printf("%s", Text);
   fflush(stdout);
-  if (strlen(Text)>0 && Text[strlen(Text)-1]=='\n') rl_on_new_line(); // New prompt
+  if (Text[strlen(Text)-1] == '\n') rl_on_new_line(); // New prompt
 
   // Send to DIM text service
@@ -550,5 +522,5 @@
 
 
-// Ramp to new voltage with maximum step size given in fMaxDiff
+// Ramp to new voltage with given maximum step
 // No ramping when decreasing voltage
 unsigned int User::RampVoltages(int Crate, map<unsigned int, double> Voltages) {
@@ -556,4 +528,5 @@
   map<unsigned int, double> Target;
   int Errors = 0;
+  double MaxDiff = atof(GetConfig("RampSpeed").c_str());
 
   // Ramp until all channels at desired value
@@ -567,11 +540,11 @@
 	Target = Voltages;
 	for (map<unsigned int, double>::iterator it = Target.begin(); it != Target.end(); ++it) {
-	  if (Crates[Crate]->GetVoltage(it->first) + fMaxDiff < it->second) {
-		it->second = Crates[Crate]->GetVoltage(it->first) + fMaxDiff;
+	  if (Crates[Crate]->GetVoltage(it->first) + MaxDiff < it->second) {
+		it->second = Crates[Crate]->GetVoltage(it->first) + MaxDiff;
 	  }
 	}	
 	
 	// Set channels to next target and wait 10 ms
-	if (Crates[Crate]->SetChannels(Target) != 1) Errors++;
+	if (!Crates[Crate]->SetChannels(Target)) Errors++;
 	usleep(10000);
   }
@@ -586,7 +559,5 @@
 void User::Monitor() {
 
-  static bool Warned = false;
   int Ret;
-  unsigned int Count=0;
 
   while (!ExitRequest) {
@@ -596,7 +567,5 @@
 	  Message(FATAL, "pthread_setcancelstate() failed (%s)", strerror(Ret));
 	}
-	if (usleep((unsigned long) floor(1000000./fStatusRefreshRate)) == -1) {
-	  Message(FATAL, "usleep() failed (%s)", strerror(errno));
-	}
+	sleep(min(atoi(GetConfig("UpdatePeriod").c_str()), 1));
 	if ((Ret=pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL)) != 0) {
 	  Message(FATAL, "pthread_setcancelstate() failed (%s)", strerror(Ret));
@@ -605,40 +574,30 @@
 	// Check all crates
 	for (unsigned int i=0; i<Crates.size(); i++) {
-      if (Crates[i]->ErrorCount > MAX_ERR_COUNT) {
-    	if (!Warned) {
-          Warned = true;
-          Message(WARN, "Crate %d has many read/write errors, further error reporting disabled", i);
-    	}
-    	continue;
+	  // Crate disabled because of too many errors?
+      if (Crates[i]->Disabled) continue;
+
+	  // Read all channels
+      if (!Crates[i]->ReadAll()) {
+    	Message(ERROR, "Monitor thread could not read status from crate %d", i);
+		continue;
       }
 
+	  // Check if crate push button was hit
       if (Crates[i]->ResetHit) {
     	Message(INFO, "Manual reset of crate %d, setting voltages to zero and issuing system reset", i);
-		Crates[i]->GlobalSet(0);
-		Crates[i]->SystemReset();
+		if (!Crates[i]->GlobalSet(0)) Message(ERROR, "Global set to zero voltage of crate %d failed", i);
+		if (!Crates[i]->SystemReset()) Message(ERROR, "System reset of crate %d failed", i);
       }
 
-      if (!Crates[i]->WrapOK) {
-    	Message(ERROR, "Wrap counter mismatch of crate %d", i);
-      }
-
-      if (Crates[i]->ReadAll() != 1) {
-    	Message(ERROR, "Monitor could not read status from crate %d", i);
-		continue;
-      }
-
+	  // Check for overcurrent and set voltage to zero if occurred
 	  map<unsigned int, double> Voltages;
 	  
-      for (int j=0; j<MAX_NUM_BOARDS*NUM_CHANNELS; j++) {
-    	if (Crates[i]->OC[j/NUM_CHANNELS][j%NUM_CHANNELS]) {
-		  if (Count++ < 5) Message(WARN, "Overcurrent on crate %d, board %d, channel %d, setting voltage to zero", i, j/NUM_CHANNELS, j%NUM_CHANNELS);
-		  if (Count == 5) Message(ERROR, "Five overcurrent warnings, no more!");
+      for (unsigned int j=0; j<MAX_NUM_BOARDS*NUM_CHANNELS; j++) {
+    	if (Crates[i]->OC[j]) {
+		  Message(WARN, "Overcurrent on crate %d, board %d, channel %d, setting voltage to zero", i, j/NUM_CHANNELS, j%NUM_CHANNELS);
 		  Voltages[j] = 0;
     	}
       }
-	  if (!Voltages.empty()) {
-		Crates[i]->SetChannels(Voltages);
-		Crates[i]->SystemReset();
-	  }
+	  if (!Crates[i]->SetChannels(Voltages)) Message(ERROR, "Error when setting voltages of crate %d", i);
 	  
 	  if (Mode == mode_dynamic) Crates[i]->AdaptVoltages();
Index: /fact/BIASctrl/User.h
===================================================================
--- /fact/BIASctrl/User.h	(revision 11905)
+++ /fact/BIASctrl/User.h	(revision 11906)
@@ -18,7 +18,4 @@
 
 #define MAX_COM_SIZE 5000
-
-#define MIN_RATE 0.01
-#define MAX_RATE 50.0
 
 class User: public EvidenceServer {
@@ -50,7 +47,4 @@
 
  public:
-	double fTimeOut;
-	float fStatusRefreshRate;
-	double fMaxDiff;
 	unsigned int ActiveCrate;
 
@@ -66,6 +60,5 @@
 	void cmd_status();	void cmd_gs();
 	void cmd_load();	void cmd_save();
-	void cmd_exit();	void cmd_rate();
-	void cmd_timeout();	void cmd_reset();
+	void cmd_exit();	void cmd_reset();
 	void cmd_help();	void cmd_mode();
 	void cmd_crate();	void cmd_shell();
