Index: fact/BIASctrl/BIASctrl.cc
===================================================================
--- fact/BIASctrl/BIASctrl.cc	(revision 10119)
+++ fact/BIASctrl/BIASctrl.cc	(revision 10153)
@@ -1,9 +1,7 @@
 /**************************************************************\
 
-  Control program for the fACT G-APD bias supply
+  Control program for the FACT G-APD bias supply
 
-  Adapted from previous version 'hvcontrol'.
-  
-  Oliver Grimm, August 2010
+  Oliver Grimm
   
 \**************************************************************/
@@ -16,85 +14,25 @@
 #include <readline/history.h>
 
-#define LOCKFILE "/tmp/CTX_HV_LOCK"
 const char READLINE_HIST_FILE[] = "/tmp/.history.BIASctrl";
 
-//
-// Remove lock file before running default signal code
-//
-void CrashHandler(int Signal) {
-
-  remove(LOCKFILE);
-  printf("Caught signal number %d. Removing lockfile and performing standard signal action. Good luck.\n",Signal);
-  signal(Signal, SIG_DFL);
-  raise(Signal);
-}
-
-//
-// Dummy handler to return from blocking syscalls
-//
-void DummyHandler(int) {};
-
-//
-// This function will be implicitly called by exit()
-//
-void ExitFunction() {
-
-  if (remove(LOCKFILE) == -1) {
-    printf("Could not remove lock file %s (%s)\n", LOCKFILE, strerror(errno));
-  }
-}
-
-//
 // Main program
-//
 int main() {
 
-  char str[MAX_COM_SIZE], *Command;
-  int Lock;
+  char *Command;
   std::string LastHist;
 
-  // Assure only one instance runs
-  // O_EXCL with O_CREAT assure that the lock file cannot be 
-  // opened by another instance, i.e. there are no parallel write accesses
-  if((Lock = open(LOCKFILE,O_WRONLY|O_CREAT|O_EXCL,S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)) == -1) {
-    if(errno==EEXIST) {
-      printf("Error: Lock file already existing\n");
-      sprintf(str, "paste %s -s -d ' '", LOCKFILE);
-      system(str);
-    }
-    else printf("Could not create lock file %s (%s)\n", LOCKFILE, strerror(errno));
-    exit(EXIT_FAILURE);
-  }
-  close(Lock);
-  sprintf(str,"echo Created >%s; date >>%s; echo by $USER@$HOSTNAME>>%s", LOCKFILE, LOCKFILE, LOCKFILE);
-  system(str);
-  
+  // Uses getc() for readline library (allows interruption by signal) and load history buffer
+  rl_getc_function = getc;
+  read_history(READLINE_HIST_FILE);
+
+  // Set signal SIGTERM to interrupt blocking system calls
+  siginterrupt(SIGTERM, true);
+
   system("clear");                   
-  printf("\n*** Bias control (compiled %s, %s) ***\n\n", __DATE__, __TIME__);
- 
-  // Install signal handler and set signal SIGUSR1 to interrupt blocking system calls
-  signal(SIGUSR1, &DummyHandler);
-  siginterrupt (SIGUSR1, true);
-
-  // Assure lock file is deleted in case of a program crash or call to exit()
-  signal(SIGILL, &CrashHandler);
-  signal(SIGABRT, &CrashHandler);
-  signal(SIGFPE, &CrashHandler);
-  signal(SIGSEGV, &CrashHandler);
-  signal(SIGBUS, &CrashHandler);
-  atexit(&ExitFunction);
-  
+  printf("\n*** BIASctrl (compiled %s, %s) ***\n\n", __DATE__, __TIME__);
+   
   // Construct main instance
   static User M;
   
-  // These signals were set during construction of EvidenceServer
-  signal(SIGQUIT, &CrashHandler);  // CTRL-Backspace
-  signal(SIGINT, &CrashHandler);   // CTRL-C
-  signal(SIGHUP, &CrashHandler);   // Terminal closed
-  signal(SIGTERM, &CrashHandler);
-
-  // Load history buffer
-  read_history(READLINE_HIST_FILE);
-
   // Handle command-line input
   while (!M.ExitRequest) {        
Index: fact/BIASctrl/Crate.cc
===================================================================
--- fact/BIASctrl/Crate.cc	(revision 10119)
+++ fact/BIASctrl/Crate.cc	(revision 10153)
@@ -134,4 +134,5 @@
 	FD_ZERO(&SelectDescriptor);   FD_SET(fDescriptor, &SelectDescriptor);
 	if (select(fDescriptor+1, &SelectDescriptor, NULL, NULL, &WaitTime)==-1) {
+	  if (errno = EINTR) goto ExitCommunicate;  // in case program is exiting
       m->Message(m->FATAL, "Error with select() (%s)", strerror(errno));
 	}
Index: fact/BIASctrl/History.txt
===================================================================
--- fact/BIASctrl/History.txt	(revision 10119)
+++ fact/BIASctrl/History.txt	(revision 10153)
@@ -7,2 +7,6 @@
 6/1/2011	RampVoltages() had infinite loop if crate communication stopped
 19/1/2011	'hv' command crashed when no bias board was present
+28/1/2011	Replaced 'hv' by 'channel' and 'pixel' commands (with new pixel
+			names, the name is a number itself)
+11/2/2011	Removed Lockfile (DIM will prevent starting two instances)
+			Added 'crate' command. Changed signaling of program exit.
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
 }
Index: fact/BIASctrl/User.h
===================================================================
--- fact/BIASctrl/User.h	(revision 10119)
+++ fact/BIASctrl/User.h	(revision 10153)
@@ -30,5 +30,5 @@
 	DimService *ConsoleOut;
 	char *ConsoleText;
-	pthread_t Thread;
+	pthread_t MainThread, Thread;
 	std::vector<std::string> Parameter;
 	RunMode Mode;
@@ -52,4 +52,5 @@
 	float fStatusRefreshRate;
 	double fMaxDiff;
+	int ActiveCrate;
 
 	User();
@@ -67,4 +68,5 @@
 	void cmd_timeout();	void cmd_reset();
 	void cmd_help();	void cmd_mode();
+	void cmd_crate();
 };
 
