Index: drsdaq/DAQReadout.cc
===================================================================
--- drsdaq/DAQReadout.cc	(revision 211)
+++ drsdaq/DAQReadout.cc	(revision 226)
@@ -64,18 +64,18 @@
 //
  
-DAQReadout::DAQReadout():
-			DimCommand((char *) SERVER_NAME"/Command", (char *) "C"),
-			EvidenceServer(SERVER_NAME) {
-
-  // Global class pointer
+DAQReadout::DAQReadout(): EvidenceServer(SERVER_NAME) {
+
+  // Initialization
   This = this;
   MainThread = getpid();
-
-  // Start time of DAQ
+  ConsoleText = NULL;
   time(&StartTime);
+
+  // DIM console service used in PrintMessage()
+  ConsoleOut = new DimService(SERVER_NAME"/ConsoleOut", (char *) "");
 
   // Initialize mutex for thread synchronisation
   if (pthread_mutex_init(&Mutex, NULL) != 0) {
-    State(FATAL, "pthread_mutex_init() failed");
+    Message(FATAL, "pthread_mutex_init() failed");
   }
 
@@ -89,5 +89,5 @@
   LastBoard	     		= -1;
   MinDelay  			= 1;
-  
+
   // Get configuration data
   fRawDataPath = GetConfig("RawDataPath");
@@ -145,4 +145,7 @@
   // Create instance of HV feedback (must be called after board detection)
   HVFB	  = new HVFeedback(this);  
+
+  // Install DIM command (after all initialized)
+  Command = new DimCommand((char *) SERVER_NAME"/Command", (char *) "C", this);
 }
 
@@ -153,6 +156,7 @@
 DAQReadout::~DAQReadout() {
 
-  delete EventService;
-  delete[] DIMEventData;
+  delete Command;
+
+  delete EventService;	delete[] DIMEventData;
   delete RHeader;		delete EHeader;
   delete HVFB;			delete[] ACalibTemp;
@@ -160,7 +164,9 @@
   delete[] DRSFreq; 	delete[] BStruct;
   delete[] WaveForm;	delete[] TriggerCell;
-  
-  // Destroy mutex
-  if (pthread_mutex_destroy(&Mutex) != 0) State(ERROR, "pthread_mutex_destroy() failed");
+
+  delete ConsoleOut;
+  free(ConsoleText);
+  
+  if (pthread_mutex_destroy(&Mutex) != 0) Message(ERROR, "pthread_mutex_destroy() failed");
 }
 
@@ -171,26 +177,41 @@
 void DAQReadout::Execute(char *Command) {
 
-  if (strlen(Command)==0) return;  // Ignore empty commands
-
-  if(Command[0]=='.') {   // Shell command
+  if (Command[0]=='.') {   // Shell command
     system(&(Command[1]));
     return;
   }
 
-  for(int i=0; i<MAX_NUM_TOKEN; i++) Param[i] = "";  // All pointers point initially to empty string
+  for (int i=0; i<MAX_NUM_TOKEN; i++) Param[i] = "";  // All pointers point initially to empty string
   NParam = ParseInput(Command, Param);
-
-  for(CmdNumber=0; CmdNumber<sizeof(CommandList)/sizeof(CL_Struct); CmdNumber++)
-    if (Match(Param[0], CommandList[CmdNumber].Name)) {
-      if(CommandList[CmdNumber].NeedNotBusy && daq_state==active) PrintMessage("DAQ is busy\n");
-      else if(CommandList[CmdNumber].NeedNotBusy && NumBoards==0) PrintMessage("No boards available\n");
-      else {
-		pthread_mutex_lock(&Mutex);
-	    (this->*CommandList[CmdNumber].CommandPointer)();
-		pthread_mutex_unlock(&Mutex);
-	  }
-      return;  
-    }
-  PrintMessage("Unknown command '%s'\n",Param[0]);
+  
+  // Search for command
+  unsigned int Count;
+  for (Count=0; Count<sizeof(CommandList)/sizeof(CL_Struct); Count++) {
+    if (Match(Param[0], CommandList[Count].Name)) break;
+  }
+  
+  // Command not found?
+  if (Count == sizeof(CommandList)/sizeof(CL_Struct)) {
+	PrintMessage("Unknown command '%s'\n", Param[0]);
+	return;
+  }
+
+  if(CommandList[Count].NeedNotBusy && daq_state==active) PrintMessage("DAQ is busy\n");
+  else if(CommandList[Count].NeedNotBusy && NumBoards==0) PrintMessage("No boards available\n");
+  else {
+	int Ret;
+
+	// Lock (Execute() runs in thread spawned by commandHandler())
+	if ((Ret = pthread_mutex_lock(&Mutex)) != 0) {
+	  Message(FATAL, "pthread_mutex_lock() failed (%s)", strerror(Ret));
+  	}
+	// Run command
+	CmdNumber = Count;
+	(this->*CommandList[CmdNumber].CommandPointer)();
+	// Unlock
+	if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
+	  Message(FATAL, "pthread_mutex_unlock() failed (%s)", strerror(Ret));
+  	}
+  }
 }
   	  
@@ -199,5 +220,5 @@
   time_t ActualT;
   time (&ActualT);
-  PrintMessage("%d:%02d:%02d\n", (int) difftime(ActualT, StartTime)/3600, ((int) difftime(ActualT, StartTime)/60)%60, (int) difftime(ActualT, StartTime)%60);
+  PrintMessage("%02d:%02d:%02d\n", (int) difftime(ActualT, StartTime)/3600, ((int) difftime(ActualT, StartTime)/60)%60, (int) difftime(ActualT, StartTime)%60);
 } 
 
@@ -1116,14 +1137,6 @@
   }
   
-  // Event data (It is required that at least three chunks can be written with writev(), therefore
-  // IOV_MAX>=3 is checked at startup
-  
-
-  // First chunk: trigger cells
-  //DataPart[Count].iov_base = (char *) TriggerCell + FirstBoard*RHeader->NChips*sizeof(int); // TriggerCell is without cast a pointer to an 8-byte unit (two ints) !
-  //DataPart[Count++].iov_len = RHeader->NBoards * RHeader->NChips * sizeof(int);
-  //Size += DataPart[Count-1].iov_len;
-
-  // Remaining chunks: ADC data (two chucks per channel if wrap around of pipeline occurred)
+  // ADC data (two chucks per channel if wrap around of pipeline occurred, therefore
+  // IOV_MAX>=2 is checked at startup
   for (int i=FirstBoard; (i<=LastBoard + (NumBoards==0)); i++) {
     for (unsigned int k=0; k<RHeader->NChips; k++) {
@@ -1202,30 +1215,24 @@
 void DAQReadout::DoPrintMessage(const char *Format, va_list ArgumentPointer, int Target) {
 
-  static char Textbuffer[MAX_COM_SIZE];
-  
-  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 & MsgToConsole) {
-    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 & MsgToLog) {
-    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 to log if requested
+  ConsoleOut->updateService(Text);
+  if(Target & MsgToLog) SendToLog("%s %s", SERVER_NAME, Text);
+
+  // Free old text
+  if (ConsoleText != Error) free(ConsoleText);
+  ConsoleText = Text; 
 }
 
@@ -1233,7 +1240,12 @@
 void DAQReadout::commandHandler() {
 
-  // Copy command to new buffer (must be freed by the new thread)
+  // Ignore empty or illegal strings
+  if (getCommand()->getSize() == 0 ||
+  	  *((char *) getCommand()->getData()+getCommand()->getSize()-1) != '\0' ||
+	  strlen(getCommand()->getString()) == 0) return;
+
+  // Copy command to new buffer (will be freed by global Execute() function)
   char *Command;
-  if (asprintf(&Command, "%s", getString()) == -1) {
+  if (asprintf(&Command, "%s", getCommand()->getString()) == -1) {
 	PrintMessage("asprintf() failed in DRSReadout::commandHandler() (%s)\n", strerror(errno));
 	return;
@@ -1314,8 +1326,6 @@
       else if (daq_runtype == pedestal) StopDRS();   // ..or for software trigger
 
-      // Read event data
+      // Read event data and restart (reduces dead-time because waiting for next trigger while writing)
 	  ReadCalibratedDRSData();
-	  
-	  // Restart here reduces dead-time (already waiting for next trigger while writing)
 	  StartDRS();
 
@@ -1386,8 +1396,4 @@
   else PrintMessage("\rRun #%d (%s) aborted due to error after %d events\n", RunNumber, daq_runtype_str[daq_runtype], NumEvents);
 
-  // Write run summary to slow data file
-  //m->SlowDataClass->NewEntry("Runinfo");
-  //m->SlowDataClass->AddToEntry("%d %s %s %d %d %s", m->RunNumber, WriteError?"Error":"OK", daq_runtype_str[m->daq_runtype], m->NumEvents, m->FileNumber, m->RHeader->Description);
-
   // Print run statistics
   if (NumEvents>0 && !WriteError) {
@@ -1445,4 +1451,5 @@
 }
 
+// Stub to call Execute() metho of class and free command memory
 void Execute(char *Command) {
 
Index: drsdaq/DAQReadout.h
===================================================================
--- drsdaq/DAQReadout.h	(revision 211)
+++ drsdaq/DAQReadout.h	(revision 226)
@@ -33,11 +33,14 @@
 enum runtype_enum {data, pedestal, reserved, test};
 
-class DAQReadout : public DRS, public DRSCallback, public DimCommand, public EvidenceServer {
+class DAQReadout : public DRS, public DRSCallback, public EvidenceServer {
 
-    time_t StartTime;
+	time_t StartTime;
 	pid_t MainThread;
 	DimService *EventService;
 	int MinDelay;
     unsigned int CmdNumber;
+	DimCommand *Command;
+	DimService *ConsoleOut;
+	char *ConsoleText;
 
     void PrintUsage();
Index: drsdaq/HVFeedback.cc
===================================================================
--- drsdaq/HVFeedback.cc	(revision 211)
+++ drsdaq/HVFeedback.cc	(revision 226)
@@ -25,6 +25,5 @@
 // Constructor: Initialise feedback 
 //
-HVFeedback::HVFeedback(DAQReadout* DAQClass){//:
-			//EvidenceServer(SERVER_NAME){
+HVFeedback::HVFeedback(DAQReadout* DAQClass){
 
   m = DAQClass;
@@ -139,5 +138,5 @@
   }
   
-  // Update DIM service regularly
+  // Update DIM count service regularly
   if (time(NULL)-LastServiceUpdate > 2) {
     LastServiceUpdate = time(NULL);
@@ -148,4 +147,6 @@
 
   // Feedback action
+  std::stringstream Cmd;
+  
   for (i=m->FirstBoard; i<=m->LastBoard; i++) {
   for (j=0; j<fNumberOfChips; j++) {
@@ -165,6 +166,7 @@
 
 		if(fabs(Average[i][j][k]) < 2*Sigma[i][j][k]) printf("Too noisy!\n");
-		else WriteHVCommand("hv %s %+f\n",PixMap->DRS_to_Pixel(i,j,k).c_str(), Correction);
-
+		else {
+		  Cmd << PixMap->DRS_to_Pixel(i,j,k)+" " << std::showpos << Correction << " ";
+		}
 	    break;
 
@@ -175,5 +177,7 @@
 	  case FB_ResponseFirst:  // First point of response measurement done  
 	    Buffer[i][j][k] = Average[i][j][k];
-	    if(!PixMap->DRS_to_Pixel(i,j,k).empty()) WriteHVCommand("hv %s %+f",PixMap->DRS_to_Pixel(i,j,k).c_str(), DiffVoltage);
+	    if(!PixMap->DRS_to_Pixel(i,j,k).empty()) {
+		  Cmd << PixMap->DRS_to_Pixel(i,j,k) << " " << std::showpos << DiffVoltage << " ";		  
+		}
 	    break;
 
@@ -184,5 +188,7 @@
 	    }
 	    else Response[i][j][k] = DiffVoltage/(Buffer[i][j][k]-Average[i][j][k]);
-	    if(!PixMap->DRS_to_Pixel(i,j,k).empty()) WriteHVCommand("hv %s %+f",PixMap->DRS_to_Pixel(i,j,k).c_str(), -DiffVoltage/2);
+	    if(!PixMap->DRS_to_Pixel(i,j,k).empty()) {
+		  Cmd << PixMap->DRS_to_Pixel(i,j,k) << " " << std::showpos << -DiffVoltage/2 << " ";		  		  
+		}
 	    break;
 
@@ -196,4 +202,9 @@
   FeedbackAverage->updateService();
   FeedbackSigma->updateService();
+
+  // Send command
+  if (!Cmd.str().empty()) {
+	DimClient::sendCommand("Bias/Command", ("hv "+Cmd.str()).c_str());
+  }
 
   switch (FBMode) {
@@ -269,6 +280,6 @@
   else {
     FBMode = Mode;
-	if (Mode != FB_ResponseFirst) m->State(m->INFO, "%s", FBState_Description[FBMode]);
-	else m->State(m->INFO, "%s (voltage difference %.3f)", FBState_Description[FBMode], DiffVoltage);
+	if (Mode != FB_ResponseFirst) m->Message(m->INFO, "%s", FBState_Description[FBMode]);
+	else m->Message(m->INFO, "%s (voltage difference %.3f)", FBState_Description[FBMode], DiffVoltage);
     ClearAverages();
   }
@@ -320,4 +331,6 @@
 void HVFeedback::MeasureResponse(float U) {
 
+  std::stringstream Cmd;
+
   if (U==0) {
     m->PrintMessage("HV Feedback: Error, voltage difference must not non-zero.\n");
@@ -325,11 +338,19 @@
   }
 
-  for (int i=m->FirstBoard; i<=m->LastBoard; i++) 
-    for (int j=0; j<fNumberOfChips; j++) 
-      for (int k=0; k<fNumberOfChannels; k++) {
-		if(!PixMap->DRS_to_Pixel(i,j,k).empty()) {
-          WriteHVCommand("hv %s %+f\n",PixMap->DRS_to_Pixel(i,j,k).c_str(), -U/2);
-    	}
-      }
+  for (int i=m->FirstBoard; i<=m->LastBoard; i++) { 
+  for (int j=0; j<fNumberOfChips; j++) { 
+  for (int k=0; k<fNumberOfChannels; k++) {
+	if(!PixMap->DRS_to_Pixel(i,j,k).empty()) {
+	  Cmd << PixMap->DRS_to_Pixel(i,j,k) << " " << std::showpos << -U/2 << " ";		  		  
+    }
+  }
+  }
+  }
+  
+  // Send command
+  if (!Cmd.str().empty()) {
+	DimClient::sendCommand("Bias/Command", ("hv "+Cmd.str()).c_str());
+  }
+
   DiffVoltage = U;
   SetFBMode(FB_ResponseFirst, true);
@@ -351,18 +372,4 @@
 
 //
-// Write bias voltage commmand
-//
-bool HVFeedback::WriteHVCommand(const char *Format, ...) {
-
-  char Textbuffer[MAX_COM_SIZE];
-  
-  va_list ArgumentPointer;  va_start(ArgumentPointer, Format); 
-  vsnprintf(Textbuffer, sizeof(Textbuffer), Format, ArgumentPointer);
-
-  DimClient::sendCommand("Bias/Command", Textbuffer);
-  return true;
-}
-
-//
 // Print feedback configuration
 //
Index: drsdaq/HVFeedback.h
===================================================================
--- drsdaq/HVFeedback.h	(revision 211)
+++ drsdaq/HVFeedback.h	(revision 226)
@@ -6,4 +6,5 @@
 #include <stdlib.h>
 #include <math.h>
+#include <sstream>
 
 #include "RawDataCTX.h"
@@ -12,5 +13,5 @@
 enum FBState {FB_Off, FB_Active, FB_Targets, FB_ResponseFirst, FB_ResponseSecond};
 
-class HVFeedback: public DimServer {//EvidenceServer {
+class HVFeedback: public DimServer {
 
     class DAQReadout *m;
@@ -70,5 +71,4 @@
     void GetResponse();
     void ClearAverages();
-    bool WriteHVCommand(const char *, ...);
     void PrintConfig(int);
 };
Index: drsdaq/drsdaq.cpp
===================================================================
--- drsdaq/drsdaq.cpp	(revision 211)
+++ drsdaq/drsdaq.cpp	(revision 226)
@@ -36,15 +36,6 @@
   int LockDescriptor;
 
-  // Readline library uses getc() (allows interruption by signal)
-  rl_getc_function = getc;
-
-  // writev() in DAQ thread needs to be able to write at least 3 chunks
-  if(IOV_MAX < 3) {
-	printf("Fatal error: IOV_MAX is less than 3, cannot use writev() to write event data.\n");
-	exit(EXIT_FAILURE);
-  }
-   
   // Assure only one instance of program runs (lock creator written to log file)
-  // Lock file deleted by ExitFunction()
+  // Lock file deleted by destructor
   if((LockDescriptor = open(LOCKFILE,O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)) == -1) {
     if(errno==EEXIST) {
@@ -59,13 +50,24 @@
   sprintf(str,"echo Created >%s; date >>%s; echo by $USER@$HOSTNAME >>%s",LOCKFILE,LOCKFILE,LOCKFILE);
   system(str);
-  
+
+  // Readline library uses getc() (allows interruption by signal)
+  rl_getc_function = getc;
+
+  // writev() in DAQ thread needs to be able to write at least 3 chunks
+  if(IOV_MAX < 2) {
+	printf("Fatal error: IOV_MAX is less than 2, cannot use writev() to write event data.\n");
+	exit(EXIT_FAILURE);
+  }
+     
   system("clear");
   printf("\n*** DRS readout (built %s, %s, revision %s) *** \n\n",__DATE__, __TIME__, REVISION);
+
+  // Set exit function
+  atexit(&ExitFunction);
 
   // Construct main instance (static ensures destructor is called with exit())
   static DAQReadout M;
 
-  // Set signal and exit handlers
-  atexit(&ExitFunction);
+  // Set signal handlers
   signal(SIGILL, &CrashHandler);
   signal(SIGABRT, &CrashHandler);
@@ -88,5 +90,4 @@
     // Process command
 	DimClient::sendCommand(SERVER_NAME"/Command", Command);
-
     free(Command);
   }  
@@ -94,12 +95,8 @@
 
 
-//*****************
-//  Signal handlers
-//*****************
-
 // 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);
+  printf("Caught signal number %d. Removed lockfile and performing standard signal action. Good luck.\n",Signal);
   signal(Signal, SIG_DFL);
   raise(Signal);
@@ -109,8 +106,6 @@
 void ExitFunction() {
 
-  if (remove(LOCKFILE)==-1) {
+  if (remove(LOCKFILE) == -1) {
     printf("Could not remove lock file %s (%s)\n", LOCKFILE, strerror(errno));
   }
-
-  return;          
 }
