Index: /trunk/FACT++/src/fadctrl.cc
===================================================================
--- /trunk/FACT++/src/fadctrl.cc	(revision 11376)
+++ /trunk/FACT++/src/fadctrl.cc	(revision 11377)
@@ -49,4 +49,7 @@
     uint64_t fCounter;
 
+    FAD::EventHeader fBufEventHeader;
+    vector<uint16_t> fTargetRoi;
+
 protected:
     void PrintEventHeader()
@@ -279,4 +282,13 @@
     void ConnectionEstablished()
     {
+        fBufEventHeader.clear();
+        fBufEventHeader.fEventCounter = 1;
+        fBufEventHeader.fStatus = 0xf000|
+            FAD::EventHeader::kDenable|
+            FAD::EventHeader::kDwrite|
+            FAD::EventHeader::kDcmLocked|
+            FAD::EventHeader::kDcmReady|
+            FAD::EventHeader::kSpiSclk;
+
         fEventHeader.clear();
         for (unsigned int i=0; i<FAD::kNumChannels; i++)
@@ -348,5 +360,6 @@
         Connection(ioservice, imp()), fSlot(slot),
         fIsVerbose(false), fIsHexOutput(false), fIsDataOutput(false),
-        fBlockTransmission(false), fCounter(0)
+        fBlockTransmission(false), fCounter(0),
+        fTargetRoi(FAD::kNumChannels)
     {
         // Maximum possible needed space:
@@ -358,9 +371,18 @@
     }
 
-//    void SetTcpEndpoint(const tcp::endpoint &ep) { fEndpoint = ep; }
-//    const tcp::endpoint &GetTcpEndpoint() const { return fEndpoint; }
-
     void Cmd(FAD::Enable cmd, bool on=true)
     {
+        switch (cmd)
+        {
+        case FAD::kCmdDrsEnable:   fBufEventHeader.Enable(FAD::EventHeader::kDenable,     on);  break;
+        case FAD::kCmdDwrite:      fBufEventHeader.Enable(FAD::EventHeader::kDwrite,      on);  break;
+        case FAD::kCmdTriggerLine: fBufEventHeader.Enable(FAD::EventHeader::kTriggerLine, on);  break;
+        case FAD::kCmdBusy:        fBufEventHeader.Enable(FAD::EventHeader::kBusy,        on);  break;
+        case FAD::kCmdContTrigger: fBufEventHeader.Enable(FAD::EventHeader::kContTrigger, on);  break;
+        case FAD::kCmdSocket:      fBufEventHeader.Enable(FAD::EventHeader::kSock17,      !on); break;
+        default:
+            break;
+        }
+
         PostCmd(cmd + (on ? 0 : 0x100));
     }
@@ -382,4 +404,5 @@
             return false;
 
+        fBufEventHeader.fTriggerGeneratorPrescaler = val;
         PostCmd(FAD::kCmdWriteRate, val);//uint8_t(1000./val/12.5));
         //PostCmd(FAD::kCmdWriteExecute);
@@ -390,4 +413,6 @@
     void CmdSetRunNumber(uint32_t num)
     {
+        fBufEventHeader.fRunNumber = num;
+
         PostCmd(FAD::kCmdWriteRunNumberLSW, num&0xffff);
         PostCmd(FAD::kCmdWriteRunNumberMSW, num>>16);
@@ -403,8 +428,21 @@
     }
 
-    bool CmdSetDacValue(uint8_t addr, uint16_t val)
-    {
-        if (addr>FAD::kMaxDacAddr) // NDAC
+    bool CmdSetDacValue(int8_t addr, uint16_t val)
+    {
+        if (addr<0)
+        {
+            for (unsigned int i=0; i<=FAD::kMaxDacAddr; i++)
+            {
+                fBufEventHeader.fDac[i] = val;
+                PostCmd(FAD::kCmdWriteDac + i, val);
+            }
+            PostCmd(FAD::kCmdWriteExecute);
+            return true;
+        }
+
+        if (uint8_t(addr)>FAD::kMaxDacAddr) // NDAC
             return false;
+
+        fBufEventHeader.fDac[addr] = val;
 
         PostCmd(FAD::kCmdWriteDac + addr, val);
@@ -421,5 +459,8 @@
         {
             for (unsigned int i=0; i<=FAD::kMaxRoiAddr; i++)
+            {
+                fTargetRoi[i] = val;
                 PostCmd(FAD::kCmdWriteRoi + i, val);
+            }
             PostCmd(FAD::kCmdWriteExecute);
             return true;
@@ -429,6 +470,8 @@
             return false;
 
+        fTargetRoi[addr] = val;
+
         PostCmd(FAD::kCmdWriteRoi + addr, val);
-            PostCmd(FAD::kCmdWriteExecute);
+        PostCmd(FAD::kCmdWriteExecute);
         return true;
     }
@@ -536,4 +579,16 @@
     }
 
+    bool IsConfigured() const
+    {
+        bool identical = true;
+        for (int i=0; i<FAD::kNumChannels; i++)
+            if (fTargetRoi[i]!=fChannelHeader[i].fRegionOfInterest)
+            {
+                identical = false;
+                break;
+            }
+
+        return fEventHeader==fBufEventHeader && identical;
+    }
 };
 
@@ -687,11 +742,14 @@
             return T::kSM_FatalError;
 
-        const uint32_t *dat = evt.Ptr<uint32_t>();
-
-        if (!Check(dat, FAD::kMaxDacAddr, FAD::kMaxDacValue))
-            return T::GetCurrentState();
+        const int32_t *dat = evt.Ptr<int32_t>();
 
         for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
-            i->second->CmdSetDacValue(dat[0], dat[1]);
+            if (!i->second->CmdSetDacValue(dat[0], dat[1]))
+            {
+                ostringstream msg;
+                msg << hex << "Channel " << dat[0] << " or Value " << dat[1] << " out of range.";
+                T::Error(msg);
+                return false;
+            }
 
         return T::GetCurrentState();
@@ -1011,4 +1069,53 @@
     }
 
+    int StartConfigure(const EventImp &evt)
+    {
+        const string name = evt.GetText();
+
+        fTargetConfig = fConfigs.find(name);
+        if (fTargetConfig==fConfigs.end())
+        {
+            T::Error("StartConfigure - Run-type '"+name+"' not found.");
+            return T::GetCurrentState();
+        }
+
+        T::Message("Starting configuration for '"+name+"'");
+
+        for (BoardList::iterator it=fBoards.begin(); it!=fBoards.end(); it++)
+        {
+            const FAD::Configuration &conf = fTargetConfig->second;
+
+            ConnectionFAD &fad  = *it->second;
+
+            fad.Cmd(FAD::kCmdTriggerLine, false);
+            fad.Cmd(FAD::kCmdContTrigger, false);
+            fad.Cmd(FAD::kCmdSocket,      true);
+            fad.Cmd(FAD::kCmdBusy,        false);
+
+            fad.Cmd(FAD::kCmdDwrite,      conf.fDenable);
+            fad.Cmd(FAD::kCmdDrsEnable,   conf.fDwrite);
+            fad.Cmd(FAD::kCmdContTrigger, conf.fContinousTrigger);
+
+            for (int i=0; i<FAD::kNumDac; i++)
+                fad.CmdSetDacValue(i, conf.fDac[i]);
+
+            for (int i=0; i<FAD::kNumChips; i++)
+                for (int j=0; j<FAD::kNumChannelsPerChip; j++)
+                    fad.CmdSetRoi(i*FAD::kNumChannelsPerChip+j, conf.fRoi[j]);
+
+            fad.CmdSetTriggerRate(conf.fTriggerRate);
+            fad.CmdSetRunNumber(IncreaseRunNumber());
+            fad.Cmd(FAD::kCmdResetEventCounter);
+            fad.Cmd(FAD::kCmdSingleTrigger);
+        }
+
+        return FAD::kConfiguring;
+    }
+
+    int ResetConfig()
+    {
+        return FAD::kConnected;
+    }
+
     int AddAddress(const EventImp &evt)
     {
@@ -1086,4 +1193,7 @@
                 str << " [data_ignored]";
 
+            if (fStatusC[idx])
+                str << " [configured]";
+
             T::Out() << str.str() << endl;
         }
@@ -1202,4 +1312,5 @@
     vector<uint8_t> fStatus1;
     vector<uint8_t> fStatus2;
+    vector<uint8_t> fStatusC;
     bool            fStatusT;
 
@@ -1220,7 +1331,9 @@
         uint16_t nconnected1  = 0;
         uint16_t nconnected2  = 0;
+        uint16_t nconfigured  = 0;
 
         vector<uint8_t> stat1(40);
         vector<uint8_t> stat2(40);
+        vector<bool>    statC(40);
 
         int cnt = 0; // counter for enabled board
@@ -1251,4 +1364,10 @@
                     stat1[idx] = 2;
                     nconnected1++;
+
+                    if (c->IsConfigured())
+                    {
+                        statC[idx] = 1;
+                        nconfigured++;
+                    }
                 }
 
@@ -1290,7 +1409,39 @@
         // fadctrl:       Always connecting if not disabled
         // event builder:
-        if (nconnecting1==0 && nconnected1>0 &&
-            nconnected2==nconnected1)
-            return FAD::kConnected;
+        if (nconnecting1==0 && nconnected1>0 && nconnected2==nconnected1)
+        {
+            if (nconfigured!=nconnected1)
+            {
+                if (T::GetCurrentState()==FAD::kConfiguring ||
+                    T::GetCurrentState()==FAD::kConfigured)
+                    // Stay in Configured until at least one new
+                    // event has been received
+                    return T::GetCurrentState();
+
+                return FAD::kConnected;
+            }
+
+            if (T::GetCurrentState() != FAD::kConfiguring &&
+                T::GetCurrentState() != FAD::kConfigured)
+                return FAD::kConnected;
+
+            if (T::GetCurrentState()== FAD::kConfiguring)
+            {
+                for (BoardList::iterator it=fBoards.begin(); it!=fBoards.end(); it++)
+                {
+                    //const Configuration &conf = fTargetConfig->second;
+
+                    ConnectionFAD &fad  = *it->second;
+
+                    fad.Cmd(FAD::kCmdResetEventCounter);
+                    fad.Cmd(FAD::kCmdSocket,      false);
+                    fad.Cmd(FAD::kCmdTriggerLine, true);
+
+                    // FIXME: How do we find out when the FADs
+                    //        successfully enabled the trigger lines?
+                }
+            }
+            return FAD::kConfigured;
+        }
 
         if (nconnecting1>0 || nconnecting2>0 || nconnected1!=nconnected2)
@@ -1347,5 +1498,5 @@
     StateMachineFAD(ostream &out=cout) :
         T(out, "FAD_CONTROL"), EventBuilderWrapper(*static_cast<MessageImp*>(this)), ba::io_service::work(static_cast<ba::io_service&>(*this)),
-        fStatus1(40), fStatus2(40), fStatusT(false),
+        fStatus1(40), fStatus2(40), fStatusC(40), fStatusT(false),
         fDimConnection("FAD_CONTROL/CONNECTIONS", "C:40;C:1", "")
     {
@@ -1369,4 +1520,10 @@
         T::AddStateName(FAD::kConnected, "Connected",
                         "All enabled FAD boards are connected..");
+
+        T::AddStateName(FAD::kConfiguring, "Configuring",
+                        ".");
+
+        T::AddStateName(FAD::kConfigured, "Configured",
+                        "The last header received through the command socket fits the requested configureation and has EventCounter==0.");
 
         // FAD Commands
@@ -1425,6 +1582,6 @@
             ("Adjust ADC phase (in 'steps')");
 
-        T::AddEvent("RESET_TRIGGER_ID")
-            (boost::bind(&StateMachineFAD::Cmd, this, FAD::kCmdResetTriggerId))
+        T::AddEvent("RESET_EVENT_COUNTER")
+            (boost::bind(&StateMachineFAD::Cmd, this, FAD::kCmdResetEventCounter))
             ("");
 
@@ -1455,6 +1612,14 @@
             (boost::bind(&StateMachineFAD::SetDac, this, _1))
             ("Set DAC numbers in range to value"
-            "|addr[short]:Address of register"
+            "|addr[short]:Address of register (-1 for all)"
             "|val[short]:Value to be set");
+
+        T::AddEvent("CONFIGURE", "C", FAD::kConnected)
+            (boost::bind(&StateMachineFAD::StartConfigure, this, _1))
+            ("");
+
+        T::AddEvent("RESET_CONFIGURE", FAD::kConfiguring)
+            (boost::bind(&StateMachineFAD::ResetConfig, this))
+            ("");
 
         // Verbosity commands
@@ -1618,6 +1783,33 @@
     }
 
+    typedef map<string, FAD::Configuration> Configs;
+    Configs fConfigs;
+    Configs::const_iterator fTargetConfig;
+
+
+    template<class V>
+    bool CheckConfigVal(const Configuration &conf, V max, const string &name, const string &sub)
+    {
+        if (!conf.HasDef(name, sub))
+        {
+            T::Error("Neither "+name+"default nor "+name+sub+" found.");
+            return false;
+        }
+
+        const V val = conf.GetDef<V>(name, sub);
+
+        if (val<=max)
+            return true;
+
+        ostringstream str;
+        str << name << sub << "=" << val << " exceeds allowed maximum of " << max << "!";
+        T::Error(str);
+
+        return false;
+    }
+
     int EvalConfiguration(const Configuration &conf)
     {
+        // ---------- General setup ---------
         fIsVerbose = !conf.Get<bool>("quiet");
         fIsHexOutput = conf.Get<bool>("hex-out");
@@ -1625,7 +1817,79 @@
         fDebugTx = conf.Get<bool>("debug-tx");
 
+        // ---------- Setup event builder ---------
         SetMaxMemory(conf.Get<unsigned int>("max-mem"));
 
-        // vvvvv for debugging vvvvv
+        // ---------- Setup run types ---------
+        const vector<string> types = conf.Vec<string>("run-type");
+        if (types.size()==0)
+            T::Warn("No run-types defined.");
+        else
+            T::Message("Defining run-types");
+        for (vector<string>::const_iterator it=types.begin();
+             it!=types.end(); it++)
+        {
+            T::Message(" -> "+ *it);
+
+            if (fConfigs.count(*it)>0)
+            {
+                T::Error("Run-type "+*it+" defined twice.");
+                return 1;
+            }
+
+            FAD::Configuration target;
+
+            if (!CheckConfigVal<bool>(conf, true, "enable-drs.",               *it) ||
+                !CheckConfigVal<bool>(conf, true, "enable-dwrite.",            *it) ||
+                !CheckConfigVal<bool>(conf, true, "enable-continous-trigger.", *it))
+                return 2;
+
+            target.fDenable          = conf.GetDef<bool>("enable-drs.", *it);
+            target.fDwrite           = conf.GetDef<bool>("enable-dwrite.", *it);
+            target.fContinousTrigger = conf.GetDef<bool>("enable-continous-trigger.", *it);
+
+            target.fTriggerRate = 0;
+            if (target.fContinousTrigger)
+            {
+                if (!CheckConfigVal<uint16_t>(conf, 0xffff, "trigger-rate.", *it))
+                    return 3;
+
+                target.fTriggerRate = conf.GetDef<uint16_t>("trigger-rate.", *it);
+            }
+
+            for (int i=0; i<FAD::kNumChannelsPerChip; i++)
+            {
+                ostringstream str;
+                str << "roi-ch" << i << '.';
+
+                if (!CheckConfigVal<uint16_t>(conf, FAD::kMaxRoiValue, "roi.",    *it) &&
+                    !CheckConfigVal<uint16_t>(conf, FAD::kMaxRoiValue, str.str(), *it))
+                    return 4;
+
+                target.fRoi[i] = conf.HasDef(str.str(), *it) ?
+                    conf.GetDef<uint16_t>(str.str(), *it) :
+                    conf.GetDef<uint16_t>("roi.",    *it);
+            }
+
+            for (int i=0; i<FAD::kNumDac; i++)
+            {
+                ostringstream str;
+                str << "dac-" << i << '.';
+
+                if (!CheckConfigVal<uint16_t>(conf, FAD::kMaxDacValue, "dac.",    *it) &&
+                    !CheckConfigVal<uint16_t>(conf, FAD::kMaxDacValue, str.str(), *it))
+                    return 5;
+
+                target.fDac[i] = conf.HasDef(str.str(), *it) ?
+                    conf.GetDef<uint16_t>(str.str(), *it) :
+                    conf.GetDef<uint16_t>("dac.",    *it);
+            }
+
+            fConfigs[*it] = target;
+        }
+
+        // FIXME: Add a check about unsused configurations
+
+        // ---------- Setup board addresses for fake-fad ---------
+
         if (conf.Has("debug-addr"))
         {
@@ -1643,5 +1907,6 @@
             return -1;
         }
-        // ^^^^^ for debugging ^^^^^
+
+        // ---------- Setup board addresses for the real camera ---------
 
         if (conf.Has("base-addr"))
@@ -1654,5 +1919,5 @@
             const tcp::endpoint endpoint = GetEndpoint(base);
             if (endpoint==tcp::endpoint())
-                return 1;
+                return 10;
 
             const ba::ip::address_v4::bytes_type ip = endpoint.address().to_v4().to_bytes();
@@ -1661,5 +1926,5 @@
             {
                 T::Out() << kRed << "EvalConfiguration - IP address given by --base-addr out-of-range." << endl;
-                return 3;
+                return 11;
             }
 
@@ -1679,4 +1944,6 @@
         }
 
+        // ---------- Setup board addresses one by one ---------
+
         if (conf.Has("addr"))
         {
@@ -1686,5 +1953,5 @@
                 const tcp::endpoint endpoint = GetEndpoint(*i);
                 if (endpoint==tcp::endpoint())
-                    return 1;
+                    return 12;
 
                 AddEndpoint(endpoint);
@@ -1812,9 +2079,4 @@
         ;
 
-    po::options_description builder("Event builder options");
-    builder.add_options()
-        ("max-mem,m",  var<unsigned int>(100), "Maximum memory the event builder thread is allowed to consume for its event buffer")
-        ;
-
     po::options_description connect("FAD connection options");
     connect.add_options()
@@ -1825,10 +2087,45 @@
         ;
 
+    po::options_description builder("Event builder options");
+    builder.add_options()
+        ("max-mem,m",  var<unsigned int>(100), "Maximum memory the event builder thread is allowed to consume for its event buffer")
+        ;
+
+
+    po::options_description runtype("Run type configuration");
+    runtype.add_options()
+        ("run-type",                     vars<string>(),        "")
+        ("enable-dwrite.*",              var<bool>(),           "")
+        ("enable-drs.*",                 var<bool>(),           "")
+        ("enable-continous-trigger.*",   var<bool>(),           "")
+        ("trigger-rate.*",               var<uint16_t>(),       "")
+        ("dac.*",                        var<uint16_t>(),       "")
+        ("dac-0.*",                      var<uint16_t>(),       "")
+        ("dac-1.*",                      var<uint16_t>(),       "")
+        ("dac-2.*",                      var<uint16_t>(),       "")
+        ("dac-3.*",                      var<uint16_t>(),       "")
+        ("dac-4.*",                      var<uint16_t>(),       "")
+        ("dac-5.*",                      var<uint16_t>(),       "")
+        ("dac-6.*",                      var<uint16_t>(),       "")
+        ("dac-7.*",                      var<uint16_t>(),       "")
+        ("roi.*",                        var<uint16_t>(),       "")
+        ("roi-ch0.*",                    var<uint16_t>(),       "")
+        ("roi-ch1.*",                    var<uint16_t>(),       "")
+        ("roi-ch2.*",                    var<uint16_t>(),       "")
+        ("roi-ch3.*",                    var<uint16_t>(),       "")
+        ("roi-ch4.*",                    var<uint16_t>(),       "")
+        ("roi-ch5.*",                    var<uint16_t>(),       "")
+        ("roi-ch6.*",                    var<uint16_t>(),       "")
+        ("roi-ch7.*",                    var<uint16_t>(),       "")
+        ("roi-ch8.*",                    var<uint16_t>(),       "")
+        ;
+
     conf.AddEnv("dns", "DIM_DNS_NODE");
 
     conf.AddOptions(config);
     conf.AddOptions(control);
+    conf.AddOptions(connect);
     conf.AddOptions(builder);
-    conf.AddOptions(connect);
+    conf.AddOptions(runtype);
 }
 
