Index: fact/BIASctrl/User.cc
===================================================================
--- fact/BIASctrl/User.cc	(revision 10119)
+++ fact/BIASctrl/User.cc	(revision 10153)
@@ -15,15 +15,15 @@
 								const char *Help;
   } CommandList[] = 
-   {{"synch", &User::cmd_synch, 0, "", "Synchronize board"},
-    {"pixel", &User::cmd_hv, 2, "<pixel id> <v>", "Change bias of pixel"},
-	{"channel", &User::cmd_hv, 2, "<channel|all> <v>", "Change bias of (all) channels of active boards"},
-    {"gs", &User::cmd_gs, 1, "[crate] <volt>", "Global voltage set"},
+   {{"pixel", &User::cmd_hv, 2, "<pixel id> <v>", "Change bias of pixel"},
+	{"channel", &User::cmd_hv, 2, "<channel range> <v>", "Change bias of (all) channels of active crate"},
+    {"gs", &User::cmd_gs, 1, "[crate] <volt>", "Global voltage set active crate"},
+	{"reset", &User::cmd_reset, 0, "", "Reset active crate"},
+	{"synch", &User::cmd_synch, 0, "", "Synchronize active crate"},	{"crate", &User::cmd_crate, 1, "<number>", "Select active crate"},
 	{"status", &User::cmd_status, 0, "[dac|current]", "Show status information (DAC values if requested)"},
-	{"mode", &User::cmd_mode, 1, "<static|dynamic>", "Set voltage stabilization mode"},
+	{"mode", &User::cmd_mode, 1, "<static|dynamic>", "Set voltage stabilization mode (experimental)"},
 	{"load", &User::cmd_load, 1, "<file>", "Load and set bias settings from file"},
 	{"save", &User::cmd_save, 1, "<file>", "Save current bias settings to file"},
 	{"rate", &User::cmd_rate, 1, "<rate>", "Set refresh rate in Hz"},
 	{"timeout", &User::cmd_timeout, 1, "<time>", "Set timeout to return from read in seconds"},
-	{"reset", &User::cmd_reset, 1, "<crates>", "Reset crates"},
 	{"help", &User::cmd_help, 0, "", "Print help"},
 	{"exit", &User::cmd_exit, 0, "", "Exit program"}};
@@ -34,4 +34,6 @@
 //
 User::User(): EvidenceServer(SERVER_NAME) {
+
+  MainThread = pthread_self();
 
   // DIM console service used in PrintMessage()
@@ -63,4 +65,8 @@
   }
 
+  // Set active crate
+  if (!Boards.empty()) ActiveCrate = 0;
+  else ActiveCrate = -1;
+
   // Create PixelMap instance (map from config server)
   DimRpcInfo RPC((char *) "ConfigRequest", (char *) "");
@@ -77,5 +83,4 @@
 }
 
-
 //
 // Destructor
@@ -84,7 +89,6 @@
 
   // Wait for thread to quit
-  if (pthread_join(Thread, NULL) != 0) {
-    PrintMessage("pthread_join() failed");
-  }
+  if (pthread_cancel(Thread) != 0) Message(ERROR, "pthread_cancel() failed in ()");
+  if (pthread_join(Thread, NULL) != 0) Message(ERROR, "pthread_join() failed in ()");
 
   // Delete all crates
@@ -144,5 +148,6 @@
   
   PrintMessage(".<command>                  Execute shell command\n\n"
-  	"Items in <> are mandatory, in [] optional, | indicates mutual exclusive or.\n");
+  	"Items in <> are mandatory, in [] optional, | indicates mutual exclusive or.\n"
+    "Channel ranges can be 'all', a single number or in the form 'a-b'.\n"); 
 } 
 
@@ -152,8 +157,29 @@
 void User::cmd_synch() {
 
-  for (unsigned int i=0; i<Crates.size(); i++) {
-	if (Crates[i]->Synch()) PrintMessage("Synchronized crate %d\n", i);
-	else PrintMessage("Failed to synchronize crate %d\n", i);
-  }
+  if (ActiveCrate == -1) return;  
+
+  if (Crates[ActiveCrate]->Synch()) PrintMessage("Synchronized crate %d\n", ActiveCrate);
+  else PrintMessage("Failed to synchronize crate %d\n", ActiveCrate);
+}
+
+//
+// Select active crate
+//
+void User::cmd_crate() {
+
+  int Crate;
+
+  if (!ConvertToInt(Parameter[1], &Crate)) {
+     PrintMessage("Error: Wrong number format\n");
+     return;   
+  }
+
+  // Check limits
+  if (Crate<0 || Crate>=(int) Crates.size()) {
+    PrintMessage("Crate number %d not existing\n", Crate);
+    return;
+  }
+
+  ActiveCrate = Crate;
 }
 
@@ -183,22 +209,13 @@
 	// Channel identification
 	else {
-      vector<string> T = Tokenize(Parameter[n], "/");
-	  Crt.Min = 0;
-	  Crt.Max = Crates.size()-1;
+	  if (ActiveCrate == -1) continue;
+	  else 	Crt.Min = Crt.Max = ActiveCrate;
+
 	  Chan.Min = 0;
-	  Chan.Max = MAX_NUM_BOARDS*NUM_CHANNELS-1;
-	  
-	  if (T.size() == 2) {
-		if(!ConvertToRange(T[0], Crt) || !ConvertToRange(T[1], Chan)) {
-		  PrintMessage("Numeric conversion or out-of-range error for parameter %d, skipping channel\n", n);
-		  continue;
-		}
-	  }
-	  else {
-		Crt.Min = Crt.Max = 0;
-		if (!ConvertToRange(T[0], Chan)) {
-		  PrintMessage("Numeric conversion or out-of-range error for parameter %d, skipping channel\n", n);
-		  continue;
-		}
+	  Chan.Max = MAX_NUM_BOARDS*NUM_CHANNELS-1;	  
+
+	  if (!ConvertToRange(Parameter[n], Chan)) {
+		PrintMessage("Numeric conversion or out-of-range error for parameter %d, skipping channel\n", n);
+		continue;
 	  }
 	}
@@ -246,5 +263,4 @@
   char Buffer[MAX_COM_SIZE];
   int Errors = 0, Channel;
-  unsigned int NBoards = 0;
   double Value;
   FILE *File;
@@ -261,5 +277,6 @@
     for (unsigned int Crate=0; Crate<Crates.size(); Crate++) if (Match(Crates[Crate]->Name, Buffer)) {
 
-	  PrintMessage("Found bias settings for board %s (#%d)\n\r", Crates[Crate]->Name, Crate);
+	  if ((int) Crate != ActiveCrate) continue;
+	  PrintMessage("Found bias settings for crate %s (#%d)\n\r", Crates[Crate]->Name, Crate);
 
 	  Voltages.clear();
@@ -280,13 +297,8 @@
 	  }
 	  else PrintMessage("\nFinished updating board\n");
-      NBoards++;
     } // Loop over boards
   } // while()
     	    
-  if (NBoards != Crates.size()) PrintMessage("Warning: Could not load bias settings for all connected crates\n");
-  else if (Errors == 0) PrintMessage("Success: Read bias settings for all connected crates\n");
-
   if (Errors != 0) PrintMessage("Warning: %d error(s) occurred\n", Errors);
-
   if (fclose(File) != 0) PrintMessage("Error: Could not close file '%s'\n", Parameter[1].c_str());
 }
@@ -319,32 +331,28 @@
 void User::cmd_reset() {
 
-  struct Range R = {0, Crates.size()-1};
-
-  // Check ranges  
-  if(!ConvertToRange(Parameter[1], R)) {
-	PrintMessage("Error, crate number out of range\n");
+  if (ActiveCrate == -1) return;  
+  
+  if (Crates[ActiveCrate]->SystemReset() == 1) PrintMessage("System reset of crate %d\n", ActiveCrate);
+  else PrintMessage("Error: Could not reset crate %d\n", ActiveCrate);
+
+}
+
+//
+// Read channel
+//
+void User::cmd_gs() {
+
+  double Voltage;
+
+  if (ActiveCrate == -1) return;  
+
+  if (!ConvertToDouble(Parameter[1], &Voltage)) {
+    PrintMessage("Error: Wrong number format\n");
 	return;
   }
   
-  for (int i=R.Min; i<=R.Max; i++) {
-	if (Crates[i]->SystemReset() == 1) PrintMessage("System reset of crate %s (#%d)\n", Crates[i]->Name, i);
-	else PrintMessage("Error: Could not reset board %s (#%d)\n", Crates[i]->Name, i);
-  }
-}
-
-//
-// Read channel
-//
-void User::cmd_gs() {
-
-  double Voltage;
-
-  if (!ConvertToDouble(Parameter[1], &Voltage)) return;
-
-  for (unsigned int i=0; i<Crates.size(); i++) {
-	if (Crates[i]->GlobalSet(Voltage) != 1) {
-	  PrintMessage("Error: Could not global set crate %d\n", i);
-	}
-  }    
+  if (Crates[ActiveCrate]->GlobalSet(Voltage) != 1) {
+	PrintMessage("Error: Could not global set crate %d\n", ActiveCrate);
+  }  
 }
 
@@ -396,4 +404,5 @@
 
   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);
@@ -437,10 +446,9 @@
     
 //
-// Exit program
+// Exit program (Signal makes readline return and sets ExitRequest)
 //
 void User::cmd_exit() {
 
-  ExitRequest = true;
-  pthread_kill(Thread, SIGUSR1);  // Make tjread return from usleep()
+  pthread_kill(MainThread, SIGTERM);
 }
   
@@ -512,11 +520,25 @@
 
   static bool Warned = false;
+  int Ret;
 
   while (!ExitRequest) {
+
+  	// Wait (this is the only allowed cancelation point)
+	if ((Ret=pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) != 0) {
+	  Message(FATAL, "pthread_setcancelstate() failed (%s)", strerror(Ret));
+	}
+	if (usleep((unsigned long) floor(1000000./fStatusRefreshRate)) == -1) {
+	  Message(FATAL, "usleep() failed (%s)", strerror(errno));
+	}
+	if ((Ret=pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL)) != 0) {
+	  Message(FATAL, "pthread_setcancelstate() failed (%s)", strerror(Ret));
+	}
+
+	// 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, "Warning: Crate %d has many read/write errors, further error reporting disabled", i);
+          Message(WARN, "Crate %d has many read/write errors, further error reporting disabled", i);
     	}
     	continue;
@@ -553,7 +575,4 @@
 	  if (Mode == mode_dynamic) Crates[i]->AdaptVoltages();
 	} // for
-
-	// Wait
-	usleep((unsigned long) floor(1000000./fStatusRefreshRate));
   } // while
 }
