Index: trunk/FACT++/src/smartfact.cc
===================================================================
--- trunk/FACT++/src/smartfact.cc	(revision 13850)
+++ trunk/FACT++/src/smartfact.cc	(revision 13872)
@@ -334,4 +334,7 @@
     deque<float> fMagicWeatherHist[kWeatherEnd];
 
+    deque<float> fTngWeatherDustHist;
+    Time  fTngWeatherDustTime;
+
     vector<float> fFeedbackCalibration;
 
@@ -361,5 +364,5 @@
     deque<float> fFtmControlTriggerRateHist;
 
-    vector<float> fFtmPatchThresholds;
+    float fFtmPatchThresholdMed;
 
     bool fFtmControlFtuOk;
@@ -368,4 +371,6 @@
     uint8_t   fRateScanBoard;
     deque<float> fRateScanDataHist[41];
+
+    bool fHasError;
 
     // ------------- Initialize variables before the Dim stuff ------------
@@ -377,4 +382,5 @@
     DimDescribedState fDimDriveControl;
     DimDescribedState fDimMagicWeather;
+    DimDescribedState fDimTngWeather;
     DimDescribedState fDimFeedback;
     DimDescribedState fDimBiasControl;
@@ -475,6 +481,13 @@
             return;
 
-        const string str  = fControlMessageHist.size()>0 ? fControlMessageHist.back() : "         ";
         const string time = d.GetTimeAsStr("%H:%M:%S ");
+
+        string str = "         ";
+        for (auto it=fControlMessageHist.rbegin(); it!=fControlMessageHist.rend(); it++)
+        {
+            str = it->substr(0, time.length());
+            if (str!="--:--:-- ")
+                break;
+        }
 
         ostringstream tst;
@@ -482,5 +495,5 @@
 
         string msg;
-        msg += str.substr(0, time.length())==time ? "--:--:-- " : time;
+        msg += str==time ? "--:--:-- " : time;
         msg += "<->"+string(d.Ptr<char>())+"</->";
 
@@ -497,5 +510,5 @@
         out << '\n';
 
-        ofstream(fPath+"/test.txt") << out.str();
+        ofstream(fPath+"/scriptlog.txt") << out.str();
     }
 
@@ -514,5 +527,11 @@
 
         if (d.GetQoS()<0)
-            HandleControlMessageImp(d);
+        {
+            DimControl ctrl;
+            ctrl.Handler(d);
+
+            const string msg = ctrl.shortmsg+"<br>"+ctrl.file;
+            HandleControlMessageImp(Event(d, msg.data(), msg.length()+1));
+        }
     }
 
@@ -595,6 +614,11 @@
             out << "#ffffff\t" << fMagicWeatherHist[i].back() << '\n';
         out << "#ffffff\t" << dir[idx] << '\n';
-
-        ofstream(fPath+"/magicweather.txt") << out.str();
+        out << "#ffffff\t";
+        if (fTngWeatherDustHist.size()>0)
+            out << fTngWeatherDustHist.back() << '\t' << fTngWeatherDustTime.GetAsStr("%H:%M") << '\n';
+        else
+            out << "\t\n";
+
+        ofstream(fPath+"/weather.txt") << out.str();
 
         out.str("");
@@ -613,4 +637,5 @@
         out << kHtmlWhite << '\t' << moon.fMoonTransit.GetAsStr("%H:%M") << '\n';
         out << kHtmlWhite << '\t' << moon.fMoonSet.GetAsStr("%H:%M") << '\n';
+        out << kHtmlWhite << '\t';
 
         ofstream(fPath+"/astro.txt") << out.str();
@@ -622,4 +647,29 @@
         WriteWeather(d, "gusts", kGusts,   0,  100);
         WriteWeather(d, "press", kPress, 700, 1000);
+
+        return GetCurrentState();
+    }
+
+    int HandleTngWeatherDust(const EventImp &d)
+    {
+        if (!CheckDataSize(d, "TngWeather:Dust", 4))
+            return GetCurrentState();
+
+        fTngWeatherDustTime = d.GetTime();
+
+        fTngWeatherDustHist.push_back(d.GetFloat());
+        if (fTngWeatherDustHist.size()>300)
+                fTngWeatherDustHist.pop_front();
+
+        const Statistics stat(fTngWeatherDustHist);
+
+        const double scale = stat.max>0 ? pow(10, ceil(log10(stat.max))) : 0;
+
+        WriteBinary(d, "tng-dust-hist", fTngWeatherDustHist, scale);
+
+        ostringstream out;
+        out << d.GetJavaDate() << '\n';
+
+        ofstream(fPath+"/tngdust.txt") << out.str();
 
         return GetCurrentState();
@@ -763,5 +813,5 @@
     int HandleFeedbackDeviation(const EventImp &d)
     {
-        if (!CheckDataSize(d, "Feedback:Deviation", 2*4*416+8))
+        if (!CheckDataSize(d, "Feedback:Deviation", (2*416+2)*4))
             return GetCurrentState();
 
@@ -1079,4 +1129,6 @@
 
         const Statistics stat(vec);
+
+        fFtmPatchThresholdMed = stat.med;
 
         ostringstream out;
@@ -1267,17 +1319,19 @@
         }
 
+        // Cycle by time!
         fRateScanBoard ++;
         fRateScanBoard %= 40;
 
         WriteBinary(d, "ratescan-hist",  fRateScanDataHist[0],                10, -2);
-        WriteBinary(d, "ratescan-board", fRateScanDataHist[fRateScanBoard+1], 10, -2);
+        WriteBinary(d, "ratescan-board", fRateScanDataHist[fRateScanBoard+1], 10, -4);
 
         ostringstream out;
         out << setprecision(3);
         out << d.GetJavaDate() << '\n';
+        out << "#ffffff\t" << fFtmPatchThresholdMed << '\n';
         out << "#ffffff\t" << pow(10, fRateScanDataHist[0].back()) << '\n';
         out << "#ffffff\t" << max << '\n';
 
-        ofstream(fPath+"/ratecan.txt") << out.str();
+        ofstream(fPath+"/ratescan.txt") << out.str();
 
         out.str("");
@@ -1286,5 +1340,5 @@
         out << "#ffffff\t" << pow(10, fRateScanDataHist[fRateScanBoard+1].back()) << '\n';
 
-        ofstream(fPath+"/ratecan_board.txt") << out.str();
+        ofstream(fPath+"/ratescan_board.txt") << out.str();
 
         return GetCurrentState();
@@ -1296,5 +1350,5 @@
     {
         ostringstream out;
-        out << d.GetJavaDate() << '\t' << fDimControl.online() << '\n';
+        out << d.GetJavaDate() << '\t' << fHasError << '\n';
         switch (d.GetQoS())
         {
@@ -1335,4 +1389,5 @@
         Out() << fDimFscControl   << endl;
         Out() << fDimMagicWeather << endl;
+        Out() << fDimTngWeather   << endl;
         Out() << fDimRateScan     << endl;
         Out() << fDimChatServer   << endl;
@@ -1347,9 +1402,5 @@
 
         if (&state==&fDimControl)
-        {
-            ostringstream out;
-            out << kHtmlGreen << '\t';
-            return kHtmlGreen+'\t'+(state.state()==-3?"Idle":state.msg)+'\n';
-        }
+            return kHtmlGreen +'\t'+(state.state()==-3?"Idle":fDimControl.shortmsg)+'\n';
 
         const State rc = state.description();
@@ -1392,6 +1443,70 @@
         fLastUpdate=now;
 
+        // ==============================================================
+
+        ostringstream msg;
+
+        if (fDimDriveControl.state()>0xff)
+            msg << "Drive in ERROR state<br/>";
+        if (fDimBiasControl.state()<BIAS::kRamping && (fDimMcp.state()==11 || fDimMcp.state()==12))
+            msg << "BIAS not operating during data-taking<br/>";
+        if (fDimBiasControl.state()==BIAS::kOverCurrent)
+            msg << "BIAS channels in OverCurrent<br/>";
+        if (fDimBiasControl.state()==BIAS::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))
+            msg << "Outside humidity exceeds 98% during data-taking<br/>";
+        if (fMagicWeatherHist[kGusts].size()>0 && fMagicWeatherHist[kGusts].back()>98 && fDimDriveControl.state()==7)
+            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))
+            msg << "Trigger rate below 10mHz during data taking<br/>";
+        if (fFscControlHumidityAvg>60)
+            msg << "Average camera humidity exceed 60%<br/>";
+        if (!fDimControl.online())
+            msg << "dimctrl offline<br/>";
+
+        /* // Check offline and disconnected status?
+          Out() << fDimMcp          << endl;
+          Out() << fDimControl      << endl;
+          Out() << fDimDataLogger   << endl;
+          Out() << fDimDriveControl << endl;
+          Out() << fDimFadControl   << endl;
+          Out() << fDimFtmControl   << endl;
+          Out() << fDimBiasControl  << endl;
+          Out() << fDimFeedback     << endl;
+          Out() << fDimRateControl  << endl;
+          Out() << fDimFscControl   << endl;
+          Out() << fDimMagicWeather << endl;
+          Out() << fDimRateScan     << endl;
+          Out() << fDimChatServer   << endl;
+          */
+
+        // FTU in error
+        // FAD lost
+
+        // --------------------------------------------------------------
+
+        const bool haserror = msg.str().size()>0;
+
         ostringstream out;
-        out << now.JavaDate() << '\t' << fDimControl.online() << '\n';
+        out << now.JavaDate() << '\t' << haserror << '\n';
+        out << setprecision(3);
+        out << kHtmlWhite << '\t' << msg.str() << '\n';
+
+        if (haserror || fHasError)
+            ofstream(fPath+"/error.txt") << out.str();
+
+        fHasError = haserror;
+
+        // ==============================================================
+
+        out.str("");
+        out << now.JavaDate() << '\t' << fHasError << '\n';
         out << setprecision(3);
 
@@ -1623,13 +1738,10 @@
             out << kHtmlWhite << '\n';
 
-
-        // ------------------------------------------
-
         ofstream(fPath+"/fact.txt") << out.str();
 
-        // ==========================================
+        // ==============================================================
 
         out.str("");
-        out << now.JavaDate() << '\t' << fDimControl.online() << '\n';
+        out << now.JavaDate() << '\t' << fHasError << '\n';
 
         if (!fDimDNS.online())
@@ -1639,6 +1751,6 @@
             out << kHtmlGreen << '\t' << fDimDNS.version() << '\n';
 
+            out << GetStateHtml(fDimControl,      0);
             out << GetStateHtml(fDimMcp,          4);
-            out << GetStateHtml(fDimControl,      0);
             out << GetStateHtml(fDimDataLogger,   1);
             out << GetStateHtml(fDimDriveControl, 2);
@@ -1650,4 +1762,5 @@
             out << GetStateHtml(fDimFscControl,   2);
             out << GetStateHtml(fDimMagicWeather, 2);
+            out << GetStateHtml(fDimTngWeather,   2);
             out << GetStateHtml(fDimRateScan,     4);
             out << GetStateHtml(fDimChatServer,   1);
@@ -1665,9 +1778,13 @@
         fMcpConfigurationMaxTime(0),
         fMcpConfigurationMaxEvents(0),
+        fTngWeatherDustTime(Time::none),
         fBiasControlVoltageMed(0),
+        fBiasControlCurrentMed(0),
         fBiasControlCurrentMax(0),
         fFscControlHumidityAvg(0),
+        fFtmControlTriggerRateCam(0),
         fRateScanDataId(0),
         fRateScanBoard(0),
+        fHasError(false),
         // ---
         fDimMcp         ("MCP"),
@@ -1675,4 +1792,5 @@
         fDimDriveControl("DRIVE_CONTROL"),
         fDimMagicWeather("MAGIC_WEATHER"),
+        fDimTngWeather  ("TNG_WEATHER"),
         fDimFeedback    ("FEEDBACK"),
         fDimBiasControl ("BIAS_CONTROL"),
@@ -1690,4 +1808,5 @@
         fDimDriveControl.Subscribe(*this);
         fDimMagicWeather.Subscribe(*this);
+        fDimTngWeather.Subscribe(*this);
         fDimFeedback.Subscribe(*this);
         fDimBiasControl.Subscribe(*this);
@@ -1700,23 +1819,25 @@
 
         Subscribe("DIM_CONTROL/MESSAGE")
-            (bind(&StateMachineSmartFACT::HandleDimControlMessage,  this, placeholders::_1));
+            (bind(&StateMachineSmartFACT::HandleDimControlMessage,   this, placeholders::_1));
 
         Subscribe("MCP/CONFIGURATION")
-            (bind(&StateMachineSmartFACT::HandleMcpConfiguration,   this, placeholders::_1));
+            (bind(&StateMachineSmartFACT::HandleMcpConfiguration,    this, placeholders::_1));
 
         Subscribe("DRIVE_CONTROL/POINTING_POSITION")
-            (bind(&StateMachineSmartFACT::HandleDrivePointing,      this, placeholders::_1));
+            (bind(&StateMachineSmartFACT::HandleDrivePointing,       this, placeholders::_1));
         Subscribe("DRIVE_CONTROL/TRACKING_POSITION")
-            (bind(&StateMachineSmartFACT::HandleDriveTracking,      this, placeholders::_1));
+            (bind(&StateMachineSmartFACT::HandleDriveTracking,       this, placeholders::_1));
         Subscribe("DRIVE_CONTROL/SOURCE_POSITION")
-            (bind(&StateMachineSmartFACT::HandleDriveSource,        this, placeholders::_1));
+            (bind(&StateMachineSmartFACT::HandleDriveSource,         this, placeholders::_1));
 
         Subscribe("FSC_CONTROL/TEMPERATURE")
-            (bind(&StateMachineSmartFACT::HandleFscTemperature,     this, placeholders::_1));
+            (bind(&StateMachineSmartFACT::HandleFscTemperature,      this, placeholders::_1));
         Subscribe("FSC_CONTROL/HUMIDITY")
-            (bind(&StateMachineSmartFACT::HandleFscHumidity,        this, placeholders::_1));
+            (bind(&StateMachineSmartFACT::HandleFscHumidity,         this, placeholders::_1));
 
         Subscribe("MAGIC_WEATHER/DATA")
-            (bind(&StateMachineSmartFACT::HandleMagicWeatherData,   this, placeholders::_1));
+            (bind(&StateMachineSmartFACT::HandleMagicWeatherData,    this, placeholders::_1));
+        Subscribe("TNG_WEATHER/DUST")
+            (bind(&StateMachineSmartFACT::HandleTngWeatherDust,      this, placeholders::_1));
 
         Subscribe("FEEDBACK/DEVIATION")
