Index: fact/BIASctrl/User.cc
===================================================================
--- fact/BIASctrl/User.cc	(revision 11781)
+++ 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();
