Index: hvcontrol/HV.conf
===================================================================
--- hvcontrol/HV.conf	(revision 14)
+++ hvcontrol/HV.conf	(revision 14)
@@ -0,0 +1,29 @@
+# Main configuration file for the HV control program V1.0, 2009 03 17, 18:46:08
+# Note: this file will be updated at program exit
+
+LogPath            /home/lstark/hvcontrol/log/
+
+TimeOut            0.10 s   # Timeout to return from read (0.01,...5.00) s
+
+StatusRefreshRate  50.00 Hz   # Status update rate (0.01,...50.00) Hz
+
+CCPort             3000   # Port used to look for commands from the Central Control
+CCClient           ihp-eth63   # Central Control client name
+
+IsDAC              FALSE   # Define here if user input is interpreted as DAC value or voltage
+
+HVCalibOffset      -0.800000   # Calibration of DAC to voltage values
+HVCalibSlope       0.006400   # Calibration of DAC to voltage values
+
+HVMaxDiff          500.000000   # Speed for HV changes limited to 1V/ms
+# List of HV boards (at most 20 HV boards will be recognized):
+Board0             FTCVIP44
+Board1             FTE11AW4
+Board2             DUMMY
+Board3             DUMMY
+Board4             FTE11ANQ
+Board5             DUMMY
+Board6             FTCVINZA
+Board7             DUMMY
+Board8             DUMMY
+Board9             FTE11ATK
Index: hvcontrol/Makefile
===================================================================
--- hvcontrol/Makefile	(revision 14)
+++ hvcontrol/Makefile	(revision 14)
@@ -0,0 +1,49 @@
+#
+#  Makefile for the CTX HV utility 
+#
+
+include Makefile.general
+
+PROGRAMS = hvcontrol remotecontrol 
+
+SUBDIRS = src
+
+
+all: $(PROGRAMS) 
+
+
+OBJECTS   = $(SUBDIRS:=/*.o)
+
+INCDIRS   = -I. $(SUBDIRS:%=-I%)
+
+MRPROPERS = $(SUBDIRS:=.mrproper)
+
+CLEANERS  = $(SUBDIRS:=.cleaner)
+
+LIBRARIES = $(SUBDIRS:=.all)
+
+
+$(PROGRAMS) : % : %.o $(LIBRARIES)
+	$(G++) $(CFLAGS) -o $@ $@.o  $(OBJECTS) $(LIBS) 
+
+include Makefile.rules
+
+$(LIBRARIES):
+	@echo " Calling make in $(@:.all=)"
+	@(cd $(@:.all=); $(MAKE) -f Makefile all)
+
+$(MRPROPERS):
+	@echo " Doing Mr.Proper in $(@:.mrproper=)"
+	@(cd $(@:.mrproper=); $(MAKE) -f Makefile mrproper)
+
+$(CLEANERS):
+	@echo " Doing clean in $(@:.cleaner=)"
+	@(cd $(@:.cleaner=); $(MAKE) -f Makefile clean)
+
+mrproper: $(MRPROPERS) rmobj rmbak rmdep
+	@rm -f $(PROGRAMS)
+	@echo " Done."
+
+clean: $(CLEANERS) rmobj
+	@echo " Done."
+
Index: hvcontrol/Makefile.general
===================================================================
--- hvcontrol/Makefile.general	(revision 14)
+++ hvcontrol/Makefile.general	(revision 14)
@@ -0,0 +1,22 @@
+# 
+# General definitions for Makefiles
+#
+
+C++ = c++
+CC  = gcc
+#CC  = c++
+G++ = g++
+
+#OSTYPE = linux
+
+ifeq ($(OSTYPE),linux)
+ OSXLIBS = -L/sw/lib
+ DO_CAST = -DDO_CAST
+endif
+
+
+CFLAGS = -pedantic -pipe -fthread-jumps -funroll-all-loops -g -O3 -Wall -Wuninitialized -Wmissing-prototypes
+CPPFLAGS = -pedantic -pipe -fthread-jumps -funroll-all-loops -g -O3 -Wall -Wuninitialized -Wno-deprecated $(DO_CAST)
+
+LIBS = -lz -lpthread -lutil -lfl -lusb -lftdi -L/usr/lib $(OSXLIBS)
+
Index: hvcontrol/Makefile.rules
===================================================================
--- hvcontrol/Makefile.rules	(revision 14)
+++ hvcontrol/Makefile.rules	(revision 14)
@@ -0,0 +1,24 @@
+include Dep.d
+
+%.d : 
+	@echo " - Generating dependencies" $@
+	@$(CC) -MM $(SOURCES) $(INCDIRS) \
+	| sed 's/^\(.*\).o:/$@ \1.o:/' > $@
+
+%.o : %.c
+	$(CC) $(CFLAGS) $(INCDIRS) -c -o $@ $<
+
+%.o : %.cc
+	$(G++) $(CPPFLAGS) $(INCDIRS) -c -o $@ $<
+
+%.o : %.cpp
+	$(G++) $(CPPFLAGS) $(INCDIRS) -c -o $@ $< 
+
+rmobj:
+	@rm -f *.o
+
+rmbak:
+	@rm -f *~
+
+rmdep: 
+	@rm -f *.d
Index: hvcontrol/hvcontrol.cpp
===================================================================
--- hvcontrol/hvcontrol.cpp	(revision 14)
+++ hvcontrol/hvcontrol.cpp	(revision 14)
@@ -0,0 +1,117 @@
+
+/**************************************************************\
+
+  Main program for the CTX G-APD HV supply, sends commands, 
+  reads and monitors status of the G-APD HV supply
+
+  Name:         hvcontrol.cpp
+
+  Actions:      Do global initialization, start threads  
+
+  Created by:   Sebastian Commichau, November 2008
+                commichau@phys.ethz.ch
+
+\**************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <signal.h>
+
+#include "ConsoleCommand.h"
+#include "CCCommand.h"
+#include "ProcessIO.h"
+#include "HVMonitor.h"
+#include "Types.h"
+
+#define Sleep(x) usleep(x*1000)
+
+#define DEFAULT_CONFIG "HV.conf"     // Default configuration file
+#define LOCKFILE "/tmp/CTX_HV_LOCK"
+
+
+int main(int argc, char *argv[]) {
+
+
+  char config_file[] = DEFAULT_CONFIG, str[MAX_COM_SIZE];
+
+  pthread_t thread_ConsoleCommand; // Read commands from console
+  pthread_t thread_HVMonitor;      // Reads continuously from HV board(s)
+  pthread_t thread_CCCommand;      // Thread listening to commands from Central Control
+
+  int LockDescriptor;
+
+  // Assure only one instance of the HV control program runs
+  // The flag O_EXCL together with O_CREAT assure that the lock 
+  // file cannot be opened by another instance, i.e. there are no parallel write accesses
+  if ((LockDescriptor = open(LOCKFILE,O_RDONLY|O_CREAT|O_EXCL)) == -1) {  
+    sprintf(str, "Could not create lock file %s", LOCKFILE);
+    perror(str);
+    exit(EXIT_FAILURE);
+  }
+  close(LockDescriptor);
+
+
+  for (int i=1; i<argc; i++) {
+    if (argv[i][0] == '-') {
+      if (argv[i][1] == 'h') {
+	printf("Usage: %s [-c <ConfigFile>]  default file is \"%s\"\n", argv[0], config_file);
+	exit(1);
+      }
+      if (argv[i][1] == 'c') {
+	if (argc<i+2) {
+	  printf("Error: missing configuration file after -c option\n");
+	  exit(1);
+	} else {
+	  sprintf(config_file, "%s", argv[i+1]);
+	}
+      }
+    }
+  }
+  
+  system("clear");                   
+  printf("\n****************** HV Control %s built %s, %s by S. Commichau ******************\n\n",HV_CONTROL_VERSION,__DATE__,__TIME__);
+
+
+  // Construct main instance
+  ProcessIO pio(config_file);
+  
+  // Install signal handler and set signal SIGUSR1 to interrupt blocking system calls
+  signal(SIGUSR1, &SignalHandler);
+  siginterrupt (SIGUSR1, true);
+
+  // Create threads
+  if ((pthread_create(&thread_ConsoleCommand, NULL, (void * (*)(void *)) ConsoleCommand,(void *) &pio)) != 0) {
+    fprintf(stderr, "pthread_create failed with ConsoleCommand\n");
+    exit(1);
+  }
+
+  if ((pthread_create(&thread_HVMonitor, NULL, (void * (*)(void *)) HVMonitor,(void *) &pio)) != 0) {
+    fprintf(stderr, "pthread_create failed with HVMonitor\n");
+    exit(1);
+  }
+
+  if ((pthread_create(&thread_CCCommand, NULL, (void * (*)(void *)) CCCommand,(void *) &pio)) != 0) {
+    fprintf(stderr, "pthread_create failed with CCCommand\n");
+    exit(1);
+  }
+
+  // Threads should be accessible for sending signals
+  pio.status->HVMonitor = thread_HVMonitor;
+  pio.status->SocketThread = thread_CCCommand;
+
+  // Wait for threads to quit
+  pthread_join(thread_CCCommand, NULL);
+  pthread_join(thread_ConsoleCommand, NULL);
+  pthread_join(thread_HVMonitor, NULL);
+
+  // Remove lockfile
+  if (remove(LOCKFILE)==-1) {
+    sprintf(str, "Could not remove lock file %s", LOCKFILE);
+    perror(str);
+    exit(EXIT_FAILURE);
+  }
+
+  return 0;
+}
Index: hvcontrol/src/CCCommand.cc
===================================================================
--- hvcontrol/src/CCCommand.cc	(revision 14)
+++ hvcontrol/src/CCCommand.cc	(revision 14)
@@ -0,0 +1,121 @@
+
+/********************************************************************\
+
+  Name:         CCCommand.cc
+
+  Created by:   Oliver Grimm, Sebastian Commichau, January 2009
+                oliver.grimm@phys.ethz.ch, commichau@phys.ethz.ch
+
+  Actions:      Listen to commands from Central Control (CC)
+
+\********************************************************************/
+
+#include "CCCommand.h"
+
+
+void CCCommand(ProcessIO *m) {
+
+  siginterrupt(SIGUSR1, true);
+
+  int ServerSocket,ConnectionSocket,ReadResult;
+  struct sockaddr_in SocketAddress, ClientAddress;
+  socklen_t SizeClientAddress=sizeof(ClientAddress);
+  char comline[MAX_COM_SIZE], str[MAX_COM_SIZE];
+  
+  // Set up server socket
+  if ((ServerSocket = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
+    sprintf(str,"error: could not open server socket, no remote connection possible");
+    m->PrintMessage(str);
+    return;
+  }
+ 
+  SocketAddress.sin_family = PF_INET;
+  SocketAddress.sin_port = htons((unsigned short) m->config->fCCPort);
+  SocketAddress.sin_addr.s_addr = INADDR_ANY;
+
+  if (bind(ServerSocket, (struct sockaddr *) &SocketAddress, sizeof(SocketAddress)) == -1) {
+    sprintf(str,"error: could not bind port to socket");
+    m->PrintMessage(str);
+    close(ServerSocket);
+    return;
+  }
+  if (listen(ServerSocket, 0) == -1) {
+    sprintf(str,"error: could not set socket to listening");
+    m->PrintMessage(str);
+    close(ServerSocket);
+    return;
+  }
+  
+  while (!m->status->Exit) { // Looping to wait for incoming connection
+
+    if ((ConnectionSocket = accept(ServerSocket, (struct sockaddr *) &ClientAddress, &SizeClientAddress)) == -1) {
+      if (errno!=EINTR) {
+	sprintf(str,"error: failed to accept incoming connection");
+	m->PrintMessage(str);
+      }
+      close(ServerSocket);
+      return;
+    }
+
+    pthread_mutex_lock(&m->control_mutex);
+    m->status->Socket = ConnectionSocket;
+    m->status->cc_state = connected;
+    sprintf(str,"connected to client (%s)",inet_ntoa(ClientAddress.sin_addr));
+    m->PrintMessage(str);
+    pthread_mutex_unlock(&m->control_mutex);
+
+    while (!m->status->Exit) {  // Looping as long as client exists
+      bzero(comline,sizeof(comline));
+      ReadResult = read(ConnectionSocket, comline, MAX_COM_SIZE);
+      if (ReadResult==0) break; // Client does not exist anymore
+      if (ReadResult==-1) {
+	if (errno!=EINTR) {
+	  sprintf(str,"error: socket read failed");
+	  m->PrintMessage(str);
+	}
+	break;
+      }
+            
+      m->status->Pc = comline;      
+                 
+      sprintf(str,"Test in CCComand: %s",m->status->Pc);
+      printf(str);
+
+      ParseInput(m->status->Pc,&(m->status->NParam),m->status->Param);
+      
+      if (!(Match(m->status->Param[0], "exit") || Match(m->status->Param[0], "quit"))) {
+	
+	sprintf(str,"CC> %s",m->status->Pc);
+	m->log->LogWrite(str);
+	
+	sprintf(str,"%s",m->status->Pc);
+	printf(str);
+
+	pthread_mutex_lock(&m->control_mutex);
+	// Process CC command
+	if (m->CommandControl()==0)
+	  pthread_cond_broadcast(&m->control_cond);
+	pthread_mutex_unlock(&m->control_mutex);
+	
+      }
+      else
+	printf("remote exit|quit forbidden\n");
+           
+      m->PrintMessage(NULL);
+            
+    }
+
+    if (!(m->status->Exit)) {
+      sprintf(str,"disconnected from client (%s)",inet_ntoa(ClientAddress.sin_addr));
+      m->PrintMessage(str);
+    }
+    m->status->Socket = -1;
+    pthread_mutex_lock(&m->control_mutex);
+    m->status->cc_state = disconnected;
+    pthread_mutex_unlock(&m->control_mutex);
+    close(ConnectionSocket);
+
+  } 
+  close(ServerSocket);
+    
+}
Index: hvcontrol/src/CCCommand.h
===================================================================
--- hvcontrol/src/CCCommand.h	(revision 14)
+++ hvcontrol/src/CCCommand.h	(revision 14)
@@ -0,0 +1,17 @@
+#ifndef CCCommand_H_SEEN
+#define CCCommand_H_SEEN
+
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+
+#include "ProcessIO.h"
+#include "Types.h"
+#include "Utilities.h"
+
+void CCCommand(ProcessIO *m);
+
+#endif
Index: hvcontrol/src/ConsoleCommand.cc
===================================================================
--- hvcontrol/src/ConsoleCommand.cc	(revision 14)
+++ hvcontrol/src/ConsoleCommand.cc	(revision 14)
@@ -0,0 +1,60 @@
+
+/********************************************************************\
+
+  Name:         ConsoleCommand.cc
+
+  Created by:   Sebastian Commichau, March 2008
+                commichau@phys.ethz.ch
+
+  Actions:      Handle console input
+
+\********************************************************************/
+ 
+
+#include "ConsoleCommand.h"
+
+
+void ConsoleCommand(ProcessIO *m) {
+
+  siginterrupt(SIGUSR1, true);
+
+  char comline[MAX_COM_SIZE];
+
+  char str[MAX_COM_SIZE];
+  char *c;
+
+  do {
+        
+    fprintf(stdout,m->status->Prompt);
+    c = fgets(comline, MAX_COM_SIZE, stdin);
+
+    m->status->Pc = comline;
+      sprintf(str,"Test in ConsoleCommand: %s",m->status->Pc);
+      printf(str);
+    /*
+    if (strlen(m->status->Pc) < 2 )  // Ignore commands with only '\n'
+      continue;
+    m->status->Pc[strlen(m->status->Pc)-1]='\0';  // Remove '\n'
+    */
+    //if(m->status->Pc[0]=='.') {   // Shell command
+    //  system(&(m->status->Pc[1]));
+    //  continue;
+    //}
+
+    
+    sprintf(str,"USER> %s",m->status->Pc);
+    m->log->LogWrite(str);
+
+    ParseInput(m->status->Pc,&(m->status->NParam),m->status->Param);
+     
+    pthread_mutex_lock(&m->control_mutex);
+
+    if (m->CommandControl()==0) 
+      pthread_cond_broadcast(&m->control_cond);
+
+    pthread_mutex_unlock(&m->control_mutex);      
+      
+  } while ((c != NULL) && (!m->status->Exit));
+
+}
+
Index: hvcontrol/src/ConsoleCommand.h
===================================================================
--- hvcontrol/src/ConsoleCommand.h	(revision 14)
+++ hvcontrol/src/ConsoleCommand.h	(revision 14)
@@ -0,0 +1,14 @@
+#ifndef CONSOLECOMMAND_H_SEEN
+#define CONSOLECOMMAND_H_SEEN
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h> 
+#include <pthread.h>
+
+#include "ProcessIO.h"
+#include "Utilities.h"
+
+void ConsoleCommand(ProcessIO *m);
+
+#endif
Index: hvcontrol/src/HV.cc
===================================================================
--- hvcontrol/src/HV.cc	(revision 14)
+++ hvcontrol/src/HV.cc	(revision 14)
@@ -0,0 +1,686 @@
+
+/********************************************************************\
+
+  Name:         HV.cc
+
+  Created by:   Sebastian Commichau, November 2008
+                commichau@phys.ethz.ch
+
+  Contents:     Main class for HV supply
+
+  Requirements: Both libftdi and libusb are required for the 
+                communication - see manual for more details.
+
+                libftdi: library for talking with FTDI USB <-> Serial 
+                converter, UM245R.
+                http://www.intra2net.com/de/produkte/opensource/ftdi/
+                
+                libusb: library for talking to USB devices from 
+                user-space. Also needed by libftdi. 
+                http://libusb.wiki.sourceforge.net/
+                
+\********************************************************************/
+
+
+#include "HV.h"
+
+
+HV::HV(char** usbdevice, int* usbdevicenumber, FILE* f): fNumberOfBoards(0) {
+  
+  int i = 0, j = 0, ret = 0;
+
+  char manufacturer[STR_LENGTH], type[STR_LENGTH], serial[STR_LENGTH];
+
+  bzero(manufacturer, sizeof(manufacturer));
+  bzero(type, sizeof(type));
+  bzero(serial, sizeof(serial));
+
+  fprintf(stdout,"Scan: ");
+
+  // Search for FTDI devices
+  for (i = 0;i<MAX_NUM_HVBOARDS;i++)
+    ftdi_init(&ftdic[i]);
+
+  ftdi_init(&ftdic_dummy);
+
+  if ((i = ftdi_usb_find_all(&ftdic_dummy, &devlist, USB_VENDOR, USB_PRODUCT)) < 0)
+    fprintf(stderr,"error: ftdi_usb_find_all failed: %d (%s)\n", i, ftdi_get_error_string(&ftdic_dummy));
+    
+  fprintf(stdout,"found %d FTDI device(s)\n", i);
+  i = 0;
+ 
+  // Obtain information on FTDI devices
+  for (curdev = devlist; (curdev != NULL && i<MAX_NUM_HVBOARDS); i++) {
+    
+    fprintf(stdout,"Device %d:\n", i);
+    
+    if ((ret = ftdi_usb_get_strings(&ftdic_dummy, curdev->dev, manufacturer, STR_LENGTH, type, STR_LENGTH, serial, STR_LENGTH)) < 0) {
+      fprintf(stderr," Error: ftdi_usb_get_strings failed: %d (%s)\n", ret, ftdi_get_error_string(&ftdic_dummy));
+      break;
+    }
+
+    fprintf(stdout," Manufacturer: %s - Type: %s - Serial: %s\n", manufacturer, type, serial);
+
+    // Fixme: the following code should be revised!
+    while (j<MAX_NUM_HVBOARDS) {
+      if (strcmp(serial,usbdevice[j])==0)
+	break;
+      j++;
+    }
+
+    if (j<MAX_NUM_HVBOARDS) {
+      ret = ftdi_usb_open_desc(&ftdic[fNumberOfBoards], USB_VENDOR, USB_PRODUCT, type, serial);
+      
+      // Fixme: this function does not work properly if there is more than one device???!!!
+      // ret = ftdi_usb_open(&ftdic[fNumberOfBoards], USB_VENDOR, USB_PRODUCT);
+      
+      if (ret < 0 && ret != -5)
+	fprintf(stderr," Error: unable to open FTDI device: %d (%s)\n", i, ftdi_get_error_string(&ftdic[fNumberOfBoards]));
+      else {
+	
+	ftdi_set_baudrate(&ftdic[fNumberOfBoards], USB_BAUDRATE);
+	ftdi_usb_reset(&ftdic[fNumberOfBoards]);
+	ftdi_usb_purge_buffers(&ftdic[fNumberOfBoards]);
+	/*
+	  The FTDI chip keeps data in the internal buffer for a specific
+	  amount of time if the buffer is not full yet to decrease load on the usb bus.
+	*/
+	ftdi_set_latency_timer(&ftdic[fNumberOfBoards], USB_LATENCY_TIMER);
+	
+	fHVBoard[fNumberOfBoards] = new HVBoard(serial, usbdevicenumber[j], &ftdic[fNumberOfBoards]);
+	fNumberOfBoards++;
+	/*
+	  fprintf(stdout," FTDI open succeeded\n");
+	  fprintf(stdout," Baudrate: %d\n", ftdic[i].baudrate);
+	  fprintf(stdout," USB_read_timeout: %d\n", ftdic[i].usb_read_timeout);
+	  fprintf(stdout," USB_write_timeout: %d\n", ftdic[i].usb_write_timeout);
+	*/
+      }
+      
+    }
+    else
+      fprintf(stdout," Warning: found new USB device - check configuration file!\n");
+
+    j=0;    
+
+    curdev = curdev->next;
+  }
+
+  // Re-order board numbering otherwise it is determined by the connection sequence
+  ArrangeHVBoards(fHVBoard,fNumberOfBoards);
+
+}
+
+
+/* Bubble-sort HV boards according to board number */
+void HV::ArrangeHVBoards(HVBoard** fHVBoard, int size) {
+
+  HVBoard* tmp;
+
+  for (int i=size-1;i>0;--i)
+    for (int pos=0;pos<i;++pos)            
+      if (fHVBoard[pos]->GetBoardNumber()>fHVBoard[pos+1]->GetBoardNumber()) {
+	tmp             = fHVBoard[pos];
+	fHVBoard[pos]   = fHVBoard[pos+1];
+	fHVBoard[pos+1] = tmp;
+      }
+  
+}
+
+
+HV::~HV() {
+ 
+  int i, ret = 0;
+  
+  for (i=0;i<fNumberOfBoards;i++) {
+    fprintf(stdout,"Device %d: ",i);
+    
+    ret = ftdi_usb_close(&ftdic[i]);
+
+    if (ret < 0)
+      fprintf(stderr, "Unable to close FTDI device: %d (%s)\n", i, ftdi_get_error_string(&ftdic[i]));
+    else 
+      fprintf(stdout, "FTDI close succeeded\n");
+
+    delete fHVBoard[i];
+  }
+  
+  fprintf(stdout,"FTDI list free\n");
+  ftdi_list_free(&devlist);
+
+  for (i=0;i<MAX_NUM_HVBOARDS;i++)
+    ftdi_deinit(&ftdic[i]);
+
+  ftdi_deinit(&ftdic_dummy);
+
+}
+
+
+HVBoard::HVBoard(char* serial, int number, struct ftdi_context* ftdic) : fTimeOut(.5) 
+{
+ 
+  FTDI_C = ftdic;
+  sprintf(Serial,"%s",serial);
+  BoardNumber = number;
+     
+}
+
+
+HVBoard::~HVBoard() {
+ 
+}
+
+
+/* For test purposes only - never use this function with a real HV board!!! */
+void HVBoard::TestIO() {
+
+  int ret = 0, werrors = 0, rerrors = 0, mismatches = 0;
+
+  unsigned char wbuf[BUFFER_LENGTH], rbuf[BUFFER_LENGTH];
+
+  for (int i=0;i<=0XFF;i++) {
+    
+    wbuf[0] = (unsigned char)i;
+
+#ifdef DO_CAST
+    ret = ftdi_write_data(FTDI_C,(char*)wbuf,1);
+#endif
+    ret = ftdi_write_data(FTDI_C,wbuf,1);
+
+    if (ret < 0)
+      werrors++;
+    
+#ifdef DO_CAST
+    ret = ftdi_read_data(FTDI_C,(char*)rbuf,1);
+#endif    
+    ret = ftdi_write_data(FTDI_C,wbuf,1);   
+
+    if (ret < 0)
+      rerrors++;
+    
+    if (rbuf[0]!=wbuf[0]) {
+      mismatches++;
+      fprintf(stdout,"Mismatch - written: 0X%.2X read: 0X%.2X\n",wbuf[0],rbuf[0]);
+    }
+  }
+  fprintf(stdout, "Result: %d write errors, %d read errors, %d mismatches\n",werrors,rerrors,mismatches);
+}
+
+
+int HVBoard::Write(unsigned char* data, int size) {
+#ifdef DO_CAST
+  return ftdi_write_data(FTDI_C, (char*)data, size);
+#endif
+  return ftdi_write_data(FTDI_C, data, size);
+}
+
+
+int HVBoard::Read(unsigned char* data, int size) {
+#ifdef DO_CAST
+  return ftdi_read_data(FTDI_C, (char*)data, size);
+#endif
+  return ftdi_read_data(FTDI_C, data, size);
+}
+
+
+/*
+ TRead: read from HV Board until fTimeOut has been reached 
+
+ Returns:
+     0 if a read error has occured
+     1 on success
+    -1 if fTimeOut [s] has been exceeded
+*/
+int HVBoard::TRead(FILE* fptr, unsigned char* rbuf, bool verbose) {
+  
+  char str[STR_LENGTH];
+
+  long int t1, t2;
+  int ret = 0;
+
+  t1 = GetMicroSeconds();
+  
+  do {
+    
+    if ((ret = Read(rbuf,BUFFER_LENGTH)) < 1) {
+      if (verbose) 
+	if (ret < 0) {
+	  fprintf(stderr, " Read error: %d (%s)\n", ret, ftdi_get_error_string(FTDI_C));
+	  return 0;
+	}
+    }
+    else {
+
+      if (verbose)
+	fprintf(fptr," %d byte(s) read:\n",ret);
+      
+      for (int i=0;i<ret;i++) {
+	sPrintByteBin(rbuf[i],str);
+	if (verbose)
+	  fprintf(fptr," Byte %d: %s| 0X%.2X\n",i,str,rbuf[i]);
+      }
+      return 1;
+    }
+
+    t2 = GetMicroSeconds();
+
+    if ((t2-t1)/1000000. >= fTimeOut) {
+      fprintf(fptr," Warning: timeout exceeded\n");
+      return -1;
+    }
+
+  } while(1);
+  
+}
+
+
+/* Reset HV board - uses TRead() and has same return values */
+int HVBoard::Reset(FILE* fptr, unsigned char* rbuf, bool verbose) {
+
+  char str[STR_LENGTH];
+
+  unsigned char wbuf[] = {REG_RESET,0,0};
+  
+  if (Write(wbuf,3) < 1) {
+    fprintf(fptr," Error: could not write to HV board\n");
+    return 0;
+  }
+  
+  if (verbose)
+    fprintf(fptr," 3 bytes written:\n");
+  
+  for (int i=0;i<3;i++) {
+    sPrintByteBin(wbuf[i],str);
+    if (verbose)
+      fprintf(fptr," Byte %d: %s| 0X%.2X\n",i,str,wbuf[i]);
+  }
+
+  return TRead(fptr,rbuf,verbose);
+
+}
+
+
+/* Read status register - uses TRead() and has same return values */
+int HVBoard::GetStatus(FILE* fptr, unsigned char* rbuf, bool verbose) {
+
+  char str[STR_LENGTH];
+
+  unsigned char wbuf[] = {REG_STATUS,0,0};
+  
+  if (Write(wbuf,3) < 1) {
+    if (verbose)
+      fprintf(fptr," Error: could not write to HV board\n");
+    return 0;
+  }
+
+  if (verbose)
+    fprintf(fptr," 3 bytes written:\n");
+  
+  for (int i=0;i<3;i++) {
+    sPrintByteBin(wbuf[i],str);
+    if (verbose)
+      fprintf(fptr," Byte %d: %s| 0X%.2X\n",i,str,wbuf[i]);
+  }
+  
+  return TRead(fptr,rbuf,verbose);
+
+}
+
+
+/* Set high voltage - uses TRead() and has same return values */
+int HVBoard::SetHV(FILE* fptr, int chain, unsigned int channel, unsigned int hv, unsigned char* rbuf, bool verbose) {
+  
+  char str[STR_LENGTH];
+
+  unsigned char wbuf[] = {0,0,0};
+  
+  if (!(hv>=0.0 && hv<=0X3FFF)) {
+    fprintf(fptr," Error: HV beyond limits [0 - 0x3FFF]\n"); 
+    return 0;
+  }
+
+  switch (chain) {
+    
+  case 0: wbuf[0] = REG_HV0; break;
+  case 1: wbuf[0] = REG_HV1; break;
+  case 2: wbuf[0] = REG_HV2; break;
+  case 3: wbuf[0] = REG_HV3; break;
+
+  default : fprintf(fptr," Error: chain %d does not exist\n",chain); return 0;
+
+  }
+ 
+  // Assemble bytes
+  wbuf[0] |= (unsigned char)((channel >> 2) & 0X00000007);  // Add address [A4-A3]
+  wbuf[1] |= (unsigned char)((hv >> 8) & 0X000000FF);       // Add [D13-D8]
+  wbuf[1] |= (unsigned char)((channel << 6)  & 0X000000C0); // Add [A1-A0]
+  wbuf[2] |= (unsigned char)(hv & 0X000000FF);              // Add [D7-D0]
+   
+
+  if (Write(wbuf,3) < 1) {
+    fprintf(fptr," Error: could not write to HV board\n");
+    return 0;
+  }
+
+  if (verbose)
+    fprintf(fptr," 3 bytes written:\n");
+
+  for (int i=0;i<3;i++) {
+    sPrintByteBin(wbuf[i],str);
+    if (verbose)
+      fprintf(fptr," Byte %d: %s| 0X%.2X\n",i,str,wbuf[i]);
+  }
+
+  return TRead(fptr,rbuf,verbose);
+  
+}
+
+
+/* Set reference voltage - uses TRead() and has same return values */
+int HVBoard::SetVRef(FILE* fptr, int chain, unsigned int vref, unsigned char* rbuf, bool verbose) {
+  
+  char str[STR_LENGTH];
+
+  unsigned char wbuf[] = {0,0,0};
+  
+  if (!(vref>=0 && vref<=0X3FFF)) {
+    if (verbose)
+      fprintf(fptr," Error: vref beyond limits\n"); 
+    return 0;
+  }
+
+  switch (chain) {
+
+  case 0: wbuf[0] = REG_VREF0; break;
+  case 1: wbuf[0] = REG_VREF1; break;
+  case 2: wbuf[0] = REG_VREF2; break;
+  case 3: wbuf[0] = REG_VREF3; break;
+
+  default : fprintf(fptr," Error: chain %d does not exist\n",chain); return 0;
+
+  }
+ 
+  // Assemble bytes
+  wbuf[0] |= (unsigned char)((vref >> 13) & 0X0000000F); // Add [D13]
+  wbuf[1] |= (unsigned char)((vref >> 5)  & 0X000000FF); // Add [D12-D5]
+  wbuf[2] |= (unsigned char)((vref << 3)  & 0X000000FF); // Add [D4-D0]
+   
+  // PD bits (device clear) are not used
+  wbuf[0] &= ~REG_PD1; 
+  wbuf[0] &= ~REG_PD2;
+
+  if (Write(wbuf,3) < 1) {
+    fprintf(fptr," Error: could not write to HV board\n");
+    return 0;
+  }
+
+  if (verbose)
+    fprintf(fptr," 3 bytes written:\n");
+
+  for (int i=0;i<3;i++) {
+    sPrintByteBin(wbuf[i],str);
+    if (verbose)
+      fprintf(fptr," Byte %d: %s| 0X%.2X\n",i,str,wbuf[i]);
+  }
+
+  return TRead(fptr,rbuf,verbose);
+  
+}
+
+
+/* 
+ Init: initialize (synchronize) HV board - to be used before any other access! 
+
+ Returns 0 if an error has occured, 1 on success.
+
+ Before any other access the HV board communication has to be synchronized.
+ Each write access requires three bytes to be sent from the computer to the
+ HV board. The HV board sends back one byte containing status information.
+
+ The normal initialization procedure would be the following:
+
+ 1.   send one byte (0X80 = REG_STATUS).
+ 1.1. try reading as long as fTimeOut is not exceeded.
+
+ 2.   send again one byte (0X00).
+ 2.1. try reading as long as fTimeOut is not exceeded.
+
+ 3.   send again one byte (0X00).
+ 3.1. try reading again as long as fTimeOut is not exceeded.
+ 
+ Note: from time to time there are problems when performing only 3 trials! Reason:
+ the first byte written by libftdi can get lost somewhere between 
+ libusb <-> kernel <-> FTDI chip. I haven't found yet any solution to this.
+ To solve the issue, another byte is sent to assure a proper synchronization,
+ even though the first byte was lost:
+
+ 4.   send again one byte (0X00).
+ 4.1. try reading again as long as fTimeOut is not exceeded; if fTimeOut
+      has been exceeded return.
+
+ See also: http://lists.omnipotent.net/pipermail/lcdproc/2008-June/012235.html
+*/
+int HVBoard::Init(bool verbose) {
+
+  unsigned char wbuf = REG_STATUS;
+  unsigned char rbuf[STR_LENGTH];
+  
+  int trial = 1;
+  int ret = 0;
+
+  long int t1, t2;
+
+
+  // First send 0X80
+  if (Write(&wbuf,1) < 1) {
+    if (verbose)
+      fprintf(stdout," Error: could not write to HV board\n");
+    return 0;
+  }
+  else
+    if (verbose)
+      fprintf(stdout," 1 byte written: 0X%.2X\n",wbuf);
+  
+
+  t1 = GetMicroSeconds();
+
+
+  // Read - first trial
+  do {
+
+    t2 = GetMicroSeconds();
+    
+    if ((ret = Read(rbuf,BUFFER_LENGTH)) < 1) {
+      if (verbose) 
+	if (ret < 0) {
+	  fprintf(stderr, " Read error: %d (%s)\n",ret,ftdi_get_error_string(FTDI_C));
+	  return 0;
+	}
+    }
+    else {
+      if (verbose)
+	fprintf(stdout," %d byte(s) read:",ret);
+      for (int i=0;i<ret;i++)
+	if (verbose)
+	  fprintf(stdout," 0X%.2X",rbuf[i]);
+      if (verbose)
+	fprintf(stdout,"\n");
+      fprintf(stdout," Success: initialization done (%d trial)\n",trial);
+      return 1;
+    }
+    
+    if ((t2-t1)/1000000. > fTimeOut) {
+      if (verbose)
+	fprintf(stdout," Warning: timeout exceeded\n");
+      trial++;
+      
+      // Second write
+      wbuf = 0;
+      if (Write(&wbuf,1) < 1) {
+	if (verbose)
+	  fprintf(stdout," Error: could not write to HV board\n");
+	return 0;
+      }
+      else
+	if (verbose)
+	  fprintf(stdout," 1 byte written: 0X%.2X\n",wbuf);
+      
+      t1 = GetMicroSeconds();
+      
+      // Read - second trial
+      do {
+
+	t2 = GetMicroSeconds();
+    
+	if ((ret = Read(rbuf,BUFFER_LENGTH)) < 1) {
+	  if (verbose) 
+	    if (ret < 0) {
+	      fprintf(stderr, " Read error: %d (%s)\n",ret,ftdi_get_error_string(FTDI_C));
+	      return 0;
+	    }
+	}
+	else {
+	  if (verbose)
+	    fprintf(stdout," %d byte(s) read:",ret);
+	  for (int i=0;i<ret;i++)
+	    if (verbose)
+	      fprintf(stdout," 0X%.2X",rbuf[i]);
+	  if (verbose)
+	    fprintf(stdout,"\n");
+	  fprintf(stdout," Success: initialization done (%d trials)\n",trial);
+	  return 1;
+	}
+
+	if ((t2-t1)/1000000. > fTimeOut) {
+	  if (verbose)
+	    fprintf(stdout," Warning: timeout exceeded\n");
+	  trial++;
+	  
+	  // Third write
+	  wbuf = 0;
+	  if (Write(&wbuf,1) < 1) {
+	    if (verbose)
+	      fprintf(stdout," Error: could not write to HV board\n");
+	    return 0;
+	  }
+	  else
+	    if (verbose)
+	      fprintf(stdout," 1 byte written: 0X%.2X\n",wbuf);
+
+
+	  // Read - third trial
+	  do {
+	    
+	    t2 = GetMicroSeconds();
+	    
+	    if ((ret = Read(rbuf,BUFFER_LENGTH)) < 1) {
+	      if (verbose) 
+		if (ret < 0) {
+		  fprintf(stderr, " Read error: %d (%s)\n",ret,ftdi_get_error_string(FTDI_C));
+		  return 0;
+		}
+	    }
+	    else {
+	      if (verbose)
+		fprintf(stdout," %d byte(s) read:",ret);
+	      for (int i=0;i<ret;i++)
+		if (verbose)
+		  fprintf(stdout," 0X%.2X",rbuf[i]);
+	      if (verbose)
+		fprintf(stdout,"\n");
+	      fprintf(stdout," Success: initialization done (%d trials)\n",trial);
+	      return 1;
+	    }
+	    
+	    
+	    if ((t2-t1)/1000000. > fTimeOut) {
+	      if (verbose)
+		fprintf(stdout," Warning: timeout exceeded\n");
+	      trial++;
+	      
+	      // Fourth write
+	      wbuf = 0;
+	      if (Write(&wbuf,1) < 1) {
+		if (verbose)
+		  fprintf(stdout," Error: could not write to HV board\n");
+		return 0;
+	      }
+	      else
+		if (verbose)
+		  fprintf(stdout," 1 byte written: 0X%.2X\n",wbuf);
+	   
+	      
+	      // Read - fourth and last trial
+	      do {
+		
+		t2 = GetMicroSeconds();
+		
+		if ((ret = Read(rbuf,BUFFER_LENGTH)) < 1) {
+		  if (verbose) 
+		    if (ret < 0) {
+		      fprintf(stderr, " Read error: %d (%s)\n",ret,ftdi_get_error_string(FTDI_C));
+		      return 0;
+		    }
+		}
+		else {
+		  if (verbose)
+		    fprintf(stdout," %d byte(s) read:",ret);
+		  for (int i=0;i<ret;i++)
+		    if (verbose)
+		      fprintf(stdout," 0X%.2X",rbuf[i]);
+		  if (verbose)
+		    fprintf(stdout,"\n");
+		  fprintf(stdout," Success: initialization done (%d trials)\n",trial);
+		  return 1;
+		}
+				
+		if ((t2-t1)/1000000. > fTimeOut) {
+		  if (verbose)
+		    fprintf(stdout," Error: timeout exceeded - initialization failed (%d trials)\n",trial);
+		  return 0;
+		 
+		}
+		
+	      } while (1);
+	      	      
+	    }
+	   	    
+	  } while (1);
+
+	}
+
+      } while (1);
+            
+    }
+
+  } while (1);
+
+
+  return 0;
+}
+
+
+/* Decode wrap counter */
+int HVBoard::DecodeWrap(unsigned char* rbuf) {
+
+  return (*rbuf & 0X07);
+
+}
+
+
+/* Decode over current bits */
+void HVBoard::DecodeOC(bool OC[], unsigned char* rbuf) {
+
+  for (int i=0;i<MAX_NUM_CHAINS;i++)
+    OC[i]=(*rbuf & (0X08 << i));
+}
+
+
+/* Decode bit indicating manual reset */
+bool HVBoard::DecodeReset(unsigned char* rbuf) {
+
+  return (bool)(*rbuf & 0X80);
+
+}
+
+
Index: hvcontrol/src/HV.h
===================================================================
--- hvcontrol/src/HV.h	(revision 14)
+++ hvcontrol/src/HV.h	(revision 14)
@@ -0,0 +1,120 @@
+
+#include "Types.h"
+#include "Utilities.h"
+
+#include <ftdi.h>
+#include <sys/ioctl.h>
+
+
+#ifndef NULL
+#ifdef __cplusplus
+#define NULL 0
+#else
+#define NULL ((void *)0)
+#endif
+#endif 
+
+
+#ifndef HV_H_SEEN
+#define HV_H_SEEN
+
+
+// Have a look at http://www.linux-usb.org/usb.ids
+// Vendor: Future Technology Devices International, Ltd (FTDI)
+#define USB_VENDOR  0X0403 
+// Product: FT232 USB-Serial (UART) IC (USB <-> Serial converter, UM245R)
+#define USB_PRODUCT 0X6001 
+
+
+#define USB_BAUDRATE 115000
+#define USB_LATENCY_TIMER 1
+
+
+// HV board control registers
+#define REG_VREF0   0X00
+#define REG_VREF1   0X08
+#define REG_VREF2   0X10
+#define REG_VREF3   0X18
+
+#define REG_HV0     0X20
+#define REG_HV1     0X28
+#define REG_HV2     0X30
+#define REG_HV3     0X38
+
+#define REG_RESET   0XF8
+#define REG_STATUS  0X80
+
+#define REG_PD1     0X04
+#define REG_PD2     0X02
+
+
+// HV board status bits
+#define BIT_OC0    (1<<3)
+#define BIT_OC1    (1<<4)
+#define BIT_OC2    (1<<5)
+#define BIT_OC3    (1<<6)
+
+#define BIT_RESET  (1<<7)
+
+
+class HVBoard {
+  
+ public:
+  
+  HVBoard(char* serial, int number, struct ftdi_context* ftdic);
+  ~HVBoard();
+
+  int Init(bool verbose);
+  int Reset(FILE* fptr, unsigned char* rbuf, bool verbose);
+  int GetStatus(FILE* fptr, unsigned char* rbuf, bool verbose);
+  int SetVRef(FILE* fptr, int chain, unsigned int vref, unsigned char* rbuf, bool verbose);
+  int SetHV(FILE* fptr, int chain, unsigned int channel, unsigned int hv, unsigned char* rbuf, bool verbose);
+  struct ftdi_context* GetFTDI_C() {return FTDI_C;}
+  char* GetSerial() {return Serial;}
+  int GetBoardNumber() {return BoardNumber;}
+  int Write(unsigned char* data, int size);
+  int Read(unsigned char* data, int size);
+  int TRead(FILE* fptr, unsigned char* rbuf, bool verbose);
+  void SetTimeOut(float t) {fTimeOut = t;}
+  float GetTimeOut() {return fTimeOut;}
+  void TestIO();       // Warning: NEVER use this function with a real HV board!!!
+  int DecodeWrap(unsigned char* rbuf);
+  void DecodeOC(bool OC[], unsigned char* rbuf);
+  bool DecodeReset(unsigned char* rbuf);
+
+  struct ftdi_context* FTDI_C;
+  char Serial[STR_LENGTH];
+  int  BoardNumber;
+  float fTimeOut;      // [s] timeout to return from read 
+  
+};
+
+
+
+class HV {
+
+ public:
+  
+  HV(char** usbdevice, int* usbdevicenumber, FILE* f);
+  ~HV();
+
+  int fNumberOfBoards;
+  int fMaxNumberOfBoards;
+
+  HVBoard* fHVBoard[MAX_NUM_HVBOARDS];
+  int GetNumberOfBoards() {return fNumberOfBoards;} 
+  void SetNumberOfBoards(int i) {fNumberOfBoards = i;}
+  HVBoard* GetHVBoard(int i) {return fHVBoard[i];}
+  
+ protected:
+
+  // For FTDI USB <-> serial converter 
+  struct ftdi_context ftdic[MAX_NUM_HVBOARDS];
+  struct ftdi_context ftdic_dummy;
+  struct ftdi_device_list *devlist, *curdev;
+  
+  void ArrangeHVBoards(HVBoard** fHVBoard, int size);
+ 
+};
+
+#endif
Index: hvcontrol/src/HVConfig.cc
===================================================================
--- hvcontrol/src/HVConfig.cc	(revision 14)
+++ hvcontrol/src/HVConfig.cc	(revision 14)
@@ -0,0 +1,184 @@
+
+/********************************************************************\
+
+  Name:         HVConfig.cc
+
+  Created by:   Sebastian Commichau, November 2008
+                commichau@phys.ethz.ch
+
+  Contents:     Class reading the HV utility configuration file
+
+\********************************************************************/
+
+
+#include "ReadCard.h"
+#include "HVConfig.h"
+
+
+HVConfig::HVConfig(FILE* fptr, char *configfile) {
+
+  fLogPath   = new char[FILENAME_MAX_SIZE];
+  fUSBDevice = new char*[MAX_NUM_HVBOARDS];
+  fCCClient  = new char[FILENAME_MAX_SIZE];
+    
+  for (int i=0; i<MAX_NUM_HVBOARDS; i++) {
+    fUSBDevice[i]      = new char[FILENAME_MAX_SIZE];
+    USBDeviceNumber[i] = 0;
+
+    for (int j=0; j<MAX_NUM_CHAINS; j++)
+      for (int k=0; k<2; k++)
+	Coef[i][j][k] = 0.;
+  }
+
+  NumHVBoards        = 0;
+  FileName           = configfile;
+  fStatusRefreshRate = 1.;
+  fTimeOut           = 1.;
+  IsDAC              = true;
+  fHVCalibOffset      = -.8;
+  fHVCalibSlope       = 0.0064;
+  fHVMaxDiff          = 1.0;  
+
+  if (configfile != NULL) {
+    if (!ReadHVConfig(fptr, configfile)) {
+      fprintf(fptr, "Error (HVConfig): could not configure HV control\n");
+      exit(1);
+    }
+  }
+}
+
+
+HVConfig::~HVConfig() {
+
+  delete [] fLogPath;
+
+  for (int i=0; i<MAX_NUM_HVBOARDS; i++)
+    delete [] fUSBDevice[i];
+  delete [] fUSBDevice;
+
+}
+
+
+int HVConfig::ReadHVConfig(FILE* fptr, char *configfile) {
+
+  FILE *f;
+  char str[MAX_COM_SIZE], dev[MAX_COM_SIZE];
+  int j = 0;
+
+  if ((f = fopen(configfile,"r")) == NULL) {
+    fprintf(fptr,"Could not open configuration file: %s\n", configfile);
+    return 0;
+  }
+  else {
+    fprintf(fptr,"Opening configuration file: %s\n", configfile);
+  }
+ 
+  ReadCard("LogPath",fLogPath,'s',f);
+
+  for (int i=0;i<MAX_NUM_HVBOARDS;i++) {
+    sprintf(str,"Board%d",i);
+
+    if (ReadCard(str, dev, 's', f)==0) {
+      USBDeviceNumber[j] = i;
+      sprintf(fUSBDevice[j++],"%s",dev);
+      NumHVBoards++;     
+    }
+  }
+  
+  ReadCard("TimeOut",           &fTimeOut,           'f', f);
+  ReadCard("StatusRefreshRate", &fStatusRefreshRate, 'f', f);
+  ReadCard("CCPort",            &fCCPort,            'I', f);
+  ReadCard("CCClient",           fCCClient,          's', f);
+  ReadCard("IsDAC",             &str,                's', f);
+  ReadCard("HVCalibOffset",     &fHVCalibOffset,     'f', f);
+  ReadCard("HVCalibSlope",      &fHVCalibSlope,      'f', f);
+  ReadCard("HVMaxDiff",         &fHVMaxDiff,         'f', f);
+
+  if (strcmp(str,"TRUE"))
+    IsDAC = false;
+  
+  fclose(f);
+  return 1;
+}
+
+
+int HVConfig::PrintHVConfig(FILE *fptr) {
+  
+  fprintf(fptr,"\n");                                   
+  fprintf(fptr,"********************************************* CONFIG ********************************************\n\n"); 
+  
+  fprintf(fptr," HV control configuration (%s):\n\n", FileName);
+  fprintf(fptr," Log path:          %s\n\n", fLogPath);
+  fprintf(fptr," %.2d USB devices:\n\n", NumHVBoards);
+  
+  for (int i=0;i<NumHVBoards;i++) 
+    fprintf(fptr," Board%d: %s\n", USBDeviceNumber[i], fUSBDevice[i]);
+  
+  fprintf(fptr,"\n");
+  fprintf(fptr," TimeOut:           %.2f s\n",   fTimeOut);
+  fprintf(fptr," StatusRefreshRate: %.2f Hz\n\n",fStatusRefreshRate);
+  fprintf(fptr," CCPort:            %d\n",       fCCPort);
+  fprintf(fptr," CCClient:          %s\n\n",     fCCClient);
+  fprintf(fptr," Set DAC values:    %s\n\n",     IsDAC ? "yes" : "no");
+  fprintf(fptr," HVCalibOffset :    %f\n\n",     fHVCalibOffset);
+  fprintf(fptr," HVCalibSlope :     %f\n\n",     fHVCalibSlope);
+  fprintf(fptr," HVMaxDiff :        %f\n\n",     fHVMaxDiff);
+ 
+  fprintf(fptr,"*************************************************************************************************\n\n");
+
+  return 1;
+}
+
+
+int HVConfig::WriteHVConfig(FILE* fptr, char *configfile) {
+
+  FILE *f;
+
+  time_t time_now_secs;
+  struct tm *time_now;
+
+  time(&time_now_secs);
+  time_now = localtime(&time_now_secs);
+
+  if ((f = fopen(configfile,"w")) == NULL) {
+    fprintf(fptr,"Could not open file: %s\n", configfile);
+    return 0;
+  }
+  
+  fprintf(f,"# Main configuration file for the HV control program %s, %04d %02d %02d, %02d:%02d:%02d\n",
+	  HV_CONTROL_VERSION, 
+	  1900 + time_now->tm_year, 
+	  1 + time_now->tm_mon,
+	  time_now->tm_mday,
+	  time_now->tm_hour,
+	  time_now->tm_min,
+	  time_now->tm_sec);
+
+  fprintf(f,"# Note: this file will be updated at program exit\n\n");
+
+  fprintf(f,"LogPath            %s\n\n",   fLogPath);
+
+  fprintf(f,"TimeOut            %.2f s   # Timeout to return from read (%.2f,...%.2f) s\n\n",fTimeOut,MIN_TIMEOUT,MAX_TIMEOUT);
+
+  fprintf(f,"StatusRefreshRate  %.2f Hz   # Status update rate (%.2f,...%.2f) Hz\n\n",fStatusRefreshRate,MIN_RATE,MAX_RATE);
+
+  fprintf(f,"CCPort             %d   # Port used to look for commands from the Central Control\n",fCCPort);
+  fprintf(f,"CCClient           %s   # Central Control client name\n\n",fCCClient);
+  fprintf(f,"IsDAC              %s   # Define here if user input is interpreted as DAC value or voltage\n\n",((IsDAC) ? "TRUE" : "FALSE"));
+  fprintf(f,"HVCalibOffset      %f   # Calibration of DAC to voltage values\n",fHVCalibOffset);
+  fprintf(f,"HVCalibSlope       %f   # Calibration of DAC to voltage values\n\n",fHVCalibSlope);
+  fprintf(f,"HVMaxDiff          %f   # Speed for HV changes limited to 1V/ms\n",fHVMaxDiff);
+
+  fprintf(f,"# List of HV boards (at most %d HV boards will be recognized):\n",MAX_NUM_HVBOARDS);
+
+  for (int i=0;i<NumHVBoards;i++) 
+    fprintf(f,"Board%d             %s\n",USBDeviceNumber[i],fUSBDevice[i]);
+  
+  fprintf(fptr,"Configuration file successfully updated\n");
+  
+  fclose(f);
+  return 1;
+
+}
+
+
Index: hvcontrol/src/HVConfig.h
===================================================================
--- hvcontrol/src/HVConfig.h	(revision 14)
+++ hvcontrol/src/HVConfig.h	(revision 14)
@@ -0,0 +1,44 @@
+
+#ifndef HVCONFIG_H_SEEN
+#define HVCONFIG_H_SEEN
+
+#include <time.h>
+
+#include <string.h>
+
+#include "Types.h"
+
+class HVConfig {
+
+ public:
+
+  HVConfig(FILE* fptr, char *configfile=NULL);
+  ~HVConfig();
+
+  int ReadHVConfig(FILE* fptr, char *configfile);
+  int PrintHVConfig(FILE* fptr);
+  int WriteHVConfig(FILE* fptr, char *configfile);
+
+  int NumHVBoards;
+  int USBDeviceNumber[MAX_NUM_HVBOARDS];
+
+  int fCCPort;
+  char *fCCClient;
+
+  bool IsDAC;
+  float Coef[MAX_NUM_HVBOARDS][MAX_NUM_CHAINS][2];
+ 
+  char*  FileName;
+  char*  fLogPath;
+  char** fUSBDevice;
+
+  float  fTimeOut;
+  float  fStatusRefreshRate;
+
+  float  fHVCalibOffset;
+  float  fHVCalibSlope;
+  float  fHVMaxDiff;
+
+};
+
+#endif
Index: hvcontrol/src/HVMonitor.cc
===================================================================
--- hvcontrol/src/HVMonitor.cc	(revision 14)
+++ hvcontrol/src/HVMonitor.cc	(revision 14)
@@ -0,0 +1,28 @@
+
+/********************************************************************\
+
+  Name:         HVMonitor.cc
+
+  Created by:   Sebastian Commichau, November 2008
+                commichau@phys.ethz.ch
+
+  Actions:      Monitor HV board status
+
+\********************************************************************/
+
+#include "HVMonitor.h"
+
+
+void HVMonitor(ProcessIO *m) {
+  
+  siginterrupt(SIGUSR1, true);
+ 
+  while (!m->status->Exit) {
+
+    if (!m->status->Stop)
+      m->Monitor();
+
+    usleep((unsigned long)floor(1000000./(m->hv->GetNumberOfBoards()*m->status->fStatusRefreshRate)));
+  }
+
+}
Index: hvcontrol/src/HVMonitor.h
===================================================================
--- hvcontrol/src/HVMonitor.h	(revision 14)
+++ hvcontrol/src/HVMonitor.h	(revision 14)
@@ -0,0 +1,14 @@
+#ifndef HVMonitor_H_SEEN
+#define HVMonitor_H_SEEN
+
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "ProcessIO.h"
+#include "Types.h"
+#include "Utilities.h"
+
+void HVMonitor(ProcessIO *m);
+
+#endif
Index: hvcontrol/src/HVStatus.cc
===================================================================
--- hvcontrol/src/HVStatus.cc	(revision 14)
+++ hvcontrol/src/HVStatus.cc	(revision 14)
@@ -0,0 +1,173 @@
+
+/********************************************************************\
+
+  Name:         HVStatus.cc
+
+  Created by:   Sebastian Commichau, November 2008
+                commichau@phys.ethz.ch
+
+  Contents:     Store HV supply status information
+
+\********************************************************************/
+
+#include "HVStatus.h"
+
+static char* state_str[]    = {"active", "stopped", "n.a."}; 
+static char* isok_str[]     = {"error", "ok"};
+static char* cc_state_str[] = {"disconnected", "connected"};
+
+void InitStatus(Status* status, HVConfig* config) {
+
+  status->state     = active;
+  status->cc_state  = disconnected;
+  status->Exit      = FALSE;
+  status->Stop      = FALSE;
+  status->Log       = TRUE;
+  status->Verbose   = FALSE;
+  status->CCCommand = FALSE;
+
+  status->Socket    = -1;
+  sprintf(status->CCClient,"%s", config->fCCClient);
+  status->CCPort    = config->fCCPort;
+
+
+  status->fUSBDevice = new char*[MAX_NUM_HVBOARDS];
+  
+  for (int i=0; i<MAX_NUM_HVBOARDS; i++) {
+    status->fUSBDevice[i]      = new char[FILENAME_MAX_SIZE];
+    status->USBDeviceNumber[i] = USB_MAX_DEVICE_NUMBER+1;
+  }
+
+  status->USBMinDeviceNumber = USB_MAX_DEVICE_NUMBER;
+  status->USBMaxDeviceNumber = USB_MIN_DEVICE_NUMBER;
+
+  for (int i=0;i<MAX_NUM_HVBOARDS;i++) {
+    status->IsUpdated[i] = FALSE;
+    status->isok[i]      = TRUE;
+    status->MR[i]        = FALSE;
+    status->WC[0][i]     = 0;
+    status->WC[1][i]     = 1;
+
+    for (int j=0;j<MAX_NUM_CHAINS;j++) {
+      status->VRef[i][j] = 0;
+      status->OC[i][j]   = FALSE;
+
+      for (int k=0;k<MAX_NUM_CHANNELS;k++)
+	status->HV[i][j][k] = 0;
+    }
+  }
+
+  status->NumHVBoards = 0;
+  status->FirstBoard  = 0;
+  status->LastBoard   = -1;
+
+  status->FirstChain  = 0;
+  status->LastChain   = 3;
+  
+
+  if (config->fTimeOut >= (float)MIN_TIMEOUT && config->fTimeOut <= (float)MAX_TIMEOUT)
+    status->fTimeOut  = config->fTimeOut;
+  else
+    status->fTimeOut  = 1.;
+
+  if (config->fStatusRefreshRate >= (float)MIN_RATE && config->fStatusRefreshRate <= (float)MAX_RATE) 
+    status->fStatusRefreshRate = config->fStatusRefreshRate;
+  else
+    status->fStatusRefreshRate = 1.;
+} 
+
+
+void ReInitStatus(Status* status) {
+
+  for (int i=0;i<MAX_NUM_HVBOARDS;i++) {
+    status->IsUpdated[i] = FALSE;
+    for (int j=0;j<MAX_NUM_CHAINS;j++) {
+      status->VRef[i][j] = 0;
+      for (int k=0;k<MAX_NUM_CHANNELS;k++)
+	status->HV[i][j][k] = 0;
+    }
+  }
+  
+} 
+
+
+void ReInitStatusOneBoard(Status* status, int board) {
+
+  status->IsUpdated[board] = FALSE;
+  for (int j=0;j<MAX_NUM_CHAINS;j++) {
+    status->VRef[board][j] = 0;
+    for (int k=0;k<MAX_NUM_CHANNELS;k++)
+      status->HV[board][j][k] = 0;
+  }
+    
+} 
+
+
+void PrintStatus(Status* status, HVConfig* config, FILE* fptr) {
+
+  fprintf(fptr,"\n");
+  fprintf(fptr,"********************************************* STATUS ********************************************\n\n");
+  fprintf(fptr," Status monitor: %s\n",state_str[status->state]);
+  fprintf(fptr," Logging: %s\n", ((status->Log) ? "on" : "off"));
+  fprintf(fptr," Verbose: %s\n", ((status->Verbose) ? "on" : "off"));
+  fprintf(fptr," Timeout [s]: %.2f\n",status->fTimeOut);
+  fprintf(fptr," Status refresh rate [Hz]: %.2f\n",status->fStatusRefreshRate);
+  fprintf(fptr," CC state: %s\n",                     cc_state_str[status->cc_state]);
+  fprintf(fptr," CC client: %s\n",                    status->CCClient);
+  fprintf(fptr," CC port: %d\n",                      status->CCPort);
+  fprintf(fptr," Total number of HV boards: %d\n",   status->NumHVBoards);
+  if (!status->NumHVBoards)
+    fprintf(fptr," Active HV boards: 0\n\n");
+  else if (status->NumHVBoards == ((status->LastBoard - status->FirstBoard) + 1))
+    fprintf(fptr," Active HV boards: all\n\n");
+  else
+    fprintf(fptr," Active HV boards: %d\n\n",            (status->LastBoard - status->FirstBoard) + 1);
+
+  for (int i=status->FirstBoard;i<=status->LastBoard;i++) {
+    fprintf(fptr," BOARD %d (%s):\n",status->USBDeviceNumber[i],status->fUSBDevice[i]);
+    fprintf(fptr,"  Wrap counter: %s (%d)\n",isok_str[status->isok[i]], status->WC[1][i]);
+    fprintf(fptr,"  Manual reset: %s\n\n",((status->MR[i]) ? "yes" : "no"));
+
+    for (int j=status->FirstChain;j<=status->LastChain;j++) {
+      fprintf(fptr,"  CHAIN %d:\n",j);
+      fprintf(fptr,"   Over-current: %s\n",((status->OC[i][j]) ? "yes" : "no"));
+      fprintf(fptr,"   Reference voltage: %d\n",status->VRef[i][j]);
+      fprintf(fptr,"   High voltage:\n");
+      for (int k=0;k<4;k++) {
+	fprintf(fptr,"    Channels %.2d-%.2d: ",k*8,k*8+7);
+	for (int l=0;l<8;l++) 
+	  fprintf(fptr," %5d ",status->HV[i][j][k*8+l]);
+	fprintf(fptr,"\n");
+      }
+	fprintf(fptr,"\n");
+    }
+  }
+
+
+  fprintf(fptr,"*************************************************************************************************\n\n");
+
+}
+
+
+void sPrintStatus(Status* status, char* str, int i) {
+
+  sprintf(str,"status board %d (%s): MR %s OC0 %s OC1 %s OC2 %s OC3 %s WC %s (%d)\n",status->USBDeviceNumber[i],status->fUSBDevice[i],
+	  ((status->MR[i]) ? "yes" : "no"),
+	  ((status->OC[i][0]) ? "yes" : "no"),
+	  ((status->OC[i][1]) ? "yes" : "no"),
+	  ((status->OC[i][2]) ? "yes" : "no"),
+	  ((status->OC[i][3]) ? "yes" : "no"),
+	  isok_str[status->isok[i]],
+	  status->WC[1][i]);
+ 
+  if (status->Socket != -1) // Print status string to socket if open
+    write(status->Socket,str,strlen(str));
+
+}
+
+
+char* GetStateStr(Status* status) {
+
+  return state_str[status->state];
+
+}
Index: hvcontrol/src/HVStatus.h
===================================================================
--- hvcontrol/src/HVStatus.h	(revision 14)
+++ hvcontrol/src/HVStatus.h	(revision 14)
@@ -0,0 +1,81 @@
+
+#ifndef HVSTATUS_H_SEEN
+#define HVSTATUS_H_SEEN
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include "Types.h"
+#include "HVConfig.h"
+
+typedef enum stateenum { active, stopped, na } state_enum;
+typedef enum connection  { disconnected, connected } connect_enum;
+
+typedef struct status_str {
+  
+  pthread_t HVMonitor;
+
+  char Prompt[MAX_COM_SIZE];
+  
+  bool Log;
+  bool Verbose;
+
+  char Param[10][MAX_COM_SIZE], *Pc; // For parser
+  int NParam;
+  
+  connect_enum cc_state;
+
+  int Socket;                   // PrintMessage() uses this socket, -1 if not connected
+  pthread_t SocketThread;       // exit function sends signal to this thread
+
+  int CCPort;
+  char CCClient[STR_LENGTH];
+  
+  char** fUSBDevice;
+  int USBDeviceNumber[MAX_NUM_HVBOARDS];
+  int USBMinDeviceNumber;
+  int USBMaxDeviceNumber;
+
+  int NumHVBoards;
+  int FirstBoard;
+  int LastBoard;
+
+  int FirstChain;
+  int LastChain;
+  
+  unsigned int VRef[MAX_NUM_HVBOARDS][MAX_NUM_CHAINS];     
+  unsigned int HV[MAX_NUM_HVBOARDS][MAX_NUM_CHAINS][MAX_NUM_CHANNELS];
+
+  float fTimeOut;
+  float fStatusRefreshRate;
+
+  bool OC[MAX_NUM_HVBOARDS][MAX_NUM_CHAINS]; // Overcurrent flag
+  bool MR[MAX_NUM_HVBOARDS];                 // Manual reset
+  
+  bool isok[MAX_NUM_HVBOARDS];
+  state_enum   state;
+
+  bool IsUpdated[MAX_NUM_HVBOARDS];
+
+  int WC[2][MAX_NUM_HVBOARDS];
+  
+  int CCCommand;
+  int Exit;
+  int Stop;
+
+} Status;
+
+
+void InitStatus(Status* status, HVConfig* config);
+void ReInitStatus(Status* status);
+void ReInitStatusOneBoard(Status* status, int board);
+void PrintStatus(Status* status, HVConfig* config, FILE* fptr);
+void sPrintStatus(Status* status, char* str, int i);
+char* GetStateStr(Status* status);
+
+#endif
Index: hvcontrol/src/Log.cc
===================================================================
--- hvcontrol/src/Log.cc	(revision 14)
+++ hvcontrol/src/Log.cc	(revision 14)
@@ -0,0 +1,56 @@
+
+#include "Log.h"
+
+Log::Log(char logpath[]) {
+
+  char logfile[FILENAME_MAX_SIZE];
+  time_t time_now_secs;
+  struct tm *time_now;
+
+  time(&time_now_secs);
+  time_now = localtime(&time_now_secs);
+
+  // Open log file
+  sprintf(logfile, "%s/hvutil_%04d_%02d_%02d_%02d_%02d_%02d.log", 
+	  logpath,
+	  1900 + time_now->tm_year,
+	  1 + time_now->tm_mon,
+	  time_now->tm_mday,
+	  time_now->tm_hour,
+	  time_now->tm_min,
+	  time_now->tm_sec);
+  if ((logptr = fopen(logfile, "w")) == NULL) {
+    fprintf(stderr,"Log::Log: could not open file %s => check DAQ config file\n", logfile);
+    exit(1);
+  }  
+
+  LogWrite("start logfile\n");
+}
+
+
+Log::~Log() {
+  LogWrite("end logfile\n");
+  fclose(logptr);
+  printf("Logfile closed\n");
+}
+
+
+int Log::LogWrite(char logtext[]) {
+  time_t time_now_secs;
+  struct tm *time_now;
+
+  time(&time_now_secs);
+  time_now = localtime(&time_now_secs);
+
+  fprintf(logptr, "[%04d:%02d:%02d:%02d:%02d:%02d] %s",
+	  1900 + time_now->tm_year,
+	  1 + time_now->tm_mon,
+	  time_now->tm_mday,
+	  time_now->tm_hour,
+	  time_now->tm_min,
+	  time_now->tm_sec,
+	  logtext);
+  fflush(logptr);
+
+  return 0;
+}
Index: hvcontrol/src/Log.h
===================================================================
--- hvcontrol/src/Log.h	(revision 14)
+++ hvcontrol/src/Log.h	(revision 14)
@@ -0,0 +1,25 @@
+#ifndef LOG_H_SEEN
+#define LOG_H_SEEN
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "Types.h"
+
+#define MAX_LOG_SIZE 220
+
+class Log {
+
+ public:
+  Log(char logpath[]);
+  ~Log();
+  
+  int LogWrite(char logtext[]);
+  
+ public:
+  FILE *logptr;
+  char logtext[MAX_LOG_SIZE];
+};
+
+#endif
Index: hvcontrol/src/Makefile
===================================================================
--- hvcontrol/src/Makefile	(revision 14)
+++ hvcontrol/src/Makefile	(revision 14)
@@ -0,0 +1,33 @@
+#
+#  Makefile 
+#
+
+include ../Makefile.general
+
+INCDIRS = -I. -I/usr/local/include
+
+CC_SOURCES =  $(shell ls *.cc)
+CC_SOURCES := $(notdir $(CC_SOURCES))
+CC_OBJECTS =  $(CC_SOURCES:%.cc=%.o)
+
+C_SOURCES  =  $(shell ls *.c)
+C_SOURCES  := $(notdir $(C_SOURCES))
+C_OBJECTS  =  $(C_SOURCES:%.c=%.o)
+
+OBJECTS = $(CC_OBJECTS)  $(C_OBJECTS) 
+SOURCES = $(CC_SOURCES)  $(C_SOURCES) 
+
+all: $(OBJECTS) 
+
+include ../Makefile.rules
+
+clean: rmobj rmdep
+
+mrproper: clean rmbak
+
+
+
+
+
+
+
Index: hvcontrol/src/ProcessIO.cc
===================================================================
--- hvcontrol/src/ProcessIO.cc	(revision 14)
+++ hvcontrol/src/ProcessIO.cc	(revision 14)
@@ -0,0 +1,1805 @@
+
+/********************************************************************\
+
+  Name:         ProcessIO.cc
+
+  Created by:   Sebastian Commichau, November 2008
+                commichau@phys.ethz.ch
+
+  Contents:     Main class processing user input
+
+\********************************************************************/
+
+
+#include "ProcessIO.h"
+
+
+ProcessIO::ProcessIO(char *ConfigFile) {
+
+  // Get program start time - only needed for uptime command
+  time (&StartTime);
+
+  status  = new Status;
+  config  = new HVConfig(stdout,ConfigFile);
+  log     = new Log(config->fLogPath);
+  hv      = new HV(config->fUSBDevice,config->USBDeviceNumber,stdout);
+
+  // Initialize status structure (HVStatus.cc/h)
+  InitStatus(status,config);    
+
+  // Print HV control configuration to the log file
+  config->PrintHVConfig(log->logptr);
+
+  // The following loop was added to allow for an arbitrary numeration of the HV boards
+  for (int i=0;i<hv->GetNumberOfBoards();i++) {
+    
+    sprintf(status->fUSBDevice[i],"%s",(hv->GetHVBoard(i))->GetSerial());
+    status->USBDeviceNumber[i] = (hv->GetHVBoard(i))->GetBoardNumber();
+
+    if ((hv->GetHVBoard(i))->GetBoardNumber() > status->USBMaxDeviceNumber)
+      status->USBMaxDeviceNumber = (hv->GetHVBoard(i))->GetBoardNumber();
+
+    if ((hv->GetHVBoard(i))->GetBoardNumber() < status->USBMinDeviceNumber)
+      status->USBMinDeviceNumber = (hv->GetHVBoard(i))->GetBoardNumber();
+
+    (hv->GetHVBoard(i))->SetTimeOut(config->fTimeOut);
+  }
+
+  // Initialize HV boards (see below)
+  InitializeHV();
+
+  status->FirstBoard  = 0;
+  status->NumHVBoards = hv->GetNumberOfBoards();
+  status->LastBoard   = hv->GetNumberOfBoards()-1;
+
+  // Print status information to the log file
+  PrintStatus(status,config,log->logptr);
+
+  // Send reset command to all boards
+  ResetAllBoards();
+
+  // Print some information
+  sprintf(str,"status monitor: %s\n", GetStateStr(status));
+  if (hv->GetNumberOfBoards()>0) DoPrompt(str);
+  
+  sprintf(str,"type (h)elp to get a list of available commands\n");
+  DoPrompt(str);
+
+  // Print empty prompt
+  DoPrompt(NULL);
+  
+  // Initialize mutex variable for thread synchronization
+  pthread_mutex_init (&control_mutex, NULL);
+  pthread_cond_init  (&control_cond,  NULL);
+    
+}
+
+
+ProcessIO::~ProcessIO() {
+  
+  pthread_mutex_destroy (&control_mutex);
+  pthread_cond_destroy  (&control_cond);
+  
+  config->fStatusRefreshRate = status->fStatusRefreshRate;
+  config->fTimeOut           = status->fTimeOut;
+  config->WriteHVConfig(stdout,config->FileName);
+
+  if (hv)      delete hv;
+  if (status)  delete status;
+  if (config)  delete config;
+  if (log)     delete log;
+  
+}
+
+
+// Print list of all commands 
+void ProcessIO::PrintHelp() {
+
+  puts("");
+  puts("********************************************** HELP *********************************************\n");
+  puts(" board <i>|<i> <j>|<all>           Address board i, boards i-j or all boards");
+  puts(" chain <i>|<i> <j>|<all>           Address chain i, chains i-j or all chains");
+  puts(" clear                             Clear screen");
+  puts(" config                            Print configuration");
+  puts(" help                              Print help");
+  puts(" hv <ch>|<all> [b][x]<v>           Set chan. <ch>|<all> chan. of active chain(s)/board(s) to <v>");
+  puts(" hvdiff <ch>|<all> [b][x]<diff>    Set chan. <ch>|<all> chan. of active chain(s)/board(s) to <diff>");
+  puts(" list                              List all HV boards");
+  puts(" load <file>                       Load HV settings from <file>");
+  puts(" log <on>|<off>                    Enable|disable logging");
+  puts(" quit|exit                         Exit program");
+  puts(" rate <rate>                       Set status refresh rate to <rate> [Hz]");
+  puts(" reset                             Reset active HV board");
+  puts(" save [file]                       Save current HV settings to [file]");
+  puts(" start                             Start HV status monitor");
+  puts(" status                            Show status information");
+  puts(" stop                              Stop HV status monitor - not recommended!");
+  puts(" time                              Print current date and time");
+  puts(" timeout <time>                    Set timeout to return from read to <time> [s]");
+  puts(" uptime                            Get program uptime [h:m:s]");
+  puts(" verbose <on>|<off>                Enable|disable verbosity");
+  puts(" vref [b][x]<v>                    Set reference voltage of active chain(s)/board(s) to <v>\n");
+  puts("*************************************************************************************************\n");
+
+}
+
+
+// Process user input
+int ProcessIO::CommandControl() {
+
+  //  bool IsDAC;
+  //  float  fHVCalibOffset;
+  //  float  fHVCalibSlope;
+  //  float  fHVMaxDiff;
+
+
+  // Adress HV board
+  if (Match(status->Param[0], "board")) {
+    
+    if (!NBoards())
+      return 0;
+    else {
+  
+      // Select all boards
+      if (status->Param[1][0] == 'a' && !status->Param[2][0]) {
+	
+	status->FirstBoard = 0;
+	status->LastBoard = hv->GetNumberOfBoards()-1;
+	
+      }
+      // Wrong type of argument
+      else if (!IsNoDigit(status->Param[1]) || !IsNoDigit(status->Param[2]) || status->Param[3][0] || !status->Param[1][0]) {
+	sprintf(str,"usage: <board> <i>|<i> <j>|<all>\n");
+	DoPrompt(str);	
+	return 0;
+      } 
+      // Check if board(s) exist(s)
+      else if (status->Param[1][0] || status->Param[2][0]) {
+
+	if (!IsBoard(atoi(status->Param[1]))) {
+	  sprintf(str,"board #%d does not exist\n", atoi(status->Param[1]));
+	  DoPrompt(str);
+	  return 0;
+	}
+	
+	if (status->Param[2][0])
+	  if (!IsBoard(atoi(status->Param[2]))) {
+	    sprintf(str,"board #%d does not exist\n", atoi(status->Param[2]));
+	    DoPrompt(str);
+	    return 0;
+	  }
+
+	if (status->Param[1][0] && status->Param[2][0]) {
+	  
+	  status->FirstBoard = GetBoardIdx(atoi(status->Param[1]));
+	  status->LastBoard  = GetBoardIdx(atoi(status->Param[2]));
+
+	}
+	else if (status->Param[1][0]) {
+
+	  status->FirstBoard = GetBoardIdx(atoi(status->Param[1]));
+	  status->LastBoard = status->FirstBoard;
+	  
+	}
+      }
+    
+      //DoPrompt(NULL);
+    }
+    
+    DoPrompt(NULL);
+    return 0;
+  } 
+
+
+  // Adress chains
+  else if (Match(status->Param[0], "chain")) {
+    
+    if (!NBoards())
+      return 0;
+    else {
+      
+      if (status->Param[1][0] == 'a') {
+	
+	status->FirstChain = 0;
+	status->LastChain  = 3;
+	
+      } 
+      else if (!IsNoDigit(status->Param[1]) || !status->Param[1][0]) {
+	sprintf(str,"usage: <chain> <i>|<i> <j>|<all>\n");
+	DoPrompt(str);	
+	return 0;
+      }
+      else if (status->Param[1][0] >= 0 && atoi(status->Param[1]) >= 0 && atoi(status->Param[1]) < 4 && !status->Param[2][0]) {
+	
+	status->FirstChain = atoi(status->Param[1]);
+	status->LastChain = status->FirstChain;
+	
+      }
+      else if ((status->Param[1][0] >= 0 && atoi(status->Param[1]) >= 0 && atoi(status->Param[1]) < 4) && 
+	       (status->Param[2][0] > 0 && atoi(status->Param[2]) > 0 && atoi(status->Param[2]) < 4)) {
+	
+	status->FirstChain = atoi(status->Param[1]);
+	status->LastChain = atoi(status->Param[2]);
+	
+      }
+      else {
+	
+	if (atoi(status->Param[1]) < 0 || atoi(status->Param[1]) > 3) {
+	  sprintf(str,"chain #%d does not exist\n", atoi(status->Param[1]));
+	  DoPrompt(str);
+	}
+	
+	
+	if ((atoi(status->Param[2]) < 0 || atoi(status->Param[2]) > 3) && (atoi(status->Param[1]) != atoi(status->Param[2]))) {
+	  sprintf(str,"chain #%d does not exist\n", atoi(status->Param[2]));
+	  DoPrompt(str);
+	}
+	
+	return 0;
+	
+      }
+
+      DoPrompt(NULL);
+    }
+    
+    return 0;
+  } 
+
+
+  // Clear screen
+  else if (Match(status->Param[0], "clear") || Match(status->Param[0], "cls")) {
+
+  system("clear");
+  DoPrompt(NULL);
+
+  return 0;
+  
+  }
+
+
+  // Print HV utility configuration
+  else if (Match(status->Param[0], "config")) {
+
+    config->PrintHVConfig(stdout);
+    
+    return 0;
+  }
+
+
+  // Print help
+  if (Match(status->Param[0], "help")) {
+
+    PrintHelp();
+    DoPrompt(NULL);
+   
+    return 0;
+  } 
+
+
+  // Write high voltage -----------------------------------------------------------------------------------------
+  if (Match(status->Param[0], "hv")) {
+
+    if (!NBoards())
+      return 0;
+
+    int errors = 0;
+    unsigned int hvoltage = 0;
+    float hvoltageV = 0.0;
+    int channel = 0;
+    bool allchannels = FALSE;
+
+    if (status->Param[1][0]>0 && status->Param[2][0]>0) {
+
+      // Set channel
+      if (IsNoDigit(status->Param[1]))
+	channel = atoi(status->Param[1]);
+      else if(status->Param[1][0] == 'a')
+	allchannels = TRUE;
+      else {
+	DoPrompt("error: wrong input format - usage: hv <channel>|<all> <voltage>\n");
+	return 0;
+      }
+          
+      // Binary input
+      if (tolower(status->Param[2][0])=='x' && strlen(status->Param[2])>2) {
+	if (sPrintHex2Dec(Chop(status->Param[2]+1),&hvoltage)!=0) {
+	  DoPrompt("error: wrong input format - usage: hv <channel>|<all> <voltage>\n");
+	  return 0;
+	}
+      }
+      // Hexadecimal input
+      else if (tolower(status->Param[2][0])=='b' && strlen(status->Param[2])>2) {
+	if (sPrintBin2Dec(Chop(status->Param[2]+1),&hvoltage)!=0) {
+	  DoPrompt("wrong input format - usage: hv <channel>|<all> <voltage>\n");
+	  return 0;
+	}
+      }
+      // Decimal input
+      else if (IsNoDigit(status->Param[2])&&config->IsDAC)
+	hvoltage = atoi(status->Param[2]);
+      else if (IsNoDigit(status->Param[2])&&(!(config->IsDAC)))
+	hvoltageV = atof(status->Param[2]);
+      // Wrong input format
+      else {
+	DoPrompt("wrong input format - usage: hv <channel>|<all> <voltage>\n");
+	return 0;
+      }
+
+      // Check limits
+      if (channel>31 || channel <0) {
+	DoPrompt("channel out of range (0...31)!\n");
+	return 0;
+      }
+      else if ((hvoltage>0X3FFF || hvoltage <0)&&config->IsDAC) {
+	DoPrompt("high voltage out of range (Vmin: 0, Vmax: 16383)!\n");
+	return 0;
+      }
+      else if ((hvoltage>78.0 || hvoltage <0)&&(!(config->IsDAC))) {
+	DoPrompt("high voltage out of range (Vmin: 0, Vmax: 78.)!\n");
+	return 0;
+      }
+
+      if (!(config->IsDAC))
+	hvoltage=(unsigned int)((hvoltageV-config->fHVCalibOffset)/config->fHVCalibSlope);
+
+      StopMonitor();
+      
+      
+      for (int i=status->FirstBoard;i<=status->LastBoard;i++) {
+
+	for (int j=status->FirstChain;j<=status->LastChain;j++) {
+	  if (!allchannels) {
+	    if ((hv->GetHVBoard(i))->SetHV(stdout,j,channel,hvoltage,rbuf,status->Verbose)==1) {
+	      
+	      status->HV[i][j][channel]=hvoltage;
+	      sprintf(str, "Test1   status->HV = %d\n",hvoltage);
+	      DoPrompt(str);
+	      UpdateStatus(i,rbuf);
+	      
+	      sprintf(str,"board %d: high voltage of chain %d channel %d set to %d | 0X%.4X\n",hv->GetHVBoard(i)->GetBoardNumber(),j,channel,hvoltage,hvoltage);
+	      DoPrompt(str);
+	      if (status->Verbose) {
+		sPrintStatus(status,str,i);
+		DoPrompt(str);
+	      }
+	      sPrintStatus(status,str,i); // Print status only to socket 
+	    }
+	    else {
+	      sprintf(str,"board %d error: could not set hv - check timeout and try again\n",hv->GetHVBoard(i)->GetBoardNumber());
+	      DoPrompt(str);
+	      errors++;
+	    }
+
+	  }
+	  else {
+
+	    sprintf(str,"updating board %d chain %d\n",hv->GetHVBoard(i)->GetBoardNumber(),j);
+	    DoPrompt(str);
+	    
+
+	    for (int k=0;k<MAX_NUM_CHANNELS;k++) {
+	      if ((hv->GetHVBoard(i))->SetHV(stdout,j,k,hvoltage,rbuf,status->Verbose)==1) {
+		
+		status->HV[i][j][k]=hvoltage;
+		UpdateStatus(i,rbuf);
+		
+		if (status->Verbose) {
+		  sprintf(str,"board %d: high voltage of chain %d channel %d set to %d | 0X%.4X\n",hv->GetHVBoard(i)->GetBoardNumber(),j,k,hvoltage,hvoltage);
+		  DoPrompt(str);
+		  sPrintStatus(status,str,i);
+		  DoPrompt(str);
+		}
+		sPrintStatus(status,str,i); // Print status only to socket 
+		
+	      }
+	      else {
+		sprintf(str,"board %d error: could not set HV - check timeout and try again\n",hv->GetHVBoard(i)->GetBoardNumber());
+		DoPrompt(str);
+		errors++;
+	      }
+	    }
+	  }
+	}
+      }
+
+      
+
+      StartMonitor();
+
+      if (errors) {
+	sprintf(str,"warning %d error(s) => check timeout and try again\n",errors);
+	DoPrompt(str);
+      }
+      else {
+	sprintf(str,"no error(s)... success!\n");
+	DoPrompt(str);
+      }
+
+    }
+    else {
+      sprintf(str,"usage: hv <channel>|<all> <voltage>\n");
+      DoPrompt(str);
+    }
+
+    return 0;
+  }  // End: Write high voltage  ----------------------------------------------------------------------------------------
+
+
+
+  // Write difference of high voltage ------------------------------------------------------------------------------------
+  if (Match(status->Param[0], "hvdiff")) {
+
+    if (!NBoards())
+      return 0;
+
+    int errors = 0;
+    int hvdiff = 0;
+    unsigned int hvoltage = 0;
+    float hvdiffV = 0.0;
+    int channel = 0;
+    bool allchannels = FALSE;
+
+    if (status->Param[1][0]>0 && status->Param[2][0]>0) {
+
+      // Set channel
+      if (IsNoDigit(status->Param[1]))
+	channel = atoi(status->Param[1]);
+      else if(status->Param[1][0] == 'a')
+	allchannels = TRUE;
+      else {
+	DoPrompt("error: wrong input format - usage: hvdiff <channel>|<all> <hv difference>\n");
+	return 0;
+      }
+
+      // Binary input
+      if (tolower(status->Param[2][0])=='x' && strlen(status->Param[2])>2) {
+	if (sPrintHex2Dec(Chop(status->Param[2]+1),(unsigned int *)hvdiff)!=0) {
+	  DoPrompt("error: wrong input format - usage: hvdiff <channel>|<all> <hv difference>\n");
+	  return 0;
+	}
+      }
+      // Hexadecimal input
+      else if (tolower(status->Param[2][0])=='b' && strlen(status->Param[2])>2) {
+	if (sPrintBin2Dec(Chop(status->Param[2]+1),(unsigned int *)hvdiff)!=0) {
+	  DoPrompt("wrong input format - usage: hvdiff <channel>|<all> <hv difference>\n");
+	  return 0;
+	}
+      }
+      // Decimal input
+      else if (IsNoDigit(status->Param[2])&&(config->IsDAC))
+	hvdiff = atoi(status->Param[2]);
+      else if (IsNoDigit(status->Param[2])&&(!(config->IsDAC)))
+	hvdiffV = atof(status->Param[2]);
+      // Wrong input format
+      else {
+	DoPrompt("wrong input format - usage: hvdiff <channel>|<all> <hv difference>\n");
+	return 0;
+      }
+      // Check limits
+      if (channel>31 || channel <0) {
+	DoPrompt("channel out of range (0...31)!\n");
+	return 0;
+      }
+      else if (hvdiff>0X3FFF) {
+	DoPrompt("difference of high voltage out of range (Vmin: -16383, Vmax: 16383)!\n");
+	return 0;
+      }
+      else if (hvdiffV>78.0 && (-78.0<hvdiffV)) {
+	DoPrompt("difference of high voltage out of range (Vmin: -78.0, Vmax: 78.0)!\n");
+	return 0;
+      }
+
+      if (!(config->IsDAC)){
+	hvdiff=(int)(hvdiffV/config->fHVCalibSlope);
+      }
+      StopMonitor();
+
+      
+      for (int i=status->FirstBoard;i<=status->LastBoard;i++) {
+
+	for (int j=status->FirstChain;j<=status->LastChain;j++) {
+	  if (!allchannels) {
+	    hvoltage = status->HV[i][j][channel];
+	    for (int k=0;k<=abs((int)(hvdiff/config->fHVMaxDiff));k++){
+	      if (k<abs((int)(hvdiff/config->fHVMaxDiff))){
+		hvoltage=(unsigned int)(hvoltage + config->fHVMaxDiff*hvdiff/abs(hvdiff));
+	      }
+	      if (k==(int)(abs((int)(hvdiff/config->fHVMaxDiff)))){
+		hvoltage=(unsigned int)(hvoltage + (hvdiff%(int)config->fHVMaxDiff));
+	      }
+
+
+	      status->HV[i][j][channel]=hvoltage;
+	      if ((hv->GetHVBoard(i))->SetHV(stdout,j,channel,hvoltage,rbuf,status->Verbose)==1) {
+		UpdateStatus(i,rbuf);
+		sprintf(str,"board %d: high voltage of chain %d channel %d set to %d | 0X%.4X\n",hv->GetHVBoard(i)->GetBoardNumber(),j,channel,hvoltage,hvoltage);
+		DoPrompt(str);
+		if (status->Verbose) {
+		  sPrintStatus(status,str,i);
+		  DoPrompt(str);
+		}
+		sPrintStatus(status,str,i); // Print status only to socket 
+	      }
+	      else {
+		sprintf(str,"board %d error: could not set hv - check timeout and try again\n",hv->GetHVBoard(i)->GetBoardNumber());
+		DoPrompt(str);
+		errors++;
+	      }
+	      //	    Sleep(1);
+	    }
+	  }
+	  else {
+	    
+	    sprintf(str,"updating board %d chain %d\n",hv->GetHVBoard(i)->GetBoardNumber(),j);
+	    DoPrompt(str);
+	    
+
+	    for (int k=0;k<MAX_NUM_CHANNELS;k++) {
+   	      int hvoltage = status->HV[i][j][k];
+	      for (int l=0;l<=abs((int)(hvdiff/config->fHVMaxDiff));l++){
+	    	if (l<abs((int)(hvdiff/config->fHVMaxDiff)))
+		  hvoltage=(unsigned int)(hvoltage + config->fHVMaxDiff*hvdiff/abs(hvdiff));
+		if (l==(int)(abs((int)(hvdiff/config->fHVMaxDiff))))
+		  hvoltage=(unsigned int)(hvoltage + (hvdiff%(int)config->fHVMaxDiff));
+		status->HV[i][j][k]=hvoltage;
+		if ((hv->GetHVBoard(i))->SetHV(stdout,j,k,hvoltage,rbuf,status->Verbose)==1) {
+		
+		  UpdateStatus(i,rbuf);
+		
+		  if (status->Verbose) {
+		    sprintf(str,"board %d: high voltage of chain %d channel %d set to %d | 0X%.4X\n",hv->GetHVBoard(i)->GetBoardNumber(),j,k,hvoltage,hvoltage);
+		    DoPrompt(str);
+		    sPrintStatus(status,str,i);
+		    DoPrompt(str);
+		  }
+		  sPrintStatus(status,str,i); // Print status only to socket 
+		  
+		}
+		else {
+		  sprintf(str,"board %d error: could not set HV - check timeout and try again\n",hv->GetHVBoard(i)->GetBoardNumber());
+		  DoPrompt(str);
+		  errors++;
+		}
+		//		Sleep(0.001);
+	      }
+	    }
+	  }
+	}
+      }
+      StartMonitor();
+
+      if (errors) {
+	sprintf(str,"warning %d error(s) => check timeout and try again\n",errors);
+	DoPrompt(str);
+      }
+      else {
+	sprintf(str,"no error(s)... success!\n");
+	DoPrompt(str);
+      }
+    }
+    else {
+      sprintf(str,"usage: hvdiff <channel>|<all> <hv difference>\n");
+      DoPrompt(str);
+    }
+    return 0;
+
+    }
+
+      // End: Write difference of high voltage --------------------------------------------------------------------
+  
+
+
+  // List HV boards
+  else if (Match(status->Param[0], "list")) {
+    
+    sprintf(str,"%d HV board(s) active:\n",hv->GetNumberOfBoards());
+    DoPrompt(str);
+
+    for (int i=0;i<hv->GetNumberOfBoards();i++) {
+      sprintf(str,"board %d (%s)\n",(hv->GetHVBoard(i))->GetBoardNumber(),(hv->GetHVBoard(i))->GetSerial());
+      DoPrompt(str);
+    }
+    
+    return 0;
+  }
+
+
+  // Load HV settings from file
+  else if (Match(status->Param[0], "load")) {
+
+    char param[20][MAX_COM_SIZE];
+    char buffer[128];
+
+    int nparam  = 0;
+    int nrows   = 0;
+    int board   = 0;
+    int chain   = 0;
+    int channel = 0;
+    int nboards = 0;
+    int errors  = 0;
+    unsigned int hvoltage = 0;
+
+    FILE *file;
+    
+    if (status->Param[1][0] && !status->Param[2][0]) {
+      
+      if ((file=fopen((char *)Chop(status->Param[1]),"r"))!=NULL) {
+	
+	if (status->Verbose) {
+	  sprintf(str,"file \"%s\" opened\n",Chop(status->Param[1]));
+	  DoPrompt(str);
+	}
+	
+	StopMonitor();
+
+	while (fgets(buffer,100,file)) {
+	  
+	  ParseInput(buffer,&nparam,param);
+	  
+	  if (nparam==2 && Match(param[0],"Device:")) {
+	    	    
+	    for (int j=0;j<hv->GetNumberOfBoards();j++)
+	      if (Match(Chop(status->fUSBDevice[j]),Chop(param[1]))) {
+
+		board = j;
+		
+		sprintf(str,"found HV settings for board %d (%s)\n",hv->GetHVBoard(board)->GetBoardNumber(),Chop(param[1]));
+		DoPrompt(str);
+		
+		nboards++;
+		nrows = 0;
+	      
+		while (fgets(buffer,100,file)) {
+		  
+		  ParseInput(buffer,&nparam,param);
+		  
+		  if (nparam==8) { 
+
+		    chain = nrows/4;
+
+		    if (!((nrows)%4)) {
+		      sprintf(str,"updating board %d chain %d\n",hv->GetHVBoard(board)->GetBoardNumber(),chain);
+		      DoPrompt(str);
+		    }
+
+		    
+		    for (int i=0;i<nparam;i++) {
+		      
+		      hvoltage = atoi(param[i]);
+		      channel  = (i+8*nrows)%32;
+		      
+		      // Submit HV values
+		      if ((hv->GetHVBoard(board))->SetHV(stdout,chain,channel,hvoltage,rbuf,status->Verbose)==1) {
+			
+			status->HV[board][chain][channel]=hvoltage;
+			UpdateStatus(board,rbuf);
+			
+			if (status->Verbose) {
+			  sprintf(str,"board %d: high voltage of chain %d channel %d set to %d | 0X%.4X\n",
+				  hv->GetHVBoard(board)->GetBoardNumber(),chain,channel,hvoltage,hvoltage);
+			  DoPrompt(str);
+			  sPrintStatus(status,str,board);
+			  DoPrompt(str);
+			}
+		      }
+		      else {
+			sprintf(str,"board %d error: could not set HV - check timeout and try again\n",hv->GetHVBoard(board)->GetBoardNumber());
+			DoPrompt(str);
+			errors++;
+		      }
+		      
+		    }
+		    
+		    nrows++;
+		    
+		  }
+		  else if (nparam==2)
+		    break;
+		}
+	      }
+	  } 
+	}
+	
+	if (fclose (file)) {
+	  sprintf(str,"error: could not close file \"%s\"\n",Chop(status->Param[1]));
+	  DoPrompt(str);
+	} 
+	else {
+	  if (status->Verbose) {
+	    sprintf(str,"file \"%s\" closed\n",Chop(status->Param[1]));
+	    DoPrompt(str);
+	  }
+	}
+
+	if (nboards!=hv->GetNumberOfBoards()) {
+	  sprintf(str,"warning: could not load HV settings for all connected HV boards\n");
+	  DoPrompt(str);
+	}
+	else {
+	  sprintf(str,"success: read HV settings for all connected HV boards\n");
+	  DoPrompt(str);
+	}
+
+	if (errors) {
+	  sprintf(str,"warning %d error(s) => check timeout and try again\n",errors);
+	  DoPrompt(str);
+	}
+	else {
+	  sprintf(str,"no error(s)... success!\n");
+	  DoPrompt(str);
+	}
+	
+      }
+      else {
+	sprintf(str,"error: could not open file \"%s\"\n",Chop(status->Param[1]));
+	DoPrompt(str);
+      }
+      
+    }
+    else
+      DoPrompt("usage: load <file>\n");
+
+    StartMonitor();
+
+    return 0;
+    
+  }
+	   
+
+  // Enable/disable logging
+  else if (Match(status->Param[0], "log")) {
+
+    if (Match(status->Param[1], "on") && status->Param[1][0]) {
+      status->Log = TRUE;
+      sprintf(str,"logging enabled\n");
+      DoPrompt(str);
+    }
+    
+    else if (Match(status->Param[1], "off") && status->Param[1][0]) {
+      status->Log = FALSE;
+      sprintf(str,"logging disabled\n");
+      DoPrompt(str);
+    }
+    
+    else
+      DoPrompt("usage: log <on>|<off>\n");
+  
+    return 0;
+  }
+
+
+  // Set status refresh rate
+  if (Match(status->Param[0], "rate")) {
+
+    if (!NBoards())
+      return 0;
+
+    if (status->Param[1][0]>0) {
+
+      if (!IsNoDigit(status->Param[1])) {
+	DoPrompt("wrong input format - usage: rate <rate>\n");
+	return 0;
+      }
+      // Check limits
+      else if (atof(status->Param[1]) < MIN_RATE || atof(status->Param[1]) > MAX_RATE) {
+	sprintf(str,"refresh rate out of range (min: %.2f Hz, max: %.2f Hz)!\n",MIN_RATE,MAX_RATE);
+	DoPrompt(str);
+	return 0;
+      }
+      else {
+	StopMonitor();
+	status->fStatusRefreshRate=atof(status->Param[1]);
+	sprintf(str,"status refresh rate set to %.2f Hz\n",status->fStatusRefreshRate);
+	DoPrompt(str);
+      }
+      StartMonitor();
+      return 0;
+      
+    }
+    else {
+      sprintf(str,"usage: rate <rate>\n");
+      DoPrompt(str);
+    }
+    
+    return 0;
+  }
+
+  /*
+  // Read from device - NEVER use this function with a real HV board!!!
+  if (Match(status->Param[0], "read")) {
+
+    if (!NBoards())
+      return 0;
+
+    if (status->state==active) {
+      StopMonitor();
+      sprintf(str,"warning: status monitoring deactivated\n");
+      DoPrompt(str);
+    }
+    
+    for (int i=status->FirstBoard;i<=status->LastBoard;i++) {
+      if (1 == ((hv->GetHVBoard(i))->Read(rbuf,1))) {
+	sPrintByteBin(rbuf[0],bdata);
+	sprintf(str,"%d byte(s) read (board %d): %d | 0X%.2X | B%s\n",1,i,rbuf[0],rbuf[0],bdata);
+      }
+      else
+	sprintf(str,"error: could not read from board %d\n",i);
+
+      usleep(1000);
+
+      DoPrompt(str);
+    }
+
+    return 0;
+  } 
+  */
+  
+  // Reset
+  if (Match(status->Param[0], "reset")) {
+
+    if (!NBoards())
+      return 0;
+
+    StopMonitor();
+    ResetActiveBoards();
+    ReInitStatus(status);
+    StartMonitor();
+    return 0;
+  }
+
+
+  // Start ROOT
+  else if (Match(status->Param[0], "root")) {
+    
+    sprintf(str,"starting ROOT... type '.q' to return\n");
+    DoPrompt(str);
+    system ("root");
+
+  return 0;
+  
+  }
+
+
+  // Save HV settings of all boards
+  else if (Match(status->Param[0], "save")) {
+
+    if (status->Param[1][0] && !status->Param[2][0]) {
+      
+      if (SaveHVSettings(Chop(status->Param[1]))) {
+	sprintf(str,"HV settings written to \"%s\"\n",Chop(status->Param[1]));
+	DoPrompt(str);
+      }
+      
+    }
+    else {
+      
+      char buffer[MAX_COM_SIZE];
+      
+      time_t time_now_secs;
+      struct tm *time_now;
+      
+      time(&time_now_secs);
+      time_now = localtime(&time_now_secs);
+      
+      sprintf(buffer,"hvsettings/HV_%04d-%02d-%02d_%02d-%02d-%02d.txt",
+	      1900 + time_now->tm_year, 
+	      1 + time_now->tm_mon,
+	      time_now->tm_mday,
+	      time_now->tm_hour,
+	      time_now->tm_min,
+	      time_now->tm_sec);
+
+      //sprintf(str,"warning: HV settings will be written to \"%s\"\n",buffer);
+      //DoPrompt(str);
+      
+      if (SaveHVSettings(buffer)) {
+	sprintf(str,"HV settings successfully written to \"%s\"\n",buffer);
+	DoPrompt(str);
+      }
+    }
+
+    return 0;
+   
+  }
+
+
+  // Start monitoring
+  else if (Match(status->Param[0], "start")) {
+
+    if (!NBoards())
+      return 0;
+    
+    if (status->state==active) {
+      sprintf(str,"status monitoring is already active\n");
+      DoPrompt(str);
+      return 0;
+    }
+
+    StartMonitor();
+
+    sprintf(str,"status monitoring activated\n");
+    DoPrompt(str);
+
+    return 0;
+  
+  }
+
+ 
+  // Print status
+  else if (Match(status->Param[0], "status") || Match(status->Param[0], "info")) {
+    
+    if (!NBoards())
+      return 0;
+
+    PrintStatus(status,config,stdout);
+    PrintStatus(status,config,log->logptr);
+
+    return 0;
+  } 
+
+
+  // Stop monitoring
+  else if (Match(status->Param[0], "stop")) {
+
+    if (!NBoards())
+      return 0;
+    
+    if (status->state!=active) {
+      sprintf(str,"status monitoring is already deactivated\n");
+      DoPrompt(str);
+      return 0;
+    }
+
+    StopMonitor();
+    
+    sprintf(str,"warning: status monitoring deactivated\n");
+    DoPrompt(str);
+
+    return 0;
+  
+  }
+
+  /*
+  // Sweep HV
+  else if (Match(status->Param[0], "sweep")) {
+
+    if (!NBoards())
+      return 0;
+
+    int errors = 0;
+    int channel = 0;
+
+    unsigned int hv1 = 0;
+    unsigned int hv2 = 0;
+    unsigned int dv  = 10;
+
+    bool allchannels = FALSE;
+
+    float delay = 1.;
+
+    if (status->Param[1][0]>0 && status->Param[2][0]>0 && status->Param[3][0]>0 && status->Param[4][0]>0){
+      
+      if (status->Param[1][0] == 'a' )
+	allchannels = TRUE;
+      else if (IsNoDigit(status->Param[1])) {
+	channel = atoi(status->Param[1]);
+	// Check limits
+	if (channel>31 || channel <0) {
+	  DoPrompt("channel out of range (0...31)!\n");
+	  return 0;
+	}
+      }
+      
+      if (IsNoDigit(status->Param[2]) && IsNoDigit(status->Param[3]) && IsNoDigit(status->Param[4])) {
+	
+	hv1 = atoi(status->Param[2]);
+	hv2 = atoi(status->Param[3]);
+	dv  = atoi(status->Param[4]);
+	
+	if ((hv1>0X3FFF || hv1 <0) || (hv2>0X3FFF || hv2 <0)) {
+	  DoPrompt("high voltage out of range (Vmin: 0, Vmax: 16383)!\n");
+	  return 0;
+	}
+
+	if (hv1 > hv2) {
+	  DoPrompt("wrong limits (Vmin < Vmax)!\n");
+	  return 0;
+	}
+
+	if (dv < 1 || dv > abs(hv2-hv1)) {
+	  DoPrompt("step size out of range (dVmin: 1, dVmax: |hv2-hv1|)!\n");
+	  return 0;
+	}
+	
+	if (status->Param[5][0]>0 && IsNoDigit(status->Param[5])) {
+	  if (atof(status->Param[5])<MIN_SWEEP_RATE || atof(status->Param[5])>MAX_SWEEP_RATE) {
+	    sprintf(str,"rate out of range (min: %.2f Hz, max: %.2f Hz)!\n",MIN_SWEEP_RATE,MAX_SWEEP_RATE);	    
+	    DoPrompt(str);
+	    return 0;
+	  }
+	  else 
+	    delay = 1./atof(status->Param[5]);
+	}
+      }
+      else {
+	DoPrompt("error: wrong input format - usage: sweep <channel>|<all> <v1> <v2> <dv> [rate]\n");
+	return 0;
+      }
+
+
+      StopMonitor();
+      
+      for (int i=status->FirstBoard;i<=status->LastBoard;i++) 
+	for (int j=status->FirstChain;j<=status->LastChain;j++) {
+	  if (!allchannels) {
+	    
+	    for (unsigned int v = hv1; v<=hv2; v+=dv) {
+	      if ((hv->GetHVBoard(i))->SetHV(stdout,j,channel,v,rbuf,status->Verbose)==1) {
+		sprintf(str,"board %d: high voltage of chain %d channel %d set to %d | 0X%.4X\n",i,j,channel,v,v);
+		status->HV[i][j][channel]=v;
+		DoPrompt(str);
+		UpdateStatus(i,rbuf);
+		sPrintStatus(status,str,i);
+		DoPrompt(str);
+	      }
+	      else {
+		sprintf(str,"board %d error: could not set hv - check timeout and try again\n",i);
+		DoPrompt(str);
+		errors++;
+	      }
+
+	      usleep((unsigned long)floor(delay*1000000.));
+	    }
+
+	  }
+	  else {
+	    for (int k=0;k<MAX_NUM_CHANNELS;k++) {
+
+	      for (unsigned int v = hv1; v<=hv2; v+=dv) {
+		
+		if ((hv->GetHVBoard(i))->SetHV(stdout,j,k,v,rbuf,status->Verbose)==1) {
+		  sprintf(str,"board %d: high voltage of chain %d channel %d set to %d | 0X%.4X\n",i,j,k,v,v);
+		  status->HV[i][j][k]=v;
+		  DoPrompt(str);
+		  UpdateStatus(i,rbuf);
+		  sPrintStatus(status,str,i);
+		  DoPrompt(str);
+		}
+		else {
+		  sprintf(str,"board %d error: could not set hv - check timeout and try again\n",i);
+		  DoPrompt(str);
+		  errors++;
+		}
+		
+		usleep((unsigned long)floor(delay*1000000.));
+
+	      }
+	    }
+	  }
+	}
+
+      StartMonitor();
+
+      if (errors) {
+	sprintf(str,"warning %d error(s) => check timeout and try again\n",errors);
+	DoPrompt(str);
+      }
+      else {
+	sprintf(str,"no error(s)... success!\n");
+	DoPrompt(str);
+      }
+    }
+    else {
+      DoPrompt("usage: sweep <channel>|<all> <v1> <v2> <dv> [rate]\n");
+      return 0;
+    }
+    
+    return 0;
+  
+  }
+  */
+
+  // Print time and date
+  else if (Match(status->Param[0], "date") || Match(status->Param[0], "time")) {
+
+    PrintDateAndTime();
+   
+    return 0;
+  } 
+
+
+  /*
+  // Test I/O - NEVER use this function with a real HV board!!!
+  else if (Match(status->Param[0], "testio")) {
+
+    for (int i=status->FirstBoard;i<=status->LastBoard;i++) 
+      (hv->GetHVBoard(i))->TestIO();
+
+    return 0;
+  } 
+  */
+
+
+  // Set timeout to return from read
+  if (Match(status->Param[0], "timeout")) {
+
+    if (!NBoards())
+      return 0;
+
+    if (status->Param[1][0]>0) {
+
+      if (!IsNoDigit(status->Param[1])) {
+	DoPrompt("wrong input format - usage: timeout <time>\n");
+	return 0;
+      }
+      // Check limits
+      else if (atof(status->Param[1]) < MIN_TIMEOUT || atof(status->Param[1]) > MAX_TIMEOUT) {
+	sprintf(str,"timeout out of range (min: %.2f s, max: %.2f s)!\n",MIN_TIMEOUT,MAX_TIMEOUT);
+	DoPrompt(str);
+	return 0;
+      }
+      else {
+	StopMonitor();  
+	for (int i=0;i<hv->GetNumberOfBoards();i++) 
+	  (hv->GetHVBoard(i))->SetTimeOut((float)atof(status->Param[1]));
+	status->fTimeOut = atof(status->Param[1]);	
+	sprintf(str,"timeout set to %.2f s\n",status->fTimeOut);
+
+	DoPrompt(str);
+	
+	StartMonitor();
+	return 0;
+      }
+    }
+    else {
+      sprintf(str,"usage: timeout <time>\n");
+      DoPrompt(str);
+    }
+    
+    return 0;
+  }
+
+    
+  // Print uptime
+  if (Match(status->Param[0], "uptime")) {
+
+    double difftime = GetDiffTime(&StartTime);
+
+    sprintf(str,"%d:%02d:%02d\n",(int)difftime/SECONDS_HOUR,((int)difftime/SECONDS_MINUTE)%SECONDS_MINUTE,(int)difftime%SECONDS_MINUTE);
+    DoPrompt(str);
+
+    return 0;
+  } 
+
+
+  // Enable/disable verbosity
+  else if (Match(status->Param[0], "verbose")) {
+
+    if (Match(status->Param[1], "on") && status->Param[1][0]) {
+      if (status->Verbose == TRUE) {
+	sprintf(str,"verbosity is already enabled\n");
+	DoPrompt(str);
+      }
+      else {
+	status->Verbose = TRUE;
+	sprintf(str,"verbosity enabled\n");
+	DoPrompt(str);
+      }
+    }
+    
+    else if (Match(status->Param[1], "off") && status->Param[1][0]) {
+      if (status->Verbose == FALSE) {
+	sprintf(str,"verbosity is already disabled\n");
+	DoPrompt(str);
+      }
+      else {
+	status->Verbose = FALSE;
+	sprintf(str,"verbosity disabled\n");
+	DoPrompt(str);
+      }
+    }
+    
+    else
+      DoPrompt("usage: verbose <on>|<off>\n");
+  
+    return 0;
+  }
+  
+  
+  // Write reference voltage
+  if (Match(status->Param[0], "vref")) {
+
+    if (!NBoards())
+      return 0;
+
+    unsigned int voltage = 0;
+
+    if (status->Param[1][0]>0) {
+      
+      // Binary input
+      if (tolower(status->Param[1][0])=='x' && strlen(status->Param[1])>2) {
+	if (sPrintHex2Dec(Chop(status->Param[1]+1),&voltage)!=0) {
+	    DoPrompt("error: wrong input format - usage: vref <voltage>\n");
+	    return 0;
+	}
+      }
+      // Hexadecimal input
+      else if (tolower(status->Param[1][0])=='b' && strlen(status->Param[1])>2) {
+	if (sPrintBin2Dec(Chop(status->Param[1]+1),&voltage)!=0) {
+	  DoPrompt("wrong input format - usage: vref <voltage>\n");
+	  return 0;
+	}
+      }
+      // Decimal input
+      else if (IsNoDigit(status->Param[1]))
+	voltage = atoi(status->Param[1]);
+      // Wrong input format
+      else {
+	DoPrompt("wrong input format - usage: vref <voltage>\n");
+	return 0;
+      }
+
+      // Check limits
+      if (voltage>0X3FFF || voltage <0) {
+	DoPrompt("reference voltage out of range (Vmin: 0, Vmax: 16383)!\n");
+	return 0;
+      }
+
+
+      StopMonitor();
+          
+      for (int i=status->FirstBoard;i<=status->LastBoard;i++) 
+	for (int j=status->FirstChain;j<=status->LastChain;j++) {
+	  if (((hv->GetHVBoard(i))->SetVRef(stdout,j,voltage,rbuf,status->Verbose)==1)) {
+	    sprintf(str,"board %d: reference voltage of chain %d set to %d | 0X%.4X\n",hv->GetHVBoard(i)->GetBoardNumber(),j,voltage,voltage);
+	    status->VRef[i][j]=voltage;
+	    DoPrompt(str);
+	    UpdateStatus(i,rbuf);
+	    sPrintStatus(status,str,i);
+	    DoPrompt(str);
+	  } else {
+	    sprintf(str,"board %d error: could not set vref - check timeout and try again\n",hv->GetHVBoard(i)->GetBoardNumber());
+	    DoPrompt(str);
+	  }
+	}
+      
+      StartMonitor();
+    }
+    else {
+      sprintf(str,"usage: vref <voltage>\n");
+      DoPrompt(str);
+    }
+
+    return 0;
+  }
+
+  /*
+  // Write to device - NEVER use this function with a real HV board!!!
+  if (Match(status->Param[0], "write")) {
+    
+    if (!NBoards())
+      return 0;
+
+    if (status->Param[1][0]>0) {
+      
+      // Binary input
+      if (tolower(status->Param[1][0])=='x' && strlen(status->Param[1])>2) {
+	if (sPrintHex2Dec(Chop(status->Param[1]+1),(unsigned int*)wbuf)!=0) {
+	  DoPrompt("wrong input format or value out of range!\n");
+	  return 0;
+	}
+      }
+      // Hexadecimal input
+      else if (tolower(status->Param[1][0])=='b' && strlen(status->Param[1])>2) {
+	if (sPrintBin2Dec(Chop(status->Param[1]+1),(unsigned int*)wbuf)!=0) {
+	  DoPrompt("wrong input format or value out of range!\n");
+	  return 0;
+	}
+      }
+      // Decimal input
+      else if (atoi(status->Param[1])>=0 && atoi(status->Param[1])<=255 && IsNoDigit(status->Param[1]))
+	wbuf[0] = (unsigned char)atoi(status->Param[1]);
+      // Wrong input
+      else {
+	DoPrompt("wrong input format or value out of range!\n");
+	return 0;
+      }
+      
+      if (status->state==active) {
+	StopMonitor();
+	sprintf(str,"warning: status monitoring deactivated\n");
+	DoPrompt(str);
+      }
+      
+      for (int i=status->FirstBoard;i<=status->LastBoard;i++) 
+        if ((hv->GetHVBoard(i))->Write(wbuf,1) == 1) {
+	  sPrintByteBin(wbuf[0],bdata);
+	  sprintf(str,"%d byte(s) written (board %d): %d | 0X%.2X | B%s\n",1,i,wbuf[0],wbuf[0],bdata);
+	  DoPrompt(str);
+	}
+	else {
+	  sprintf(str,"error: could not write to board %d\n",i);
+	  DoPrompt(str);
+	}
+
+    }
+    else {
+      sprintf(str,"error: no input\n");
+      DoPrompt(str);
+    }
+    return 0;
+  }
+  */
+
+  // Exit program
+  else if(Match(status->Param[0], "exit") || Match(status->Param[0], "quit")) {
+
+    StopMonitor();
+    
+    ResetAllBoards();
+
+    status->Exit = TRUE;
+
+    pthread_kill(status->HVMonitor, SIGUSR1);
+    pthread_kill(status->SocketThread, SIGUSR1);
+ 
+    return 0;
+  }
+  
+  else if (strchr(status->Param[0],'\n')-status->Param[0]==0) {
+    return 0;
+  }
+
+  else {
+    
+    if (strchr(status->Param[0],'\n') == 0)
+      sprintf(str,"unknown command: %s\n",status->Param[0]);
+    else
+      sprintf(str,"unknown command: %s",status->Param[0]);
+    
+    DoPrompt(str);
+    
+    return 0;
+
+  }
+ 
+  return 0;
+}
+
+
+void ProcessIO::PrintDateAndTime() {
+
+  char str[MAX_COM_SIZE];
+
+  time_t rawtime;
+  struct tm * timeinfo;
+  
+  time(&rawtime);
+  timeinfo = localtime(&rawtime); // Get local time
+  fflush(stdout);
+  sprintf(str,"current date/time is: %s",asctime(timeinfo));
+  DoPrompt(str);
+
+}
+
+void ProcessIO::DoPrompt(char* str) {
+ 
+  if (str!=NULL) {
+    if (status->NumHVBoards == 0) {
+      sprintf(status->Prompt,"HV> %s",str);
+      printf(status->Prompt);
+      if (status->Log)
+	log->LogWrite(status->Prompt);
+      sprintf(status->Prompt,"HV> ");
+    }
+    else if (status->FirstBoard == status->LastBoard) {
+
+      int board = hv->GetHVBoard(status->FirstBoard)->GetBoardNumber();
+
+      if (status->FirstChain == status->LastChain) {
+	sprintf(status->Prompt,"HV|C%d|B%d> %s",status->FirstChain,board,str);
+	printf(status->Prompt);
+	if (status->Log)
+	  log->LogWrite(status->Prompt);
+	sprintf(status->Prompt,"HV|C%d|B%d> ",status->FirstChain,board);
+      }
+      else {
+	sprintf(status->Prompt,"HV|C%d-%d|B%d> %s",status->FirstChain,status->LastChain,board,str);
+	printf(status->Prompt);
+	if (status->Log)
+	  log->LogWrite(status->Prompt);
+	sprintf(status->Prompt,"HV|C%d-%d|B%d> ",status->FirstChain,status->LastChain,board);
+      }
+
+    }
+    else {
+     
+      int firstboard = (hv->GetHVBoard(status->FirstBoard)->GetBoardNumber() > hv->GetHVBoard(status->LastBoard)->GetBoardNumber()) ?
+	hv->GetHVBoard(status->LastBoard)->GetBoardNumber() : hv->GetHVBoard(status->FirstBoard)->GetBoardNumber();
+
+      int lastboard = (hv->GetHVBoard(status->FirstBoard)->GetBoardNumber() > hv->GetHVBoard(status->LastBoard)->GetBoardNumber()) ?
+	hv->GetHVBoard(status->FirstBoard)->GetBoardNumber() : hv->GetHVBoard(status->LastBoard)->GetBoardNumber();
+
+      if (status->FirstChain == status->LastChain) {
+	sprintf(status->Prompt,"HV|C%d|B%d-%d> %s",status->FirstChain,firstboard,lastboard,str);
+	printf(status->Prompt);
+	if (status->Log)
+	  log->LogWrite(status->Prompt);
+	sprintf(status->Prompt,"HV|C%d|B%d-%d> ",status->FirstChain,firstboard,lastboard);
+      }
+      else {
+	sprintf(status->Prompt,"HV|C%d-%d|B%d-%d> %s",status->FirstChain,status->LastChain,firstboard,lastboard,str);
+	printf(status->Prompt);
+	if (status->Log)
+	  log->LogWrite(status->Prompt);
+	sprintf(status->Prompt,"HV|C%d-%d|B%d-%d> ",status->FirstChain,status->LastChain,firstboard,lastboard);
+      }
+    }
+  }
+  else {
+    if (status->NumHVBoards == 0)
+      sprintf(status->Prompt,"HV> ");
+    else if (status->FirstBoard == status->LastBoard) {
+      
+      int board = hv->GetHVBoard(status->FirstBoard)->GetBoardNumber();
+
+      if (status->FirstChain == status->LastChain)
+	sprintf(status->Prompt,"HV|C%d|B%d> ",status->FirstChain,board);
+      else
+	sprintf(status->Prompt,"HV|C%d-%d|B%d> ",status->FirstChain,status->LastChain,board);
+    }
+    else {
+
+      int firstboard = (hv->GetHVBoard(status->FirstBoard)->GetBoardNumber() > hv->GetHVBoard(status->LastBoard)->GetBoardNumber()) ?
+	hv->GetHVBoard(status->LastBoard)->GetBoardNumber() : hv->GetHVBoard(status->FirstBoard)->GetBoardNumber();
+
+      int lastboard = (hv->GetHVBoard(status->FirstBoard)->GetBoardNumber() > hv->GetHVBoard(status->LastBoard)->GetBoardNumber()) ?
+	hv->GetHVBoard(status->FirstBoard)->GetBoardNumber() : hv->GetHVBoard(status->LastBoard)->GetBoardNumber();
+
+     if (status->FirstChain == status->LastChain)
+       sprintf(status->Prompt,"HV|C%d|B%d-%d> ",status->FirstChain,firstboard,lastboard);
+     else 
+       sprintf(status->Prompt,"HV|C%d-%d|B%d-%d> ",status->FirstChain,status->LastChain,firstboard,lastboard);
+     }
+  }
+
+  
+}
+
+
+void ProcessIO::PrintMessage(char *str) {
+
+  char outstr[MAX_COM_SIZE];
+  
+  fflush(stdout);
+  if (str!=NULL) {
+
+    if (status->NumHVBoards == 0) 
+      sprintf(outstr,"%s\nHV> ",str); 
+    else if (status->FirstBoard == status->LastBoard) {
+      
+      int board = hv->GetHVBoard(status->FirstBoard)->GetBoardNumber();
+      
+      if (status->FirstChain == status->LastChain) 
+	sprintf(outstr,"%s\nHV|C%d|B%d> ",str,status->FirstChain,board); 
+      else 
+	sprintf(outstr,"%s\nHV|C%d-%d|B%d> ",str,status->FirstChain,status->LastChain,board); 
+    }
+    else {
+      
+      int firstboard = (hv->GetHVBoard(status->FirstBoard)->GetBoardNumber() > hv->GetHVBoard(status->LastBoard)->GetBoardNumber()) ?
+	hv->GetHVBoard(status->LastBoard)->GetBoardNumber() : hv->GetHVBoard(status->FirstBoard)->GetBoardNumber();
+      
+      int lastboard = (hv->GetHVBoard(status->FirstBoard)->GetBoardNumber() > hv->GetHVBoard(status->LastBoard)->GetBoardNumber()) ?
+	hv->GetHVBoard(status->FirstBoard)->GetBoardNumber() : hv->GetHVBoard(status->LastBoard)->GetBoardNumber();
+      
+      if (status->FirstChain == status->LastChain)
+	sprintf(outstr,"%s\nHV|C%d|B%d-%d> ",str,status->FirstChain,firstboard,lastboard);
+      else 
+	sprintf(outstr,"%s\nHV|C%d-%d|B%d-%d> ",str,status->FirstChain,status->LastChain,firstboard,lastboard); 
+    }
+  }
+  else {
+
+    if (status->NumHVBoards == 0) 
+      sprintf(outstr,"HV> "); 
+    else if (status->FirstBoard == status->LastBoard) {
+      
+      int board = hv->GetHVBoard(status->FirstBoard)->GetBoardNumber();
+      
+      if (status->FirstChain == status->LastChain) 
+	sprintf(outstr,"HV|C%d|B%d> ",status->FirstChain,board); 
+      else 
+	sprintf(outstr,"HV|C%d-%d|B%d> ",status->FirstChain,status->LastChain,board); 
+    }
+    else {
+      
+      int firstboard = (hv->GetHVBoard(status->FirstBoard)->GetBoardNumber() > hv->GetHVBoard(status->LastBoard)->GetBoardNumber()) ?
+	hv->GetHVBoard(status->LastBoard)->GetBoardNumber() : hv->GetHVBoard(status->FirstBoard)->GetBoardNumber();
+      
+      int lastboard = (hv->GetHVBoard(status->FirstBoard)->GetBoardNumber() > hv->GetHVBoard(status->LastBoard)->GetBoardNumber()) ?
+	hv->GetHVBoard(status->FirstBoard)->GetBoardNumber() : hv->GetHVBoard(status->LastBoard)->GetBoardNumber();
+      
+      if (status->FirstChain == status->LastChain)
+	sprintf(outstr,"HV|C%d|B%d-%d> ",status->FirstChain,firstboard,lastboard);
+      else 
+	sprintf(outstr,"HV|C%d-%d|B%d-%d> ",status->FirstChain,status->LastChain,firstboard,lastboard);
+    }
+
+
+  }
+
+  fflush(stdout);
+  fputs(outstr, stdout);
+  fflush(stdout);
+
+}
+
+
+void ProcessIO::PrintMessageToLog(char *str) {
+
+  char outstr[MAX_COM_SIZE];
+
+  if (status->NumHVBoards == 0) {
+    sprintf(outstr,"HV|B> %s\n",str);
+    log->LogWrite(outstr);
+  }
+  else if (status->FirstBoard == status->LastBoard) {
+    
+    int board = hv->GetHVBoard(status->FirstBoard)->GetBoardNumber();
+    
+    sprintf(outstr,"HV|B%d> %s\n",board,str);
+    log->LogWrite(outstr);
+  }
+  else {
+    
+    int firstboard = (hv->GetHVBoard(status->FirstBoard)->GetBoardNumber() > hv->GetHVBoard(status->LastBoard)->GetBoardNumber()) ?
+      hv->GetHVBoard(status->LastBoard)->GetBoardNumber() : hv->GetHVBoard(status->FirstBoard)->GetBoardNumber();
+    
+    int lastboard = (hv->GetHVBoard(status->FirstBoard)->GetBoardNumber() > hv->GetHVBoard(status->LastBoard)->GetBoardNumber()) ?
+      hv->GetHVBoard(status->FirstBoard)->GetBoardNumber() : hv->GetHVBoard(status->LastBoard)->GetBoardNumber();
+
+    sprintf(outstr,"HV|B%d-%d> %s\n",firstboard,lastboard,str);
+   log->LogWrite(outstr);
+  }
+
+}
+
+
+// Print message to screen, log file and socket
+void ProcessIO::PrintMessageO(char *Format, ...) {
+
+  char Textbuffer[MAX_COM_SIZE];
+
+  va_list ArgumentPointer;  va_start(ArgumentPointer, Format);
+  vsprintf(Textbuffer, Format, ArgumentPointer);
+
+  fputs(Textbuffer, stdout);   fflush(stdout);  // Print to console
+  
+  if(status->Socket != -1)                      // Print to socket if open
+    write(status->Socket,Textbuffer,strlen(Textbuffer)+1); // +1 to transmit '\0'
+}
+
+
+int ProcessIO::NBoards() {
+
+  if (status->NumHVBoards==0)
+    DoPrompt("no HV boards available!\n");
+
+  return status->NumHVBoards;
+}
+
+
+int ProcessIO::InitializeHV() {
+
+  int nb = 0;
+
+  if (hv->GetNumberOfBoards())
+    printf("Initialization:\n");
+
+  for (int i=0;i<hv->GetNumberOfBoards();i++) {
+    printf(" HV board %d (%s):\n",hv->GetHVBoard(i)->GetBoardNumber(),hv->GetHVBoard(i)->GetSerial());
+    nb+=hv->GetHVBoard(i)->Init(status->Verbose);
+  }
+
+  return nb;
+}
+
+
+void ProcessIO::UpdateStatus(int i, unsigned char* rbuf) {
+
+  if (status->IsUpdated[i])
+    status->WC[0][i] = status->WC[1][i];
+  else {
+    status->WC[0][i] = hv->GetHVBoard(i)->DecodeWrap(rbuf)-1;
+    status->IsUpdated[i] = TRUE;
+  }
+  
+  status->WC[1][i] = hv->GetHVBoard(i)->DecodeWrap(rbuf);
+
+  int d = (int)abs(status->WC[0][i]-status->WC[1][i]);
+
+  status->isok[i] = (d==1 || d==7) ? 1 : 0;
+
+  hv->GetHVBoard(i)->DecodeOC(status->OC[i], rbuf);
+  status->MR[i] = hv->GetHVBoard(i)->DecodeReset(rbuf);
+
+}
+
+
+void ProcessIO::StartMonitor() {
+
+  status->state = active;
+  status->Stop  = FALSE;
+
+  pthread_kill(status->HVMonitor, SIGUSR1);
+
+}
+
+
+void ProcessIO::StopMonitor() {
+
+  status->state = stopped;
+  status->Stop  = TRUE;
+
+  pthread_kill(status->HVMonitor, SIGUSR1);
+
+}
+
+
+void ProcessIO::Monitor() {
+
+  char str[MAX_COM_SIZE];
+
+  for (int i=0;i<hv->GetNumberOfBoards() ;i++) {
+
+    if ((hv->GetHVBoard(i))->GetStatus(stdout,rbuf,FALSE)!=1) {
+      sprintf(str,"board %d error: could not read status - check timeout and status refresh rate...",hv->GetHVBoard(i)->GetBoardNumber());
+      PrintMessage(str);      
+    }
+    else
+      UpdateStatus(i,rbuf);
+    
+    if (status->MR[i]) {
+      sprintf(str,"warning: manual reset of board %d!",hv->GetHVBoard(i)->GetBoardNumber());
+      PrintMessage(str);      
+      StopMonitor();
+      ResetBoard(i);
+      ReInitStatusOneBoard(status,i);
+      StartMonitor();
+    }
+    
+    if (!status->isok[i]) {
+      sprintf(str,"error: wrap counter mismatch board %d (%d,%d)!",hv->GetHVBoard(i)->GetBoardNumber(),status->WC[0][i],status->WC[1][i]);
+      PrintMessage(str);      
+    }
+
+    for (int j=0;j<MAX_NUM_CHAINS;j++) 
+      if (status->OC[i][j]) {
+	sprintf(str,"warning: overcurrent in chain %d of board %d!",j,hv->GetHVBoard(i)->GetBoardNumber());
+	PrintMessage(str);      
+	ResetBoard(i);
+	ReInitStatusOneBoard(status,i);
+      }
+  }
+}
+
+
+void ProcessIO::ResetActiveBoards() {
+  
+  for (int i=status->FirstBoard;i<=status->LastBoard;i++) {
+    if ((hv->GetHVBoard(i))->Reset(stdout,rbuf,status->Verbose)==1) {
+      sprintf(str,"software reset done board %d\n",hv->GetHVBoard(i)->GetBoardNumber());
+      DoPrompt(str);
+      UpdateStatus(i,rbuf);
+      sPrintStatus(status,str,i);
+      DoPrompt(str);
+    }
+    else {
+      sprintf(str,"board %d error: could not reset - check timeout and try again\n",hv->GetHVBoard(i)->GetBoardNumber());
+	DoPrompt(str);
+    }    
+  }
+  
+}
+
+
+void ProcessIO::ResetAllBoards() {
+  
+  for (int i=0;i<hv->GetNumberOfBoards();i++) {
+    if ((hv->GetHVBoard(i))->Reset(stdout,rbuf,status->Verbose)==1) {
+      sprintf(str,"software reset done board %d\n",hv->GetHVBoard(i)->GetBoardNumber());
+      DoPrompt(str);
+      UpdateStatus(i,rbuf);
+      sPrintStatus(status,str,i);
+      DoPrompt(str);
+    }
+    else {
+      sprintf(str,"board %d error: could not reset - check timeout and try again\n",hv->GetHVBoard(i)->GetBoardNumber());
+      DoPrompt(str);
+    }    
+  }
+  
+}
+
+
+void ProcessIO::ResetBoard(int i) {
+    
+  if ((hv->GetHVBoard(i))->Reset(stdout,rbuf,status->Verbose)==1) {
+    sprintf(str,"software reset done board %d",hv->GetHVBoard(i)->GetBoardNumber());
+    PrintMessage(str);
+    UpdateStatus(i,rbuf);
+    sPrintStatus(status,str,i);
+    PrintMessage(Chop(str));
+  }
+  else {
+    sprintf(str,"board %d error: could not reset - check timeout and try again",hv->GetHVBoard(i)->GetBoardNumber());
+    PrintMessage(str);
+  }    
+  
+}
+
+
+int ProcessIO::SaveHVSettings(char* filename) {
+
+  char str[MAX_COM_SIZE];
+
+  FILE *fptr;
+
+  time_t time_now_secs;
+  struct tm *time_now;
+  
+  time(&time_now_secs);
+  time_now = localtime(&time_now_secs);
+
+  if ((fptr = fopen(filename,"w")) == NULL) {
+    sprintf(str,"error: could not open file \"%s\"\n", filename);
+    return 0;
+  }
+  
+  fprintf(fptr,"\n********** HV settings written by hvutil %s, %04d %02d %02d, %02d:%02d:%02d **********\n\n",
+	  HV_CONTROL_VERSION, 
+	  1900 + time_now->tm_year, 
+	  1 + time_now->tm_mon,
+	  time_now->tm_mday,
+	  time_now->tm_hour,
+	  time_now->tm_min,
+	  time_now->tm_sec);
+  
+  for (int i=0;i<status->NumHVBoards;i++) {
+    fprintf(fptr,"Device: %s\n\n",status->fUSBDevice[i]);
+    
+    for (int j=0;j<MAX_NUM_CHAINS;j++) {
+      for (int k=0;k<4;k++) {
+	for (int l=0;l<8;l++) 
+	  fprintf(fptr,"%5d ",status->HV[i][j][k*8+l]);
+	fprintf(fptr,"\n");
+      }
+      fprintf(fptr,"\n");
+    }
+  }
+   
+  fclose(fptr);
+
+  return 1;
+}
+
+
+int ProcessIO::IsBoard(int board) {
+
+  for (int i=0;i<MAX_NUM_HVBOARDS;i++)
+    if (board == status->USBDeviceNumber[i])
+      return 1;
+
+  return 0;
+}
+
+
+int ProcessIO::GetBoardIdx(int board) {
+
+  for (int i=0;i<MAX_NUM_HVBOARDS;i++)
+    if (board == status->USBDeviceNumber[i])
+      return i;
+
+  return -1;
+}
Index: hvcontrol/src/ProcessIO.h
===================================================================
--- hvcontrol/src/ProcessIO.h	(revision 14)
+++ hvcontrol/src/ProcessIO.h	(revision 14)
@@ -0,0 +1,87 @@
+
+#ifndef PROCESSIO_H_SEEN
+#define PROCESSIO_H_SEEN
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <time.h>
+#include <errno.h>
+#include <unistd.h>
+#include <math.h>
+#include <pthread.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <dirent.h>
+#include <sys/time.h>  
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <signal.h>
+
+#include "Types.h"
+#include "HVStatus.h"
+#include "Log.h"
+#include "HVConfig.h"
+#include "Utilities.h"
+#include "HV.h"
+
+
+class ProcessIO {
+
+ private:
+  
+  time_t StartTime;
+
+  char str[MAX_COM_SIZE];
+
+  unsigned char wbuf[BUFFER_LENGTH];
+  unsigned char rbuf[BUFFER_LENGTH];
+
+  char bdata[16];
+
+ public:
+  
+  HVConfig*    config;
+  Status*      status;
+  Log*         log;
+
+  pthread_mutex_t control_mutex;
+  pthread_cond_t  control_cond;
+
+  
+  HV *hv;
+  HVBoard *hvboard;
+  
+
+  ProcessIO(char *config_file);
+  ~ProcessIO();
+
+  void Scan();
+  void PrintHelp();
+  void PrintDateAndTime();
+  void DoPrompt(char* str);
+  void PrintMessage(char* str);
+  void PrintMessageToLog(char *str);
+  void PrintMessageO(char *Format, ...);
+  int CommandControl();
+  int NBoards(); 
+  int InitializeHV();
+  void UpdateStatus(int i, unsigned char* rbuf);
+  void StartMonitor();
+  void StopMonitor();
+  void Monitor();
+  void ResetActiveBoards();
+  void ResetAllBoards();
+  void ResetBoard(int i);
+  int SaveHVSettings(char* filename);
+  int IsBoard(int i);
+  int GetBoardIdx(int board);
+
+};
+
+#endif
Index: hvcontrol/src/ReadCard.cc
===================================================================
--- hvcontrol/src/ReadCard.cc	(revision 14)
+++ hvcontrol/src/ReadCard.cc	(revision 14)
@@ -0,0 +1,151 @@
+
+/********************************************************************\
+
+  Name:         ReadCard.cc
+
+  Created by:   F. Goebel
+
+  Contents:     Read input card
+
+\********************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "ReadCard.h"
+
+int ReadCard(char *card_flag, void *store, char type, FILE *fptr, int id) {
+  char id_flag[100];
+  sprintf(id_flag, "%d", id);
+  return ReadCard(card_flag, store, type, fptr, id_flag);
+}
+
+
+int ReadCard(char *card_flag, void *store, char type, FILE *fptr, char *id_flag) {
+  char *card_name, *card_val, *card_id=NULL;
+  char  line[160];
+
+  rewind(fptr);
+
+  while (fgets(line, 160, fptr) != NULL) {    // Read line by line
+    card_name = strtok(line," \t\n");
+    if (id_flag!=NULL) {
+      card_id = strtok(NULL," \t\n");
+    }
+    card_val  = strtok(NULL," \t\n");
+    
+    if (card_name != NULL && card_val != NULL   // Comment or empty line?
+        && card_name[0] != '*' && card_name[0] != '#') {
+      
+      if (strcmp(card_name, card_flag)!=0) {   // Is this the card name we are looking for?
+	continue;  
+      }
+      if ((id_flag!=NULL) &&                // Is id_flag required
+	  (strcmp(card_id, id_flag)!=0)) {  // Is it the correct id_flag
+	continue;  
+      }
+
+      switch (type) {
+      case 'I':
+	*((int *) store) = (int) strtol(card_val, (char**)NULL, 10);
+	break;
+      case 'i':
+	*((short *) store) = (short) strtol(card_val, (char**)NULL, 10);
+	break;
+      case 'U':
+	*((unsigned int *) store)   
+	  = (unsigned int) strtoul(card_val, (char**)NULL, 10);
+	break;
+      case 'u':
+	*((unsigned short *) store) 
+	  = (unsigned short) strtoul(card_val, (char**)NULL, 10);
+	break;
+      case 'f' :
+	*((float *) store) = atof(card_val);
+	break;
+      case 'd' :
+	*((double *) store) = atof(card_val);
+	break;
+      case 's' :
+	sprintf((char *) store,"%s",card_val);
+	break;
+      case 'c' :
+	*((char *) store) = card_val[0];
+	break;
+      default :
+	fprintf(stderr,"WARNING: ReadCard: unknown type: %c\n", type);
+	return -2;
+      }
+
+      return 0; // Found card name
+    }
+  }
+
+  //fprintf(stderr,"WARNING: ReadCard: card: %s not found\n", card_flag);
+  return -1;
+}
+
+
+int ReadCardExt(char *card_flag, void *store, char type, FILE *fptr, char *id_flag) {
+  char *card_name, *card_val, *card_id=NULL;
+  char  line[160];
+
+  rewind(fptr);
+
+  while (fgets(line, 160, fptr) != NULL) {    // Read line by line
+    card_name = strtok(line," \t\n");
+    if (id_flag!=NULL) {
+      card_id = strtok(NULL," \t\n");
+    }
+    card_val  = strtok(NULL," \t\n");
+    
+    if (card_name != NULL && card_val != NULL   // Comment or empty line?
+        && card_name[0] != '*' && card_name[0] != '#') {
+      
+      if (strcmp(card_name, card_flag)!=0) {   // Is this the card name we are looking for?
+	continue;  
+      }
+      if ((id_flag!=NULL) &&                // Is id_flag required
+	  (strcmp(card_id, id_flag)!=0)) {  // Is it the correct id_flag
+	continue;  
+      }
+
+      switch (type) {
+      case 'I':
+	*((int *) store) = (int) strtol(card_val, (char**)NULL, 10);
+	break;
+      case 'i':
+	*((short *) store) = (short) strtol(card_val, (char**)NULL, 10);
+	break;
+      case 'U':
+	*((unsigned int *) store)   
+	  = (unsigned int) strtoul(card_val, (char**)NULL, 10);
+	break;
+      case 'u':
+	*((unsigned short *) store) 
+	  = (unsigned short) strtoul(card_val, (char**)NULL, 10);
+	break;
+      case 'f' :
+	*((float *) store) = atof(card_val);
+	break;
+      case 'd' :
+	*((double *) store) = atof(card_val);
+	break;
+      case 's' :
+	sprintf((char *) store,"%s",card_val);
+	break;
+      case 'c' :
+	*((char *) store) = card_val[0];
+	break;
+      default :
+	fprintf(stderr,"WARNING: ReadCard: unknown type: %c\n", type);
+	return -2;
+      }
+
+      return 0; // Found card name
+    }
+  }
+
+  //fprintf(stderr,"WARNING: ReadCard: card: %s not found\n", card_flag);
+  return -1;
+}
Index: hvcontrol/src/ReadCard.h
===================================================================
--- hvcontrol/src/ReadCard.h	(revision 14)
+++ hvcontrol/src/ReadCard.h	(revision 14)
@@ -0,0 +1,10 @@
+#ifndef READCARD_H_SEEN
+#define READCARD_H_SEEN
+
+#include <stdio.h>
+
+int ReadCard(char *card_flag, void *store, char type, FILE *fptr, char *id_flag=NULL);
+int ReadCardExt(char *card_flag, void *store, char type, FILE *fptr, char *id_flag=NULL);
+int ReadCard(char *card_flag, void *store, char type, FILE *fptr, int id);
+
+#endif
Index: hvcontrol/src/Types.h
===================================================================
--- hvcontrol/src/Types.h	(revision 14)
+++ hvcontrol/src/Types.h	(revision 14)
@@ -0,0 +1,42 @@
+#ifndef CTXTYPES_H_SEEN
+#define CTXTYPES_H_SEEN
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define HV_CONTROL_VERSION "V1.0"
+
+#define I8      char
+#define U8      unsigned char
+#define I16     short
+#define U16     unsigned short
+#define I32     int
+#define U32     unsigned int
+#define F32     float
+#define F64     double
+#define Boolean char
+
+#define TRUE 1
+#define FALSE 0
+
+#define FILENAME_MAX_SIZE 256
+#define MAX_COM_SIZE 1000
+#define MAX_NUM_HVBOARDS 20
+#define MAX_NUM_CHAINS 4
+#define MAX_NUM_CHANNELS 32
+#define MAX_PATH 256
+#define STR_LENGTH 256
+#define BUFFER_LENGTH 256
+
+#define USB_MAX_DEVICE_NUMBER 65000
+#define USB_MIN_DEVICE_NUMBER 0
+
+#define MIN_TIMEOUT 0.01
+#define MAX_TIMEOUT 5.0
+
+#define MIN_RATE 0.01
+#define MAX_RATE 50.0
+
+#endif
+
+
Index: hvcontrol/src/Utilities.cc
===================================================================
--- hvcontrol/src/Utilities.cc	(revision 14)
+++ hvcontrol/src/Utilities.cc	(revision 14)
@@ -0,0 +1,437 @@
+
+
+/********************************************************************\
+
+  Name:         Utilities.cc
+
+  Created by:   Sebastian Commichau, July 2008
+                commichau@phys.ethz.ch
+
+  Content:      Provides numerous utilities
+
+\********************************************************************/
+ 
+
+#include "Utilities.h"
+
+
+// Parse user input 
+void ParseInput(char* Pc, int* NParam, char Param[][MAX_COM_SIZE])
+{
+  int i;
+  *NParam = 0;
+
+  for (i = 0; i<10; i++)
+    Param[i][MAX_COM_SIZE] = 0;
+
+  while (*Pc == ' ') // Ignore leading blanks
+    Pc++;
+  
+  do {
+    if (*Pc == '"') {
+      Pc++;
+      for (i = 0; *Pc && *Pc != '"'; i++)
+	Param[*NParam][i] = *Pc++;
+      if (*Pc)
+	Pc++;
+    } else if (*Pc == '\'') {
+      Pc++;
+      for (i = 0; *Pc && *Pc != '\''; i++)
+	Param[*NParam][i] = *Pc++;
+      if (*Pc)
+	Pc++;
+    } else if (*Pc == '`') {
+      Pc++;
+      for (i = 0; *Pc && *Pc != '`'; i++)
+	Param[*NParam][i] = *Pc++;
+      if (*Pc)
+	Pc++;
+    } else
+      for (i = 0; *Pc && *Pc != ' '; i++)
+	Param[*NParam][i] = *Pc++;
+    Param[*NParam][i] = 0;
+    while (*Pc == ' ' || *Pc == '\r' || *Pc == '\n')
+      Pc++;
+    (*NParam)++;
+  } while (*Pc);
+
+}
+
+
+// Check if two strings match
+int Match(char *str, char *cmd)
+{
+   int i;
+
+   if(str[0] == '\r' || str[0] == '\n')
+     return 0;
+
+   for(i = 0; i < (int) strlen(str); i++) 
+     {
+       if(toupper(str[i]) != toupper(cmd[i]) && str[i] != '\r' && str[i] != '\n')
+         return 0;
+     }
+
+   return 1;
+}
+
+
+// Remove newline from string
+char* Chop(char str[]) {
+
+  char *ptr;
+
+  if ((ptr = strchr(str, '\n')) != NULL)
+    *ptr = '\0';
+
+  return str;
+
+}
+
+
+int MakeDir(char *Dir, char *RunDate) {
+
+   char str[MAX_COM_SIZE];
+
+   sprintf(str,"%s/%s",Dir,RunDate);
+
+   struct stat buf;
+
+   if (stat(str, &buf)) 
+     return mkdir(str, 0711);
+   
+   return 0;
+}
+
+
+
+void GetUTCSecondsOfDay(double* t) {
+  
+  struct tm * timeinfo;
+  time_t rawtime;
+  
+  struct timezone tz;
+  struct timeval actual_time;   // Actual time 
+  
+  gettimeofday(&actual_time, &tz);
+  
+  time(&rawtime);
+  
+  timeinfo = gmtime(&rawtime);      // Get UTC (or GMT timezone).
+  
+  *t = (timeinfo->tm_hour*3600 + timeinfo->tm_min*60 + timeinfo->tm_sec) + actual_time.tv_usec/1000000.;
+  
+}
+
+
+void GetLocalSecondsOfDay(double* t) {
+  
+  struct tm * timeinfo;
+  time_t rawtime;
+  
+  struct timezone tz;
+  struct timeval actual_time;   // Actual time 
+  
+  gettimeofday(&actual_time, &tz);
+  
+  time(&rawtime);
+  
+  timeinfo = localtime(&rawtime); // Get local time
+  
+  *t = (timeinfo->tm_hour*3600 + timeinfo->tm_min*60 + timeinfo->tm_sec) + actual_time.tv_usec/1000000.;
+  
+}
+
+
+void GetLocalDay(int* t) {
+  
+  struct tm * timeinfo;
+  time_t rawtime;
+  
+  time(&rawtime);
+  
+  timeinfo = localtime(&rawtime); // Get local time
+  
+  *t = (timeinfo->tm_yday);
+  
+}
+
+
+double GetDiffTime(time_t* StartT) {
+
+  time_t ActualT;
+
+  time (&ActualT);
+
+  return difftime (ActualT,*StartT);
+
+}
+
+
+long int GetMicroSeconds() {
+
+  struct tm * timeinfo;
+  time_t rawtime;
+  
+  struct timezone tz;
+  struct timeval actual_time;   // Actual time
+  
+  gettimeofday(&actual_time, &tz);
+  
+  time(&rawtime);
+  
+  timeinfo = gmtime(&rawtime);  // Get UTC (or GMT timezone).
+  
+  return (timeinfo->tm_hour*3600 + timeinfo->tm_min*60 + timeinfo->tm_sec)*1000000 + actual_time.tv_usec;
+
+}
+
+
+/* Prints the binary representation of a 1 byte-integer to stdout */
+void PrintByteBin(unsigned char i) {
+
+  for (int k=7;k>=0;k--)
+    if ((i & (1 << k)) !=0) {
+        if ((k)%8)
+        printf("1");
+        else
+        printf("1 ");
+    }
+    else {
+        if ((k)%8)
+        printf("0");
+        else
+        printf("0 ");
+    }
+  printf("\n");
+}
+
+
+/* Prints the binary representation of a 1-byte integer to str */
+void sPrintByteBin(unsigned char i, char* str) {
+
+  bzero(str,sizeof(str));
+
+  for (int k=7;k>=0;k--)
+    if ((i & (1 << k)) !=0) {
+      if ((k)%8)
+        strcat(str,"1");
+      else
+        strcat(str,"1 ");
+    }
+    else {
+      if ((k)%8)
+	strcat(str,"0");
+      else
+	strcat(str,"0 ");
+    }
+}
+
+
+/* Prints the binary representation of a 2-byte integer to stdout */
+void PrintWordBin(unsigned short i) {
+
+  for (int k=15;k>=0;k--)
+    if ((i & (1 << k)) !=0) {
+        if ((k)%8)
+        printf("1");
+        else
+        printf("1 ");
+    }
+    else {
+        if ((k)%8)
+        printf("0");
+        else
+        printf("0 ");
+    }
+  printf("\n");
+
+}
+
+
+/* Prints the binary representation of a 2-byte integer to str */
+void sPrintWordBin(unsigned short i, char* str) {
+
+  bzero(str,sizeof(str));
+
+  for (int k=15;k>=0;k--)
+    if ((i & (1 << k)) !=0) {
+      if ((k)%8)
+	strcat(str,"1");
+      else
+	strcat(str,"1 ");
+    }
+    else {
+      if ((k)%8)
+	strcat(str,"0");
+      else
+	strcat(str,"0 ");
+    }
+}
+
+
+/* 
+  Converts a hexadecimal string to integer - returns
+ -1    - Conversion was abnormally terminated by
+         occurrence of an illegal character
+  0    - Conversion was successful 
+  1    - String is empty
+  2    - String has more than 2 characters
+*/
+int sPrintHex2Dec(const char* xs, unsigned int* result) {
+
+  size_t szlen = strlen(xs);
+  int xv, fact;
+  
+  if (szlen>0) {
+    // Converting more than 32 bit hexadecimal value?
+    if (szlen>4) return 4; 
+    
+    // Begin conversion here
+    *result = 0;
+    fact = 1;
+    
+    // Run until no more character to convert
+    for (int i=szlen-1; i>=0; i--) {
+      if (isxdigit(*(xs+i))) {
+	if (*(xs+i)>=97) {
+	  xv = ( *(xs+i) - 97) + 10;
+	}
+	else if ( *(xs+i) >= 65) {
+	  xv = (*(xs+i) - 65) + 10;
+	}
+	else {
+	    xv = *(xs+i) - 48;
+	}
+	*result += (xv * fact);
+	fact *= 16;
+      }
+      else {
+	// Conversion was abnormally terminated
+	// by non hexadecimal digit, hence
+	// returning only the converted with
+	// an error value 0 (illegal hex character)
+	return -1;
+      }
+    }
+    return 0;
+  }
+
+  // Nothing to convert - string is empty
+  return 1;
+}
+
+
+/* An integer is interpreted as binary number and converted to an integer */
+int Bin2Dec(int bin)
+{
+  int power = 0;
+  int decimal = 0;
+  int num;
+  
+  while (bin > 0) {
+
+    num = bin % 10;
+    decimal = decimal + num * (int) pow(num * 2, power++);
+    bin = bin / 10;
+  }
+  
+  return decimal;
+}
+
+
+/* 
+  Converts a binary string to integer - returns
+ -1    - Conversion was abnormally terminated by
+         occurrence of an illegal character
+  0    - Conversion was successful 
+  1    - String is empty
+  8    - String has more than 8 characters
+*/
+int sPrintBin2Dec(const char* bs, unsigned int* result) {
+
+  size_t szlen = strlen(bs);
+
+  *result = 0;
+
+  int p=0;
+
+  if (szlen>0) {
+
+    // Converting more than 32 bit value?
+    if (szlen>32) return 32; 
+
+    // Begin conversion here    
+    for (int i=szlen-1; i>=0; i--) {
+
+      if (*(bs+i)=='1' || *(bs+i)=='0') {
+
+	if (*(bs+i)=='1') 
+	  *result += (int)pow(2.,(double)p);
+	
+	p++;
+      }
+      else return -1;
+    }
+    return 0;
+
+  }
+  // Nothing to convert - string is empty
+  return 1;   
+}
+
+
+
+/* Converts a binary string to a decimal number, returns decimal value */
+int Bin2Dec(const char *bs) {
+
+  int b, /*m,*/ n;
+  int len, sum = 0;
+  
+  len = strlen(bs) - 1;
+  
+  for (int k = 0; k <= len; k++) {
+        
+    b = 1;
+
+    n = (bs[k] - '0'); // Char to numeric value
+    
+    if ((n > 1) || (n < 0))
+      return 0;
+    
+    
+    b = b << (len-k);
+    
+    //for (b = 1, m = len; m > k; m--) 
+    //b *= 2; // 1 2 4 8 16 32 64 ... place-values, reversed here
+        
+    // Sum it up
+    sum = sum + n * b;
+    
+    //printf("%d*%d + ",n,b);
+  }
+  return sum;
+}
+
+
+int IsNoDigit(const char* str) {
+
+  size_t szlen = strlen(str); 
+
+  if (szlen>0) {
+
+    for (int i=szlen-1; i>=0; i--) {
+      if (isalpha((int)*(str+i)))
+	return 0;
+    }
+    // Okay, no alphabetic character found
+    return 1;
+  }
+  // String is empty
+  return -1;
+}
+
+
+void SignalHandler(int Signal) {
+  return;          
+}
Index: hvcontrol/src/Utilities.h
===================================================================
--- hvcontrol/src/Utilities.h	(revision 14)
+++ hvcontrol/src/Utilities.h	(revision 14)
@@ -0,0 +1,40 @@
+
+#ifndef UTILITIES_H_SEEN
+#define UTILITIES_H_SEEN
+
+#define SECONDS_DAY  86400
+#define SECONDS_HOUR  3600
+#define SECONDS_MINUTE  60
+
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <sys/time.h>  
+#include <math.h>
+
+#include "Types.h"
+
+void ParseInput(char* Pc, int* Nparam, char Param[][MAX_COM_SIZE]);
+int Match(char *str, char *cmd);
+char* Chop(char str[]);
+int MakeDir(char *Dir, char *RunDate);
+void GetUTCSecondsOfDay(double* t);
+void GetLocalSecondsOfDay(double* t);
+void GetLocalDay(int* t);
+double GetDiffTime(time_t* StartT);
+long int GetMicroSeconds();
+
+void PrintByteBin(unsigned char i);
+void sPrintByteBin(unsigned char i, char* str);
+void PrintWordBin(unsigned short i);
+void sPrintWordBin(unsigned short i, char* str);
+int sPrintBin2Dec(const char* bs, unsigned int* result);
+int Bin2Dec(int bin);
+int Bin2Dec(const char *bs);
+int sPrintHex2Dec(const char* xs, unsigned int* result);
+int IsNoDigit(const char* str);
+void SignalHandler(int Signal);
+
+#endif
