Index: hvcontrol/src/ProcessIO.cc
===================================================================
--- hvcontrol/src/ProcessIO.cc	(revision 220)
+++ hvcontrol/src/ProcessIO.cc	(revision 226)
@@ -22,6 +22,5 @@
   } CommandList[] = 
    {{"board", &ProcessIO::cmd_board, 1, "<i>|<i j>|<all>" ,"Address board i, boards i-j or all boards or list boards"},
-	{"chain", &ProcessIO::cmd_chain, 1, "<i>|<i> <j>|<all>","Address chain i, chains i-j or all chains"},
-	{"hv", &ProcessIO::cmd_hv, 2, "<id>|<ch>|<all> <v>", "Change bias of pixel, ch. or all ch. of active chain(s)/board(s)"},
+	{"hv", &ProcessIO::cmd_hv, 2, "<id>|<ch>|<all> <v>", "Change bias of pixel or (all) chan. of active boards"},
 	{"status", &ProcessIO::cmd_status, 0, "[dac]", "Show status information (DAC values if requested)"},
 	{"config", &ProcessIO::cmd_config, 0, "", "Print configuration"},
@@ -40,4 +39,6 @@
 using namespace std;
 
+
+// Constructor
 ProcessIO::ProcessIO(): EvidenceServer(SERVER_NAME) {
 
@@ -46,12 +47,18 @@
 
   // Initialize status variables
-  state     = active;
-  Exit      = false;
-  
+  state       = active;
+  ConsoleText = NULL;
+
   NumHVBoards = 0;
   FirstBoard  = 0;
   LastBoard   = -1;
-  FirstChain  = 0;
-  LastChain   = NUM_CHAINS-1;
+
+  // Initialize mutex for thread synchronisation
+  if (pthread_mutex_init(&Mutex, NULL) != 0) {
+    Message(FATAL, "pthread_mutex_init() failed");
+  }
+
+  // DIM console service used in PrintMessage()
+  ConsoleOut = new DimService(SERVER_NAME"/ConsoleOut", (char *) "");
 
   // Get configuration data
@@ -94,4 +101,5 @@
 
 
+// Destructor
 ProcessIO::~ProcessIO() {
   
@@ -101,5 +109,11 @@
   delete[] fHVBoard;
     
-  delete pm;	    delete calib;
+  delete pm;
+  delete calib;
+  delete ConsoleOut;	
+  free(ConsoleText);
+  
+  // Destroy mutex
+  if (pthread_mutex_destroy(&Mutex) != 0) Message(ERROR, "pthread_mutex_destroy() failed");
 }
 
@@ -180,24 +194,4 @@
 } 
 
-// Adress chains
-void ProcessIO::cmd_chain() {
-    
-  if (!NumHVBoards) return;
-
-  if (Match(Parameter[1],"all")) {
-    FirstChain = 0;
-    LastChain = 3;
-  } 
-  else if (Parameter.size()==2 && atoi(Parameter[1].c_str())>=0 && atoi(Parameter[1].c_str())<NUM_CHAINS) {
-    FirstChain = atoi(Parameter[1].c_str());
-    LastChain = FirstChain;
-  }
-  else if (Parameter.size()==3 && atoi(Parameter[1].c_str())>=0 && atoi(Parameter[1].c_str())<NUM_CHAINS && 
-         atoi(Parameter[2].c_str())>0 && atoi(Parameter[2].c_str())<NUM_CHAINS) {
-    FirstChain = atoi(Parameter[1].c_str());
-    LastChain = atoi(Parameter[2].c_str());
-  }
-  else PrintMessage("Cannot address chain(s), out of range.\n");
-} 
 
 // Print configuration
@@ -209,6 +203,5 @@
   for (int i=0; i<NumHVBoards; i++) PrintMessage(" Board %d: %s\n", i, fHVBoard[i]->BoardName);
 
-  PrintMessage( " TimeOut:           %.2f s\n"
-    	    	" StatusRefreshRate: %.2f Hz\n"
+  PrintMessage(	" StatusRefreshRate: %.2f Hz\n"
     	    	" DACMin value:      %d\n"
     	    	" DACMax value:      %d\n"
@@ -216,5 +209,5 @@
     	    	" HVCalibSlope :     %f\n"
     	    	" HVMaxDiff :        %u\n",
-		fTimeOut, fStatusRefreshRate, DACMin,
+		fStatusRefreshRate, DACMin,
 		DACMax, fHVCalibOffset, fHVCalibSlope, fHVMaxDiff);
 }
@@ -236,83 +229,65 @@
 void ProcessIO::cmd_hv() {
 
-  int hvoltage, DACValue, Errors=0, Board=-1, Chain=-1, Channel=-1;
-  double hvoltageV;
+  int Int, SingleChannel; 
+  unsigned int DACValue, Errors=0;
+  double Double;
   bool SetDac;
 
-  // If array of channels, evaluate here (used by DIM)
-  if (Parameter.size()>3 && pm->Pixel_to_HVboard(Parameter[3]) != 999999999) {
-	for (unsigned int n=1; n<Parameter.size()-1; n+=2) {
-	  if (pm->Pixel_to_HVboard(Parameter[n]) != 999999999) {
-      	Board = pm->Pixel_to_HVboard(Parameter[n]);
-      	Chain = pm->Pixel_to_HVchain(Parameter[n]);
-    	Channel = pm->Pixel_to_HVchannel(Parameter[n]);
-		hvoltageV = atof(Parameter[n+1].c_str());
-		if (isdigit(Parameter[n+1][0])==0) fHVBoard[Board]->HVV[Chain][Channel] += hvoltageV;
-	    else fHVBoard[Board]->HVV[Chain][Channel] = hvoltageV;
-	    DACValue = calib->HVToDAC(fHVBoard[Board]->HVV[Chain][Channel], Board, Chain, Channel);
-
-	  }
-	}	
-    return;
-  }
-
-  // Evaluate voltage parameter
-  if (Parameter.size()==4 && Match(Parameter[3], "dac")) {
-    SetDac = true;
-    if (!ConvertToInt(Parameter[2], &hvoltage)) {
-      PrintMessage("Error: Wrong number format for DAC voltage setting\n");
-      return;
-    } 
-  }
-  else {
-    SetDac = false;
-    if (!ConvertToDouble(Parameter[2], &hvoltageV)) {
-      PrintMessage("Error: Wrong number format for voltage setting\n");
-      return;
-    }
-  } 
-
-  // Evaluate pixel or channel parameter    
-  if(pm->Pixel_to_HVboard(Parameter[1]) != 999999999) {
-    Board = pm->Pixel_to_HVboard(Parameter[1]);
-    Chain = pm->Pixel_to_HVchain(Parameter[1]);
-    Channel = pm->Pixel_to_HVchannel(Parameter[1]);
-  }
-  else if (!Match(Parameter[1], "all") && !ConvertToInt(Parameter[1], &Channel)) {
-    PrintMessage("Error: Wrong channel identification\n");
-    return;
-  }
-
+  // Interpretation as DAC value requested?
+  if (Parameter.size() == 4 && Match(Parameter[3], "dac")) SetDac = true;
+  else SetDac = false;
+
+  // Interprete first number (might be channel number)
+  if (!ConvertToInt(Parameter[1], &SingleChannel)) SingleChannel = -1;
+
+  // Loop over all boards
   for (int i=FirstBoard; i<=LastBoard; i++) {
-    if (i!=Board && Board!=-1) continue;
-  for (int j=FirstChain; j<=LastChain; j++) {
-      if (j!=Chain && Chain!=-1) continue;
-  for (int k=0; k<NUM_CHANNELS; k++) {
-	if (k!=Channel && Channel!=-1) continue;
-
-	// Voltage change ignored if DAC value is zero
-	if (isdigit(Parameter[2][0])==0 && fHVBoard[i]->HV[j][k] == 0) continue;
-
-	// Determine new DAC values
-	if (!SetDac){
-	  if (isdigit(Parameter[2][0])==0) fHVBoard[i]->HVV[j][k] += hvoltageV; // voltage change
-	  else fHVBoard[i]->HVV[j][k] = hvoltageV;
-	  DACValue = calib->HVToDAC(fHVBoard[i]->HVV[j][k], i, j, k);
-	}
-	else {
-	  if (isdigit(Parameter[2][0])==0) DACValue = fHVBoard[i]->HV[j][k] + hvoltage; // voltage change
-	  else DACValue = hvoltage;
-	}
-
-	// Set new voltage (if DAC value, update calibrated value)
-	if (!RampVoltage(DACValue, i, j, k)) Errors++;
-	if (SetDac) fHVBoard[i]->HVV[j][k] = calib->DACToHV(fHVBoard[i]->HV[j][k], i, j, k);
-  } // Channels	
-  } // Chains
-
-  // Update DIM service
-  fHVBoard[i]->BiasVolt->updateService();
+	// Loop over all channels given as command parameter
+ 	for (unsigned int n=1; n<Parameter.size()-1; n+=2) {
+	  // Loop over all channels
+	  for (int j=0; j<NUM_CHAINS; j++) for (int k=0; k<NUM_CHANNELS; k++) {
+
+		// Current channel must be considered?
+		if (!Match(Parameter[1], "all") && !(i == (int) pm->Pixel_to_HVboard(Parameter[n]) &&
+			j == (int) pm->Pixel_to_HVchain(Parameter[n]) && k == (int) pm->Pixel_to_HVchannel(Parameter[n])) &&
+			!(j == SingleChannel/NUM_CHANNELS && k == SingleChannel%NUM_CHANNELS)) continue;
+
+		// Voltage change (number starts with + oder -) ignored if current DAC value is zero
+		if (isdigit(Parameter[n+1][0])==0 && fHVBoard[i]->HV[j][k] == 0) continue;
+
+		// Set new voltage/DAC value
+		if (!SetDac){
+		  // Convert voltage value and check format 
+		  if (!ConvertToDouble(Parameter[n+1], &Double)) {
+			PrintMessage("Error: Wrong number format for voltage setting\n");
+			goto LeaveLoop;
+		  }
+		  // Adjust voltage and DAV value
+		  if (isdigit(Parameter[n+1][0]) == 0) fHVBoard[i]->HVV[j][k] += Double;
+		  else fHVBoard[i]->HVV[j][k] = Double;
+		  DACValue = calib->HVToDAC(fHVBoard[i]->HVV[j][k], i, j, k);
+		}
+		else {
+		  // Convert DAC value and check format 
+		  if (!ConvertToInt(Parameter[n+1], &Int)) {
+			PrintMessage("Error: Wrong number format for DAC voltage setting\n");
+			goto LeaveLoop;
+		  } 
+		  // Adjust DAC value
+		  if (isdigit(Parameter[n+1][0]) == 0) DACValue = fHVBoard[i]->HV[j][k] + Int;
+		  else DACValue = Int;
+		}
+
+		// Set new voltage (if DAC value, update calibrated value)
+		if (!RampVoltage(DACValue, i, j, k)) Errors++;
+		if (SetDac) fHVBoard[i]->HVV[j][k] = calib->DACToHV(fHVBoard[i]->HV[j][k], i, j, k);
+	  } // Channels and chains	
+	} // Loop over command argument
+
+	// Update DIM service for this boar
+	LeaveLoop:
+	fHVBoard[i]->BiasVolt->updateService();
   } // Boards
-
+  
   if (Errors > 0) PrintMessage("Errors on %d channel(s) occurred\n", Errors);
 }
@@ -454,21 +429,16 @@
   for (int i=FirstBoard; i<=LastBoard; i++) {
     PrintMessage(" BOARD %d (%s)   Wrap counter: %s (%d)  Manual reset: %s\n    Time-out: %.2f s  Error count: %d\n\n",
-  fHVBoard[i]->GetBoardNumber(), fHVBoard[i]->BoardName,
-  fHVBoard[i]->WrapOK ? "ok":"error",
-  fHVBoard[i]->LastWrapCount, 
-  fHVBoard[i]->ResetButton ? "yes" : "no",
-  fHVBoard[i]->fTimeOut,
-  fHVBoard[i]->ErrorCount);
-
-    for (int j=FirstChain; j<=LastChain; j++) {
+		fHVBoard[i]->GetBoardNumber(), fHVBoard[i]->BoardName,
+		fHVBoard[i]->WrapOK ? "ok":"error",	fHVBoard[i]->LastWrapCount, 
+		fHVBoard[i]->ResetButton ? "yes" : "no", fHVBoard[i]->fTimeOut, fHVBoard[i]->ErrorCount);
+
+    for (int j=0; j<NUM_CHAINS; j++) {
 	  PrintMessage("  CHAIN %d     Over-current: %s\n", j, fHVBoard[i]->Overcurrent[j] ? "yes" : "no");
-	  for (int k=0;k<4;k++) {
-        PrintMessage("\r");
-	    for (int l=0;l<8;l++) {
-		  if(Parameter.size() == 2) PrintMessage("%5d ",fHVBoard[i]->HV[j][k*8+l]);
-    	  else PrintMessage("%#5.2f ",fHVBoard[i]->HVV[j][k*8+l]);
-    	}
-	    PrintMessage("\n");
-	  }
+	  for (int l=0; l<NUM_CHANNELS; l++) {
+		if (l%8 == 0) PrintMessage("\r%3.1d:  ", j*NUM_CHANNELS+l);
+		if (Parameter.size() == 2) PrintMessage("%5d ",fHVBoard[i]->HV[j][l]);
+    	else PrintMessage("%#5.2f ",fHVBoard[i]->HVV[j][l]);
+		if (l%8 == 7) PrintMessage("\n");
+      }
     }
   }
@@ -508,5 +478,5 @@
 void ProcessIO::cmd_exit() {
 
-  Exit = true;
+  ExitRequest = true;
   pthread_kill(HVMonitor, SIGUSR1); 
 }
@@ -535,30 +505,24 @@
 void ProcessIO::DoPrintMessage(const char *Format, va_list ArgumentPointer, MsgTarget Target) {
 
-  static char Textbuffer[MAX_COM_SIZE]; // static because of DIM service
-
-  memset(Textbuffer, 0, sizeof(Textbuffer));  
-  vsnprintf(Textbuffer, sizeof(Textbuffer), Format, ArgumentPointer);
+  static char Error[] = "vasprintf() failed in DoPrintMessage()";
+  char *Text;
+
+  // Evaluate arguments    
+  if (vasprintf(&Text, Format, ArgumentPointer) == -1) Text = Error;
   
   // Print to console
   if(Target & Console) {
-    if(strlen(Textbuffer)>0 && Textbuffer[strlen(Textbuffer)-1]=='\n') {
-      printf("\r%s%s", Textbuffer, Prompt);   // New prompt
-    }
-    else printf("%s", Textbuffer);
+    if(strlen(Text)>0 && Text[strlen(Text)-1]=='\n') printf("\r%s%s", Text, Prompt); // New prompt
+    else printf("%s", Text);
     fflush(stdout);
   }
 
-  // Send to DIM service
-  SetStdOut(Textbuffer); 
-
-  // Send to log
-  if(Target & Log) {
-    char *Buf;
-    if (asprintf(&Buf, "%s %s", SERVER_NAME, Textbuffer) != -1) { 
-      DimClient::sendCommandNB("DColl/Log", Buf);
-      free(Buf);
-    }
-    else DimClient::sendCommandNB("DColl/Log", SERVER_NAME" asprintf() failed"); 
-  }
+  // Send to DIM console service and log
+  ConsoleOut->updateService(Text); 
+  if(Target & Log) SendToLog("%s %s", SERVER_NAME, Text);
+
+  // Free old text
+  if (ConsoleText != Error) free(ConsoleText);
+  ConsoleText = Text; 
 }
 
@@ -572,5 +536,5 @@
 
     if (fHVBoard[Board]->SetHV(Chain, Channel, fHVBoard[Board]->HV[Chain][Channel]+Diff) != 1) {
-      State(ERROR, "Could not set bias of board %d, chain %d, channel %d. Skipping channel\n",fHVBoard[Board]->GetBoardNumber(),Chain,Channel);
+      Message(ERROR, "Could not set bias of board %d, chain %d, channel %d. Skipping channel\n",fHVBoard[Board]->GetBoardNumber(),Chain,Channel);
       return false;
     }
@@ -585,5 +549,11 @@
 
   static bool Warned = false;
-  
+  int Ret;
+
+  // Lock because command execution runs in different thread
+  if ((Ret = pthread_mutex_lock(&Mutex)) != 0) {
+	Message(FATAL, "pthread_mutex_lock() failed in commandHandler() (%s)", strerror(Ret));
+  }
+
   for (int i=0; i<NumHVBoards; i++) {
     if (fHVBoard[i]->ErrorCount > 10) {
@@ -591,5 +561,5 @@
         Warned = true;
         PrintMessage(All, "Warning: Some board has many read/write errors, status monitor disabled\n");
-        State(WARN, "Warning: Some board has many read/write errors, status monitor disabled\n");
+        Message(WARN, "Warning: Some board has many read/write errors, status monitor disabled\n");
       }
       continue;
@@ -598,10 +568,10 @@
     if (fHVBoard[i]->GetStatus() != 1) {
       PrintMessage(All, "Error: Monitor could not read status of board %d\n", fHVBoard[i]->GetBoardNumber());
-      State(ERROR, "Error: Monitor could not read status of board %d\n", fHVBoard[i]->GetBoardNumber());
+      Message(ERROR, "Error: Monitor could not read status of board %d\n", fHVBoard[i]->GetBoardNumber());
     }
     
     if (fHVBoard[i]->ResetButton) {
       PrintMessage(All, "Manual reset of board %d\n",fHVBoard[i]->GetBoardNumber());
-      State(INFO, "Manual reset of board %d\n",fHVBoard[i]->GetBoardNumber());
+      Message(INFO, "Manual reset of board %d\n",fHVBoard[i]->GetBoardNumber());
       ResetBoard(i);
     }
@@ -609,5 +579,5 @@
     if (!fHVBoard[i]->WrapOK) {
       PrintMessage(All, "Error: Wrap counter mismatch board %d\n",fHVBoard[i]->GetBoardNumber());
-      State(ERROR, "Error: Wrap counter mismatch board %d\n",fHVBoard[i]->GetBoardNumber());
+      Message(ERROR, "Error: Wrap counter mismatch board %d\n",fHVBoard[i]->GetBoardNumber());
     }
 
@@ -615,9 +585,15 @@
       if (fHVBoard[i]->Overcurrent[j]) {
 		PrintMessage(All, "Warning: Overcurrent in chain %d of board %d\n",j,fHVBoard[i]->GetBoardNumber());
-		State(WARN, "Warning: Overcurrent in chain %d of board %d\n",j,fHVBoard[i]->GetBoardNumber());
+		Message(WARN, "Warning: Overcurrent in chain %d of board %d\n",j,fHVBoard[i]->GetBoardNumber());
 		ResetBoard(i);
       }
     }
   }
+  
+  // Unlock
+  if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
+	Message(FATAL, "pthread_mutex_lock() failed in commandHandler() (%s)", strerror(Ret));
+  }
+
 }
 
@@ -651,7 +627,15 @@
 void ProcessIO::commandHandler() {
 
-  pthread_mutex_lock(&control_mutex);
+  int Ret;
+
+  if ((Ret = pthread_mutex_lock(&Mutex)) != 0) {
+	Message(FATAL, "pthread_mutex_lock() failed in commandHandler() (%s)", strerror(Ret));
+  }
+
   if (getCommand() == Command) CommandControl(getCommand()->getString());
-  pthread_mutex_unlock(&control_mutex);
+
+  if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
+	Message(FATAL, "pthread_mutex_unlock() failed in commandHandler() (%s)", strerror(Ret));
+  }
 }
 
Index: hvcontrol/src/ProcessIO.h
===================================================================
--- hvcontrol/src/ProcessIO.h	(revision 220)
+++ hvcontrol/src/ProcessIO.h	(revision 226)
@@ -33,4 +33,6 @@
 	PixelMap *pm;
 	DimCommand *Command;
+	DimService *ConsoleOut;
+	char *ConsoleText;
 
 	void commandHandler();
@@ -39,6 +41,4 @@
 	HVCalib     *calib;
 	HVBoard **fHVBoard;
-
-	pthread_mutex_t control_mutex;
 
 	char Prompt[MAX_COM_SIZE];
@@ -57,13 +57,10 @@
 	// Status variables  
 	pthread_t HVMonitor;       // exit function sends signal to these threads
+	pthread_mutex_t Mutex;
 
 	int NumHVBoards;
 	int FirstBoard;
 	int LastBoard;
-	int FirstChain;
-	int LastChain;
-  
 	state_enum   state;
-	bool Exit;
 
 	// Methods
@@ -87,5 +84,4 @@
 	void cmd_start();	void cmd_stop();
 	void cmd_uptime();	void cmd_help();
-	void cmd_chain();
 };
 
