Index: /hvcontrol/History.txt
===================================================================
--- /hvcontrol/History.txt	(revision 219)
+++ /hvcontrol/History.txt	(revision 220)
@@ -34,2 +34,3 @@
 			server
 29/1/2010	DAC value 0 is now equivilant to calibrated voltage value 0
+4/6/2010	Command 'hv' allows an array of pixel IDs/voltages (used by feedback)
Index: /hvcontrol/src/HV.cc
===================================================================
--- /hvcontrol/src/HV.cc	(revision 219)
+++ /hvcontrol/src/HV.cc	(revision 220)
@@ -17,5 +17,5 @@
 HVBoard::HVBoard(int DeviceNumber, char *DeviceName, class ProcessIO *PIO) {
    
-  char Buffer[BUFFER_LENGTH];
+  char *Buffer;
   struct termios tio;
  
@@ -27,9 +27,17 @@
   
   // Create DIM services
-  snprintf(Buffer, sizeof(Buffer), SERVER_NAME"/NAME/ID%.2d", BoardNumber);
+  if (asprintf(&Buffer, SERVER_NAME"/NAME/ID%.2d", BoardNumber) == -1) {
+    m->PrintMessage(All, "asprintf() failed for DIM service name creation\n");
+	return;
+  }
   Name = new DimService (Buffer, BoardName);
-
-  snprintf(Buffer, sizeof(Buffer), SERVER_NAME"/VOLT/ID%.2d", BoardNumber);
+  free(Buffer);
+  
+  if (asprintf(&Buffer, SERVER_NAME"/VOLT/ID%.2d", BoardNumber) == -1) {
+    m->PrintMessage(All, "asprintf() failed for DIM service name creation\n");
+	return;
+  }
   BiasVolt = new DimService (Buffer, "D", HVV, NUM_CHAINS*NUM_CHANNELS*sizeof(double));
+  free(Buffer);
 
   for (int i=0; i<NUM_CHAINS; i++) Overcurrent[i] = false;
@@ -42,9 +50,14 @@
 
   // Open device (do not warn on non-existing device)
-  snprintf(Buffer, BUFFER_LENGTH, "/dev/%s",DeviceName);
+  if (asprintf(&Buffer, "/dev/%s",DeviceName) == -1) {
+    m->PrintMessage(All, "asprintf() failed for device name creation\n");
+	return;
+  }
   if ((fDescriptor = open(Buffer, O_RDWR|O_NOCTTY|O_NDELAY)) == -1) {
     if(errno != 2) m->PrintMessage(All, "Error: Could not open device %d/%s (%s)\n", DeviceNumber,DeviceName, strerror(errno));
+	free(Buffer);
     return;
   }
+  free(Buffer);
 
   // Get current serial port settings
Index: /hvcontrol/src/ProcessIO.cc
===================================================================
--- /hvcontrol/src/ProcessIO.cc	(revision 219)
+++ /hvcontrol/src/ProcessIO.cc	(revision 220)
@@ -14,7 +14,31 @@
 static char* state_str[]    = {"active", "stopped", "n.a."};
 
-ProcessIO::ProcessIO(): 
-    	    DimCommand((char *) SERVER_NAME"/Command", (char *) "C"),
-    	    EvidenceServer(SERVER_NAME) {
+// Branch table for command evaluation
+static const struct CL_Struct { const char *Name;    
+								void (ProcessIO::*CommandPointer)();
+								unsigned int MinNumParameter;
+								const char *Parameters;
+								const char *Help;
+  } 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)"},
+	{"status", &ProcessIO::cmd_status, 0, "[dac]", "Show status information (DAC values if requested)"},
+	{"config", &ProcessIO::cmd_config, 0, "", "Print configuration"},
+	{"load", &ProcessIO::cmd_load, 1, "<file>", "Load and set bias settings from file"},
+	{"save", &ProcessIO::cmd_save, 1, "<file>", "Save current bias settings to file"},
+	{"exit", &ProcessIO::cmd_exit, 0, "", "Exit program"},
+	{"rate", &ProcessIO::cmd_rate, 1, "<rate>", "Set status refresh rate in Hz"},
+	{"timeout", &ProcessIO::cmd_timeout, 1, "<time>", "Set timeout to return from read in seconds"},
+	{"reset", &ProcessIO::cmd_reset, 0, "", "Reset active bias board"},
+	{"start", &ProcessIO::cmd_start, 0, "", "Start bias status monitor"},
+	{"stop", &ProcessIO::cmd_stop, 0, "", "Stop bias status monitor"},
+	{"uptime", &ProcessIO::cmd_uptime, 0, "", "Get program uptime"},
+	{"help", &ProcessIO::cmd_help, 0, "", "Print help"}};
+
+
+using namespace std;
+
+ProcessIO::ProcessIO(): EvidenceServer(SERVER_NAME) {
 
   // Get program start time
@@ -30,6 +54,4 @@
   FirstChain  = 0;
   LastChain   = NUM_CHAINS-1;
-
-  UpdateDelay = 0.0;
 
   // Get configuration data
@@ -62,8 +84,11 @@
   }
   LastBoard = NumHVBoards-1;
-  
+
   // Create instances
   calib  = new HVCalib(this);
-  pm 	 = new PixelMap(fPixMapTable);  
+  pm 	 = new PixelMap(fPixMapTable);
+  
+  // Install DIM command (after all initialized)
+  Command = new DimCommand((char *) SERVER_NAME"/Command", (char *) "C", this);
 }
 
@@ -71,4 +96,6 @@
 ProcessIO::~ProcessIO() {
   
+  delete Command;
+
   for (int i=0; i<NumHVBoards; i++) delete fHVBoard[i];
   delete[] fHVBoard;
@@ -81,445 +108,412 @@
 void ProcessIO::CommandControl(char *Command) {
 
-  if (strlen(Command)==0) return;  // Ignore empty commands
-
-  if(Command[0]=='.') {   // Shell command
+  // Ignore empty commands
+  if (strlen(Command)==0) return;
+
+  // Shell command
+  if(Command[0]=='.') {
     system(&(Command[1]));
     return;
   }
 
-  for(int i=0; i<MAX_NUM_TOKEN; i++) Param[i] = "";  // All pointers point initially to empty string
-  NParam = ParseInput(Command, Param);
-
-  // Adress board
-  if (Match(Param[0], "board")) {
+  // Parse command into tokens
+  Parameter.clear();
+  char *Start; 
+  while(true) {
+    while (isspace(*Command)) Command++; // Ignore initial white spaces
+    if(*Command=='\0') break;
+    if (*Command == '\"') {
+	  Start = ++Command;
+      while(*Command!='\"' && *Command!='\0') Command++;
+    }
+    else {
+	  Start = Command;
+      while(!isspace(*Command) && *Command!='\0') Command++;
+    }
+    if(*Command != '\0') *Command++ = '\0';
+	Parameter.push_back(Start);
+  }
+
+  // Search for command in command list
+  for(unsigned int CmdNumber=0; CmdNumber<sizeof(CommandList)/sizeof(CL_Struct); CmdNumber++) {
+    if (Match(Parameter[0], CommandList[CmdNumber].Name)) {
+      if(Parameter.size()-1 < CommandList[CmdNumber].MinNumParameter) {
+		PrintMessage("Usage: %s %s\n", CommandList[CmdNumber].Name, CommandList[CmdNumber].Parameters);
+		return;
+	  }
+
+	  // Jump to command function
+	  (this->*CommandList[CmdNumber].CommandPointer)();
+	  return;  
+    }
+  }
+  PrintMessage("Unknown command '%s'\n", Parameter[0].c_str());
+}
+
+
+// Adress board
+void ProcessIO::cmd_board() {
     
-    if (!NumHVBoards) return;
-
-    // Print list of boards
-    if (NParam == 1) {
-      for (int i=0; i<NumHVBoards; i++) {
-        PrintMessage("Board %d: %s\n", fHVBoard[i]->GetBoardNumber(), fHVBoard[i]->BoardName);
-      }
+  // Print list of boards
+  if (Parameter.size() == 1) {
+    for (int i=0; i<NumHVBoards; i++) {
+      PrintMessage("Board %d: %s\n", fHVBoard[i]->GetBoardNumber(), fHVBoard[i]->BoardName);
+    }
+    return;
+  }
+
+  //Select board(s)
+  if (Match(Parameter[1].c_str(), "all")) {
+    FirstBoard = 0;
+    LastBoard = NumHVBoards-1;
+  } 
+  else if (Parameter.size()==2 && atoi(Parameter[1].c_str())>=0 && atoi(Parameter[1].c_str())<NumHVBoards) {
+    FirstBoard = atoi(Parameter[1].c_str());
+    LastBoard = FirstBoard;
+  }
+  else if (Parameter.size()==3 && atoi(Parameter[1].c_str())>=0 && atoi(Parameter[1].c_str())<NumHVBoards && 
+         atoi(Parameter[2].c_str())>0 && atoi(Parameter[2].c_str())<NumHVBoards) {
+    FirstBoard = atoi(Parameter[1].c_str());
+    LastBoard = atoi(Parameter[2].c_str());
+  }
+  else PrintMessage("Cannot address board(s), out of range.\n");
+} 
+
+// 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
+void ProcessIO::cmd_config() {
+
+  PrintMessage( " Pixel map table:   %s\n"
+    	    	" %d USB devices:\n", fPixMapTable, NumHVBoards);  
+
+  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"
+    	    	" DACMin value:      %d\n"
+    	    	" DACMax value:      %d\n"
+    	    	" HVCalibOffset :    %f\n"
+    	    	" HVCalibSlope :     %f\n"
+    	    	" HVMaxDiff :        %u\n",
+		fTimeOut, fStatusRefreshRate, DACMin,
+		DACMax, fHVCalibOffset, fHVCalibSlope, fHVMaxDiff);
+}
+
+// Print help
+void ProcessIO::cmd_help() {
+
+  char Buffer[MAX_COM_SIZE];
+  for(unsigned int i=0; i<sizeof(CommandList)/sizeof(CL_Struct); i++) {
+    snprintf(Buffer, sizeof(Buffer), "%s %s", CommandList[i].Name, CommandList[i].Parameters);
+    PrintMessage("%-28s%s\n", Buffer, CommandList[i].Help);
+  }
+  
+  PrintMessage(".<command>                  Execute shell command\n\n"
+  	"Items in <> are mandatory, in [] optional, | indicates mutual exclusive or.\n");
+} 
+
+// Set new bias voltage
+void ProcessIO::cmd_hv() {
+
+  int hvoltage, DACValue, Errors=0, Board=-1, Chain=-1, Channel=-1;
+  double hvoltageV;
+  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;
-    }
-
-    //Select board(s)
-    if (Match(Param[1],"all")) {
-      FirstBoard = 0;
-      LastBoard = NumHVBoards-1;
     } 
-    else if (NParam==2 && atoi(Param[1])>=0 && atoi(Param[1])<NumHVBoards) {
-      FirstBoard = atoi(Param[1]);
-      LastBoard = FirstBoard;
-    }
-    else if (NParam==3 && atoi(Param[1])>=0 && atoi(Param[1])<NumHVBoards && 
-           atoi(Param[2])>0 && atoi(Param[2])<NumHVBoards) {
-      FirstBoard = atoi(Param[1]);
-      LastBoard = atoi(Param[2]);
-    }
-    else PrintMessage("Cannot address board(s), out of range.\n");
-
+  }
+  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;
-  } 
-
-
-  // Adress chains
-  else if (Match(Param[0], "chain")) {
+  }
+
+  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();
+  } // Boards
+
+  if (Errors > 0) PrintMessage("Errors on %d channel(s) occurred\n", Errors);
+}
+
+// Load bias settings from file
+void ProcessIO::cmd_load() {
+
+  char Buffer[MAX_COM_SIZE];
+  int NBoards = 0, Errors = 0, Chain, Channel;
+  unsigned int DACValue;
+  FILE *File;
+
+  if ((File=fopen(Parameter[1].c_str(), "r")) == NULL) {
+    PrintMessage("Error: Could not open file '%s' (%s)\n", Parameter[1].c_str(), strerror(errno));
+    return;
+  }
+
+  while (fgets(Buffer, sizeof(Buffer), File) != NULL) {
+    for (int Board=0; Board<NumHVBoards; Board++) {
+	  if (Match(fHVBoard[Board]->BoardName, Buffer)) {
+		PrintMessage("Found bias settings for board %d (%s)\n\r",fHVBoard[Board]->GetBoardNumber(), fHVBoard[Board]->BoardName);
+
+		Chain = 0;  Channel = 0;
+		while (fscanf(File, "%u", &DACValue)==1 && Chain<NUM_CHAINS) {
+    		  if (!RampVoltage(DACValue, Board, Chain, Channel)) {
+	    	Errors++;
+	    	PrintMessage("Error: Could not ramp chain %d, channel %d\n", Chain, Channel);
+    		  }
+		  else {
+	    	PrintMessage("Ramped chain %d, channel %d to %u (%.2f V)                         \r",
+	    	   Chain,Channel,DACValue,calib->DACToHV(DACValue,Board,Chain,Channel));
+    		  }
+		  fHVBoard[Board]->HVV[Chain][Channel] = calib->DACToHV(fHVBoard[Board]->HV[Chain][Channel], Board, Chain, Channel);
+
+		  if(++Channel == NUM_CHANNELS) {
+	    	Chain++;
+	    	Channel = 0;
+		  }
+		}
+
+    	// Update DIM service
+		fHVBoard[Board]->BiasVolt->updateService();
+
+		if (ferror(File) != 0) {
+		  PrintMessage("Error reading DAC value from file, terminating. (%s)\n",strerror(errno));
+    		  return;
+		}
+		else PrintMessage("\nFinished updating board\n");
+    	NBoards++;
+	  }
+    } // Loop over boards
+  } // while()
+    	    
+  if (NBoards != NumHVBoards) {
+    PrintMessage("Warning: Could not load bias settings for all connected HV boards\n");
+  }
+  else if (Errors == 0) PrintMessage("Success: Read bias settings for all connected HV boards\n");
+  if (Errors != 0) PrintMessage("Warning: Errors on %d channel(s) occurred\n", Errors);
+
+  if (fclose(File) != 0) PrintMessage("Error: Could not close file '%s'\n",Parameter[1].c_str());
+}
+	   
+// Set status refresh rate
+void ProcessIO::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
+void ProcessIO::cmd_reset() {
+
+  for (int i=FirstBoard; i<=LastBoard; i++) ResetBoard(i);
+}
+
+// Save bias settings of all boards
+void ProcessIO::cmd_save() {
+
+  FILE *File;
+  time_t time_now_secs;
+  struct tm *Time;
+
+  time(&time_now_secs);
+  Time = localtime(&time_now_secs);
+
+  if ((File = fopen(Parameter[1].c_str(), "w")) == NULL) {
+    PrintMessage("Error: Could not open file '%s' (%s)\n", Parameter[1].c_str(), strerror(errno));
+    return;
+  }
+
+  fprintf(File,"********** Bias settings, %04d %02d %02d, %02d:%02d:%02d **********\n\n",
+	  1900 + Time->tm_year, 1 + Time->tm_mon,
+	  Time->tm_mday, Time->tm_hour, Time->tm_min, Time->tm_sec);
+
+  for (int i=0; i<NumHVBoards; i++) {
+    fprintf(File, "%s\n\n", fHVBoard[i]->BoardName);
+
+    for (int j=0; j<NUM_CHAINS; j++) {
+  for (int k=0; k<NUM_CHANNELS; k++) fprintf(File,"%5d ",fHVBoard[i]->HV[j][k]);
+  fprintf(File, "\n");
+    }
+    fprintf(File, "\n");
+  }
+
+  if (fclose(File) != 0) {
+    PrintMessage("Error: Could not close file '%s' (%s)\n", Parameter[1].c_str(), strerror(errno));  
+  }
+}
+
+// Start monitoring
+void ProcessIO::cmd_start() {
+
+  state = active;
+  pthread_kill(HVMonitor, SIGUSR1);
+  PrintMessage(All, "Status monitoring activated\n");
+}
+
+// Print status
+void ProcessIO::cmd_status() {
+
+  PrintMessage("\n Status monitor: %s\n", state_str[state]);
+  PrintMessage(" Status refresh rate [Hz]: %.2f\n", fStatusRefreshRate);
+  PrintMessage(" Total number of boards: %d\n", NumHVBoards);
+  PrintMessage(" Active boards: %d\n\n", LastBoard - FirstBoard + 1);
+
+  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++) {
+	  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");
+	  }
+    }
+  }
+} 
+
+// Stop monitoring
+void ProcessIO::cmd_stop() {
+
+  state = stopped;
+  pthread_kill(HVMonitor, SIGUSR1);
+  PrintMessage(All, "Status monitor stopped\n");
+}
+
+// Set timeout to return from read
+void ProcessIO::cmd_timeout() {
+
+  double Timeout;
+
+  if (!ConvertToDouble(Parameter[1], &Timeout)) {
+     PrintMessage("Error: Wrong number format\n");
+     return;   
+  }
+
+  for (int i=0; i<NumHVBoards; i++) fHVBoard[i]->SetTimeOut(Timeout);
+  if (NumHVBoards > 0) PrintMessage("Timeout set to %.2f s for all boards\n", Timeout);
+}
     
-    if (!NumHVBoards) return;
-    
-    if (Match(Param[1],"all")) {
-      FirstChain = 0;
-      LastChain = 3;
-    } 
-    else if (NParam==2 && atoi(Param[1])>=0 && atoi(Param[1])<NUM_CHAINS) {
-      FirstChain = atoi(Param[1]);
-      LastChain = FirstChain;
-    }
-    else if (NParam==3 && atoi(Param[1])>=0 && atoi(Param[1])<NUM_CHAINS && 
-           atoi(Param[2])>0 && atoi(Param[2])<NUM_CHAINS) {
-      FirstChain = atoi(Param[1]);
-      LastChain = atoi(Param[2]);
-    }
-    else PrintMessage("Cannot address chain(s), out of range.\n");
-        
-    return;
-  } 
-
-
-  // Print HV utility configuration
-  else if (Match(Param[0], "config")) {
-    PrintMessage( " Pixel map table:   %s\n"
-    	    	  " %d USB devices:\n", fPixMapTable,
-		  NumHVBoards);  
-    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"
-    	    	  " DACMin value:      %d\n"
-    	    	  " DACMax value:      %d\n"
-    	    	  " HVCalibOffset :    %f\n"
-    	    	  " HVCalibSlope :     %f\n"
-    	    	  " HVMaxDiff :        %u\n", fTimeOut,
-		  fStatusRefreshRate, DACMin,
-		  DACMax, fHVCalibOffset, fHVCalibSlope,
-		  fHVMaxDiff);
-
-    return;
-  }
-
-
-  // Print help
-  if (Match(Param[0], "help")) {
-    PrintMessage(" board <i>|<i> <j>|<all>           Address board i, boards i-j or all boards or list boards\n"
-    	" chain <i>|<i> <j>|<all>           Address chain i, chains i-j or all chains\n"
-    	" hv <PXL id>|<ch>|<all> <v>        Set/change bias of pixel, ch. or all ch. of active chain(s)/board(s)\n"
-		" status [dac]                      Show status information (DAC values if requested)\n"
-		" config                            Print configuration\n"
-		" load <file>                       Load and set bias settings from <file>\n"
-		" save <file>                       Save current bias settings to [file]\n"
-		" exit                              Exit program\n"
-		" rate <rate>                       Set status refresh rate to <rate> [Hz]\n"
-		" timeout <time>                    Set timeout to return from read to <time> [s]\n"
-		" reset                             Reset active bias board\n"
-		" start                             Start bias status monitor\n"
-		" stop                              Stop bias status monitor - not recommended!\n"
-		" uptime                            Get program uptime [h:m:s]\n"
-		" help                              Print help\n"
-		" .<cmd>                   	     Execute shell command <cmd>");
-
-    return;
-  } 
-
-
-  // Set new bias voltage (if no boards available, simply returns OK)
-  // First reponse to socket should be 'OK' if no error occurred.
-  if (Match(Param[0], "hv")) {
-
-    int hvoltage, DACValue, Errors=0, Board=-1, Chain=-1, Channel=-1;
-    double hvoltageV;
-    bool SetDac;
-    
-    // Need two or parameters
-    if (NParam<3 || NParam>4) {
-      PrintMessage("Usage: hv <channel>|<all> <voltage> [dac]\n");
-      return;
-    }
-
-    // Evaluate voltage parameter
-    if (NParam==4 && Match(Param[3], "dac")) {
-      SetDac = true;
-      if (!ConvertToInt(Param[2], &hvoltage)) {
-        PrintMessage("Error: Wrong number format for DAC voltage setting\n");
-        return;
-      } 
-    }
-    else {
-      SetDac = false;
-      if (!ConvertToDouble(Param[2], &hvoltageV)) {
-        PrintMessage("Error: Wrong number format for voltage setting\n");
-        return;
-      }
-    } 
-
-    // Evaluate pixel or channel parameter    
-    if(pm->Pixel_to_HVboard(Param[1]) != 999999999) {
-      Board = pm->Pixel_to_HVboard(Param[1]);
-      Chain = pm->Pixel_to_HVchain(Param[1]);
-      Channel = pm->Pixel_to_HVchannel(Param[1]);
-    }
-    else if (!Match(Param[1], "all") && !ConvertToInt(Param[1], &Channel)) {
-      PrintMessage("Error: Wrong channel identification\n");
-      return;
-    }
-
-    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(*Param[2])==0 && fHVBoard[i]->HV[j][k] == 0) continue;
-
-	  // Determine new DAC values
-	  if (!SetDac){
-		if (isdigit(*Param[2])==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(*Param[2])==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);
-
-      // Update DIM services
-      //fHVBoard[i]->BiasVolt[j][k]->updateService();
-	  UpdateDelay = 1.0;
-	} // Channels	
-    } // Chains
-    } // Boards
-
-    if (Errors > 0) PrintMessage("Errors on %d channel(s) occurred\n", Errors);
-    
-    return;
-  }
-
-
-  // Load HV settings from file
-  else if (Match(Param[0], "load")) {
-
-    char Buffer[MAX_COM_SIZE];
-    int NBoards = 0, Errors = 0, Chain, Channel;
-    unsigned int DACValue;
-    FILE *File;
-    
-    if (NParam != 2) {
-      PrintMessage("Usage: load <file>\n");
-      return;
-    }
-    
-    if ((File=fopen(Param[1], "r")) == NULL) {
-      PrintMessage("Error: Could not open file '%s' (%s)\n", Param[1], strerror(errno));
-      return;
-    }
-	
-    while (fgets(Buffer, sizeof(Buffer), File) != NULL) {
-      for (int Board=0; Board<NumHVBoards; Board++) {
-	if (Match(fHVBoard[Board]->BoardName, Buffer)) {
-	  PrintMessage("Found bias settings for board %d (%s)\n\r",fHVBoard[Board]->GetBoardNumber(), fHVBoard[Board]->BoardName);
-
-	  Chain = 0;  Channel = 0;
-	  while (fscanf(File, "%u", &DACValue)==1 && Chain<NUM_CHAINS) {
-    	    if (!RampVoltage(DACValue, Board, Chain, Channel)) {
-	      Errors++;
-	      PrintMessage("Error: Could not ramp chain %d, channel %d\n", Chain, Channel);
-    	    }
-	    else {
-	      PrintMessage("Ramped chain %d, channel %d to %u (%.2f V)                         \r",
-	      	 Chain,Channel,DACValue,calib->DACToHV(DACValue,Board,Chain,Channel));
-    	    }
-	    fHVBoard[Board]->HVV[Chain][Channel] = calib->DACToHV(fHVBoard[Board]->HV[Chain][Channel], Board, Chain, Channel);
-
-	    // Update DIM services
-    	    //fHVBoard[Board]->BiasVolt[Chain][Channel]->updateService();
-		UpdateDelay = 1.0;
-	    if(++Channel == NUM_CHANNELS) {
-	      Chain++;
-	      Channel = 0;
-	    }
-	  }
-	  if (ferror(File) != 0) {
-	    PrintMessage("Error reading DAC value from file, terminating. (%s)\n",strerror(errno));
-    	    return;
-	  }
-	  else PrintMessage("\nFinished updating board\n");
-    	  NBoards++;
-	}
-      } // Loop over boards
-    } // while()
-    	    
-    if (NBoards != NumHVBoards) {
-      PrintMessage("Warning: Could not load bias settings for all connected HV boards\n");
-    }
-    else if (Errors == 0) PrintMessage("Success: Read bias settings for all connected HV boards\n");
-    if (Errors != 0) PrintMessage("Warning: Errors on %d channel(s) occurred\n", Errors);
-    
-    if (fclose(File) != 0) PrintMessage("Error: Could not close file '%s'\n",Param[1]);
-
-    return;    
-  }
-	   
-
-  // Set status refresh rate
-  if (Match(Param[0], "rate")) {
-
-    double Rate;
-    
-    if (NParam != 2) {
-      PrintMessage("Usage: rate <Hz>\n");
-      return;
-    }
-    
-    if (!ConvertToDouble(Param[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);
-
-    return;
-  }
-  
-  // Reset
-  if (Match(Param[0], "reset")) {
-
-    if (!NumHVBoards) return;
-    for (int i=FirstBoard; i<=LastBoard; i++) ResetBoard(i);
-    return;
-  }
-
-
-  // Save HV settings of all boards
-  else if (Match(Param[0], "save")) {
-
-    FILE *File;
-    time_t time_now_secs;
-    struct tm *Time;
-
-    if (NParam != 2) {
-      PrintMessage("Usage: save <Filename>\n");
-      return;
-    }
-  
-    time(&time_now_secs);
-    Time = localtime(&time_now_secs);
-
-    if ((File = fopen(Param[1], "w")) == NULL) {
-      PrintMessage("Error: Could not open file '%s' (%s)\n", Param[1], strerror(errno));
-      return;
-    }
-  
-    fprintf(File,"********** Bias settings, %04d %02d %02d, %02d:%02d:%02d **********\n\n",
-	    1900 + Time->tm_year, 1 + Time->tm_mon,
-	    Time->tm_mday, Time->tm_hour, Time->tm_min, Time->tm_sec);
-  
-    for (int i=0; i<NumHVBoards; i++) {
-      fprintf(File, "%s\n\n", fHVBoard[i]->BoardName);
-
-      for (int j=0; j<NUM_CHAINS; j++) {
-	for (int k=0; k<NUM_CHANNELS; k++) fprintf(File,"%5d ",fHVBoard[i]->HV[j][k]);
-	fprintf(File, "\n");
-      }
-      fprintf(File, "\n");
-    }
-
-    if (fclose(File) != 0) {
-      PrintMessage("Error: Could not close file '%s' (%s)\n", Param[1], strerror(errno));  
-    }
-
-    return;
-  }
-
-
-  // Start monitoring
-  else if (Match(Param[0], "start")) {
-
-    state = active;
-    pthread_kill(HVMonitor, SIGUSR1);
-    PrintMessage(All, "Status monitoring activated\n");
-    return;  
-  }
-
- 
-  // Print status
-  else if (Match(Param[0], "status")) {
-    
-    PrintMessage("\n Status monitor: %s\n", state_str[state]);
-    PrintMessage(" Status refresh rate [Hz]: %.2f\n", fStatusRefreshRate);
-    PrintMessage(" Total number of boards: %d\n", NumHVBoards);
-    PrintMessage(" Active boards: %d\n\n", LastBoard - FirstBoard + 1);
-
-    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++) {
-	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(NParam == 2) PrintMessage("%5d ",fHVBoard[i]->HV[j][k*8+l]);
-    	    else PrintMessage("%#5.2f ",fHVBoard[i]->HVV[j][k*8+l]);
-    	  }
-	  PrintMessage("\n");
-	}
-      }
-    }
-
-    return;
-  } 
-
-
-  // Stop monitoring
-  else if (Match(Param[0], "stop")) {
-
-    state = stopped;
-    pthread_kill(HVMonitor, SIGUSR1);
-    PrintMessage(All, "Status monitor stopped\n");
-
-    return;
-  }
-
-
-  // Set timeout to return from read
-  if (Match(Param[0], "timeout")) {
-
-    double Timeout;
-    
-    if (!NumHVBoards) return;
-
-    if (NParam != 2) {
-      PrintMessage("Usage: timeout <secs>\n");
-      return;
-    }
-    
-    if (!ConvertToDouble(Param[1], &Timeout)) {
-       PrintMessage("Error: Wrong number format\n");
-       return;   
-    }
-
-    for (int i=0; i<NumHVBoards; i++) fHVBoard[i]->SetTimeOut(Timeout);
-    PrintMessage("Timeout set to %.2f s for all boards\n", Timeout);
-    
-    return;
-  }
-
-    
-  // Print uptime
-  if (Match(Param[0], "uptime")) {
-    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);
-
-    return;
-  } 
-
-
-  // Exit program
-  else if(Match(Param[0], "exit")) {
-
-    Exit = true;
-    pthread_kill(HVMonitor, SIGUSR1); 
-    return;
-  }
-  
-  PrintMessage("Unknown command '%s'\n", Param[0]);
- 
-  return;
-}
-
+// Print uptime
+void ProcessIO::cmd_uptime() {
+
+  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);
+} 
+
+// Exit program
+void ProcessIO::cmd_exit() {
+
+  Exit = true;
+  pthread_kill(HVMonitor, SIGUSR1); 
+}
+  
 
 // Print message to selected target
 void ProcessIO::PrintMessage(MsgTarget Target, const char *Format, ...) {
+
   va_list ArgumentPointer;
   va_start(ArgumentPointer, Format); 
@@ -530,4 +524,5 @@
 // Print message to log file, and screen or socket (depending on command origin)
 void ProcessIO::PrintMessage(const char *Format, ...) {
+
   va_list ArgumentPointer;
   va_start(ArgumentPointer, Format);
@@ -567,5 +562,4 @@
   }
 }
-
 
 // Ramp to new voltage with maximum step size given in fHVMaxDiff
@@ -626,11 +620,4 @@
     }
   }
-
-  if (UpdateDelay >= 0) {
-	UpdateDelay -= 1.0/(NumHVBoards*fStatusRefreshRate);
-	if (UpdateDelay <= 0) for (int i=0; i<NumHVBoards; i++) {
-	  fHVBoard[i]->BiasVolt->updateService();
-	}
-  }
 }
 
@@ -661,38 +648,15 @@
 
 
-// Parse command line for white space and double-quote separated tokens 
-int ProcessIO::ParseInput(char* Command, const char *Param[]) {
-  int Count=0;
-   
-  while(Count<MAX_NUM_TOKEN) {
-    while (isspace(*Command)) Command++; // Ignore initial white spaces
-    if(*Command=='\0') break;
-    if (*Command == '\"') {
-      Param[Count] = ++Command;
-      while(*Command!='\"' && *Command!='\0') Command++;
-    }
-    else {
-      Param[Count] = Command;
-      while(!isspace(*Command) && *Command!='\0') Command++;
-    }
-    if(*Command != '\0') *Command++ = '\0';
-    Count++;
-  }
-  return Count;
-}
-
-//
-// Command handling (the only command is 'Bias/Command')
-//
+// Command handling (mutex needed because of monitor thread)
 void ProcessIO::commandHandler() {
 
-    pthread_mutex_lock(&control_mutex);
-    CommandControl(getString());
-    pthread_mutex_unlock(&control_mutex);
+  pthread_mutex_lock(&control_mutex);
+  if (getCommand() == Command) CommandControl(getCommand()->getString());
+  pthread_mutex_unlock(&control_mutex);
 }
 
 // Check if two strings match (min 1 character must match)
-bool Match(const char *str, const char *cmd) {
-  return strncasecmp(str,cmd,strlen(str)==0 ? 1:strlen(str)) ? false:true;
+bool Match(string str, const char *cmd) {
+  return strncasecmp(str.c_str(),cmd,strlen(str.c_str())==0 ? 1:strlen(str.c_str())) ? false:true;
 }
 
@@ -700,9 +664,9 @@
 // Convert string to double
 // Returns false if conversion did not stop on whitespace or EOL character
-bool ConvertToDouble(const char *String, double *Result) {
+bool ConvertToDouble(string String, double *Result) {
 
   char *EndPointer;
   
-  *Result = strtod(String, &EndPointer);
+  *Result = strtod(String.c_str(), &EndPointer);
   if(!isspace(*EndPointer) && *EndPointer!='\0') return false;
   return true;
@@ -712,9 +676,9 @@
 // Convert string to int
 // Returns false if conversion did not stop on whitespace or EOL character
-bool ConvertToInt(const char *String, int *Result) {
+bool ConvertToInt(string String, int *Result) {
 
   char *EndPointer;
   
-  *Result = (int) strtol(String, &EndPointer, 0);
+  *Result = (int) strtol(String.c_str(), &EndPointer, 0);
   if(!isspace(*EndPointer) && *EndPointer!='\0') return false;
   return true;
Index: /hvcontrol/src/ProcessIO.h
===================================================================
--- /hvcontrol/src/ProcessIO.h	(revision 219)
+++ /hvcontrol/src/ProcessIO.h	(revision 220)
@@ -18,5 +18,4 @@
 #define NUM_CHAINS 4
 #define NUM_CHANNELS 32
-#define BUFFER_LENGTH 256
 
 #define MIN_TIMEOUT 0.01
@@ -26,68 +25,72 @@
 #define MAX_RATE 50.0
 
-#define MAX_NUM_TOKEN 10
-
 enum MsgTarget {Console=1, Log=2, All=7};
 typedef enum stateenum {active, stopped, na} state_enum;
 
-class ProcessIO: public DimCommand, public EvidenceServer {
+class ProcessIO: public EvidenceServer {
 
-  time_t StartTime;
-  PixelMap *pm;
-  float UpdateDelay;
+	time_t StartTime;
+	PixelMap *pm;
+	DimCommand *Command;
 
-  void commandHandler();
+	void commandHandler();
 
  public:
+	HVCalib     *calib;
+	HVBoard **fHVBoard;
 
-  HVCalib     *calib;
-  HVBoard **fHVBoard;
+	pthread_mutex_t control_mutex;
+
+	char Prompt[MAX_COM_SIZE];
+	std::vector<std::string> Parameter;
+
+	// Configuration data
+	char *fPixMapTable;
+	float fTimeOut;
+	float fStatusRefreshRate;
+	int DACMin;
+	int DACMax;
+	float fHVCalibOffset;
+	float fHVCalibSlope;
+	unsigned int fHVMaxDiff;
+
+	// Status variables  
+	pthread_t HVMonitor;       // exit function sends signal to these threads
+
+	int NumHVBoards;
+	int FirstBoard;
+	int LastBoard;
+	int FirstChain;
+	int LastChain;
   
-  pthread_mutex_t control_mutex;
+	state_enum   state;
+	bool Exit;
 
-  char Prompt[MAX_COM_SIZE];
-  const char *Param[MAX_NUM_TOKEN]; // For parser
-  int NParam;
+	// Methods
+	ProcessIO();
+	~ProcessIO();
 
-  // Configuration data
-  char *fPixMapTable;
-  float fTimeOut;
-  float fStatusRefreshRate;
-  int DACMin;
-  int DACMax;
-  float fHVCalibOffset;
-  float fHVCalibSlope;
-  unsigned int fHVMaxDiff;
-
-  // Status variables  
-  pthread_t HVMonitor;       // exit function sends signal to these threads
-  
-  int NumHVBoards;
-  int FirstBoard;
-  int LastBoard;
-  int FirstChain;
-  int LastChain;
-  
-  state_enum   state;
-  bool Exit;
-    
-  // Methods
-  ProcessIO();
-  ~ProcessIO();
-
-  void PrintMessage(MsgTarget, const char *, ...);
-  void PrintMessage(const char *, ...);
-  void DoPrintMessage(const char *, va_list, MsgTarget);
-  void CommandControl(char*);
-  bool RampVoltage(unsigned int, int, int, int);
-  void Monitor();
-  void ResetBoard(int);
-  void PrintBoardStatus(int);
-  int ParseInput(char*, const char *Param[]);
+	void PrintMessage(MsgTarget, const char *, ...);
+	void PrintMessage(const char *, ...);
+	void DoPrintMessage(const char *, va_list, MsgTarget);
+	void CommandControl(char*);
+	bool RampVoltage(unsigned int, int, int, int);
+	void Monitor();
+	void ResetBoard(int);
+	void PrintBoardStatus(int);
+	
+	void cmd_board();	void cmd_hv();
+	void cmd_status();	void cmd_config();
+	void cmd_load();	void cmd_save();
+	void cmd_exit();	void cmd_rate();
+	void cmd_timeout();	void cmd_reset();
+	void cmd_start();	void cmd_stop();
+	void cmd_uptime();	void cmd_help();
+	void cmd_chain();
 };
 
-bool Match(const char *, const char *);
-bool ConvertToDouble(const char *, double *);
-bool ConvertToInt(const char *, int *);
+bool Match(std::string, const char *);
+bool ConvertToDouble(std::string, double *);
+bool ConvertToInt(std::string, int *);
 
 #endif
