Index: trunk/FACT++/src/smartfact.cc
===================================================================
--- trunk/FACT++/src/smartfact.cc	(revision 13562)
+++ trunk/FACT++/src/smartfact.cc	(revision 13589)
@@ -31,4 +31,10 @@
 // ------------------------------------------------------------------------
 
+const static string kHtmlWhite  = "#ffffff";
+const static string kHtmlYellow = "#fffff0";
+const static string kHtmlRed    = "#fff8f0";
+const static string kHtmlGreen  = "#f0fff0";
+const static string kHtmlBlue   = "#f0f0ff";
+
 class StateMachineSmartFACT : public StateMachineDim, public DimInfoHandler
 {
@@ -48,6 +54,11 @@
     // ----------------------------- Data storage -------------------------
 
-    enum weather_t { kTemp = 0, kDew, kHum, kPress, kWind, kGusts, kDir };
-    float fMagicWeatherData[7];
+    uint32_t fMcpConfigurationState;
+    uint64_t fMcpConfigurationMaxTime;
+    uint64_t fMcpConfigurationMaxEvents;
+    string   fMcpConfigurationName;
+
+    enum weather_t { kWeatherBegin=0, kTemp = kWeatherBegin, kDew, kHum, kPress, kWind, kGusts, kDir, kWeatherEnd = kDir };
+    deque<float> fMagicWeatherHist[kWeatherEnd+1];
 
     vector<float> fFeedbackCalibration;
@@ -59,4 +70,8 @@
 
     deque<float> fBiasControlCurrentHist;
+    deque<float> fFscControlTemperatureHist;
+
+    float fFscControlTemperatureAvg;
+    float fFscControlHumidityAvg;
 
     float  fDriveControlPointingZd;
@@ -72,63 +87,112 @@
     DimServiceInfoList fNetwork;
 
-    pair<Time, int> fStatusDim;
-    pair<Time, int> fStatusDriveControl;
-    pair<Time, int> fStatusMagicWeather;
-    pair<Time, int> fStatusFeedback;
-    pair<Time, int> fStatusBiasControl;
-    pair<Time, int> fStatusFtmControl;
-    pair<Time, int> fStatusFadControl;
-
-    DimStampedInfo fDim;
-
-    DimStampedInfo fDimDriveControl;
+    class DimState : public DimInfoHandler
+    {
+    public:
+        DimState(const string &n, const string s="STATE") :
+            server(n), info(make_pair(Time(-1), -2)),
+            dim((n+"/"+s).c_str(), (void*)NULL, 0, this) { }
+
+        string server;
+        pair<Time, int> info;
+
+        DimStampedInfo dim;
+
+        void infoHandler()
+        {
+            DimInfo *curr = getInfo(); // get current DimInfo address
+            if (!curr || curr != &dim)
+                return;
+
+            const bool disconnected = dim.getSize()==0;
+
+            // Make sure getTimestamp is called _before_ getTimestampMillisecs
+            const int tsec = dim.getTimestamp();
+            const int tms  = dim.getTimestampMillisecs();
+
+            info = make_pair(Time(tsec, tms*1000),
+                             disconnected ? -2 : dim.getQuality());
+        }
+
+        const Time &time() const { return info.first; }
+        const int  &state() const { return info.second; }
+
+        const string &name() const { return server; }
+    };
+
+    class DimVersion : public DimState
+    {
+    public:
+        DimVersion() : DimState("DIS_DNS", "VERSION_NUMBER") { }
+
+        void infoHandler()
+        {
+            DimInfo *curr = getInfo(); // get current DimInfo address
+            if (!curr || curr != &dim)
+                return;
+
+            DimState::infoHandler();
+
+            info.second = dim.getSize()==4 ? dim.getInt() : 0;
+        }
+
+        string version() const
+        {
+            if (info.second==0)
+                return "Offline";
+
+            ostringstream msg;
+            msg << "V" << info.second/100 << 'r' << info.second%100;
+            return msg.str();
+        }
+    };
+
+
+    DimVersion fDim;
+    DimState   fDimMcp;
+    DimState   fDimDataLogger;
+    DimState   fDimDriveControl;
+    DimState   fDimMagicWeather;
+    DimState   fDimFeedback;
+    DimState   fDimBiasControl;
+    DimState   fDimFtmControl;
+    DimState   fDimFadControl;
+    DimState   fDimFscControl;
+    DimState   fDimRateControl;
+    DimState   fDimRateScan;
+    DimState   fDimChatServer;
+
+    DimStampedInfo fDimMcpConfiguration;
+
     DimStampedInfo fDimDriveControlPointing;
     DimStampedInfo fDimDriveControlTracking;
     DimStampedInfo fDimDriveControlSource;
 
-    DimStampedInfo fDimMagicWeather;
+    DimStampedInfo fDimFscControlTemperature;
+    DimStampedInfo fDimFscControlHumidity;
+
     DimStampedInfo fDimMagicWeatherData;
 
-    DimStampedInfo fDimFeedback;
     DimStampedInfo fDimFeedbackCalibration;
 
-    DimStampedInfo fDimBiasControl;
     DimStampedInfo fDimBiasControlVoltage;
     DimStampedInfo fDimBiasControlCurrent;
 
-    DimStampedInfo fDimFtmControl;
     DimStampedInfo fDimFtmControlTriggerRates;
 
-    DimStampedInfo fDimFadControl;
     DimStampedInfo *fDimFadControlEventData;
 
     // -------------------------------------------------------------------
 
-    pair<Time, int> GetNewState(DimStampedInfo &info) const
-    {
-        const bool disconnected = info.getSize()==0;
-
-        // Make sure getTimestamp is called _before_ getTimestampMillisecs
-        const int tsec = info.getTimestamp();
-        const int tms  = info.getTimestampMillisecs();
-
-        return make_pair(Time(tsec, tms*1000),
-                         disconnected ? -2 : info.getQuality());
-    }
-
-    bool UpdateState(DimInfo *curr, DimStampedInfo &service, pair<Time,int> &rc)
+    const State GetState(const DimState &s) const
+    {
+        return fNetwork.GetState(s.name(), s.state());
+    }
+
+    bool HandleService(DimInfo *curr, const DimInfo &service, void (StateMachineSmartFACT::*handle)(const DimData &))
     {
         if (curr!=&service)
             return false;
 
-        rc = GetNewState(service);
-        return true;
-    }
-
-    bool HandleService(DimInfo *curr, const DimInfo &service, void (StateMachineSmartFACT::*handle)(const DimData &))
-    {
-        if (curr!=&service)
-            return false;
-
         (this->*handle)(DimData(curr));
         return true;
@@ -136,11 +200,14 @@
 
 
-    bool CheckDataSize(const DimData &d, const char *name, size_t size)
-    {
-        if (d.data.size()==size)
+    bool CheckDataSize(const DimData &d, const char *name, size_t size, bool min=false)
+    {
+        if ((!min && d.data.size()==size) || (min && d.data.size()>size))
             return true;
 
         ostringstream msg;
-        msg << name << " - Received service has " << d.data.size() << " bytes, but expected " << size << ".";
+        msg << name << " - Received service has " << d.data.size() << " bytes, but expected ";
+        if (min)
+            msg << "more than ";
+        msg << size << ".";
         Warn(msg);
         return false;
@@ -172,4 +239,35 @@
     // -------------------------------------------------------------------
 
+    void HandleMcpConfiguration(const DimData &d)
+    {
+        if (!CheckDataSize(d, "Mcp:Configuration", 16, true))
+            return;
+
+        fMcpConfigurationState     = d.qos;
+        fMcpConfigurationMaxTime   = d.get<uint64_t>();
+        fMcpConfigurationMaxEvents = d.get<uint64_t>(8);
+        fMcpConfigurationName      = d.ptr<char>(16);
+    }
+
+    void WriteWeather(const DimData &d, const string &name, int i, float min, float max)
+    {
+        const auto  fmin = min_element(fMagicWeatherHist[i].begin(), fMagicWeatherHist[i].end());
+        const auto  fmax = max_element(fMagicWeatherHist[i].begin(), fMagicWeatherHist[i].end());
+        const float favg = accumulate (fMagicWeatherHist[i].begin(), fMagicWeatherHist[i].end(), 0.)/fMagicWeatherHist[i].size();
+
+        ostringstream out;
+        out << setprecision(3);
+        out << uint64_t(d.time.UnixTime()*1000) << '\n';
+
+        out << "#ffffff\t" << fMagicWeatherHist[i].back() << '\n';
+        out << "#ffffff\t" << *fmin << '\n';
+        out << "#ffffff\t" <<  favg << '\n';
+        out << "#ffffff\t" << *fmax << '\n';
+
+        ofstream("www/"+name+".txt") << out.str();
+
+        WriteBinary("magicweather-"+name+"-hist", fMagicWeatherHist[i], max-min, -min);
+    }
+
     void HandleMagicWeatherData(const DimData &d)
     {
@@ -177,8 +275,11 @@
             return;
 
-        // FIXME: Check size (7*4+2)
-
-        //const uint16_t status = d.get<uint16_t>();
-        memcpy(fMagicWeatherData, d.ptr<float>(2), 7*sizeof(float));
+        // Store a history of the last 300 entries
+        for (int i=kWeatherBegin; i<=kWeatherEnd; i++)
+        {
+            fMagicWeatherHist[i].push_back(d.ptr<float>(2)[i]);
+            if (fMagicWeatherHist[i].size()>300)
+                fMagicWeatherHist[i].pop_front();
+        }
 
         ostringstream out;
@@ -186,8 +287,14 @@
 
         for (int i=0; i<7; i++)
-            out << "#ffffff\t" << fMagicWeatherData[i] << '\n';
-
-        ofstream fout("www/magicweather.txt");
-        fout << out.str();
+            out << "#ffffff\t" << fMagicWeatherHist[i].back() << '\n';
+
+        ofstream("www/magicweather.txt") << out.str();
+
+        WriteWeather(d, "temp",  kTemp,   -5,   35);
+        WriteWeather(d, "dew",   kDew,    -5,   35);
+        WriteWeather(d, "hum",   kHum,     0,  100);
+        WriteWeather(d, "wind",  kWind,    0,  100);
+        WriteWeather(d, "gusts", kGusts,   0,  100);
+        WriteWeather(d, "press", kPress, 700, 1000);
     }
 
@@ -244,6 +351,6 @@
     void HandleDriveControlSource(const DimData &d)
     {
-        //if (!CheckDataSize(d, "DriveControl:Source", 7*4+2))
-        //    return;
+        if (!CheckDataSize(d, "DriveControl:Source", 7*4+2, true))
+            return;
 
         const double *ptr = d.ptr<double>();
@@ -381,5 +488,4 @@
             return;
 
-
         //const float *avg = d.ptr<float>();
         //const float *rms = d.ptr<float>(1440*sizeof(float));
@@ -403,4 +509,88 @@
     }
 
+    void HandleFscControlTemperature(const DimData &d)
+    {
+        if (!CheckDataSize(d, "FscControl:Temperature", 240))
+            return;
+
+        const float *ptr = d.ptr<float>(4);
+
+        double avg =   0;
+        double rms =   0;
+        double min =  99;
+        double max = -99;
+
+        int num = 0;
+        for (const float *t=ptr; t<ptr+31; t++)
+        {
+            if (*t==0)
+                continue;
+
+            if (*t>max)
+                max = *t;
+
+            if (*t<min)
+                min = *t;
+
+            avg += *t;
+            rms += *t * *t;
+
+            num++;
+        }
+
+        avg /= num;
+        rms = sqrt(rms/num-avg*avg);
+
+        fFscControlTemperatureAvg = avg;
+
+        fFscControlTemperatureHist.push_back(avg);
+        if (fFscControlTemperatureHist.size()>300)
+            fFscControlTemperatureHist.pop_front();
+
+        const auto beg = fFscControlTemperatureHist.begin();
+        const auto end = fFscControlTemperatureHist.end();
+
+        const auto  fmin = min_element(beg, end);
+        const auto  fmax = max_element(beg, end);
+        const float favg = accumulate (beg, end, 0)/fFscControlTemperatureHist.size();
+
+        ostringstream out;
+        out << setprecision(3);
+        out << uint64_t(d.time.UnixTime()*1000) << '\n';
+        out << "#ffffff\t" << min   << '\n';
+        out << "#ffffff\t" << avg   << '\n';
+        out << "#ffffff\t" << max   << '\n';
+        out << "#ffffff\t" << *fmin << '\n';
+        out << "#ffffff\t" << favg  << '\n';
+        out << "#ffffff\t" << *fmax << '\n';
+
+        ofstream("www/fsc.txt") << out.str();
+
+        WriteBinary("fsccontrol-temperature-hist",
+                    fFscControlTemperatureHist, 30);
+
+    }
+
+    void HandleFscControlHumidity(const DimData &d)
+    {
+        if (!CheckDataSize(d, "FscControl:Humidity", 5*4))
+            return;
+
+        const float *ptr = d.ptr<float>(4);
+
+        double avg =   0;
+        int num = 0;
+
+        for (const float *t=ptr; t<ptr+4; t++)
+            if (*t>0)
+            {
+                avg += *t;
+                num++;
+            }
+
+        fFscControlHumidityAvg = avg/num;
+    }
+
+
     // -------------------------------------------------------------------
 
@@ -411,4 +601,6 @@
             return;
 
+        if (HandleService(curr, fDimMcpConfiguration,       &StateMachineSmartFACT::HandleMcpConfiguration))
+            return;
         if (HandleService(curr, fDimMagicWeatherData,       &StateMachineSmartFACT::HandleMagicWeatherData))
             return;
@@ -429,24 +621,8 @@
         if (HandleService(curr, *fDimFadControlEventData,   &StateMachineSmartFACT::HandleFadControlEventData))
             return;
-
-        if (UpdateState(curr, fDimMagicWeather, fStatusMagicWeather))
-            return;
-        if (UpdateState(curr, fDimDriveControl, fStatusDriveControl))
-            return;
-        if (UpdateState(curr, fDimFeedback, fStatusFeedback))
-            return;
-        if (UpdateState(curr, fDimBiasControl, fStatusBiasControl))
-            return;
-        if (UpdateState(curr, fDimFtmControl, fStatusFtmControl))
-            return;
-        if (UpdateState(curr, fDimFadControl, fStatusFadControl))
-            return;
-
-        if (curr==&fDim)
-        {
-            fStatusDim = GetNewState(fDim);
-            fStatusDim.second = curr->getSize()==4 ? curr->getInt() : 0;
-            return;
-        }
+        if (HandleService(curr, fDimFscControlTemperature,  &StateMachineSmartFACT::HandleFscControlTemperature))
+            return;
+        if (HandleService(curr, fDimFscControlHumidity,     &StateMachineSmartFACT::HandleFscControlHumidity))
+            return;
     }
 
@@ -462,10 +638,10 @@
     }
 
-    void PrintState(const pair<Time,int> &state, const char *server)
-    {
-        const State rc = fNetwork.GetState(server, state.second);
-
-        Out() << state.first.GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
-        Out() << kBold << server << ": ";
+    void PrintState(const DimState &state) const
+    {
+        const State rc = GetState(state);
+
+        Out() << state.time().GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
+        Out() << kBold << state.name() << ": ";
         if (rc.index==-2)
         {
@@ -477,20 +653,38 @@
     }
 
-    int Print()
-    {
-        Out() << fStatusDim.first.GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
-        Out() << kBold << "DIM_DNS: ";
-        if (fStatusDim.second==0)
-            Out() << "Offline" << endl;
-        else
-            Out() << "V" << fStatusDim.second/100 << 'r' << fStatusDim.second%100 << endl;
-
-        PrintState(fStatusMagicWeather, "MAGIC_WEATHER");
-        PrintState(fStatusDriveControl, "DRIVE_CONTROL");
-        PrintState(fStatusFeedback,     "FEEDBACK");
-        PrintState(fStatusBiasControl,  "BIAS_CONTROL");
-        PrintState(fStatusFadControl,   "FAD_CONTROL");
+    int Print() const
+    {
+        Out() << fDim.time().GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
+        Out() << kBold << "DIM_DNS: " << fDim.version() << endl;
+
+        PrintState(fDimMcp);
+        PrintState(fDimDataLogger);
+        PrintState(fDimDriveControl);
+        PrintState(fDimFadControl);
+        PrintState(fDimFtmControl);
+        PrintState(fDimBiasControl);
+        PrintState(fDimFeedback);
+        PrintState(fDimRateControl);
+        PrintState(fDimFscControl);
+        PrintState(fDimMagicWeather);
+        PrintState(fDimRateScan);
+        PrintState(fDimChatServer);
 
         return GetCurrentState();
+    }
+
+    string GetStateHtml(const DimState &state, int green) const
+    {
+        const State rc = GetState(state);
+
+        //ostringstream msg;
+        //msg << kHtmlWhite << '\t' << rc.name << " [" << rc.index << "]\n";
+        //return msg.str();
+
+        if (rc.index<1)
+            return kHtmlWhite + "\t---\n";
+
+
+        return (rc.index<green?kHtmlYellow:kHtmlGreen) + '\t' + rc.name + '\n';
     }
 
@@ -504,5 +698,5 @@
         //poll_one();
 
-        if (fStatusDim.second==0)
+        if (fDim.state()==0)
             return kStateDimNetworkNA;
 
@@ -518,21 +712,37 @@
 
         // -------------- System status --------------
-        out << "n/a\n";
-
-        const static string kWhite  = "#ffffff";
-        const static string kYellow = "#fffff0";
-        const static string kRed    = "#fff8f0";
-        const static string kGreen  = "#f0fff0";
-        const static string kBlue   = "#f0f0ff";
+        if (fDimMcp.state()>=5) // Idle
+        {
+            string col = kHtmlBlue;
+            if (fMcpConfigurationState!=5)
+                col = kHtmlYellow;
+            else
+                if (fDimFadControl.state()==FAD::kWritingData)
+                    col = kHtmlGreen;
+
+            out << fMcpConfigurationName;
+            if (fMcpConfigurationMaxEvents>0 || fMcpConfigurationMaxTime>0)
+                out << " [";
+            if (fMcpConfigurationMaxEvents>0)
+                out << fMcpConfigurationMaxEvents;
+            if (fMcpConfigurationMaxEvents>0 && fMcpConfigurationMaxTime>0)
+                out << "/";
+            if (fMcpConfigurationMaxTime>0)
+                out << fMcpConfigurationMaxTime << "s";
+            if (fMcpConfigurationMaxEvents>0 || fMcpConfigurationMaxTime>0)
+                out << "]";
+        }
+        else
+            out << kHtmlWhite << '\n';
 
         // ------------------ Drive -----------------
-        if (fStatusDriveControl.second>=5)   // Armed, Moving, Tracking
-        {
-            const State rc = fNetwork.GetState("DRIVE_CONTROL", fStatusDriveControl.second);
-            out << kWhite << '\t';
+        if (fDimDriveControl.state()>=5)   // Armed, Moving, Tracking
+        {
+            const State rc = GetState(fDimDriveControl);
+            out << kHtmlWhite << '\t';
             out << rc.name << '\t';
             out << fDriveControlPointingZd  << '\t';
             out << fDriveControlPointingAz  << '\t';
-            if (fStatusDriveControl.second==7)
+            if (fDimDriveControl.state()==7)
             {
                 out << fDriveControlTrackingDev << '\t';
@@ -543,59 +753,68 @@
         }
         else
-            out << kWhite << '\n';
+            out << kHtmlWhite << '\n';
+
+        // ------------------- FSC ------------------
+        if (fDimFscControl.state()>1)
+        {
+            out << kHtmlGreen << '\t' << fFscControlTemperatureAvg << '\n';
+        }
+        else
+            out << kHtmlWhite << '\n';
 
         // --------------- MagicWeather -------------
-        if (fStatusMagicWeather.second==3)
-        {
-            const float diff = fMagicWeatherData[kTemp]-fMagicWeatherData[kDew];
-            string col1 = kRed;
+        if (fDimMagicWeather.state()==3)
+        {
+            /*
+            const float diff = fMagicWeatherHist[kTemp].back()-fMagicWeatherHist[kDew].back();
+            string col1 = kHtmlRed;
             if (diff>0.3)
-                col1 = kYellow;
+                col1 = kHtmlYellow;
             if (diff>0.7)
-                col1 = kGreen;
-
-            const float wind = fMagicWeatherData[kGusts];
-            string col2 = kGreen;
-            if (wind>35)
-                col2 = kYellow;
-            if (wind>50)
-                col2 = kRed;
-
-            out << col1 << '\t';
-            out << fMagicWeatherData[kTemp]  << '\t';
-            out << fMagicWeatherData[kDew]   << '\n';
-            out << col2 << '\t';
-            out << fMagicWeatherData[kGusts] << '\n';
+                col1 = kHtmlGreen;
+                */
+
+            const float wind = fMagicWeatherHist[kGusts].back();
+            const float hum  = fMagicWeatherHist[kHum].back();
+            string col = kHtmlGreen;
+            if (wind>35 || hum>95)
+                col = kHtmlYellow;
+            if (wind>50 || hum>98)
+                col = kHtmlRed;
+
+            out << col << '\t';
+            out << fMagicWeatherHist[kHum].back()   << '\t';
+            out << fMagicWeatherHist[kGusts].back() << '\n';
         }
         else
-            out << kWhite << "\n\n";
+            out << kHtmlWhite << "\n";
 
         // --------------- FtmControl -------------
-        if (fStatusFtmControl.second>=FTM::kIdle)
-        {
-            string col = kGreen;
+        if (fDimFtmControl.state()>=FTM::kIdle)
+        {
+            string col = kHtmlGreen;
             if (fFtmControlTriggerRateCam<15)
-                col = kYellow;
+                col = kHtmlYellow;
             if (fFtmControlTriggerRateCam>100)
-                col = kRed;
+                col = kHtmlRed;
 
             out << col << '\t' << fFtmControlTriggerRateCam << '\n';
         }
         else
-            out << kWhite << '\n';
+            out << kHtmlWhite << '\n';
 
         // --------------- BiasControl -------------
-        if (fStatusBiasControl.second==5 || // Ramping
-            fStatusBiasControl.second==7 || // On
-            fStatusBiasControl.second==9)   // Off
-        {
-            string col = fBiasControlVoltageMed>3?kGreen:kWhite;
+        if (fDimBiasControl.state()==5 || // Ramping
+            fDimBiasControl.state()==7 || // On
+            fDimBiasControl.state()==9)   // Off
+        {
+            string col = fBiasControlVoltageMed>3?kHtmlGreen:kHtmlWhite;
             if (fBiasControlCurrentMax>280)
-                col = kYellow;
+                col = kHtmlYellow;
             if (fBiasControlCurrentMax>350)
-                col = kRed;
+                col = kHtmlRed;
 
             if (fFeedbackCalibration.size()==0)
-                col = kBlue;
+                col = kHtmlBlue;
 
             out << col << '\t';
@@ -605,10 +824,37 @@
         }
         else
-            out << kWhite << '\n';
+            out << kHtmlWhite << '\n';
 
 
         // ------------------------------------------
-        ofstream fout("www/fact.txt");
-        fout << out.str();
+
+        ofstream("www/fact.txt") << out.str();
+
+        // ==========================================
+
+        out.str("");
+        out << uint64_t(nearbyint(now.UnixTime()*1000)) << '\n';
+
+        if (fDim.state()==0)
+            out << kHtmlWhite << "\tOffline\n\n\n\n\n\n\n\n\n\n\n\n";
+        else
+        {
+            out << kHtmlGreen << '\t' << fDim.version() << '\n';
+
+            out << GetStateHtml(fDimMcp,          4);
+            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(fDimFeedback,     4);
+            out << GetStateHtml(fDimRateControl,  4);
+            out << GetStateHtml(fDimFscControl,   2);
+            out << GetStateHtml(fDimMagicWeather, 2);
+            out << GetStateHtml(fDimRateScan,     4);
+            out << GetStateHtml(fDimChatServer,   1);
+        }
+
+        ofstream("www/status.txt") << out.str();
 
         return kStateRunning;
@@ -618,33 +864,35 @@
     StateMachineSmartFACT(ostream &out=cout) : StateMachineDim(out, "SMART_FACT"),
         //---
-        fStatusDim         (make_pair(Time(), -2)),
-        fStatusDriveControl(make_pair(Time(), -2)),
-        fStatusMagicWeather(make_pair(Time(), -2)),
-        fStatusFeedback    (make_pair(Time(), -2)),
-        fStatusBiasControl (make_pair(Time(), -2)),
-        fStatusFtmControl  (make_pair(Time(), -2)),
-        fStatusFadControl  (make_pair(Time(), -2)),
+        fDimMcp                   ("MCP"),
+        fDimDataLogger            ("DATA_LOGGER"),
+        fDimDriveControl          ("DRIVE_CONTROL"),
+        fDimMagicWeather          ("MAGIC_WEATHER"),
+        fDimFeedback              ("FEEDBACK"),
+        fDimBiasControl           ("BIAS_CONTROL"),
+        fDimFtmControl            ("FTM_CONTROL"),
+        fDimFadControl            ("FAD_CONTROL"),
+        fDimFscControl            ("FSC_CONTROL"),
+        fDimRateControl           ("RATE_CONTROL"),
+        fDimRateScan              ("RATE_SCAN"),
+        fDimChatServer            ("CHAT_SERVER"),
         //---
-        fDim                      ("DIS_DNS/VERSION_NUMBER",          (void*)NULL, 0, this),
+        fDimMcpConfiguration      ("MCP/CONFIGURATION",               (void*)NULL, 0, this),
         //---
-        fDimDriveControl          ("DRIVE_CONTROL/STATE",             (void*)NULL, 0, this),
         fDimDriveControlPointing  ("DRIVE_CONTROL/POINTING_POSITION", (void*)NULL, 0, this),
         fDimDriveControlTracking  ("DRIVE_CONTROL/TRACKING_POSITION", (void*)NULL, 0, this),
         fDimDriveControlSource    ("DRIVE_CONTROL/SOURCE_POSITION",   (void*)NULL, 0, this),
         //---
-        fDimMagicWeather          ("MAGIC_WEATHER/STATE",             (void*)NULL, 0, this),
+        fDimFscControlTemperature ("FSC_CONTROL/TEMPERATURE",         (void*)NULL, 0, this),
+        fDimFscControlHumidity    ("FSC_CONTROL/HUMIDITY",            (void*)NULL, 0, this),
+        //---
         fDimMagicWeatherData      ("MAGIC_WEATHER/DATA",              (void*)NULL, 0, this),
         //---
-        fDimFeedback              ("FEEDBACK/STATE",                  (void*)NULL, 0, this),
         fDimFeedbackCalibration   ("FEEDBACK/CALIBRATION",            (void*)NULL, 0, this),
         //---
-        fDimBiasControl           ("BIAS_CONTROL/STATE",              (void*)NULL, 0, this),
         fDimBiasControlVoltage    ("BIAS_CONTROL/VOLTAGE",            (void*)NULL, 0, this),
         fDimBiasControlCurrent    ("BIAS_CONTROL/CURRENT",            (void*)NULL, 0, this),
         //---
-        fDimFtmControl            ("FTM_CONTROL/STATE",               (void*)NULL, 0, this),
         fDimFtmControlTriggerRates("FTM_CONTROL/TRIGGER_RATES",       (void*)NULL, 0, this),
         //-
-        fDimFadControl            ("FAD_CONTROL/STATE",               (void*)NULL, 0, this),
         fDimFadControlEventData(0)
     {
