Index: drsdaq/DAQReadout.cc
===================================================================
--- drsdaq/DAQReadout.cc	(revision 31)
+++ drsdaq/DAQReadout.cc	(revision 36)
@@ -10,4 +10,5 @@
 
 #include "DAQReadout.h"
+#include "SlowData.h"
 
 static const char* daq_state_str[] = {"active", "stopped"};
@@ -22,5 +23,5 @@
   {{"board", &DAQReadout::cmd_board, true, "<i> [j] | <all>" ,"Address board i, boards i-j, all boards"},
    {"status", &DAQReadout::cmd_status, false, "[daq|drs]", "Show DAQ/DRS status information"},
-   {"freq", &DAQReadout::cmd_freq, true, "<GHz>", "Set DRS sampling frequency"},
+   {"freq", &DAQReadout::cmd_freq, true, "<GHz> [reg]", "Set DRS sampling frequency (regulated)"},
    {"calib", &DAQReadout::cmd_calib, true, "<t_f> <c_f> [dir]", "Response calibration"},
    {"trigger", &DAQReadout::cmd_trigger, true, "<on|off>", "Hardware trigger on or off"},
@@ -28,6 +29,6 @@
    {"wmode", &DAQReadout::cmd_wmode, true, "<0|1>", "Set DRS wave mode"},
    {"rmode", &DAQReadout::cmd_rmode, true, "<0|1>", "Set DRS readout mode"},
-   {"mode", &DAQReadout::cmd_mode, true, "<0|1>", "Set DRS mode: 0 = single shot, 1 = continuous"},
-   {"read", &DAQReadout::cmd_read, true, "<brd> <chip> <chan>", "Read current data from board, chip, channel"},
+   {"mode", &DAQReadout::cmd_mode, true, "<single|continuous>", "Set DRS single shot or continuous mode"},
+   {"read", &DAQReadout::cmd_read, false, "<brd chip chan> [res]", "Read current data (and restart if DAQ not active)"},
    {"take", &DAQReadout::cmd_take, false, "<d|p|t> [n] [source]", "Start run (data, pedestal or test) with n events"},
    {"events", &DAQReadout::cmd_events, false, "", "Number of events in current run"},
@@ -46,6 +47,6 @@
    {"faverage", &DAQReadout::cmd_faverage, false, "[n]", "Set ot get number of averages for feedback"},
    {"fgain", &DAQReadout::cmd_fgain, false, "[gain]", "Set ot get feedback gain"},
-   {"ftarget", &DAQReadout::cmd_ftarget, false, "[brd chip chan]", "Set or get target value"},
-   {"fresponse", &DAQReadout::cmd_fresponse, false, "[V1 V2]", "Start response measurement with voltages V1 and V2"},
+   {"ftarget", &DAQReadout::cmd_ftarget, false, "[brd chip chan]", "Set or get target value (also 'all' supported)"},
+   {"fresponse", &DAQReadout::cmd_fresponse, false, "[voltage]", "Start response measurement with given voltage difference"},
    {"fconfig", &DAQReadout::cmd_fconfig, false, "", "Print feedback configuration"},
    {"help", &DAQReadout::cmd_help, false, "", "Print help"}};
@@ -61,11 +62,11 @@
    
   time(&StartTime);  // Start time of DAQ
-  Rawfile = NULL;
 
   // Initialize status structure
-  daq_state	= stopped;
-  daq_runtype	= data;
-  Socket	= -1;
-  Exit		= false;
+  daq_state	    = stopped;
+  daq_runtype	    = data;
+  Socket	    = -1;
+  Exit		    = false;
+  CalibrationRead   = false;
   NumEvents		= 0;
   NumEventsRequested	= 100;
@@ -73,5 +74,5 @@
   FirstBoard		= 0;
   LastBoard		= -1;
-  sprintf(Source,"DUMMY");
+  snprintf(Source,sizeof(Source),"DUMMY");
   
   // Read configuration file
@@ -82,6 +83,6 @@
   else {
     printf("Reading drsdaq configuration file %s\n", Configfile);
-    ReadCard("LogFile",            fLogFile,            's', File);
-    ReadCard("RawDataPath",        fRawDataPath,        's', File);
+    ReadCard("LogFile",             fLogFile,           's', File);
+    ReadCard("RawDataPath",         fRawDataPath,       's', File);
     ReadCard("RotateWave",         &fRotateWave,        'I', File);
     ReadCard("FirstSample",        &fFirstSample,       'I', File);
@@ -101,20 +102,19 @@
   }
 
-  // Open log file
+  // Open log file and print configuration
   if ((Logfile = fopen(fLogFile, "a")) == NULL)
     fprintf(stderr,"Warning: Could not open log file '%s'\n", fLogFile);
   else PrintMessage(MsgToLog,"********** Logging started **********\n");
- 
   cmd_config();
 
   // Create DRS instance and perform initial scan
-  drs     = new DRS();
+  drs = new DRS();
   drs->SetFirstVMESlot(fFirstVMESlot);
   drs->SetLastVMESlot(fLastVMESlot);
   drs->InitialScan();
 
-  RHeader  = new RunHeader;
-  EHeader  = new EventHeader;
-  DRSFreq  = new float [drs->GetNumberOfBoards()];
+  RHeader = new RunHeader;
+  EHeader = new EventHeader;
+  DRSFreq = new float [drs->GetNumberOfBoards()];
 
   // Scan for DRS boards
@@ -135,6 +135,11 @@
   WaveForm = new short [NumCMCBoards == 0 ? 1:NumCMCBoards][kNumberOfChips][kNumberOfChannels][kNumberOfBins];
   
-  // Create instance of HV feedback (must be after CMC board detection)
+  // Create instance of HV feedback (must be called after CMC board detection)
   HVFB	  = new HVFeedback(this, fHVFeedbackConfig);
+  
+  // Create instance of slow data class for DAQ
+  char Filename[MAX_PATH];
+  snprintf(Filename,sizeof(Filename),"%s/SlowData/", fRawDataPath);
+  SlowDataClass = new SlowData(this, "DAQ", Filename);
 }
 
@@ -144,4 +149,5 @@
 
 DAQReadout::~DAQReadout() {
+  delete SlowDataClass;
   delete RHeader;     delete EHeader;
   delete drs;	      delete HVFB;
@@ -176,5 +182,5 @@
   for(CmdNumber=0; CmdNumber<sizeof(CommandList)/sizeof(CL_Struct); CmdNumber++)
     if (Match(Param[0], CommandList[CmdNumber].Name)) {
-      if(CommandList[CmdNumber].NeedNotBusy && IsDAQBusy()) PrintMessage("DAQ is busy\n");
+      if(CommandList[CmdNumber].NeedNotBusy && daq_state==active) PrintMessage("DAQ is busy\n");
       else if(CommandList[CmdNumber].NeedNotBusy && NumCMCBoards==0) PrintMessage("No mezzanine boards available\n");
       else (this->*CommandList[CmdNumber].CommandPointer)();
@@ -189,10 +195,10 @@
   time_t ActualT;
   time (&ActualT);
-  PrintMessage("%d:%02d:%02d\n", (int) difftime(ActualT, StartTime)/3600, ((int) difftime(ActualT, StartTime)/60)%60, (int) difftime(ActualT, StartTime)%60);
+  PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole, "%d:%02d:%02d\n", (int) difftime(ActualT, StartTime)/3600, ((int) difftime(ActualT, StartTime)/60)%60, (int) difftime(ActualT, StartTime)%60);
 } 
 
 // Print disk space
 void DAQReadout::cmd_disk() {
-  PrintMessage("Free disk space (%s) [MB]: %lu\n", fRawDataPath, CheckDisk(fRawDataPath));
+  PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole, "Free disk space (%s) [MB]: %lu\n", fRawDataPath, CheckDisk(fRawDataPath));
 } 
 
@@ -217,14 +223,15 @@
 void DAQReadout::cmd_take() {
   
-  if(!Match(Param[1],"test") && (IsDAQBusy() || NumCMCBoards==0)) {
-    PrintMessage("DAQ is busy or no boards available.\n");
-    return;
-  }
-  if (!IsDRSFreqSet()) return;
-  if (!IsCalibrationRead()) 
-    if(!ReadCalibration()) {
-      PrintMessage("Problem with response calibration!\n");
+  if(!Match(Param[1],"test")) {
+    if (daq_state==active || NumCMCBoards==0) {
+      PrintMessage("DAQ is busy or no boards available.\n");
       return;
     }
+    if (!IsDRSFreqSet()) return;
+    if (!CalibrationRead && !ReadCalibration()) {
+      PrintMessage("Cannot start run if response calibration not read.\n");
+      return;
+    }
+  }
     
   if (Match(Param[1],"data")) {
@@ -244,10 +251,30 @@
   }
 
-  if (NParam==3 && atoi(Param[2])) NumEventsRequested = atoi(Param[2]);
+  if (NParam==3) NumEventsRequested = atoi(Param[2]);
   if (NParam==4) {
-    if(atoi(Param[2])) NumEventsRequested = atoi(Param[2]);
+    NumEventsRequested = atoi(Param[2]);
     strcpy(Source, Param[3]);
   }
 
+  // Determine new run number using the file RUN_NUM_FILE
+  FILE *RunNumFile = fopen(RUN_NUM_FILE,"r+");
+  if(RunNumFile == NULL) {
+    PrintMessage("Error: Could not open file '%s' that contains the last run number (%s)\n",RUN_NUM_FILE,strerror(errno));
+    return;
+  }
+  if(fscanf(RunNumFile,"%u", &RunNumber) != 1 ) {
+    PrintMessage("Error: Could not read run number from file '%s'\n",RUN_NUM_FILE);
+    fclose(RunNumFile);
+    return;
+  }
+  RunNumber++;
+  rewind(RunNumFile);
+  if((fprintf(RunNumFile,"%.8u   ",RunNumber) < 0) || (fclose(RunNumFile)!=0)) {
+    PrintMessage("Error: Could not write to or close run number file '%s'\n",RUN_NUM_FILE);
+    PrintMessage("*** This is a serious error because run numbers will get mixed. Fix it. DAQ will terminate.\n");
+    throw;
+  }
+
+  // Create DAQ thread
   if ((pthread_create(&thread_DAQ, NULL, (void * (*)(void *)) DAQ,(void *) this)) != 0)
     perror("pthread_create failed with DAQ thread");
@@ -295,9 +322,8 @@
   }
   
-  if (NumCMCBoards) 
-    for (i=FirstBoard; i<=LastBoard; i++) {
-      PrintMessage("BLT test started (board #%d)\n",i);
-      (drs->GetBoard(i))->TestRead(Param[2][0] && atoi(Param[2])<=10000 && atoi(Param[2])>0 ? atoi(Param[2]):1, Type);
-    }
+  if (NumCMCBoards) for (i=FirstBoard; i<=LastBoard; i++) {
+        PrintMessage("BLT test started (board #%d)\n",i);
+        (drs->GetBoard(i))->TestRead(Param[2][0] && atoi(Param[2])<=10000 && atoi(Param[2])>0 ? atoi(Param[2]):1, Type);
+      }
   else PrintMessage("No DRS boards available\n");
 } 
@@ -305,6 +331,6 @@
 // Stop DAQ 
 void DAQReadout::cmd_stop() {
-  if(!IsDAQBusy() && !IsDRSBusy()) PrintMessage("Nothing to stop\n");
-  if (IsDAQBusy()) StopRun();
+  if(!daq_state==active && !IsDRSBusy()) PrintMessage("Nothing to stop\n");
+  if (daq_state==active) StopRun();
   if (IsDRSBusy()) {
     StopDRS();
@@ -313,15 +339,41 @@
 } 
   
-// Read data 
+// Read current data
+// For socket transmission: all numbers must be separated by exactly one
+// whitespace; the first number is the number of numbers that follow, the
+// second number the sampling frequency in GHz, the third the conversion factor 
+
 void DAQReadout::cmd_read() {
-  if (IsDRSBusy()) {
-    PrintMessage("Domino wave is running, issue \"stop first\"\n");
+  if(NumCMCBoards==0) {
+    PrintMessage("No mezzanine boards available\n");
     return;
-  } 
-  if (Param[1][0] && Param[2][0] && Param[3][0]) {
-    if (IsDRSFreqSet()&& !IsCalibrationRead()) ReadCalibration();
-    ReadandPrintDRSData(atoi(Param[1]),atoi(Param[2]),atoi(Param[3]));
-  }
-  else PrintUsage();  
+  }
+  if (NParam<4) {
+    PrintUsage();
+    return;
+  }      
+  if (atoi(Param[1])>LastBoard || atoi(Param[1])<FirstBoard) {
+    PrintMessage("Error: Board number out of range\n");
+    return;
+  }
+  if (atoi(Param[3])<0 || atoi(Param[3])>=kNumberOfChannels) {
+    PrintMessage("Error: Channel number out of range\n");
+    return;
+  }
+  if (atoi(Param[2])<0 || atoi(Param[2])>=kNumberOfChips) {
+    PrintMessage("Error: Chip number out of range\n");
+    return;
+  }
+  
+  if(daq_state!=active) {
+    if (!CalibrationRead) ReadCalibration();
+    if(NParam==5) StopDRS();
+    ReadCalibratedDRSData();
+    if(NParam==5) StartDRS();
+  }  
+  PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole|MsgToLog, "==START== %d %.2f %.2f ",kNumberOfBins+2,DRSFreq[atoi(Param[1])],drs->GetBoard(atoi(Param[1]))->GetPrecision());
+  for (int k=0; k<kNumberOfBins; k++) PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole|MsgToLog, "%.1f ", (float) WaveForm[atoi(Param[1])][atoi(Param[2])][atoi(Param[3])][k]);
+  PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole|MsgToLog, "==END==");
+  PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole|MsgToLog, "\n");
 } 
 
@@ -387,8 +439,8 @@
 // Set DRS sampling frequency
 void DAQReadout::cmd_freq() {    
-  if (NParam==3 && atof(Param[1]) && atoi(Param[2]))
-    SetRegulatedDRSFrequency(atof(Param[1]));
-  else if (NParam==2 && atof(Param[1]))
-    SetDRSFrequency(atof(Param[1]));
+  if (NParam>=2 && atof(Param[1])) {
+    SetDRSFrequency(atof(Param[1]), NParam==2 ? false : true);
+    CalibrationRead = false;
+  }
   else PrintUsage();
 } 
@@ -510,4 +562,5 @@
   }
   else PrintMessage("Cannot address board(s), out of range.\n");
+  CalibrationRead = false;
 } 
 
@@ -516,8 +569,8 @@
   char Buffer[MAX_COM_SIZE];
   for(unsigned int i=0; i<sizeof(CommandList)/sizeof(CL_Struct); i++) {
-    sprintf(Buffer, "%s %s", CommandList[i].Name, CommandList[i].Parameters);
-    PrintMessage(MsgToConsole|MsgToSocket,"%-28s%s\n", Buffer, CommandList[i].Help);
+    snprintf(Buffer, sizeof(Buffer), "%s %s", CommandList[i].Name, CommandList[i].Parameters);
+    PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole,"%-28s%s\n", Buffer, CommandList[i].Help);
   }     
-  PrintMessage(MsgToConsole|MsgToSocket,".<command>                  Execute shell command\n\n"
+  PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole,".<command>                  Execute shell command\n\n"
    "Items in <> are mandatory, in [] optional, | indicates mutual exclusive or.\n"
    "Test data can also be written if no DRS boards are available.\n"
@@ -531,5 +584,5 @@
      return;
   }  	
-  if (IsDAQBusy()) PrintMessage("Issue \"stop\" first to stop daq\n");
+  if (daq_state==active) PrintMessage("Issue \"stop\" first to stop daq\n");
   else {
     Exit = true;
@@ -540,14 +593,13 @@
 // Set/get mode of feedback
 void DAQReadout::cmd_fmode() {
-  if(NParam==1) HVFB->GetFBMode();
-  else if(Match(Param[1],"off")) HVFB->SetFBMode(FB_Off);
-  else if(Match(Param[1],"active")) HVFB->SetFBMode(FB_Active);
-  else if(Match(Param[1],"targets")) HVFB->SetFBMode(FB_Targets);
-  else PrintUsage();
+  if(Match(Param[1],"off")) HVFB->SetFBMode(FB_Off);
+  if(Match(Param[1],"active")) HVFB->SetFBMode(FB_Active);
+  if(Match(Param[1],"targets")) HVFB->SetFBMode(FB_Targets);
+  HVFB->GetFBMode();
 }
 
 // Set/get current number of events
 void DAQReadout::cmd_faverage() {
-  if(NParam==1) printf("Current number of feedback events: %u   (acting when %u events are reached)\n",
+  if(NParam==1) PrintMessage("Current number of feedback events: %u   (acting when %u events are reached)\n",
                        HVFB->GetCurrentCount(), HVFB->GetNumAverages());
   else if(atoi(Param[1])>=0) HVFB->SetNumAverages(atoi(Param[1]));
@@ -557,7 +609,6 @@
 // Set/get feedback gain
 void DAQReadout::cmd_fgain() {
-  if(NParam==1) printf("Feedback gain is %.2f\n", HVFB->GetGain());
-  else if(NParam==2) HVFB->SetGain(atof(Param[1]));
-  else PrintUsage();
+  if(NParam==2) HVFB->SetGain(atof(Param[1]));
+  PrintMessage("Feedback gain is %.2f\n", HVFB->GetGain());
 }
 
@@ -566,10 +617,11 @@
   if(NParam==1) HVFB->GetTargets();
   else if(NParam!=5) PrintUsage();
-  else {
-    if(atoi(Param[1])>=0 && atoi(Param[1])<NumCMCBoards && atoi(Param[2])>=0 && 
-       atoi(Param[2])<kNumberOfChips && atoi(Param[3])>=0 && atoi(Param[3])<kNumberOfChannels)
-      	 HVFB->SetTarget(atoi(Param[1]),atoi(Param[2]),atoi(Param[3]),atoi(Param[4]));
-    else PrintMessage("Board, chip or channel number out of range.\n");
-  }
+  else for (int i=FirstBoard; i<=LastBoard; i++)
+         for (int j=0; j<kNumberOfChips; j++)
+           for (int k=0; k<kNumberOfChannels; k++)
+             if ((atoi(Param[1])==i || Match(Param[1],"all")) &&
+	         (atoi(Param[2])==j || Match(Param[2],"all")) &&
+	         (atoi(Param[3])==k || Match(Param[3],"all")))
+      	      HVFB->SetTarget(i,j,k,atof(Param[4]));
 }
 
@@ -577,6 +629,5 @@
 void DAQReadout::cmd_fresponse() {
   if(NParam==1) HVFB->GetResponse();
-  else if(atof(Param[1]) && atof(Param[2]))
-    HVFB->MeasureResponse(atof(Param[1]),atof(Param[2]));
+  else if(atof(Param[1])) HVFB->MeasureResponse(atof(Param[1]));
   else PrintUsage();
 }
@@ -599,32 +650,4 @@
 void DAQReadout::StopDRS() {
   for (int i=FirstBoard; i<=LastBoard; i++) drs->GetBoard(i)->SoftTrigger();
-}
-
-// Read current data
-void DAQReadout::ReadandPrintDRSData(int board, int chip, int channel) {
-
-  if (board>LastBoard || board<FirstBoard) {
-    PrintMessage("Error: Board %d does not exist\n",board);
-    return;
-  }
-  if (channel<0 || channel>kNumberOfChannels-1) {
-    PrintMessage("Error: Select channel between %d and %d\n",0,kNumberOfChannels-1);
-    return;
-  }
-  if (chip<0 || chip>1) {
-    PrintMessage("Error: Select chip index between 0 and 1\n");
-    return;
-  }
-  PrintMessage("Waveform from board %d, chip %d, channel %d\n",board,chip,channel);
-  ReadCalibratedDRSData();
-  
-  // Note that all numbers must be separated by exactly one whitespace
-  // to allow reading from client socket
-  // The first number is the number of numbers that follow, the second number
-  // is the sampling frequency in GHz and the third is the conversion factor. 
-  PrintMessage("==START== %d %.2f %.2f ",kNumberOfBins+2,DRSFreq[board],drs->GetBoard(board)->GetPrecision());
-  for (int k=0; k<kNumberOfBins; k++) PrintMessage("%.1f ", (float) WaveForm[board][chip][channel][k]);
-  PrintMessage("==END==");
-  PrintMessage("\n");
 }
 
@@ -650,8 +673,12 @@
   for (int i=FirstBoard; i<=LastBoard; i++) {
     (drs->GetBoard(i))->SetCalibrationDirectory(dir);
-    PrintMessage("Reading response calibration file for board %d from: \"%s\"\n",i,dir);
+    PrintMessage("Reading response calibration file for board %d from: \"%s\"\n", i, dir);
     for (int Chip=0; Chip<kNumberOfChips; Chip++)
-      if (drs->GetBoard(i)->GetResponseCalibration()->ReadCalibration(Chip)==false) return false;
-  }
+      if (drs->GetBoard(i)->GetResponseCalibration()->ReadCalibration(Chip)==false) {
+        CalibrationRead = false;
+	return false;
+      }
+  }
+  CalibrationRead = true;
   return true;
 }
@@ -735,64 +762,22 @@
 }
 
-// Read the frequency of all boards 
-double DAQReadout::ReadDRSFrequency() {
-
-  double freq = 0;
-  
-  if (NumCMCBoards) 
-    for (int i=FirstBoard; i<=LastBoard; i++) {
-      (drs->GetBoard(i))->ReadFrequency(0, &freq); 
-       PrintMessage("Domino wave of board %d is running at %1.3lf GHz\n",i,freq);
-    } 
-  else PrintMessage("No DRS boards available\n");
-
-  return freq;
-}
-
-// Set DRS sampling frequency 
-void DAQReadout::SetDRSFrequency(double freq) {
+// Set DRS sampling frequency
+void DAQReadout::SetDRSFrequency(double freq, bool Regulation) {
 
   double currentfreq;
 
-  if (NumCMCBoards) {
-    PrintMessage("Setting frequency without regulation:\n");
-    
-    for (int i=FirstBoard; i<=LastBoard; i++) { 
-      drs->GetBoard(i)->SetDebug(1);
-      
-      if (drs->GetBoard(i)->SetFrequency(freq)) {
- 	drs->GetBoard(i)->ReadFrequency(0, &currentfreq); 
-	DRSFreq[i] = freq;
-	PrintMessage("Domino wave of board %d is running at %1.3lf GHz\n",i,currentfreq);
-      } else {
-	DRSFreq[i] = 0;
-	PrintMessage("Warning: domino wave of board %d has changed but not reached the requested value\n",i);
-      }
-    }
-  }  
-  else PrintMessage("No DRS boards available\n");
-}
-
-// Regulate DRS sampling frequency 
-void DAQReadout::SetRegulatedDRSFrequency(double freq) {
-
-  double currentfreq;
-
-  if (NumCMCBoards) {
-    PrintMessage("Setting frequency with regulation:\n");
-
-    for (int i=FirstBoard; i<=LastBoard; i++) {
-      drs->GetBoard(i)->SetDebug(1);
-      
-      if (drs->GetBoard(i)->RegulateFrequency(freq)) {
-	
-	  drs->GetBoard(i)->ReadFrequency(0, &currentfreq); 
-	  PrintMessage("Domino wave of board %d is running at %1.3lf GHz\n",i,currentfreq);
-	  DRSFreq[i] = freq;;
-      }
-      else DRSFreq[i] = 0;
-    }
-  }
-  else PrintMessage("No DRS boards available\n");
+  PrintMessage("Setting frequency %s regulation:\n",Regulation ? "with":"without");
+  for (int i=FirstBoard; i<=LastBoard; i++) { 
+    drs->GetBoard(i)->SetDebug(1);
+
+    if (Regulation ? drs->GetBoard(i)->RegulateFrequency(freq) : drs->GetBoard(i)->SetFrequency(freq)) {
+      drs->GetBoard(i)->ReadFrequency(0, &currentfreq); 
+      DRSFreq[i] = freq;
+      PrintMessage("Domino wave of board %d is running at %1.3lf GHz\n",i,currentfreq);
+    } else {
+      DRSFreq[i] = 0;
+      PrintMessage("Warning: Domino wave of board %d has changed but not reached the requested value\n",i);
+    }
+  }
 }
 
@@ -811,5 +796,5 @@
       }
       closedir(pdir);
-      sprintf(str,"%s",dir);
+      snprintf(str,sizeof(str),"%s",dir);
       PrintMessage("Target: \"%s\"\n",str);
     }
@@ -858,14 +843,4 @@
 }
 
-// Check if DAQ is busy
-bool DAQReadout::IsDAQBusy() {
-
-  if (daq_state == active) {
-    PrintMessage("DAQ is busy\n");
-    return true;
-  }
-  else return false;
-}
-
 // Check if DRS is sampling
 bool DAQReadout::IsDRSBusy() {
@@ -888,18 +863,16 @@
 
 // Open new raw data file
-bool DAQReadout::OpenRawFile(int Part) {
+bool DAQReadout::OpenRawFile() {
 
   time_t rawtime;
   struct tm *timeinfo;
-  char RunDate[MAX_COM_SIZE], Buffer[MAX_COM_SIZE], SystemCommand[MAX_COM_SIZE];
-  int TempDescriptor;
+  char RunDate[MAX_COM_SIZE], Buffer[MAX_COM_SIZE];
   
   // Write run date to status structure
-  time(&rawtime);
-  timeinfo = localtime(&rawtime);
-  sprintf(RunDate,"%d%02d%02d",timeinfo->tm_year + 1900,timeinfo->tm_mon + 1,timeinfo->tm_mday);
+  time(&rawtime);   timeinfo = localtime(&rawtime);
+  snprintf(RunDate,sizeof(RunDate), "%d%02d%02d",timeinfo->tm_year+1900,timeinfo->tm_mon + 1,timeinfo->tm_mday);
 
   // Create direcory if not existing (ignore error if already existing) and change to it
-  sprintf(Buffer, "%s/%s", fRawDataPath, RunDate);
+  snprintf(Buffer, sizeof(Buffer), "%s/%s", fRawDataPath, RunDate);
   if(mkdir(Buffer, S_IRWXU|S_IRWXG)==-1 && errno!=EEXIST) {
     PrintMessage("\rError: Could not create direcory \"%s\" (%s)\n", Buffer, strerror(errno));
@@ -907,49 +880,34 @@
   }
   
-  // Determine new run number in directory (only if first file in series) by finding the
-  // last file in alphabetical order and assuming that run number starts at position 9
-  if(Part==0) {
-    char *TmpName = tmpnam(NULL); 
-    sprintf(SystemCommand, "ls -1 %s/*.raw 2>/dev/null|tail -n-1 >%s", Buffer, TmpName);
-    system(SystemCommand);
-    if ((TempDescriptor=open(TmpName,O_RDONLY)) == -1) {
-      PrintMessage("Error: Could not determine last run number (%s)\n",strerror(errno));
-      return false;
-    }
-    memset(Buffer,0,sizeof(Buffer));
-    read(TempDescriptor, Buffer, sizeof(Buffer));
-    close(TempDescriptor);
-    remove(TmpName);
-    if(sscanf(Buffer, "%*28c%u", &RunNumber) == 1) RunNumber++;
-    else RunNumber = 0;
-  }
-
   // Generate filename
-  sprintf(FileName,"%s/%s/%s_%.8d_%s_%c_%d.raw", fRawDataPath, RunDate,
-    RunDate,RunNumber,Source,daq_runtype_str[daq_runtype][0],Part);
+  snprintf(FileName,sizeof(FileName),"%s/%s/%s_%.8u_%s_%c_%d.raw", fRawDataPath, RunDate,
+    RunDate,RunNumber,Source,daq_runtype_str[daq_runtype][0],FileNumber);
  
   //  Open file with rwx right for owner and group, never overwrite file
-  TempDescriptor = open(FileName,O_WRONLY|O_CREAT|O_EXCL, S_IRWXU|S_IRWXG);
-  if(TempDescriptor==-1) {
-    PrintMessage("\rError: Could not open file \"%s\"\n",FileName);
-    perror("Error");
+  Rawfile = open(FileName,O_WRONLY|O_CREAT|O_EXCL, S_IRWXU|S_IRWXG);
+  if(Rawfile==-1) {
+    PrintMessage("\rError: Could not open file \"%s\" (%s)\n", FileName, strerror(errno));
     return false;
   }
-  Rawfile = fdopen(TempDescriptor,"w"); 
   return true;
 }
 
 // Write run header and board structures
-void DAQReadout::WriteRunHeader() {
+bool DAQReadout::WriteRunHeader() {
 
   time_t time_now_secs;
   struct tm *time_now;
 
-  RHeader->MagicNum = MAGICNUM_FILE_OPEN;
+  RHeader->MagicNum = MAGICNUM_OPEN;
   RHeader->DataFormat 	= DATA_FORMAT;
+  RHeader->RunHeaderSize = sizeof(RunHeader);
+  RHeader->EventHeaderSize = sizeof(EventHeader);
+  RHeader->BoardStructureSize = sizeof(BoardStructure);
   strcpy(RHeader->DAQVersion,   __DATE__);
+
   strcpy(RHeader->Source,       Source);
   RHeader->Type = daq_runtype_str[daq_runtype][0];
   RHeader->RunNumber  = RunNumber;
+  RHeader->FileNumber = FileNumber;
 
   time(&time_now_secs);
@@ -969,17 +927,16 @@
 
   RHeader->NCMCBoards = NumCMCBoards==0 && daq_runtype==test ? 1 : (LastBoard - FirstBoard) + 1;  
-  RHeader->NChips       = kNumberOfChips;
-  RHeader->NChannels    = kNumberOfChannels;
-
-  RHeader->Offset       = fFirstSample;
-  RHeader->Samples      = fLastSample - fFirstSample + 1;
-  
-  if(fwrite(RHeader, sizeof(RunHeader), 1, Rawfile) != 1) {
+  RHeader->NChips     = kNumberOfChips;
+  RHeader->NChannels  = kNumberOfChannels;
+
+  RHeader->Offset  = fFirstSample;
+  RHeader->Samples = fLastSample - fFirstSample + 1;
+
+  if(write(Rawfile, RHeader, sizeof(RunHeader)) != sizeof(RunHeader)) {
     PrintMessage("Error: Could not write run header, terminating run (%s)\n", strerror(errno));
-    Stop = true;
-  }
-
+    return false;
+  }
+  
   for (int i=FirstBoard; i<=LastBoard; i++) {
-    BStruct[i].Index       = i;	  
     BStruct[i].SerialNo    = drs->GetBoard(i)->GetCMCSerialNumber();	  
     BStruct[i].BoardTemp   = drs->GetBoard(i)->GetTemperature();
@@ -990,24 +947,23 @@
   // In case no boards are available, dummy data is written for one board structure   
   if (NumCMCBoards == 0) {
-    LastBoard=0;
     BStruct[0].NomFreq     = 1;
     BStruct[0].ScaleFactor = 0.1;
   }    
 
-  if(fwrite(BStruct, sizeof(BoardStructure), LastBoard-FirstBoard+1, Rawfile) != (unsigned int) (LastBoard-FirstBoard+1)) {
+  if(write(Rawfile, BStruct, sizeof(BoardStructure)*(LastBoard-FirstBoard+1+(NumCMCBoards==0))) != (ssize_t) sizeof(BoardStructure)*(LastBoard-FirstBoard+1+(NumCMCBoards==0))) {
     PrintMessage("Error: Could not write (all) board structures, terminating run (%s)\n", strerror(errno));
-    Stop = true;
-  }
-  if (NumCMCBoards == 0) LastBoard=-1;
+    return false;
+  }
+  return true;
 }
 
 // Update the run header
-void DAQReadout::UpdateRunHeader(unsigned int Events) {
+bool DAQReadout::UpdateRunHeader(unsigned int Events, bool Error) {
 
   time_t time_now_secs;
   struct tm *time_now;
   
-  RHeader->MagicNum = MAGICNUM_FILE_CLOSED;
-  RHeader->Events     = Events;
+  RHeader->MagicNum = Error==false ? MAGICNUM_CLOSED:MAGICNUM_ERROR;
+  RHeader->Events   = Events;
 
   time(&time_now_secs);
@@ -1021,34 +977,33 @@
   RHeader->EndSecond   = time_now->tm_sec;
 
-  rewind(Rawfile);
-  if(fwrite(RHeader, sizeof(RunHeader), 1, Rawfile) != 1) {
+  if(lseek(Rawfile,0,SEEK_SET)==-1) {
+    PrintMessage("Error: Could not rewind file to write updated run header, terminating run (%s)\n", strerror(errno));
+    return false;
+  }
+
+  if(write(Rawfile, RHeader, sizeof(RunHeader)) != sizeof(RunHeader)) {
     PrintMessage("Error: Could not write updated run header, terminating run (%s)\n", strerror(errno));
-    Stop = true;
-  }
+    return false;
+  }
+  return true;
 }
 
 // Write event header
-void DAQReadout::WriteEventHeader() {
-
-  time_t time_now_secs;
-  struct tm *time_now;
-  struct timezone tz;
-  struct timeval actual_time;
-
+bool DAQReadout::WriteEventHeader() {
+
+  struct timeval Time;
+
+  gettimeofday(&Time, NULL);
+  
   strcpy(EHeader->Name,"EVTH");
- 
   EHeader->EventNumber = NumEvents;
   EHeader->TriggerType = 0XFFFF;
-
-  time(&time_now_secs);
-  time_now = localtime(&time_now_secs);
-  
-  gettimeofday(&actual_time, &tz);
-  EHeader->TimeSec = time_now->tm_sec + actual_time.tv_usec/1000000.;
-
-  if(fwrite(EHeader, sizeof(EventHeader), 1, Rawfile) != 1) {
+  EHeader->TimeSec = Time.tv_sec + (float) Time.tv_usec/1000000.;
+
+  if(write(Rawfile, EHeader, sizeof(EventHeader)) != sizeof(EventHeader)) {
     PrintMessage("Error: Could not write event header, terminating run (%s)\n", strerror(errno));
-    Stop = true;
-  }
+    return false;
+  }
+  return true;
 }
 
@@ -1080,5 +1035,5 @@
 
   memset(Textbuffer, 0, sizeof(Textbuffer));  
-  vsprintf(Textbuffer, Format, ArgumentPointer);
+  vsnprintf(Textbuffer, sizeof(Textbuffer), Format, ArgumentPointer);
   
   // Print to console and generate new prompt
@@ -1205,11 +1160,15 @@
 
   struct timeval StartTime, StopTime;
-  int Filepart;
+  int Count;
   unsigned int EventsInFile;
-  unsigned long long RunSize;
-   
-  Filepart = 0;   RunSize = 0;
+  unsigned long long RunSize = 0;
+  bool WriteError = false;
+  struct iovec DataPart[IOV_MAX];
+  ssize_t WriteResult;
+  off_t FileSize;
+
+  m->NumEvents = 0;
+  m->FileNumber = 0;
   m->HVFB->ClearAverages();    
-  m->NumEvents = 0;
   gettimeofday(&StartTime, NULL);
 
@@ -1223,21 +1182,21 @@
 
     // Init run header, open raw file, write run header
-    if (!m->OpenRawFile(Filepart)) break;
+    if (!m->OpenRawFile()) break;
     m->PrintMessage("\rData file \"%s\" opened.\n",m->FileName);
     EventsInFile = 0;
-    m->WriteRunHeader();
+    FileSize = 0;
+    WriteError |= !m->WriteRunHeader();
     
     if (m->daq_runtype != test) m->StartDRS(); 
 
     // Take data until finished, stopped or file too large   
-    while (m->NumEvents<m->NumEventsRequested && !m->Stop && 
-      ftell (m->Rawfile)/1024/1024<m->fMaxFileSizeMB) {
+    while ((m->NumEvents<m->NumEventsRequested || m->NumEventsRequested==0) &&
+      !m->Stop && FileSize/1024/1024<m->fMaxFileSizeMB && !WriteError) {
 
       if (m->daq_runtype == data) while (m->IsDRSBusy());  // Wait for hardware trigger (if DAQ stopped, DRS will not be busy anymore)
-      else if (m->daq_runtype == pedestal) m->StopDRS();      // Wait for software trigger
-
-      EventsInFile++;
-      m->NumEvents++;	
-      m->WriteEventHeader();
+      else if (m->daq_runtype == pedestal) m->StopDRS();   // ..or for software trigger
+
+      EventsInFile++;      m->NumEvents++;	
+      WriteError |= !m->WriteEventHeader();
 
       // Read event data via VME or generate test data (for one board if no boards available)
@@ -1251,12 +1210,30 @@
 	  *((short *) m->WaveForm+i) = (short) (sin(i/Period)*1000);
       }
-      // Write data to disk
-      for (int i=m->FirstBoard; i<=m->LastBoard + (m->NumCMCBoards==0); i++) {
-        for (unsigned int k=0; k<m->RHeader->NChips*m->RHeader->NChannels; k++) 
-    	  if(fwrite((short *) m->WaveForm[i] + m->RHeader->Offset + k*kNumberOfBins, sizeof(short), m->RHeader->Samples, m->Rawfile) != m->RHeader->Samples) {
-            m->PrintMessage("Error: Could not write event data, terminating run ()\n", strerror(errno));
-            m->Stop = true;
-    	  }
+
+      // Write data to disk (using writev() for performance reason)
+      Count  = 0;
+      for (int i=m->FirstBoard; (i<=m->LastBoard + (m->NumCMCBoards==0)) && !WriteError; i++) {
+        for (unsigned int k=0; k<m->RHeader->NChips*m->RHeader->NChannels; k++) {
+    	  DataPart[Count].iov_base = &m->WaveForm[i][k/m->RHeader->NChannels][k%m->RHeader->NChannels][m->RHeader->Offset];
+    	  DataPart[Count++].iov_len = m->RHeader->Samples * sizeof(short);
+	
+	  // Write to disk if either maximum size of DataPart[] array or last loop interation is reached 
+	  if (Count==IOV_MAX || (k==(m->RHeader->NChips*m->RHeader->NChannels-1) && i==(m->LastBoard+(m->NumCMCBoards==0)))) {
+	    if ((WriteResult=writev(m->Rawfile, DataPart, Count)) != (int) (Count*DataPart[0].iov_len)) {
+              if (WriteResult==-1) m->PrintMessage("Error: Could not write event data, terminating run (%s)\n", strerror(errno));
+              else m->PrintMessage("Error: Could only write %u out of %u bytes of event data, terminating run\n", WriteResult,Count*DataPart[0].iov_len);
+	      WriteError = true;
+	      break;
+	    }
+	    Count = 0;
+	  }
         }
+      }
+
+      // Update file size
+      if((FileSize = lseek(m->Rawfile, 0, SEEK_CUR)) == -1) {
+    	m->PrintMessage("Error: Could not determine file size, terminating run (%s)\n", strerror(errno));
+	WriteError = true;
+      }
       // Call feedback to process event
       m->HVFB->ProcessEvent();
@@ -1264,20 +1241,24 @@
 
     // Write updated run header, close file
-    RunSize += ftell (m->Rawfile);
-    m->UpdateRunHeader(EventsInFile);
-    fclose(m->Rawfile);  
-    m->PrintMessage("Data file closed.\n");
-
-    Filepart += 1; 
-  } while(m->NumEvents < m->NumEventsRequested && !m->Stop);
+    RunSize += FileSize;
+    WriteError |= !m->UpdateRunHeader(EventsInFile, WriteError);
+    if(close(m->Rawfile)==-1) m->PrintMessage("Error: Could not close data file (%s)\n", strerror(errno));
+    else m->PrintMessage("Data file closed (size %lu MByte).\n", FileSize/1024/1024);
+
+    m->FileNumber += 1; 
+  } while(m->NumEvents<m->NumEventsRequested && !m->Stop && !WriteError);
 
   m->StopDRS();
-
-  m->PrintMessage("\r%s run #%d %s (%d event(s))\n",daq_runtype_str[m->daq_runtype],m->RunNumber,(m->NumEvents == m->NumEventsRequested) ? "completed":"stopped",m->NumEvents);
-  if (m->NumEvents>0) {
-      gettimeofday(&StopTime, NULL);
-      float RunTime = StopTime.tv_sec-StartTime.tv_sec + (StopTime.tv_usec-StartTime.tv_usec)*1e-6;
-      m->PrintMessage("Time for run %.2f seconds, trigger rate %.2f Hz.\n", RunTime, m->NumEvents/RunTime);
-      m->PrintMessage("Run size %llu MByte, data rate %.1f MByte/s.\n", RunSize/1024/1024, RunSize/1024.0/1024/RunTime);
+  if(!WriteError) {
+    m->PrintMessage("\rRun #%d (%s) %s, %d events\n",m->RunNumber,daq_runtype_str[m->daq_runtype],(m->NumEvents == m->NumEventsRequested) ? "completed":"stopped",m->NumEvents);
+    m->SlowDataClass->NewEntry("Runinfo");
+    m->SlowDataClass->AddToEntry("%d %s %s %d",m->RunNumber,daq_runtype_str[m->daq_runtype],m->Source,m->NumEvents);
+  }
+  else m->PrintMessage("\rRun #%d (%s) aborted due to error after %d events\n",m->RunNumber,daq_runtype_str[m->daq_runtype],m->NumEvents);
+  if (m->NumEvents>0 && !WriteError) {
+    gettimeofday(&StopTime, NULL);
+    float RunTime = StopTime.tv_sec-StartTime.tv_sec + (StopTime.tv_usec-StartTime.tv_usec)*1e-6;
+    m->PrintMessage("Time for run %.2f seconds, trigger rate %.2f Hz.\n", RunTime, m->NumEvents/RunTime);
+    m->PrintMessage("Run size %llu MByte, data rate %.1f MByte/s.\n", RunSize/1024/1024, RunSize/1024.0/1024/RunTime);
   }
   m->daq_state = stopped;
Index: drsdaq/DAQReadout.h
===================================================================
--- drsdaq/DAQReadout.h	(revision 31)
+++ drsdaq/DAQReadout.h	(revision 36)
@@ -18,4 +18,5 @@
 #include "HVFeedback.h"
 
+#define RUN_NUM_FILE "/ct3data/LastRunNumber"
 #define MAX_PATH 256		// also used for filename length
 #define MAX_COM_SIZE 10000
@@ -35,6 +36,8 @@
     unsigned int CmdNumber;
     FILE *Logfile;    
+    bool CmdFromSocket;       	// Current command issued via socket
     void PrintUsage();
-    	
+    bool CalibrationRead;
+	
   public:
     RunHeader*   RHeader;
@@ -43,6 +46,7 @@
     short (*WaveForm)[kNumberOfChips][kNumberOfChannels][kNumberOfBins];
     pthread_mutex_t control_mutex;
-    FILE *Rawfile;
+    int Rawfile;
     class HVFeedback* HVFB;
+    class SlowData *SlowDataClass; 
 
     // Configuration data
@@ -62,5 +66,4 @@
     int NParam;       	      	// Number of parameters
     const char *Param[MAX_NUM_TOKEN]; // Pointers to parameters
-    bool CmdFromSocket;       	// Current command issued via socket
     int NumCMCBoards;
     int FirstBoard;
@@ -76,5 +79,5 @@
     unsigned int NumEvents;		// Number of event taken            
     unsigned int NumEventsRequested;	// Number of events requested
-    unsigned int RunNumber; 
+    unsigned int RunNumber, FileNumber; 
     char Source[32];
     char FileName[MAX_PATH];
@@ -106,10 +109,7 @@
     void StopDRS();
     void StopRun();
-    bool IsDAQBusy();
     bool IsDRSBusy();
     bool IsDRSFreqSet();
-    void SetDRSFrequency(double);
-    void SetRegulatedDRSFrequency(double);
-    double ReadDRSFrequency();
+    void SetDRSFrequency(double, bool);
     void CalibrateDRS(char*, double, double);
     void SetDOMINOMode(int);
@@ -121,12 +121,11 @@
     bool IsCalibrationRead();
     void ReadCalibratedDRSData();
-    void ReadandPrintDRSData(int, int, int);
     void PrintMessage(int, const char*, ...);
     void PrintMessage(const char*, ...);
     void PrintMessage(int, const char*, va_list); 
-    bool OpenRawFile(int);
-    void WriteRunHeader();
-    void UpdateRunHeader(unsigned int);
-    void WriteEventHeader();
+    bool OpenRawFile();
+    bool WriteRunHeader();
+    bool UpdateRunHeader(unsigned int, bool);
+    bool WriteEventHeader();
 };
 
Index: drsdaq/HVFeedback.cc
===================================================================
--- drsdaq/HVFeedback.cc	(revision 31)
+++ drsdaq/HVFeedback.cc	(revision 36)
@@ -17,12 +17,19 @@
 
 #define MAX_RETRY 5
-
+#define PIXMAP_LOCATION "../config/PixelMap.txt"
+
+//
 // Constructor: Initialise feedback 
+//
 HVFeedback::HVFeedback(DAQReadout* DAQClass, char* Configfile) {
   struct sockaddr_in SocketAddress;
-  
+  char Filename[MAX_PATH];
+
   m = DAQClass;
-  PixMap = new PixelMap("../config/PixelMap.txt", false);
-  
+  PixMap = new PixelMap(PIXMAP_LOCATION, false);
+
+  snprintf(Filename,sizeof(Filename),"%s/SlowData/", m->fRawDataPath);
+  SlowDataClass = new SlowData(m, "HVFB", Filename);
+
   // Read configuration file
   FILE *File;
@@ -32,15 +39,16 @@
   else {
     printf("Reading feedback configuration file %s\n", Configfile);
-    ReadCard("LedTrigBoard",       &fLedTrigBoard,      'I', File);
-    ReadCard("LedTrigChannel",     &fLedTrigChannel,    'I', File);
-    ReadCard("LedTrigChip",        &fLedTrigChip,       'I', File);
-    ReadCard("LedTrigSample",      &fLedTrigSample,     'I', File);
-    ReadCard("LedTrigThreshold",   &fLedTrigThreshold,  'f', File);
-    ReadCard("LedSignalSample",    &fLedSignalSample,   'I', File);
-    ReadCard("LedBaselineSample",  &fLedBaselineSample, 'I', File);
-    ReadCard("DefaultNumAverage",  &fDefaultNumAverage, 'I', File);
-    ReadCard("HVControlServer",     fHVControlServer,   's', File);
-    ReadCard("HVControlPort",      &fHVControlPort,     'I', File);
-    ReadCard("MaxCmdAckDelay",     &fMaxCmdAckDelay,    'I', File);
+    ReadCard("TrigBoard",           &fLedTrigBoard,      'I', File);
+    ReadCard("TrigChannel",         &fLedTrigChannel,    'I', File);
+    ReadCard("TrigChip",            &fLedTrigChip,       'I', File);
+    ReadCard("TrigSample",          &fLedTrigSample,     'I', File);
+    ReadCard("TrigThreshold",       &fLedTrigThreshold,  'f', File);
+    ReadCard("SignalSample",        &fLedSignalSample,   'I', File);
+    ReadCard("BaselineSample",      &fLedBaselineSample, 'I', File);
+    ReadCard("IntHalfWidth",        &fIntHalfWidth, 	 'U', File);
+    ReadCard("DefaultNumAverage",   &fDefaultNumAverage, 'I', File);
+    ReadCard("HVControlServer",      fHVControlServer,   's', File);
+    ReadCard("HVControlPort",       &fHVControlPort,     'I', File);
+    ReadCard("MaxCmdAckDelay",      &fMaxCmdAckDelay,    'I', File);
     fclose(File);
   }
@@ -48,9 +56,17 @@
 
   // Initialise
-  Average    = new float [m->NumCMCBoards][kNumberOfChips][kNumberOfChannels];
-  Response   = new float [m->NumCMCBoards][kNumberOfChips][kNumberOfChannels];
-  Target     = new float [m->NumCMCBoards][kNumberOfChips][kNumberOfChannels];
-  Buffer     = new float [m->NumCMCBoards][kNumberOfChips][kNumberOfChannels];  
- 
+  Average    = new float [m->NumCMCBoards][kNumberOfChips][kNumberOfChannels]();
+  Sigma      = new float [m->NumCMCBoards][kNumberOfChips][kNumberOfChannels]();
+  Response   = new float [m->NumCMCBoards][kNumberOfChips][kNumberOfChannels]();
+  Target     = new float [m->NumCMCBoards][kNumberOfChips][kNumberOfChannels]();
+  Buffer     = new float [m->NumCMCBoards][kNumberOfChips][kNumberOfChannels]();  
+
+/*   for (int i=m->FirstBoard; i<=m->LastBoard; i++)
+    for (int j=0; j<kNumberOfChips; j++)
+      for (int k=0; k<kNumberOfChannels; k++) {
+        Response[i][j][k] = 0.0;
+    	Target[i][j][k] = 0.0;
+      } 
+ */
   Gain = 1;
   SetFBMode(FB_Off);
@@ -77,5 +93,7 @@
 }
 
+//
 // Destructor
+//
 HVFeedback::~HVFeedback() {
   if (SocketDescriptor!=-1) {
@@ -85,106 +103,141 @@
   delete[] Average;   	delete[] Response;
   delete[] Target;   	delete[] Buffer;
-  delete PixMap;
-}
-
-
+  delete SlowDataClass; delete PixMap;
+}
+
+//
 // Check if LED trigger present, if yes accumulate feedback data and
 // calculate new high voltages if the required number of events is reached.
+//
 bool HVFeedback::ProcessEvent() {
-  float Correction;
+  int i,j,k,q;
+  float Correction, Integral, Difference, EffectiveGain;
   
   // Check for LED trigger channel on given channel and if feedback running
   if (FBMode==FB_Off || m->WaveForm[fLedTrigBoard][fLedTrigChip][fLedTrigChannel][fLedTrigSample] < fLedTrigThreshold)
     return false;
-  Count++;
   
-  // Add signal at LED bin for all channels
-  for (int i=m->FirstBoard; i<=m->LastBoard; i++)
-    for (int j=0; j<kNumberOfChips; j++)
-      for (int k=0; k<kNumberOfChannels; k++)
-        Average[i][j][k] += (m->WaveForm[i][j][k][fLedSignalSample] - m->WaveForm[i][j][k][fLedBaselineSample])*m->BStruct[i].ScaleFactor;
-  
+  // Calculate average signal of LED pulse as integral of signal
+  for (i=m->FirstBoard; i<=m->LastBoard; i++)
+    for (j=0; j<kNumberOfChips; j++)
+      for (k=0; k<kNumberOfChannels; k++) {
+	for (Integral=0, q=-fIntHalfWidth; q<=(int) fIntHalfWidth; q++) 
+          Integral += (m->WaveForm[i][j][k][fLedSignalSample+q] - m->WaveForm[i][j][k][fLedBaselineSample+q])*m->BStruct[i].ScaleFactor;
+        Integral /= 2*fIntHalfWidth+1;
+	Average[i][j][k] += Integral;
+    	Sigma[i][j][k] += pow(Integral,2);
+      }
+
+  if (++Count<NumAverages) return false;
+
   // Acquired number of event requires action
-  if (Count==NumAverages) {
-    for (int i=m->FirstBoard; i<=m->LastBoard; i++)
-      for (int j=0; j<kNumberOfChips; j++)
-        for (int k=0; k<kNumberOfChannels; k++) {
-	  Average[i][j][k] /= Count;
-	  switch (FBMode) {
-	    case FB_Active:   // Determine correction from response maxtrix and change voltages
-              Correction = (Target[i][j][k] - Average[i][j][k])*Response[i][j][k]*Gain;
-              if(Target[i][j][k]!=0 && !PixMap->DRS_to_Pixel(i,j,k).empty())
-		WriteHVCommand("hvdiff %s %f\n",PixMap->DRS_to_Pixel(i,j,k).c_str(),Correction);
-	      break;
-	    case FB_Targets:  // Take average as new targets  
-	      Target[i][j][k] = Average[i][j][k];
-	      break;
-      	    case FB_ResponseFirst:  // First point of response measurement done  
-	      Buffer[i][j][k] = Average[i][j][k];
-	      if(!PixMap->DRS_to_Pixel(i,j,k).empty()) WriteHVCommand("hvdiff %s %f",PixMap->DRS_to_Pixel(i,j,k).c_str(), Voltage2);
-	      break;
-      	    case FB_ResponseSecond: // Determine response from signal variation
-	      if(Buffer[i][j][k] == Average[i][j][k]) {
-		m->PrintMessage("HV Feedback: Warning, response singular for board %d, chip %d, channel %d.\n",i,j,k);
-		Response[i][j][k] = 0;
-	      }
-	      else Response[i][j][k] = Voltage2/(Buffer[i][j][k]-Average[i][j][k]);
-	      break;
-	    default: break;  // to suppress warning abount not handled enumeration value
-          }			
-        }
-    switch (FBMode) {
-      case FB_Active:
-      	m->PrintMessage("HV Feedback: Acted.\n");
-	break;
-      case FB_Targets:
-	m->PrintMessage("HV Feedback: New targets set, switching off.\n");
-	FBMode = FB_Off;
-	break;
-      case FB_ResponseFirst:
-        FBMode = FB_ResponseSecond;
-	m->PrintMessage("HV Feedback: Setting second voltage %f for response measurement, acquiring data.\n", Voltage2);
-	break;
-      case FB_ResponseSecond:
-	m->PrintMessage("HV Feedback: Response measurements finished, switching off.\n");
-	FBMode = FB_Off;
-	break;
-      default: break;  // to suppress warning abount not handled enumeration value
-    }			
-    ClearAverages();
-    return true;
-  }
-  else return false;   
-}
-
+  switch (FBMode) {
+    case FB_Active: SlowDataClass->NewEntry("Average");  break;
+    case FB_Targets: SlowDataClass->NewEntry("Target");  break;
+    case FB_ResponseSecond: SlowDataClass->NewEntry("Response"); SlowDataClass->AddToEntry("%.3f ",DiffVoltage);  break;
+    default: break;  // to suppress warning abount not handled enumeration value
+  }			
+
+  for (i=m->FirstBoard; i<=m->LastBoard; i++)
+    for (j=0; j<kNumberOfChips; j++)
+      for (k=0; k<kNumberOfChannels; k++) {
+	Average[i][j][k] /= Count;
+	Sigma[i][j][k] = sqrt(Sigma[i][j][k]/Count-pow(Average[i][j][k],2))/sqrt(Count);
+	switch (FBMode) {
+	  case FB_Active:   // Determine correction from response maxtrix and change voltages
+    	    Difference = Target[i][j][k] - Average[i][j][k];
+	    EffectiveGain = Gain*pow(0.5*(1+(Difference/Sigma[i][j][k]-1)/(Difference/Sigma[i][j][k]+1)),2);
+	    Correction = -Difference*Response[i][j][k]*EffectiveGain;
+            if(Correction!=0 && Target[i][j][k]!=0 && !PixMap->DRS_to_Pixel(i,j,k).empty()) {
+              printf("Average of board %d, chip %d, channel %d is %.2f +/- %.2f    Correction %.3f\n",i,j,k,Average[i][j][k],Sigma[i][j][k],Correction);
+	      SlowDataClass->AddToEntry("%d %d %d %.3f %.3f %.3f ", i,j,k,Average[i][j][k],Sigma[i][j][k],Correction);
+	      if(fabs(Average[i][j][k]) < 2*Sigma[i][j][k]) printf("Too noisy!\n");
+    	      else WriteHVCommand("hvdiff %s %f\n",PixMap->DRS_to_Pixel(i,j,k).c_str(),Correction);
+	    }
+	    break;
+	  case FB_Targets:  // Take average as new targets  
+	    Target[i][j][k] = Average[i][j][k];
+ 	    SlowDataClass->AddToEntry("%d %d %d %.3f %.3f ", i,j,k,Average[i][j][k],Sigma[i][j][k]);
+	    break;
+      	  case FB_ResponseFirst:  // First point of response measurement done  
+	    Buffer[i][j][k] = Average[i][j][k];
+	    if(!PixMap->DRS_to_Pixel(i,j,k).empty()) WriteHVCommand("hvdiff %s %f",PixMap->DRS_to_Pixel(i,j,k).c_str(), DiffVoltage);
+	    break;
+      	  case FB_ResponseSecond: // Determine response from signal variation
+	    if(Buffer[i][j][k] == Average[i][j][k]) {
+	      m->PrintMessage("HV Feedback: Warning, response singular for board %d, chip %d, channel %d.\n",i,j,k);
+	      Response[i][j][k] = 0;
+	    }
+	    else Response[i][j][k] = DiffVoltage/(Buffer[i][j][k]-Average[i][j][k]);
+	    SlowDataClass->AddToEntry("%d %d %d %.3f ", i,j,k,Response[i][j][k]);
+	    if(!PixMap->DRS_to_Pixel(i,j,k).empty()) WriteHVCommand("hvdiff %s %f",PixMap->DRS_to_Pixel(i,j,k).c_str(), -DiffVoltage/2);
+	    break;
+	  default: break;  // to suppress warning abount not handled enumeration value
+        }			
+      }
+
+  switch (FBMode) {
+    case FB_Targets:
+      m->PrintMessage("HV Feedback: New targets set, switching off.\n");
+      FBMode = FB_Off;
+      break;
+    case FB_ResponseFirst:
+      FBMode = FB_ResponseSecond;
+      m->PrintMessage("HV Feedback: Increasing voltages by %f for response measurement, acquiring data.\n", DiffVoltage);
+      break;
+    case FB_ResponseSecond:
+      m->PrintMessage("HV Feedback: Response measurements finished, original voltages set, switching off.\n");
+      FBMode = FB_Off;
+      break;
+    default: break;  // to suppress warning abount not handled enumeration value
+  }
+  ClearAverages();
+  return true;  
+}
+
+//
 // Clear average values and event counter
+//
 void HVFeedback::ClearAverages() {
   for (int i=m->FirstBoard; i<=m->LastBoard; i++)
     for (int j=0; j<kNumberOfChips; j++)
-      for (int k=0; k<kNumberOfChannels; k++) Average[i][j][k] = 0;
+      for (int k=0; k<kNumberOfChannels; k++) {
+        Average[i][j][k] = 0.0;
+	Sigma[i][j][k] = 0.0;
+      }
   Count = 0;
 }
 
+//
 // Number of events to accumulate before correction acts
+//
 void HVFeedback::SetNumAverages(unsigned int Averages) {
   NumAverages = Averages;
 }
 
+//
 // Get requested number of events
+//
 unsigned int HVFeedback::GetNumAverages() {
   return NumAverages;
 }
 
+//
 // Set feedback gain
+//
 void HVFeedback::SetGain(float FBGain) {
   Gain = FBGain;
 }
 
+//
 // Get feedback gain
+//
 float HVFeedback::GetGain() {
   return Gain;
 }
 
+//
 // Set feedback mode and clear averages
+//
 void HVFeedback::SetFBMode(FBState Mode) {
   if(Mode==FB_ResponseFirst || Mode==FB_ResponseFirst)
@@ -196,5 +249,7 @@
 }
 
+//
 // Set feedback mode and clear averages
+//
 FBState HVFeedback::GetFBMode() {
   switch (FBMode) {
@@ -208,10 +263,14 @@
 }
 
+//
 // Return current number of events
+//
 unsigned int HVFeedback::GetCurrentCount() {
   return Count;
 }
 
+//
 // Set target values
+//
 void HVFeedback::SetTarget(int Board, int Chip, int Channel, float TargetVal) {
   if(Board<m->NumCMCBoards && Chip<kNumberOfChips && Channel<kNumberOfChannels)
@@ -220,5 +279,7 @@
 }
 
+//
 // Print target values
+//
 void HVFeedback::GetTargets() {
   for (int i=m->FirstBoard; i<=m->LastBoard; i++)
@@ -228,9 +289,10 @@
 }
 
+//
 // Measure response matrix
-void HVFeedback::MeasureResponse(float U1, float U2) {
-
-  if (U2 == 0)
-    m->PrintMessage("HV Feedback: Error, econd voltage must not be zero.\n");
+//
+void HVFeedback::MeasureResponse(float U) {
+
+  if (U==0) m->PrintMessage("HV Feedback: Error, voltage difference must not non-zero.\n");
   else {
     for (int i=m->FirstBoard; i<=m->LastBoard; i++) 
@@ -238,22 +300,26 @@
         for (int k=0; k<kNumberOfChannels-2; k++) {
 	  if(PixMap->DRS_to_Pixel(i,j,k).empty()) m->PrintMessage("Could not find pixel ID of board %d, chip %d, channel %d\n",i,j,k);
-          else WriteHVCommand("hvdiff %s %f\n",PixMap->DRS_to_Pixel(i,j,k).c_str(), U1);
+          else WriteHVCommand("hvdiff %s %f\n",PixMap->DRS_to_Pixel(i,j,k).c_str(), -U/2);
         }
-    Voltage1 = U1;   Voltage2 = U2;
+    DiffVoltage = U;
     FBMode = FB_ResponseFirst;
     ClearAverages();  
-    m->PrintMessage("HV Feedback: Setting first voltage  %f for response measurement, acquiring data.\n",U1);
-  }
-}
-
+    m->PrintMessage("HV Feedback: Decreasing voltages by %f for response measurement, acquiring data.\n",DiffVoltage/2);
+  }
+}
+
+//
 // Print response values
+//
 void HVFeedback::GetResponse() {
   for (int i=m->FirstBoard; i<=m->LastBoard; i++)
     for (int j=0; j<kNumberOfChips; j++)
       for (int k=0; k<kNumberOfChannels; k++)
-         m->PrintMessage("Board %d, chip %d, channel %d: %f\n",i,j,k,Response[i][j][k]);
-}
-
+         m->PrintMessage("Board %d, chip %d, channel %d: %.3f\n",i,j,k,Response[i][j][k]);
+}
+
+//
 // Write commmand to socket
+//
 bool HVFeedback::WriteHVCommand(const char *Format, ...) {
   char Textbuffer[MAX_COM_SIZE];
@@ -263,7 +329,6 @@
   do {
     va_list ArgumentPointer;  va_start(ArgumentPointer, Format); 
-    vsprintf(Textbuffer, Format, ArgumentPointer);
-
-    printf("%s", Textbuffer);
+    vsnprintf(Textbuffer, sizeof(Textbuffer), Format, ArgumentPointer);
+
     // Write command to socket
     if(write(SocketDescriptor, Textbuffer, strlen(Textbuffer)+1)!=(int) strlen(Textbuffer)+1) {
@@ -295,13 +360,15 @@
 }
 
+//
 // Print feedback configuration
+//
 void HVFeedback::PrintConfig() {
   m->PrintMessage("LedTrigBoard: %d\t\tLedTrigChip: %d\t\tLedTrigChannel: %d\n"
         "LedTrigSample: %d\tLedTrigThreshold: %.2f\n"
         "LedSignalSample: %d\tLedBaselineSample: %d\tDefaultNumAverage: %d\n"
-        "HVControlServer: %s\tHVControlPort: %d\n"
+        "IntHalfWidth:%u\tHVControlServer: %s\tHVControlPort: %d\n"
 	"MaxCmdAckDelay: %d\n",
     fLedTrigBoard, fLedTrigChip, fLedTrigChannel, fLedTrigSample,
     fLedTrigThreshold, fLedSignalSample, fLedBaselineSample,
-    fDefaultNumAverage, fHVControlServer, fHVControlPort, fMaxCmdAckDelay);
-}
+    fDefaultNumAverage, fIntHalfWidth, fHVControlServer, fHVControlPort, fMaxCmdAckDelay);
+}
Index: drsdaq/HVFeedback.h
===================================================================
--- drsdaq/HVFeedback.h	(revision 31)
+++ drsdaq/HVFeedback.h	(revision 36)
@@ -8,4 +8,5 @@
 #include "RawDataCTX.h"
 #include "DAQReadout.h"
+#include "SlowData.h"
 
 enum FBState {FB_Off, FB_Active, FB_Targets, FB_ResponseFirst, FB_ResponseSecond};
@@ -14,8 +15,10 @@
 
     class DAQReadout *m;
-    class PixelMap *PixMap;    
+    class PixelMap *PixMap;
+    class SlowData *SlowDataClass;    
     FBState FBMode;
     
     float (*Average)[kNumberOfChips][kNumberOfChannels];
+    float (*Sigma)[kNumberOfChips][kNumberOfChannels];
     float (*Response)[kNumberOfChips][kNumberOfChannels];
     float (*Target)[kNumberOfChips][kNumberOfChannels];
@@ -26,5 +29,5 @@
     
     float Gain;     	    	// Feedback gain
-    float Voltage1, Voltage2;	// for response measurement	
+    float DiffVoltage;	    	// for response measurement	
     int SocketDescriptor;
     char TextBuf[BUF_LENGTH];
@@ -37,9 +40,10 @@
     int fLedSignalSample;
     int fLedBaselineSample;
+    unsigned int fIntHalfWidth;
     int fDefaultNumAverage;
     char fHVControlServer[BUF_LENGTH];
     int fHVControlPort;
     int fMaxCmdAckDelay;
-   	    	  
+
   public:
     HVFeedback(class DAQReadout*, char*);
@@ -56,5 +60,5 @@
     FBState GetFBMode();
     unsigned int GetCurrentCount();
-    void MeasureResponse(float, float);
+    void MeasureResponse(float);
     void GetResponse();
     void ClearAverages();
Index: drsdaq/History.txt
===================================================================
--- drsdaq/History.txt	(revision 31)
+++ drsdaq/History.txt	(revision 36)
@@ -13,2 +13,13 @@
 2/4/2009    Intoduced check for magic number in RawDataCTX.cc
 3/4/2009    Added frequency and scale factor transmission to socket protocol
+6/4/2009    Allowed reading of data via read command also while DAQ is active.
+22/4/2009   Included sizes of RunHeader, EventHeader and BoardStructure in
+    	    RunHeader and changed some data widths in RunHeader to U32 to
+	    increase compatibility with Magic raw data format. Unique run
+	    numbers are now generated using the file LastRunNumber.
+28/4/2009   Raw file writing uses now writev() and is changed entirely to
+    	    Linux system calls instead of C++ library functions. Introduced
+	    new magic number that indicates an error while writing. More
+	    extensive error checking for I/O functions. Requesting zero events
+	    will let run go until stopped manually. Feedback writes slow data.
+29/4/2009   DAQ writes run summary to slow data file.
Index: drsdaq/Makefile
===================================================================
--- drsdaq/Makefile	(revision 31)
+++ drsdaq/Makefile	(revision 36)
@@ -8,10 +8,9 @@
 VMECTRL = -DCT_VME
 
-#CC  	= g++   	# Compiler to use
+CC  	= g++   	# Compiler to use
 
-SOURCES = HVFeedback.cc DAQReadout.cc RawDataCTX.cc ../pixelmap/Pixel.cc ../pixelmap/PixelMap.cc DRS/DRS.cc DRS/mxml.c DRS/strlcpy.c drsdaq.cpp
+SOURCES = HVFeedback.cc DAQReadout.cc RawDataCTX.cc SlowData.cc ../pixelmap/Pixel.cc ../pixelmap/PixelMap.cc DRS/DRS.cc DRS/mxml.c DRS/strlcpy.c drsdaq.cpp
 OBJECTS = $(addsuffix .o, $(basename $(SOURCES)))
 
-SOBJECTS = RawDataCTX
 INCDIRS   = -I. -IDRS -I../pixelmap
 
@@ -31,8 +30,7 @@
 drsdaq: $(OBJECTS)
 	$(CC) $(CPPFLAGS) -o $@ $(OBJECTS) $(LIBS)
-	$(CC) -shared -Wl,-soname,$(SOBJECTS).so -o $(SOBJECTS).so $(SOBJECTS).o -lc
 
 clean:
-	@rm -f $(OBJECTS) $(SOBJECTS).so
+	@rm -f $(OBJECTS)
 	@rm -f *.d
 	@rm -f *~
Index: drsdaq/RawDataCTX.cc
===================================================================
--- drsdaq/RawDataCTX.cc	(revision 31)
+++ drsdaq/RawDataCTX.cc	(revision 36)
@@ -43,5 +43,5 @@
   }
   // Check magic number of run header
-  if (RHeader->MagicNum!=MAGICNUM_FILE_OPEN && RHeader->MagicNum!=MAGICNUM_FILE_CLOSED) {
+  if (RHeader->MagicNum!=MAGICNUM_OPEN && RHeader->MagicNum!=MAGICNUM_CLOSED && RHeader->MagicNum!=MAGICNUM_ERROR) {
     if(!Silent) printf("Error: Magic number of run header incorrect\n");
     fclose(Rawfile);
@@ -62,12 +62,15 @@
   // If requested, print run header (including board structures) to file 
   if(fptr != NULL) {
-    int RAhour, RAmin, RAsec, DEChour, DECmin, DECsec;
-
-    fprintf(fptr, "Magic number      %x\n", RHeader->MagicNum);
-    fprintf(fptr, "Data format:      %d\n", RHeader->DataFormat);
+    fprintf(fptr, "Magic number          %x (%s)\n", RHeader->MagicNum, RHeader->MagicNum==MAGICNUM_CLOSED?"OK":(RHeader->MagicNum==MAGICNUM_OPEN?"File not closed":"Error"));
+    fprintf(fptr, "Data format:          %d\n", RHeader->DataFormat);
+    fprintf(fptr, "Run header size:      %d\n", RHeader->RunHeaderSize);
+    fprintf(fptr, "Event header size:    %d\n", RHeader->EventHeaderSize);
+    fprintf(fptr, "Board structure size: %d\n", RHeader->BoardStructureSize);
+   
     fprintf(fptr, "DAQ compilation:  %s\n", RHeader->DAQVersion);         
     fprintf(fptr, "Source:           %s\n", RHeader->Source);
     fprintf(fptr, "Run type:         %c\n", RHeader->Type);
     fprintf(fptr, "Run number:       %u\n", RHeader->RunNumber);
+    fprintf(fptr, "File number:      %u\n", RHeader->FileNumber);
     fprintf(fptr, "Events:           %u\n", RHeader->Events);
     fprintf(fptr, "CMC Boards:       %u\n", RHeader->NCMCBoards);
@@ -77,23 +80,8 @@
     fprintf(fptr, "Offset:           %d\n", RHeader->Offset);
 
-    RAsec   = (int) (RHeader->SourceRA)%60;
-    RAmin   = (int) (RHeader->SourceRA/60)%60;
-    RAhour  = (int) (RHeader->SourceRA/3600);
-    DECsec  = (int) (RHeader->SourceDEC)%60;
-    DECmin  = (int) (RHeader->SourceDEC/60)%60;
-    DEChour = (int) (RHeader->SourceDEC/3600);
-
-    fprintf(fptr, "Source RA:        %f (%d %d %d)\n", RHeader->SourceRA, RAhour, RAmin, RAsec);
-    fprintf(fptr, "Source DEC:       %f (%d %d %d)\n", RHeader->SourceDEC, DEChour, DECmin, DECsec);
-
-    RAsec   = (int) (RHeader->TelescopeRA)%60;
-    RAmin   = (int) (RHeader->TelescopeRA/60)%60;
-    RAhour  = (int) (RHeader->TelescopeRA/3600);
-    DECsec  = (int) (RHeader->TelescopeDEC)%60;
-    DECmin  = (int) (RHeader->TelescopeDEC/60)%60;
-    DEChour = (int) (RHeader->TelescopeDEC/3600);
-
-    fprintf(fptr, "Telescope RA:     %f (%d %d %d)\n", RHeader->TelescopeRA, RAhour, RAmin, RAsec);
-    fprintf(fptr, "Telescope DEC:    %f (%d %d %d)\n", RHeader->TelescopeDEC, DEChour, DECmin, DECsec);
+    fprintf(fptr, "Source RA:        %f\n", RHeader->SourceRA);
+    fprintf(fptr, "Source DEC:       %f\n", RHeader->SourceDEC);
+    fprintf(fptr, "Telescope RA:     %f\n", RHeader->TelescopeRA);
+    fprintf(fptr, "Telescope DEC:    %f\n", RHeader->TelescopeDEC);
 
     fprintf(fptr, "Start year:       %u\n", RHeader->StartYear);
Index: drsdaq/RawDataCTX.h
===================================================================
--- drsdaq/RawDataCTX.h	(revision 31)
+++ drsdaq/RawDataCTX.h	(revision 36)
@@ -20,14 +20,15 @@
 #define DATA_FORMAT 1
 
-#define I8      char
-#define U8      unsigned char
-#define I16     short
-#define U16     unsigned short
-#define I32     int
-#define U32     unsigned int
-#define F32     float
+typedef char I8;
+typedef unsigned char U8;
+typedef short I16;
+typedef unsigned short U16;
+typedef int I32;
+typedef unsigned int U32;
+typedef float F32;
 
-#define MAGICNUM_FILE_OPEN 0xe0e1    // Magic number for run header while file open
-#define MAGICNUM_FILE_CLOSED 0xe0e0  //    ... and when file is closed
+#define MAGICNUM_OPEN 0xe0e1    // Magic number for run header while file open
+#define MAGICNUM_CLOSED 0xe0e0  //    ... and when file is closed
+#define MAGICNUM_ERROR 0xe0e2   //    ... and when an error occurred
 
 // Error codes
@@ -39,24 +40,32 @@
 // Run header
 typedef struct {
-  U16 MagicNum;
-  U16 DataFormat;       // Increasing whenever header format changes
+  U32 MagicNum;
+  U32 DataFormat;       // Increasing whenever header format changes
+
+  U32 RunHeaderSize;
+  U32 EventHeaderSize;
+  U32 BoardStructureSize;
+
   I8  DAQVersion[12]; 	// contains result of __DATE__ macro
+
   I8  Source[16];
   I8  Type;          // run type (char): pedestal, data, ...
+
   U32 RunNumber;
+  U32 FileNumber;
   
-  U16 StartYear;
-  U8  StartMonth;
-  U8  StartDay;
-  U8  StartHour;
-  U8  StartMinute;
-  U8  StartSecond;
+  U32 StartYear;
+  U32 StartMonth;
+  U32 StartDay;
+  U32 StartHour;
+  U32 StartMinute;
+  U32 StartSecond;
   
-  U16 EndYear;
-  U8  EndMonth;
-  U8  EndDay;
-  U8  EndHour;
-  U8  EndMinute;
-  U8  EndSecond;
+  U32 EndYear;
+  U32 EndMonth;
+  U32 EndDay;
+  U32 EndHour;
+  U32 EndMinute;
+  U32 EndSecond;
 
   F32 SourceRA;
@@ -65,5 +74,5 @@
   F32 TelescopeDEC;
   
-  U32 Events;                     // Number of events in the run 
+  U32 Events;                     // Number of events in the file 
   U32 NCMCBoards;                 // Number of used boards
   U32 NChips;			  // Number of DRS chips per board
@@ -75,5 +84,4 @@
 // Board structure
 typedef struct {
-  I32 Index; 	   // Index number (data written in this order)
   I32 SerialNo;    // Board serial number
   F32 NomFreq;     // Nominal sampling frequency [GHz]
Index: drsdaq/SlowData.cc
===================================================================
--- drsdaq/SlowData.cc	(revision 36)
+++ drsdaq/SlowData.cc	(revision 36)
@@ -0,0 +1,84 @@
+/********************************************************************\
+
+  SlowData.cc
+
+  Class handling the writing of slow data. String to be written in the
+  slow data file are checked that they do not contain control characters.
+    
+  Oliver Grimm
+
+\********************************************************************/
+
+#include "SlowData.h"
+#include "DAQReadout.h"
+
+//
+// Constructor: Open slow data file (filename generate using current date)
+//
+SlowData::SlowData(DAQReadout* DAQClass, const char* IssuerName, char* Direcory) {
+
+  time_t rawtime;
+  struct tm *timeinfo;
+  char Filename[MAX_PATH];
+
+  m = DAQClass;
+  Issuer = IssuerName;
+  NewEntryCalled = false;
+  InternalCall = false;
+  
+  time(&rawtime);   timeinfo = localtime(&rawtime);
+  snprintf(Filename,sizeof(Filename),"%s/%s_%d%02d%02d.slow",Direcory,Issuer,timeinfo->tm_year+1900,timeinfo->tm_mon+1,timeinfo->tm_mday);
+
+  if ((SlowdataFile = fopen(Filename, "a")) == NULL)
+    m->PrintMessage("Warning: Could not open slowdata file '%s' (%s)\n", Filename, strerror(errno));
+}
+
+//
+// Destructor
+//
+SlowData::~SlowData() {
+  if(SlowdataFile!=NULL && fclose(SlowdataFile)==-1)
+    m->PrintMessage("SlowData: Error, could not close slowdata file (%s)\n", strerror(errno));  
+}
+
+//
+// Add a new entry to slow data file
+//
+bool SlowData::NewEntry(char *Variable) {
+
+  struct timeval Time;
+
+  gettimeofday(&Time, NULL);
+  InternalCall = true;
+  NewEntryCalled = AddToEntry("\n%s %s %lu %lu ", Issuer, Variable, Time.tv_sec, Time.tv_usec);
+  InternalCall = false;
+  return NewEntryCalled;
+}
+
+//
+// Add data to an open entry
+//
+bool SlowData::AddToEntry(char *Format, ...) {
+
+  char Textbuffer[MAX_COM_SIZE];
+  va_list ArgumentPointer;
+
+  if(SlowdataFile==NULL || (!NewEntryCalled && !InternalCall)) return false;  
+
+  va_start(ArgumentPointer, Format); 
+  vsnprintf(Textbuffer, sizeof(Textbuffer), Format, ArgumentPointer);
+  va_end(ArgumentPointer);
+
+  if(!InternalCall)
+    for(unsigned int i=0; i<strlen(Textbuffer); i++)
+      if (iscntrl(Textbuffer[i])) return false;
+
+  if(fprintf(SlowdataFile, "%s", Textbuffer) == -1) {
+    m->PrintMessage("SlowData: Error, could not write data to file (%s); closing file\n", strerror(errno));
+    fclose(SlowdataFile);
+    SlowdataFile = NULL;  
+    return false;
+  }
+  fflush(SlowdataFile);
+  return true;
+}
Index: drsdaq/SlowData.h
===================================================================
--- drsdaq/SlowData.h	(revision 36)
+++ drsdaq/SlowData.h	(revision 36)
@@ -0,0 +1,23 @@
+#ifndef SLOWDATA_H_SEEN
+#define SLOWDATA_H_SEEN
+
+#include <stdlib.h>
+#include <stdio.h>
+
+class SlowData {
+
+    class DAQReadout *m;
+    const char *Issuer;
+    FILE *SlowdataFile;
+    bool NewEntryCalled;
+    bool InternalCall;
+	   	    	  
+  public:
+    SlowData(class DAQReadout*, const char*, char*);
+    ~SlowData();
+
+    bool NewEntry(char*);
+    bool AddToEntry(char*, ...);
+};
+
+#endif
Index: drsdaq/drsdaq.cpp
===================================================================
--- drsdaq/drsdaq.cpp	(revision 31)
+++ drsdaq/drsdaq.cpp	(revision 36)
@@ -75,4 +75,5 @@
   signal(SIGTERM, &CrashHandler);
   signal(SIGINT, &CrashHandler);
+  signal(SIGHUP, &CrashHandler);
     
   // Construct main instance
