Index: /trunk/FACT++/src/EventBuilderWrapper.h
===================================================================
--- /trunk/FACT++/src/EventBuilderWrapper.h	(revision 11714)
+++ /trunk/FACT++/src/EventBuilderWrapper.h	(revision 11715)
@@ -12,6 +12,7 @@
 #include <boost/date_time/posix_time/posix_time_types.hpp>
 
-
-#include <CCfits/CCfits>
+#ifdef HAVE_FITS
+#include "FitsFile.h"
+#endif
 
 #include "EventBuilder.h"
@@ -61,5 +62,5 @@
     //! @param extension a string containing the extension to be appened to the file name
     //
-    static string FormFileName(uint32_t runid, string extension)
+    static string FormFileName(uint32_t runid, const string &extension)
     {
         ostringstream name;
@@ -131,7 +132,7 @@
     static vector<float>   fStats;
 
-    static uint32_t fNumOffset;
-    static uint32_t fNumGain;
-    static uint32_t fNumTrgOff;
+    static uint64_t fNumOffset;
+    static uint64_t fNumGain;
+    static uint64_t fNumTrgOff;
 
     static int fStep;
@@ -203,4 +204,6 @@
         InitSize(1440, 1024);
 
+        fFileName = FormFileName(GetRunId(), "drs.fits");
+
         return true;
     }
@@ -224,4 +227,54 @@
         return true;
     }
+
+    void WriteFits()
+    {
+#ifdef HAVE_FITS
+        FitsFile file(fMsg);
+
+        file.AddColumn('I', "RunNumberBaseline");
+        file.AddColumn('I', "RunNumberGain");
+        file.AddColumn('I', "RunNumberTriggerOffset");
+        file.AddColumn('F', "BaselineMean", 1024*1440);
+        file.AddColumn('F', "BaselineRms", 1024*1440);
+        file.AddColumn('F', "GainMean", 1024*1440);
+        file.AddColumn('F', "GainRms", 1024*1440);
+        file.AddColumn('F', "TriggerOffsetMean", 1024*1440);
+        file.AddColumn('F', "TriggerOffsetRms", 1024*1440);
+
+        if (!file.OpenFile(fFileName))
+            return;
+
+        if (!file.OpenTable("DrsCalibration"))
+            return;
+
+        if (!file.WriteDefaultKeys("fadctrl"))
+            return;
+
+        if (!file.WriteKeyNT("STEP", fStep, ""))
+            return;
+
+        vector<char> buf;
+        buf.reserve(fStats.size()*sizeof(float));
+
+        char *src  = reinterpret_cast<char*>(fStats.data());
+        char *end  = reinterpret_cast<char*>(fStats.data()+1024*1440*6+3);
+        char *dest = buf.data();
+
+        while (src<end)
+        {
+            reverse_copy(src, src+sizeof(float), dest);
+            src  += sizeof(float);
+            dest += sizeof(float);
+        }
+
+        if (!file.AddRow())
+            return;
+
+        if (!file.WriteData(buf.data(), 1024*1440*sizeof(float)*6+3))
+            return;
+#endif
+    }
+
     bool Close(RUN_TAIL * = 0)
     {
@@ -230,14 +283,23 @@
             fOffset.assign(fSum.begin(), fSum.end());
             fNumOffset = fNumEntries;
+
+            // 0.5: Scale from ADC to Millivolt
+            GetSampleStats(fStats.data()+3, 0.5);
             reinterpret_cast<uint32_t*>(fStats.data())[0] = GetRunId();;
-            GetSampleStats(fStats.data()+3, 0.5);
         }
         if (fStep==1)
         {
             fGain.assign(fSum.begin(), fSum.end());
-            fNumGain = fNumEntries*1000;
+            //fNumGain = fNumEntries*1000;
+
+            // DAC:  0..2.5V == 0..65535
+            // V-mV: 1000
+            for (int i=0; i<1024*1440; i++)
+                fGain[i] *= 125;
+            fNumGain = fNumEntries * 65535;
+
+            // 0.5: Scale from ADC to Millivolt
+            GetSampleStats(fStats.data()+1024*1440*2+3, 0.5);
             reinterpret_cast<uint32_t*>(fStats.data())[1] = GetRunId();;
-            // Scale from Volt to Millivolt
-            GetSampleStats(fStats.data()+1024*1440*2+3, 0.5);
         }
         if (fStep==2)
@@ -245,7 +307,12 @@
             fTrgOff.assign(fSum.begin(), fSum.end());
             fNumTrgOff = fNumEntries;
+
+            // 0.5: Scale from ADC to Millivolt
+            GetSampleStats(fStats.data()+1024*1440*4+3, 0.5);
             reinterpret_cast<uint32_t*>(fStats.data())[2] = GetRunId();;
-            GetSampleStats(fStats.data()+1024*1440*4+3, 0.5);
-        }
+        }
+
+        if (fStep>=0 && fStep<=2)
+            WriteFits();
 
         fDim.Update(fStats);
@@ -280,7 +347,7 @@
 vector<float>   DataFileCalib::fStats (1440*1024*6+3);
 
-uint32_t DataFileCalib::fNumOffset = 1;
-uint32_t DataFileCalib::fNumGain   = 1;
-uint32_t DataFileCalib::fNumTrgOff = 1;
+uint64_t DataFileCalib::fNumOffset = 1;
+uint64_t DataFileCalib::fNumGain   = 1;
+uint64_t DataFileCalib::fNumTrgOff = 1;
 
 
@@ -493,16 +560,15 @@
 
 #ifdef HAVE_FITS
+
+
 class DataFileFits : public DataFileImp
 {
-    CCfits::FITS*  fFile;        /// The pointer to the CCfits FITS file
-    CCfits::Table* fTable;       /// The pointer to the CCfits binary table
-
-    uint64_t fNumRows;                ///the number of rows that have been written already to the FITS file.
-
     Converter *fConv;
+
+    FitsFile fFile;
 
 public:
     DataFileFits(uint32_t runid, MessageImp &imp) :
-        DataFileImp(runid, imp), fFile(0), fNumRows(0), fConv(0)
+        DataFileImp(runid, imp), fFile(imp)
     {
     }
@@ -516,47 +582,4 @@
     ~DataFileFits() { Close(); delete fConv; }
 
-    // --------------------------------------------------------------------------
-    //
-    //! Add a new column to the vectors storing the column data.
-    //! @param names the vector of string storing the columns names
-    //! @param types the vector of string storing the FITS data format
-    //! @param numElems the number of elements in this column
-    //! @param type the char describing the FITS data format
-    //! @param name the name of the particular column to be added.
-    //
-    inline void AddColumnEntry(vector<string>& names, vector<string>& types, int numElems, char type, string name)
-    {
-        names.push_back(name);
-
-        ostringstream str;
-        if (numElems != 1)
-            str << numElems;
-        str << type;
-        types.push_back(str.str());
-    }
-
-    // --------------------------------------------------------------------------
-    //
-    //! Writes a single header key entry
-    //! @param name the name of the key
-    //! @param value its value
-    //! @param comment the comment associated to that key
-    //
-    //FIXME this function is a duplicate from the class Fits. should we try to merge it ?
-    template <typename T>
-    void WriteKey(const string &name, const T &value, const string &comment)
-    {
-        try
-        {
-            fTable->addKey(name, value, comment);
-        }
-        catch (CCfits::FitsException e)
-        {
-            ostringstream str;
-            str << "Could not add header key " << name;
-            Error(str);
-        }
-    }
-
     template <typename T>
     void WriteKey(const string &name, const int idx, const T &value, const string &comment)
@@ -568,5 +591,5 @@
         com << "Board " << setw(2) << idx << ": " << comment;
 
-        WriteKey(str.str(), value, com.str());
+        fFile.WriteKey(str.str(), value, com.str());
     }
 
@@ -578,59 +601,21 @@
     //
     bool OpenFile(RUN_HEAD* h)
-        {
-        //Form filename, based on runid and run-type
-        const string fileName = FormFileName(GetRunId(), "fits");
-        if (access(fileName.c_str(), F_OK)==0)
-        {
-            Error("File '"+fileName+"' already exists.");
-            return false;
-        }
-
-        fFileName = fileName;
-
-        /*
-         out <<
-         "SIMPLE  =                    T / file does conform to FITS standard             "
-         "BITPIX  =                    8 / number of bits per data pixel                  "
-         "NAXIS   =                    0 / number of data axes                            "
-         "EXTEND  =                    T / FITS dataset may contain extensions            "
-         "COMMENT   FITS (Flexible Image Transport System) format is defined in 'Astronomy"
-         "COMMENT   and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H "
-         "END                                                                             ";
-         for (int i=0; i<29; i++)
-         out << "                                                                                "
-         */
-
-        //create the FITS object
-        try
-        {
-            fFile = new CCfits::FITS(fileName, CCfits::RWmode::Write);
-        }
-        catch (CCfits::FitsException e)
-        {
-            ostringstream str;
-            str << "Could not open FITS file " << fileName << ": " << e.message();
-            Error(str);
-            return false;
-        }
-
-        vector<string> colNames;
-        vector<string> dataTypes;
-        AddColumnEntry(colNames, dataTypes, 1,                'J', "EventNum");
-        AddColumnEntry(colNames, dataTypes, 1,                'J', "TriggerNum");
-        AddColumnEntry(colNames, dataTypes, 1,                'I', "TriggerType");
-        AddColumnEntry(colNames, dataTypes, 1,                'J', "NumBoards");
-        AddColumnEntry(colNames, dataTypes, 1,                'J', "reserved");
-        AddColumnEntry(colNames, dataTypes, 1,                'J', "SoftTrig");
-        AddColumnEntry(colNames, dataTypes, 2,                'J', "PCTime");
-        AddColumnEntry(colNames, dataTypes, NBOARDS/*h->NBoard*/, 'J', "BoardTime");
-        AddColumnEntry(colNames, dataTypes, NPIX   /*h->NPix*/,   'I', "StartCellData");
-        AddColumnEntry(colNames, dataTypes, NTMARK /*h->NTm*/,    'I', "StartCellTimeMarker");
-        AddColumnEntry(colNames, dataTypes, h->NPix*h->Nroi,      'I', "Data");
-        AddColumnEntry(colNames, dataTypes, h->NTm*h->NroiTM,     'I', "TimeMarker");
+    {
+        fFile.AddColumn('I', "EventNum");
+        fFile.AddColumn('I', "TriggerNum");
+        fFile.AddColumn('S', "TriggerType");
+        fFile.AddColumn('I', "NumBoards");
+        fFile.AddColumn('I', "reserved");
+        fFile.AddColumn('I', "SoftTrig");
+        fFile.AddColumn('I', "PCTime",              2);
+        fFile.AddColumn('I', "BoardTime",           NBOARDS);
+        fFile.AddColumn('S', "StartCellData",       NPIX);
+        fFile.AddColumn('S', "StartCellTimeMarker", NTMARK);
+        fFile.AddColumn('S', "Data",                h->NPix*h->Nroi);
+        fFile.AddColumn('S', "TimeMarker",          h->NTm*h->NroiTM);
 
         // Write length of physical pipeline (1024)
 
-        fConv = new Converter(Converter::ToFormat(dataTypes));
+        fConv = new Converter(Converter::ToFormat(fFile.GetColumnTypes()));
 
         const size_t sz = (h->NPix*h->Nroi + h->NTm*h->NroiTM)*2;
@@ -644,82 +629,66 @@
         }
 
-        //actually create the table
-        try
-        {
-            fTable = fFile->addTable("Events", 0, colNames, dataTypes);
-        }
-        catch (const CCfits::FitsException &e)
-        {
-            ostringstream str;
-            str << "Could not create FITS table 'Events' in file " << fileName << " reason: " << e.message();
-            Error(str);
+        //Form filename, based on runid and run-type
+        fFileName = FormFileName(GetRunId(), "fits");
+
+        if (!fFile.OpenFile(fFileName))
             return false;
-        }
-
-        if (fTable->rows() != 0)
-        {
-            Error("FITS table created on the fly looks non-empty.");
+
+        if (!fFile.OpenTable("Events"))
             return false;
-        }
+
+        if (!fFile.WriteDefaultKeys("fadctrl"))
+            return false;
+
+        Info("==> TODO: Write sampling frequency...");
 
         //write header data
         //first the "standard" keys
-        WriteKey("EXTREL",   1.0f,   "Release Number");
-        WriteKey("TELESCOP", "FACT",    "Telescope that acquired this data");
-        WriteKey("ORIGIN",   "ISDC",    "Institution that wrote the file");
-        WriteKey("CREATOR",  "fadctrl", "Program that wrote this file (FACT++ Event Builder)");
-
-        WriteKey("PACKAGE",   PACKAGE_NAME, "Package name");
-        WriteKey("VERSION",   PACKAGE_VERSION, "Package description");
-        WriteKey("COMPILED",  __DATE__" "__TIME__, "Compile time");
-        WriteKey("REVISION",  REVISION, "SVN revision");
-        //WriteKey("CONTACT",   PACKAGE_BUGREPORT, "Current package maintainer");
-        //WriteKey("URL",       PACKAGE_URL, "Current repositiory location");
-
-        WriteKey("BLDVER",   h->Version,  "Builder version");
-        WriteKey("RUNID",    GetRunId(),  "Run number");
-        WriteKey("RUNTYPE",  h->RunType,  "Type of run");
-        WriteKey("NBOARD",   h->NBoard,   "Number of acquisition boards");
-        WriteKey("NPIX",     h->NPix,     "Number of pixels");
-        WriteKey("NTMARK",   h->NTm,      "Number of Time marks");
-        WriteKey("NROI",     h->Nroi,     "Number of slices per pixels");
-        WriteKey("NROITM",   h->NroiTM,   "Number of slices per time-marker");
-
-        const Time now;
-        WriteKey("TIMESYS",  "UTC",       "Time system");
-        WriteKey("DATE",     now.Iso(),   "File creation date");
-        WriteKey("NIGHT",    now.NightAsInt(), "Night as int");
-
-        //FIXME should we also put the start and stop time of the received data ?
-        //now the events header related variables
-        WriteKey("CAMERA",   "MGeomCamFACT", "");
-        WriteKey("DAQ",      "DRS4", "");
-
-        WriteKey("ADCCOUNT",  2.0f,       "ADC Counts per milliVolt");
-
-        Info("==> TODO: Write sampling frequency...");
-
-        // Write a single key for:
-        // -----------------------
-        // Start package flag
-        // package length
-        // version number
-        // status
-        // Prescaler
-
-        // Write 40 kays for (?)
-        // Phaseshift
-        // DAC
-
-        for (int i=0; i<h->NBoard; i++)
-        {
-            const PEVNT_HEADER &hh = h->FADhead[i];
-
-            // Header values whihc won't change during the run
-            WriteKey("ID",    i, hh.board_id,   "Board ID");
-            WriteKey("DNA",   i, hh.DNA,        "DNA");
-            WriteKey("FWVER", i, hh.version_no, "Firmware Version");
-        }
-
+        try
+        {
+            fFile.WriteKey("BLDVER",   h->Version,  "Builder version");
+            fFile.WriteKey("RUNID",    GetRunId(),  "Run number");
+            fFile.WriteKey("RUNTYPE",  h->RunType,  "Type of run");
+            fFile.WriteKey("NBOARD",   h->NBoard,   "Number of acquisition boards");
+            fFile.WriteKey("NPIX",     h->NPix,     "Number of pixels");
+            fFile.WriteKey("NTMARK",   h->NTm,      "Number of Time marks");
+            fFile.WriteKey("NROI",     h->Nroi,     "Number of slices per pixels");
+            fFile.WriteKey("NROITM",   h->NroiTM,   "Number of slices per time-marker");
+
+            //FIXME should we also put the start and stop time of the received data ?
+            //now the events header related variables
+            fFile.WriteKey("CAMERA",   "MGeomCamFACT", "");
+            fFile.WriteKey("DAQ",      "DRS4", "");
+
+            fFile.WriteKey("ADCCOUNT",  2.0f,       "ADC Counts per milliVolt");
+
+
+            // Write a single key for:
+            // -----------------------
+            // Start package flag
+            // package length
+            // version number
+            // status
+            // Prescaler
+
+            // Write 40 kays for (?)
+            // Phaseshift
+            // DAC
+
+            for (int i=0; i<h->NBoard; i++)
+            {
+                const PEVNT_HEADER &hh = h->FADhead[i];
+
+                // Header values whihc won't change during the run
+                WriteKey("ID",    i, hh.board_id,   "Board ID");
+                WriteKey("DNA",   i, hh.DNA,        "DNA");
+                WriteKey("FWVER", i, hh.version_no, "Firmware Version");
+            }
+        }
+        catch (const CCfits::FitsException &e)
+        {
+            Error("CCfits::Table::addKey failed in "+fFileName+"': "+e.message());
+            return false;
+        }
 
         /*
@@ -759,28 +728,8 @@
 
         //Last but not least, add header keys that will be updated when closing the file
-        WriteFooter(NULL);
-
-        return true;
-    }
-
-
-    int WriteColumns(size_t &start, size_t size, const void *e)
-    {
-        int status = 0;
-        fits_write_tblbytes(fFile->fitsPointer(), fNumRows, start, size,
-                            (unsigned char*)e, &status);
-        if (status)
-        {
-            char text[30];//max length of cfitsio error strings (from doc)
-            fits_get_errstatus(status, text);
-
-            ostringstream str;
-            str << "Writing FITS row " << fNumRows << ": " << text << " (file_write_tblbytes, rc=" << status << ")";
-            Error(str);
-        }
-
-        start += size;
-        return status;
-    }
+        return WriteFooter(NULL);
+    }
+
+
 
     // --------------------------------------------------------------------------
@@ -789,94 +738,44 @@
     //! @param e the pointer to the EVENT
     //
-    virtual bool WriteEvt(EVENT *e)
-    {
-        //FIXME As discussed earlier, we do not swap the bytes yet.
-        fTable->makeThisCurrent();
-
-        //insert a new row
-        int status(0);
-        if (fits_insert_rows(fTable->fitsPointer(), fNumRows, 1, &status))
-        {
-            char text[30];//max length of cfitsio error strings (from doc)
-            fits_get_errstatus(status, text);
-
-            ostringstream str;
-            str << "Inserting row " << fNumRows << " into " << fFileName << ": " << text << " (fits_insert_rows, rc=" << status << ")";
-            Error(str);
-
+    bool WriteEvt(EVENT *e)
+    {
+        if (!fFile.AddRow())
             return false;
-        }
-        fNumRows++;
-
-        // FIXME: Get NPIX and NTMARK from header
+
         const size_t sz = sizeof(EVENT) + sizeof(e->StartPix)*e->Roi+sizeof(e->StartTM)*e->RoiTM;
 
         const vector<char> data = fConv->ToFits(reinterpret_cast<char*>(e)+4, sz-4);
 
-        // column size pointer
-        size_t col = 1;
-        if (!WriteColumns(col, data.size(), data.data()))
-            return true;
-
-        //TODO output an error
-        return false;
-
-        /*
-        //write the data, chunk by chunk
-        //FIXME hard-coded size corresponds to current variables of the event, in bytes.
-        //FIXME no padding was taken into account. Because smallest member is 2 bytes, I don't think that this should be a problem.
-        const long sizeInBytesOfEventBeforePointers = 16;
-
-        long col = 1;
-        if (FitsWriteTblBytes(col, sizeInBytesOfEventBeforePointers, e))
-        {
-            //TODO output an error
+        return fFile.WriteData(data.data(), data.size());
+    }
+
+    bool WriteFooter(RUN_TAIL *rt)
+    {
+        try
+        {
+            fFile.WriteKey("NBEVTOK",  rt ? rt->nEventsOk  : uint32_t(0),
+                           "How many events were written");
+
+            fFile.WriteKey("NBEVTREJ", rt ? rt->nEventsRej : uint32_t(0),
+                           "How many events were rejected by SW-trig");
+
+            fFile.WriteKey("NBEVTBAD", rt ? rt->nEventsBad : uint32_t(0),
+                           "How many events were rejected by Error");
+
+            //FIXME shouldn't we convert start and stop time to MjD first ?
+            //FIXME shouldn't we also add an MjD reference ?
+
+            fFile.WriteKey("TSTART",   rt ? rt->PCtime0    : uint32_t(0),
+                           "Time when first event received");
+
+            fFile.WriteKey("TSTOP",    rt ? rt->PCtimeX    : uint32_t(0),
+                           "Time when last event received");
+        }
+        catch (const CCfits::FitsException &e)
+        {
+            Error("CCfits::Table::addKey failed in '"+fFile.GetName()+"': "+e.message());
             return false;
         }
-        if (FitsWriteTblBytes(col, NBOARDS*2, e->BoardTime))
-        {
-            //TODO output an error
-            return false;
-        }
-        if (FitsWriteTblBytes(col, NPIX*2, e->StartPix))
-        {
-            //TODO output an error
-            return false;
-        }
-        if (FitsWriteTblBytes(col, NTMARK*2, e->StartTM))
-        {
-            //TODO output an error
-            return false;
-        }
-        if (FitsWriteTblBytes(col, NPIX*fRoi*2, e->Adc_Data))
-        {
-            //TODO output an error
-            return false;
-        }
-        return true;*/
-    }
-
-    void WriteFooter(RUN_TAIL *rt)
-    {
-        //write final header keys
-        fTable->makeThisCurrent();
-
-        WriteKey("NBEVTOK",  rt ? rt->nEventsOk  : uint32_t(0),
-                 "How many events were written");
-
-        WriteKey("NBEVTREJ", rt ? rt->nEventsRej : uint32_t(0),
-                 "How many events were rejected by SW-trig");
-
-        WriteKey("NBEVTBAD", rt ? rt->nEventsBad : uint32_t(0),
-                 "How many events were rejected by Error");
-
-        //FIXME shouldn't we convert start and stop time to MjD first ?
-        //FIXME shouldn't we also add an MjD reference ?
-
-        WriteKey("TSTART",   rt ? rt->PCtime0    : uint32_t(0),
-                 "Time when first event received");
-
-        WriteKey("TSTOP",    rt ? rt->PCtimeX    : uint32_t(0),
-                 "Time when last event received");
+        return true;
     }
 
@@ -886,13 +785,12 @@
     //! @param rt the pointer to the RUN_TAIL data structure
     //
-    virtual bool Close(RUN_TAIL *rt = 0)
-    {
-        if (!fFile)
+    bool Close(RUN_TAIL *rt = 0)
+    {
+        if (!fFile.IsOpen())
             return false;
 
         WriteFooter(rt);
 
-        delete fFile;
-        fFile = NULL;
+        fFile.Close();
 
         return true;
@@ -992,4 +890,6 @@
                 break;
             if (access((name+"fits").c_str(), F_OK) == 0)
+                break;
+            if (access((name+"drs.fits").c_str(), F_OK) == 0)
                 break;
         }
