Index: /trunk/FACT++/src/smartfact.cc
===================================================================
--- /trunk/FACT++/src/smartfact.cc	(revision 13931)
+++ /trunk/FACT++/src/smartfact.cc	(revision 13932)
@@ -22,4 +22,10 @@
 #include "HeadersBIAS.h"
 #include "HeadersFTM.h"
+#include "HeadersFSC.h"
+#include "HeadersMCP.h"
+#include "HeadersDrive.h"
+#include "HeadersRateScan.h"
+#include "HeadersRateControl.h"
+#include "HeadersMagicWeather.h"
 
 #include <boost/filesystem.hpp>
@@ -364,5 +370,7 @@
     deque<float> fDriveControlTrackingDevHist;
 
-    int64_t fFadControlNumEvents;
+     int64_t fFadControlNumEvents;
+     int32_t fFadControlDrsStep;
+    uint32_t fFadControlDrsRuns[3];
 
     float  fFtmControlTriggerRateCam;
@@ -402,4 +410,7 @@
     bool CheckDataSize(const EventImp &d, const char *name, size_t size, bool min=false)
     {
+        if (d.GetSize()==0)
+            return false;
+
         if ((!min && d.GetSize()==size) || (min && d.GetSize()>size))
             return true;
@@ -878,5 +889,5 @@
         }
 
-        if (fDimBiasControl.state()==BIAS::kVoltageOn)
+        if (fDimBiasControl.state()==BIAS::State::kVoltageOn)
             WriteBinary(d, "biascontrol-voltage", val, 10, 65);
         else
@@ -1019,4 +1030,21 @@
 
         fFadControlNumEvents = d.Get<uint32_t>();
+
+        return GetCurrentState();
+    }
+
+    int HandleFadDrsRuns(const EventImp &d)
+    {
+        if (!CheckDataSize(d, "FadControl:DrsRuns", 4*4))
+        {
+            fFadControlDrsStep = -1;
+            return GetCurrentState();
+        }
+
+        const uint32_t *ptr = d.Ptr<uint32_t>();
+        fFadControlDrsStep    = ptr[0];
+        fFadControlDrsRuns[0] = ptr[1];
+        fFadControlDrsRuns[1] = ptr[2];
+        fFadControlDrsRuns[2] = ptr[3];
 
         return GetCurrentState();
@@ -1467,5 +1495,5 @@
 
         if (&state==&fDimControl)
-            return kHtmlGreen +'\t'+(state.state()==-3?"Idle":fDimControl.shortmsg)+'\n';
+            return kHtmlGreen +'\t'+(state.state()<-2?"Idle":fDimControl.shortmsg)+'\n';
 
         const State rc = state.description();
@@ -1515,21 +1543,24 @@
         if (fDimDriveControl.state()>0xff)
             msg << "Drive in ERROR state<br/>";
-        if (fDimBiasControl.state()<BIAS::kRamping && (fDimMcp.state()==11 || fDimMcp.state()==12))
+        if (fDimBiasControl.state()<BIAS::State::kRamping && (fDimMcp.state()==MCP::State::kTriggerOn || fDimMcp.state()==MCP::State::kTakingData))
             msg << "BIAS not operating during data-taking<br/>";
-        if (fDimBiasControl.state()==BIAS::kOverCurrent)
+        if (fDimBiasControl.state()==BIAS::State::kOverCurrent)
             msg << "BIAS channels in OverCurrent<br/>";
-        if (fDimBiasControl.state()==BIAS::kNotReferenced)
+        if (fDimBiasControl.state()==BIAS::State::kNotReferenced)
             msg << "BIAS voltage not at reference<br/>";
-        if (fBiasControlCurrentMed>75)
-            msg << "Median current exceeds 75&micro;A/pix<br/>";
-        if (fBiasControlCurrentMax>90)
-            msg << "Maximum current exceeds 90&micro;A/pix<br/>";
-        if (fMagicWeatherHist[kHum].size()>0 && fMagicWeatherHist[kHum].back()>98 && (fDimMcp.state()==11 || fDimMcp.state()==12))
+        if (fFeedbackCalibration.size()>0)
+        {
+            if (fBiasControlCurrentMed>75)
+                msg << "Median current exceeds 75&micro;A/pix<br/>";
+            if (fBiasControlCurrentMax>90)
+                msg << "Maximum current exceeds 90&micro;A/pix<br/>";
+        }
+        if (fMagicWeatherHist[kHum].size()>0 && fMagicWeatherHist[kHum].back()>98 && (fDimMcp.state()==MCP::State::kTriggerOn || fDimMcp.state()==MCP::State::kTakingData))
             msg << "Outside humidity exceeds 98% during data-taking<br/>";
-        if (fMagicWeatherHist[kGusts].size()>0 && fMagicWeatherHist[kGusts].back()>98 && fDimDriveControl.state()==7)
+        if (fMagicWeatherHist[kGusts].size()>0 && fMagicWeatherHist[kGusts].back()>98 && fDimDriveControl.state()==Drive::State::kTracking)
             msg << "Wind gusts exceed 50km/h during tracking<br/>";
         if (fFscControlTemperatureHist.size()>0 && fFscControlTemperatureHist.back()>7)
             msg << "Sensor temperature exceeds outside temperature by more than 7&deg;C<br/>";
-        if (fFtmControlTriggerRateCam<0.01 && (fDimMcp.state()==11 || fDimMcp.state()==12))
+        if (fFtmControlTriggerRateCam<0.01 && (fDimMcp.state()==MCP::State::kTriggerOn || fDimMcp.state()==MCP::State::kTakingData))
             msg << "Trigger rate below 10mHz during data taking<br/>";
         if (fFscControlHumidityAvg>60)
@@ -1537,4 +1568,10 @@
         if (!fDimControl.online())
             msg << "dimctrl offline<br/>";
+
+        if (!fDimFeedback.state()==Feedback::State::kCalibrating &&
+            fDimBias.state()==BIAS::State::kVoltageOn &&
+            fBiasControlVoltageMed>3 &&
+            fFeedbackCalibration.size()==0)
+            msg << "bias voltage switched on, but bias crate not calibrated.";
 
         // FTM in Connected instead of Idle --> power cyclen
@@ -1583,18 +1620,19 @@
 
         // -------------- System status --------------
-        if (fDimMcp.state()>=5) // Idle
+        if (fDimMcp.state()>=MCP::State::kIdle) // Idle
         {
             string col = kHtmlBlue;
-            if (fMcpConfigurationState!= 5 &&  // Idle
-                fMcpConfigurationState!=11 &&  // Trigger On
-                fMcpConfigurationState!=12)    // Taking Data
+            if (fMcpConfigurationState!=MCP::State::kIdle &&       // Idle
+                fMcpConfigurationState!=MCP::State::kTriggerOn &&  // Trigger On
+                fMcpConfigurationState!=MCP::State::kTakingData)  // Taking Data
                 col = kHtmlYellow;
             else
-                if (fDimFadControl.state()==FAD::kWritingData)
+                if (fDimFadControl.state()==FAD::State::kWritingData)
                     col = kHtmlGreen;
 
             out << col << '\t';
 
-            if (fDimRateControl.state()!=5 && fDimRateScan.state()!=6)
+            if (fDimRateControl.state()!=RateControl::State::kSettingGlobalThreshold &&
+                fDimRateScan.state()!=RateScan::State::kInProgress)
             {
                 switch (fMcpConfigurationState)
@@ -1614,50 +1652,62 @@
             }
             else
-                if (fDimRateControl.state()==5/*kStateSettingGlobalThreshold*/)
+                if (fDimRateControl.state()==RateControl::State::kSettingGlobalThreshold)
                     out << "Calibrating threshold";
                 else
-                    if (fDimRateScan.state()==6/*kStateSettingGlobalThreshold*/)
+                    if (fDimRateScan.state()==RateScan::State::kInProgress)
                         out << "Rate scan in progress";
 
-            if (fMcpConfigurationState>10 && fDimRateControl.state()!=5)
+            if (fMcpConfigurationState>MCP::State::kConfigured &&
+                fDimRateControl.state()!=RateControl::State::kSettingGlobalThreshold)
             {
-                if (fMcpConfigurationMaxEvents>0 || fMcpConfigurationMaxTime>0 || fMcpConfigurationState==12)
-                    out << " [";
+                ostringstream evt;
                 if (fMcpConfigurationMaxEvents>0)
                 {
-                    if (fFadControlNumEvents>0 && fMcpConfigurationState==12)
-                        out << fMcpConfigurationMaxEvents-fFadControlNumEvents;
+                    const int64_t de = int64_t(fMcpConfigurationMaxEvents) - int64_t(fFadControlNumEvents);
+                    if (de>=0 && fMcpConfigurationState==MCP::State::kTakingData)
+                        evt << de;
                     else
-                        out << fMcpConfigurationMaxEvents;
-                }
-                if (fMcpConfigurationMaxEvents>0 && (fMcpConfigurationMaxTime>0 || fMcpConfigurationState==12))
-                    out << '/';
-                if (fMcpConfigurationMaxTime>0)
-                {
-                    if (fMcpConfigurationState==12)
-                    {
-
-                        const uint32_t dt = (Time()-fMcpConfigurationRunStart).total_seconds();
-                        if (dt>fMcpConfigurationMaxTime)
-                            out << "---";
-                        else
-                            out << fMcpConfigurationMaxTime-dt << 's';
-                    }
-                    else
-                        out << fMcpConfigurationMaxTime << 's';
+                        evt << fMcpConfigurationMaxEvents;
                 }
                 else
                 {
-                    if (fMcpConfigurationState==12)
+                    if (fMcpConfigurationState==MCP::State::kTakingData)
+                        evt << fFadControlNumEvents;
+                }
+
+                ostringstream tim;
+                if (fMcpConfigurationMaxTime>0)
+                {
+                    const uint32_t dt = (Time()-fMcpConfigurationRunStart).total_seconds();
+                    if (dt<=fMcpConfigurationMaxTime && fMcpConfigurationState==MCP::State::kTakingData)
+                        tim << fMcpConfigurationMaxTime-dt << 's';
+                    else
+                        tim << fMcpConfigurationMaxTime << 's';
+                }
+                else
+                {
+                    if (fMcpConfigurationState==MCP::State::kTakingData)
                     {
                         ostringstream d;
                         d << Time()-fMcpConfigurationRunStart;
-                        out << d.str().substr(3, 5);
+                        tim << d.str().substr(3, 5);
                     }
                 }
 
-                if (fMcpConfigurationMaxEvents>0 || fMcpConfigurationMaxTime>0 || fMcpConfigurationState==12)
+                const bool has_evt = !evt.str().empty();
+                const bool has_tim = !tim.str().empty();
+
+                if (has_evt || has_tim)
+                    out << " [";
+                out << evt.str();
+                if (has_evt && has_tim)
+                    out << '/';
+                out << tim.str();
+                if (has_evt || has_tim)
                     out << ']';
             }
+
+            if (fFadControlDrsRuns[2]>0)
+                out << " (" << fFadControlDrsRuns[2] << ")";
         }
         else
@@ -1666,5 +1716,5 @@
 
         // ------------------ Drive -----------------
-        if (fDimDriveControl.state()>=5)   // Armed, Moving, Tracking
+        if (fDimDriveControl.state()>=Drive::State::kArmed)   // Armed, Moving, Tracking
         {
             const double dev = fDriveControlTrackingDevHist.size()>0 ? fDriveControlTrackingDevHist.back() : 0;
@@ -1701,5 +1751,5 @@
 
         // ------------------- FSC ------------------
-        if (fDimFscControl.state()>1 && fFscControlTemperatureHist.size()>0)
+        if (fDimFscControl.state()>FSC::State::kDisconnected && fFscControlTemperatureHist.size()>0)
         {
             out << kHtmlGreen << '\t' << fFscControlTemperatureHist.back() << '\n';
@@ -1709,5 +1759,5 @@
 
         // --------------- MagicWeather -------------
-        if (fDimMagicWeather.state()==3 && fMagicWeatherHist[kWeatherBegin].size()>0)
+        if (fDimMagicWeather.state()==MagicWeather::State::kReceiving && fMagicWeatherHist[kWeatherBegin].size()>0)
         {
             /*
@@ -1738,5 +1788,5 @@
 
         // --------------- FtmControl -------------
-        if (fDimFtmControl.state()==FTM::kTriggerOn)
+        if (fDimFtmControl.state()==FTM::State::kTriggerOn)
         {
             string col = kHtmlGreen;
@@ -1752,11 +1802,11 @@
 
         // --------------- BiasControl -------------
-        if (fDimBiasControl.state()==BIAS::kRamping     ||
-            fDimBiasControl.state()==BIAS::kOverCurrent ||
-            fDimBiasControl.state()==BIAS::kVoltageOn   ||
-            fDimBiasControl.state()==BIAS::kVoltageOff)
-        {
-            const bool off = fDimBiasControl.state()==BIAS::kVoltageOff;
-            const bool oc  = fDimBiasControl.state()==BIAS::kOverCurrent;
+        if (fDimBiasControl.state()==BIAS::State::kRamping     ||
+            fDimBiasControl.state()==BIAS::State::kOverCurrent ||
+            fDimBiasControl.state()==BIAS::State::kVoltageOn   ||
+            fDimBiasControl.state()==BIAS::State::kVoltageOff)
+        {
+            const bool off = fDimBiasControl.state()==BIAS::State::kVoltageOff;
+            const bool oc  = fDimBiasControl.state()==BIAS::State::kOverCurrent;
 
             string col = fBiasControlVoltageMed>3?kHtmlGreen:kHtmlWhite;
@@ -1767,12 +1817,12 @@
 
             // Bias in overcurrent => Red
-            if (fDimBiasControl.state()==BIAS::kOverCurrent)
+            if (fDimBiasControl.state()==BIAS::State::kOverCurrent)
                 col = kHtmlRed;
 
             // MCP in ReadyForDatataking/Configuring/Configured/TriggerOn/TakingData
             // and Bias not in "data-taking state' => Red
-            if (fMcpConfigurationState>5 &&
-                fDimBiasControl.state()!=BIAS::kVoltageOn &&
-                fDimBiasControl.state()!=BIAS::kVoltageOff)
+            if (fMcpConfigurationState>MCP::State::kIdle &&
+                fDimBiasControl.state()!=BIAS::State::kVoltageOn &&
+                fDimBiasControl.state()!=BIAS::State::kVoltageOff)
                 col = kHtmlRed;
 
@@ -1828,7 +1878,7 @@
             out << GetStateHtml(fDimDataLogger,   1);
             out << GetStateHtml(fDimDriveControl, 2);
-            out << GetStateHtml(fDimFadControl,   FAD::kConnected);
-            out << GetStateHtml(fDimFtmControl,   FTM::kConnected);
-            out << GetStateHtml(fDimBiasControl,  BIAS::kConnected);
+            out << GetStateHtml(fDimFadControl,   FAD::State::kConnected);
+            out << GetStateHtml(fDimFtmControl,   FTM::State::kConnected);
+            out << GetStateHtml(fDimBiasControl,  BIAS::State::kConnected);
             out << GetStateHtml(fDimFeedback,     4);
             out << GetStateHtml(fDimRateControl,  4);
@@ -1934,4 +1984,6 @@
         Subscribe("FAD_CONTROL/EVENTS")
             (bind(&StateMachineSmartFACT::HandleFadEvents,           this, placeholders::_1));
+        Subscribe("FAD_CONTROL/DRS_RUNS")
+            (bind(&StateMachineSmartFACT::HandleFadDrsRuns,          this, placeholders::_1));
 
         Subscribe("FTM_CONTROL/TRIGGER_RATES")
