Index: /trunk/FACT++/src/DataCalib.cc
===================================================================
--- /trunk/FACT++/src/DataCalib.cc	(revision 11726)
+++ /trunk/FACT++/src/DataCalib.cc	(revision 11726)
@@ -0,0 +1,214 @@
+#include "DataCalib.h"
+
+#include "FAD.h"
+#include "FitsFile.h"
+#include "DimDescriptionService.h"
+
+using namespace std;
+
+int DataCalib::fStep = 0;
+
+vector<int32_t> DataCalib::fOffset(1440*1024, 0);
+vector<int32_t> DataCalib::fGain  (1440*1024, 2);
+vector<int32_t> DataCalib::fTrgOff(1440*1024, 0);
+vector<float>   DataCalib::fStats (1440*1024*6+3);
+
+uint64_t DataCalib::fNumOffset = 1;
+uint64_t DataCalib::fNumGain   = 1;
+uint64_t DataCalib::fNumTrgOff = 1;
+
+void DataCalib::Restart()
+{
+    // Default gain:
+    // 0.575*[45590]*2.5V / 2^16 = 0.99999 V
+    fOffset.assign(1440*1024, 0);
+    fGain.assign  (1440*1024, 2);
+    fTrgOff.assign(1440*1024, 0);
+
+    fNumOffset = 1;
+    fNumGain   = 1;
+    fNumTrgOff = 1;
+
+    reinterpret_cast<uint32_t*>(fStats.data())[0] = 0;
+    reinterpret_cast<uint32_t*>(fStats.data())[1] = 0;
+    reinterpret_cast<uint32_t*>(fStats.data())[2] = 0;
+
+    int i=0;
+    while (i<1024*1440*2+3)  // Set mean and RMS to 0
+        fStats[i++] = 0;
+    while (i<1024*1440*3+3)
+        fStats[i++] = 0.5; // Set mean to 0.5
+    while (i<1024*1440*6+3)
+        fStats[i++] = 0;   // Set everything else to 0
+
+    fStep = 0;
+}
+
+void DataCalib::Update(DimDescribedService &dim)
+{
+    dim.Update(fStats);
+}
+
+bool DataCalib::Open(RUN_HEAD* h)
+{
+    if (fStep==4)
+    {
+        fMsg.Warn("DRS Calibration already finished... please restart!");
+        return false;
+    }
+
+    if (h->NPix != 1440)
+    {
+        fMsg.Error("Number of pixels in header not 1440.");
+        return false;
+    }
+
+    if (h->Nroi != 1024)
+    {
+        fMsg.Error("Region of interest not 1024.");
+        return false;
+    }
+
+    ostringstream name;
+    name << "drs-calib-" << fStep;
+    fFileName = name.str();
+
+    Reset();
+    InitSize(1440, 1024);
+
+    fFileName = FormFileName(GetRunId(), "drs.fits");
+
+    return true;
+}
+
+bool DataCalib::WriteEvt(EVENT *e)
+{
+    // FIXME: SET StartPix to 0 if StartPix is -1
+
+    if (fStep==0)
+    {
+        AddRel(e->Adc_Data, e->StartPix);
+    }
+    if (fStep==1)
+    {
+        AddRel(e->Adc_Data, e->StartPix, fOffset.data(), fNumOffset);
+    }
+    if (fStep==2)
+    {
+        AddAbs(e->Adc_Data, e->StartPix, fOffset.data(), fNumOffset);
+    }
+
+    return true;
+}
+
+void DataCalib::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 DataCalib::Close(RUN_TAIL *)
+{
+    if (fStep==0)
+    {
+        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();;
+    }
+    if (fStep==1)
+    {
+        fGain.assign(fSum.begin(), fSum.end());
+        //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();;
+    }
+    if (fStep==2)
+    {
+        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();;
+    }
+
+    if (fStep>=0 && fStep<=2)
+        WriteFits();
+
+    fDim.Update(fStats);
+
+    fStep++;
+
+    return true;
+}
+
+void DataCalib::Apply(int16_t *val, const int16_t *start, uint32_t roi)
+{
+    CalibData::Apply(val, start, roi,
+                     fOffset.data(), fNumOffset,
+                     fGain.data(),   fNumGain,
+                     fTrgOff.data(), fNumTrgOff);
+}
+
+void DataCalib::Apply(float *vec, int16_t *val, const int16_t *start, uint32_t roi)
+{
+    CalibData::Apply(vec, val, start, roi,
+                     fOffset.data(), fNumOffset,
+                     fGain.data(),   fNumGain,
+                     fTrgOff.data(), fNumTrgOff);
+}
+
Index: /trunk/FACT++/src/DataCalib.h
===================================================================
--- /trunk/FACT++/src/DataCalib.h	(revision 11726)
+++ /trunk/FACT++/src/DataCalib.h	(revision 11726)
@@ -0,0 +1,43 @@
+#ifndef FACT_DataCalib
+#define FACT_DataCalib
+
+#include "DataProcessorImp.h"
+#include "DrsCalib.h"
+
+class DimDescribedService;
+
+class DataCalib : public DataProcessorImp, CalibData
+{
+    static std::vector<int32_t> fOffset;
+    static std::vector<int32_t> fGain;
+    static std::vector<int32_t> fTrgOff;
+
+    static std::vector<float>   fStats;
+
+    static uint64_t fNumOffset;
+    static uint64_t fNumGain;
+    static uint64_t fNumTrgOff;
+
+    static int fStep;
+
+    DimDescribedService &fDim;
+
+    void WriteFits();
+
+public:
+    DataCalib(uint32_t id, DimDescribedService &dim, MessageImp &imp) : DataProcessorImp(id, imp), fDim(dim)
+    {
+    }
+
+    static void Restart();
+    static void Update(DimDescribedService &dim);
+
+    bool Open(RUN_HEAD* h);
+    bool WriteEvt(EVENT *e);
+    bool Close(RUN_TAIL * = 0);
+
+    static void Apply(int16_t *val, const int16_t *start, uint32_t roi);
+    static void Apply(float *vec, int16_t *val, const int16_t *start, uint32_t roi);
+};
+
+#endif
Index: /trunk/FACT++/src/DataProcessorImp.cc
===================================================================
--- /trunk/FACT++/src/DataProcessorImp.cc	(revision 11726)
+++ /trunk/FACT++/src/DataProcessorImp.cc	(revision 11726)
@@ -0,0 +1,82 @@
+#include "DataProcessorImp.h"
+
+#include "FAD.h"
+
+using namespace std;
+
+
+// --------------------------------------------------------------------------
+//
+//! This creates an appropriate file name for a particular run number and type
+//! @param runNumberq the run number for which a filename is to be created
+//! @param runType an int describing the kind of run. 0=Data, 1=Pedestal, 2=Calibration, 3=Calibrated data
+//! @param extension a string containing the extension to be appened to the file name
+//
+string DataProcessorImp::FormFileName(uint32_t runid, const string &extension)
+{
+    ostringstream name;
+    name << Time().NightAsInt() << '_' << setfill('0') << setw(3) << runid << '.' << extension;
+    return name.str();
+}
+
+// =======================================================================
+
+bool DataDump::Open(RUN_HEAD* h)
+{
+    fFileName = "/dev/null";
+
+    ostringstream str;
+    str << this << " - "
+        << "OPEN_FILE #" << GetRunId() << ":"
+        << " Ver=" << h->Version
+        << " Typ=" << h->RunType
+        << " Nb="  << h->NBoard
+        << " Np="  << h->NPix
+        << " NTm=" << h->NTm
+        << " roi=" << h->Nroi;
+
+    Debug(str);
+
+    fTime = Time();
+
+    return true;
+}
+
+bool DataDump::WriteEvt(EVENT *e)
+{
+    const Time now;
+    if (now-fTime<boost::posix_time::seconds(5))
+        return true;
+
+    fTime = now;
+
+    ostringstream str;
+    str << this << " - EVENT #" << e->EventNum << " / " << e->TriggerNum;
+    Debug(str);
+
+    return true;
+}
+
+bool DataDump::Close(RUN_TAIL *)
+{
+    ostringstream str;
+    str << this << " - CLOSE FILE #" << GetRunId();
+
+    Debug(str);
+
+    return true;
+}
+
+// =======================================================================
+
+bool DataDebug::WriteEvt(EVENT *e)
+{
+    cout << "WRITE_EVENT #" << GetRunId() << " (" << e->EventNum << ")" << endl;
+    cout << " Typ=" << e->TriggerType << endl;
+    cout << " roi=" << e->Roi << endl;
+    cout << " trg=" << e->SoftTrig << endl;
+    cout << " tim=" << e->PCTime << endl;
+
+    return true;
+}
+
Index: /trunk/FACT++/src/DataProcessorImp.h
===================================================================
--- /trunk/FACT++/src/DataProcessorImp.h	(revision 11726)
+++ /trunk/FACT++/src/DataProcessorImp.h	(revision 11726)
@@ -0,0 +1,64 @@
+#ifndef FACT_DataProcessorImp
+#define FACT_DataProcessorImp
+
+#include "MessageImp.h"
+
+struct _RUN_HEAD;
+struct _EVENT;
+struct _RUN_TAIL;
+
+typedef struct _RUN_HEAD RUN_HEAD;
+typedef struct _EVENT    EVENT;
+typedef struct _RUN_TAIL RUN_TAIL;
+
+class DataProcessorImp : public MessageImp
+{
+    uint32_t fRunId;
+
+    int Write(const Time &time, const std::string &txt, int qos)
+    {
+        return fMsg.Write(time, txt, qos);
+    }
+
+protected:
+    MessageImp &fMsg;
+    std::string fFileName;
+
+public:
+    DataProcessorImp(uint32_t id, MessageImp &imp) : fRunId(id), fMsg(imp) { }
+    virtual ~DataProcessorImp() { }
+
+    virtual bool Open(RUN_HEAD* h) = 0;
+    virtual bool WriteEvt(EVENT *) = 0;
+    virtual bool Close(RUN_TAIL * = 0) = 0;
+
+    const std::string &GetFileName() const { return fFileName; }
+
+    uint32_t GetRunId() const { return fRunId; }
+
+    static std::string FormFileName(uint32_t runid, const std::string &extension);
+};
+
+#include "Time.h"
+
+class DataDump : public DataProcessorImp
+{
+    Time fTime;
+
+public:
+    DataDump(uint32_t id, MessageImp &imp) : DataProcessorImp(id, imp) { }
+
+    bool Open(RUN_HEAD* h);
+    bool WriteEvt(EVENT *e);
+    bool Close(RUN_TAIL * = 0);
+};
+
+class DataDebug : public DataDump
+{
+public:
+    DataDebug(uint32_t id, MessageImp &imp) : DataDump(id, imp) { }
+
+    bool WriteEvt(EVENT *e);
+};
+
+#endif
Index: /trunk/FACT++/src/DataWriteFits.cc
===================================================================
--- /trunk/FACT++/src/DataWriteFits.cc	(revision 11726)
+++ /trunk/FACT++/src/DataWriteFits.cc	(revision 11726)
@@ -0,0 +1,231 @@
+#include "DataWriteFits.h"
+
+#include "FAD.h"
+#include "Converter.h"
+
+using namespace std;
+
+DataWriteFits::~DataWriteFits()
+{
+    Close();
+    delete fConv;
+}
+
+template <typename T>
+    void DataWriteFits::WriteKey(const string &name, const int idx, const T &value, const string &comment)
+{
+    ostringstream str;
+    str << name << idx;
+
+    ostringstream com;
+    com << "Board " << setw(2) << idx << ": " << comment;
+
+    fFile.WriteKey(str.str(), value, com.str());
+}
+
+// --------------------------------------------------------------------------
+//
+//! DataWriteFits constructor. This is the one that should be used, not the default one (parameter-less)
+//! @param runid This parameter should probably be removed. I first thought it was the run number, but apparently it is not
+//! @param h a pointer to the RUN_HEAD structure that contains the informations relative to this run
+//
+bool DataWriteFits::Open(RUN_HEAD* h)
+{
+    if (fConv)
+    {
+        Error("DataWriteFits::Open called twice.");
+        return false;
+    }
+
+    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(fFile.GetColumnTypes()));
+
+    const size_t sz = (h->NPix*h->Nroi + h->NTm*h->NroiTM)*2;
+    if (fConv->GetSize()-sz+4!=sizeof(EVENT))
+    {
+        ostringstream str;
+        str << "The EVENT structure size (" << sizeof(EVENT) << ") doesn't match the described FITS row (";
+        str << fConv->GetSize()-sz+4 << ")";
+        Error(str);
+        return false;
+    }
+
+    //Form filename, based on runid and run-type
+    fFileName = FormFileName(GetRunId(), "fits");
+
+    if (!fFile.OpenFile(fFileName))
+        return false;
+
+    if (!fFile.OpenTable("Events"))
+        return false;
+
+    if (!fFile.WriteDefaultKeys("fadctrl"))
+        return false;
+
+    Info("==> TODO: Write sampling frequency...");
+
+    //write header data
+    //first the "standard" keys
+    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;
+    }
+
+    /*
+     //now the boards related keywords
+     for (int i=0; i<h->NBoard; i++)
+     {
+     const PEVNT_HEADER &hh = h->FADhead[i];
+
+     WriteKey("STPKGFG", i, hh.start_package_flag, "Start package flag");
+     WriteKey("PKGLEN",  i, hh.package_length, "Package length");
+     WriteKey("STATUS",  i, hh.PLLLCK, "");
+
+     //            WriteKey("TRIGCRC", i, hh.trigger_crc,      "Trigger CRC");
+     //            WriteKey("TRIGTYP", i, hh.trigger_type,     "Trigger type");
+     //            WriteKey("TRIGID",  i, hh.trigger_id,       "Trigger ID");
+     //            WriteKey("EVTCNTR", i, hh.fad_evt_counter,  "FAD Event Counter");
+     //            WriteKey("REFCLK",  i, hh.REFCLK_frequency, "Reference Clock Frequency");
+
+     WriteKey("PHASESH", i, hh.adc_clock_phase_shift,          "ADC clock phase shift");
+     WriteKey("TRGGEN",  i, hh.number_of_triggers_to_generate, "Number of triggers to generate");
+     WriteKey("PRESC",   i, hh.trigger_generator_prescaler,    "Trigger generator prescaler");
+     WriteKey("RUNNB",   i, hh.runnumber,                      "Run number");
+
+     WriteKey("TIME",    i, hh.time,      "Time");
+
+     //            for (int j=0;j<NTemp;j++)
+     //            {
+     //                str.str(""); str2.str("");
+     //                str << "DRS_T" << i << j;
+     //                str2 << "DRS temperature #" << i << " " << j;
+     //                WriteKey(str.str(), h->FADhead[i].drs_temperature[j], str2.str());
+     //            }
+     for (int j=0;j<NDAC;j++)
+     WriteKey("DAC", i*NDAC+j, hh.dac[j], "DAC");
+     }
+     */
+
+    //Last but not least, add header keys that will be updated when closing the file
+    return WriteFooter(NULL);
+}
+
+// --------------------------------------------------------------------------
+//
+//! This writes one event to the file
+//! @param e the pointer to the EVENT
+//
+bool DataWriteFits::WriteEvt(EVENT *e)
+{
+    if (!fFile.AddRow())
+        return false;
+
+    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);
+
+    return fFile.WriteData(data.data(), data.size());
+}
+
+bool DataWriteFits::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;
+    }
+    return true;
+}
+
+// --------------------------------------------------------------------------
+//
+//! Closes the file, and before this it write the TAIL data
+//! @param rt the pointer to the RUN_TAIL data structure
+//
+bool DataWriteFits::Close(RUN_TAIL *rt)
+{
+    if (!fFile.IsOpen())
+        return false;
+
+    WriteFooter(rt);
+
+    fFile.Close();
+
+    return true;
+}
Index: /trunk/FACT++/src/DataWriteFits.h
===================================================================
--- /trunk/FACT++/src/DataWriteFits.h	(revision 11726)
+++ /trunk/FACT++/src/DataWriteFits.h	(revision 11726)
@@ -0,0 +1,32 @@
+#ifndef FACT_DataWriteFits
+#define FACT_DataWriteFits
+
+#include "DataProcessorImp.h"
+#include "FitsFile.h"
+
+class Converter;
+
+class DataWriteFits : public DataProcessorImp
+{
+    FitsFile fFile;
+
+    Converter *fConv;
+
+    template <typename T>
+        void WriteKey(const string &name, const int idx, const T &value, const string &comment);
+
+    bool WriteFooter(RUN_TAIL *rt);
+
+public:
+    DataWriteFits(uint32_t runid, MessageImp &imp) :
+        DataProcessorImp(runid, imp), fFile(imp)
+    {
+    }
+
+    ~DataWriteFits();
+
+    bool Open(RUN_HEAD* h);
+    bool WriteEvt(EVENT *e);
+    bool Close(RUN_TAIL *rt = 0);
+};
+#endif
Index: /trunk/FACT++/src/DataWriteRaw.cc
===================================================================
--- /trunk/FACT++/src/DataWriteRaw.cc	(revision 11726)
+++ /trunk/FACT++/src/DataWriteRaw.cc	(revision 11726)
@@ -0,0 +1,123 @@
+#include "DataWriteRaw.h"
+
+#include "FAD.h"
+
+using namespace std;
+
+void DataWriteRaw::WriteBlockHeader(uint32_t type, uint32_t ver, uint32_t cnt, uint32_t len)
+{
+    const uint32_t val[4] = { type, ver, cnt, len };
+
+    fOut.write(reinterpret_cast<const char*>(val), sizeof(val));
+}
+
+template<typename T>
+void DataWriteRaw::WriteValue(const T &t)
+{
+    fOut.write(reinterpret_cast<const char*>(&t), sizeof(T));
+}
+
+bool DataWriteRaw::Open(RUN_HEAD *h)
+{
+    const string name = FormFileName(GetRunId(), "bin");
+    if (access(name.c_str(), F_OK)==0)
+    {
+        Error("File '"+name+"' already exists.");
+        return false;
+    }
+
+    fFileName = name;
+
+    errno = 0;
+    fOut.open(name.c_str(), ios_base::out);
+    if (!fOut)
+    {
+        ostringstream str;
+        str << "ofstream::open() failed for '" << name << "': " << strerror(errno) << " [errno=" << errno << "]";
+        Error(str);
+
+        return false;
+    }
+
+    fCounter = 0;
+
+    static uint32_t FACT = 0xFAC77e1e;
+
+    fOut.write(reinterpret_cast<char*>(&FACT), 4);
+
+    WriteBlockHeader(kIdentifier, 1, 0, 8);
+    WriteValue(uint32_t(0));
+    WriteValue(GetRunId());
+
+    WriteBlockHeader(kRunHeader, 1, 0, sizeof(RUN_HEAD)-sizeof(PEVNT_HEADER*));
+    fOut.write(reinterpret_cast<char*>(h), sizeof(RUN_HEAD)-sizeof(PEVNT_HEADER*));
+
+    for (int i=0; i<40; i++)
+    {
+        WriteBlockHeader(kBoardHeader, 1, i, sizeof(PEVNT_HEADER));
+        fOut.write(reinterpret_cast<char*>(h->FADhead+i), sizeof(PEVNT_HEADER));
+    }
+
+    // FIXME: Split this
+    const vector<char> block(sizeof(uint32_t)+sizeof(RUN_TAIL));
+    WriteBlockHeader(kRunSummary, 1, 0, block.size());
+
+    fPosTail = fOut.tellp();
+    fOut.write(block.data(), block.size());
+
+    if (!fOut)
+    {
+        ostringstream str;
+        str << "ofstream::write() failed for '" << name << "': " << strerror(errno) << " [errno=" << errno << "]";
+        Error(str);
+
+        return false;
+    }
+
+    return true;
+}
+
+bool DataWriteRaw::WriteEvt(EVENT *evt)
+{
+    const int sh = sizeof(EVENT)-2 + NPIX*evt->Roi*2;
+
+    WriteBlockHeader(kEvent, 1, fCounter++, sh);
+    fOut.write(reinterpret_cast<char*>(evt)+2, sh);
+    return true;
+}
+
+bool DataWriteRaw::Close(RUN_TAIL *tail)
+{
+    WriteBlockHeader(kEndOfFile, 0, 0, 0);
+
+    if (tail)
+    {
+        fOut.seekp(fPosTail);
+
+        WriteValue(uint32_t(1));
+        fOut.write(reinterpret_cast<char*>(tail), sizeof(RUN_TAIL));
+    }
+
+    if (!fOut)
+    {
+        ostringstream str;
+
+        str << "ofstream::write() failed for '" << GetFileName() << "': " << strerror(errno) << " [errno=" << errno << "]";
+        Error(str);
+
+        return false;
+    }
+
+    fOut.close();
+
+    if (!fOut)
+    {
+        ostringstream str;
+        str << "ofstream::close() failed for '" << GetFileName() << "': " << strerror(errno) << " [errno=" << errno << "]";
+        Error(str);
+
+        return false;
+    }
+
+    return true;
+}
Index: /trunk/FACT++/src/DataWriteRaw.h
===================================================================
--- /trunk/FACT++/src/DataWriteRaw.h	(revision 11726)
+++ /trunk/FACT++/src/DataWriteRaw.h	(revision 11726)
@@ -0,0 +1,88 @@
+#ifndef FACT_DataWriteRaw
+#define FACT_DataWriteRaw
+
+#include "DataProcessorImp.h"
+
+class DataWriteRaw : public DataProcessorImp
+{
+    std::ofstream fOut;
+
+    off_t fPosTail;
+
+    uint32_t fCounter;
+
+
+    // WRITE uint32_t 0xFAC77e1e  (FACT Tele)
+    // ===
+    // WRITE uint32_t TYPE(>0)          == 1
+    // WRITE uint32_t ID(>0)            == 0
+    // WRITE uint32_t VERSION(>0)       == 1
+    // WRITE uint32_t LENGTH
+    // -
+    // WRITE uint32_t TELESCOPE ID
+    // WRITE uint32_t RUNID
+    // ===
+    // WRITE uint32_t TYPE(>0)          == 2
+    // WRITE uint32_t ID(>0)            == 0
+    // WRITE uint32_t VERSION(>0)       == 1
+    // WRITE uint32_t LENGTH
+    // -
+    // WRITE          HEADER
+    // ===
+    // [ 40 TIMES
+    //    WRITE uint32_t TYPE(>0)       == 3
+    //    WRITE uint32_t ID(>0)         == 0..39
+    //    WRITE uint32_t VERSION(>0)    == 1
+    //    WRITE uint32_t LENGTH
+    //    -
+    //    WRITE          BOARD-HEADER
+    // ]
+    // ===
+    // WRITE uint32_t TYPE(>0)          == 4
+    // WRITE uint32_t ID(>0)            == 0
+    // WRITE uint32_t VERSION(>0)       == 1
+    // WRITE uint32_t LENGTH
+    // -
+    // WRITE          FOOTER (empty)
+    // ===
+    // [ N times
+    //    WRITE uint32_t TYPE(>0)       == 10
+    //    WRITE uint32_t ID(>0)         == counter
+    //    WRITE uint32_t VERSION(>0)    == 1
+    //    WRITE uint32_t LENGTH HEADER
+    //    -
+    //    WRITE          HEADER+DATA
+    // ]
+    // ===
+    // WRITE uint32_t TYPE   ==0
+    // WRITE uint32_t VERSION==0
+    // WRITE uint32_t LENGTH ==0
+    // ===
+    // Go back and write footer
+
+    void WriteBlockHeader(uint32_t type, uint32_t ver, uint32_t cnt, uint32_t len);
+
+    template<typename T>
+        void WriteValue(const T &t);
+
+
+public:
+    DataWriteRaw(uint32_t id, MessageImp &imp) : DataProcessorImp(id, imp), fPosTail(0) { }
+    ~DataWriteRaw() { if (fOut.is_open()) Close(); }
+
+    enum
+    {
+        kEndOfFile = 0,
+        kIdentifier = 1,
+        kRunHeader,
+        kBoardHeader,
+        kRunSummary,
+        kEvent,
+    };
+
+    bool Open(RUN_HEAD *h);
+    bool WriteEvt(EVENT *evt);
+    bool Close(RUN_TAIL *tail= 0);
+};
+
+#endif
