Index: trunk/FACT++/src/smartfact.cc
===================================================================
--- trunk/FACT++/src/smartfact.cc	(revision 13801)
+++ trunk/FACT++/src/smartfact.cc	(revision 13803)
@@ -39,5 +39,7 @@
 const static string kHtmlBlue   = "#f0f0ff";
 
-#ifdef HAVE_LIBNOVA
+// ========================================================================
+// ========================================================================
+// ========================================================================
 
 class Astro
@@ -299,5 +301,219 @@
 };
 
-// ------------------------------------------------------------------------
+// ========================================================================
+// ========================================================================
+// ========================================================================
+
+class DimState : public DimInfoHandler
+    {
+    public:
+        DimState(const string &n, const string s="STATE") :
+            server(n), info(make_pair(Time(), -4)),
+            dim((n+"/"+s).c_str(), (void*)NULL, 0, this) { }
+
+        string server;
+        pair<Time, int> info;
+        string msg;
+
+        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 ? -4 : dim.getQuality());
+
+            msg = disconnected ? "" : dim.getString();
+        }
+
+        const Time &time() const { return info.first; }
+        const int  &state() const { return info.second; }
+
+        bool online() const { return info.second>-4; }
+
+        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 out;
+            out << "V" << info.second/100 << 'r' << info.second%100;
+            return out.str();
+        }
+    };
+
+    class DimControl : public DimState
+    {
+        typedef function<void(const DimData &)> callback;
+        map<string, callback> fCallbacks;
+    public:
+        DimControl() : DimState("DIM_CONTROL") { }
+
+        void AddCallback(const string &script, const callback &cb)
+        {
+            fCallbacks[script] = cb;
+        }
+
+        void infoHandler()
+        {
+            DimInfo *curr = getInfo(); // get current DimInfo address
+            if (!curr || curr != &dim)
+                return;
+
+            DimState::infoHandler();
+
+            // Evaluate msg
+            const size_t p0 = msg.find_first_of(':');
+            if (p0==string::npos)
+                return;
+
+            const size_t p1 = msg.find_last_of('[');
+            if (p1==string::npos)
+                return;
+
+            const size_t p2 = msg.find_first_of(':', p0+1);
+
+            const size_t p3 = p2==string::npos || p2>p1 ? p1-1 : p2;
+
+            const string file = msg.substr(p0+2, p3-p0-2);
+
+            const auto func = fCallbacks.find(file);
+            if (func==fCallbacks.end())
+                return;
+
+            // Call callback
+            func->second(DimData(curr));
+        }
+    };
+
+struct DimSubscriptions
+{
+    DimServiceInfoList fNetwork;
+
+    DimVersion fDNS;
+    DimControl fControl;
+    DimState   fMcp;
+    DimState   fDataLogger;
+    DimState   fDriveControl;
+    DimState   fMagicWeather;
+    DimState   fFeedback;
+    DimState   fBiasControl;
+    DimState   fFtmControl;
+    DimState   fFadControl;
+    DimState   fFscControl;
+    DimState   fRateControl;
+    DimState   fRateScan;
+    DimState   fChatServer;
+
+    DimStampedInfo fMcpConfiguration;
+
+    DimStampedInfo fDriveControlPointing;
+    DimStampedInfo fDriveControlTracking;
+    DimStampedInfo fDriveControlSource;
+
+    DimStampedInfo fFscControlTemperature;
+    DimStampedInfo fFscControlHumidity;
+
+    DimStampedInfo fMagicWeatherData;
+
+    DimStampedInfo fFeedbackDeviation;
+    DimStampedInfo fFeedbackCalibration;
+
+    DimStampedInfo fBiasControlVoltage;
+    DimStampedInfo fBiasControlCurrent;
+
+    DimStampedInfo fFadConnections;
+    DimStampedInfo fFadEvents;
+
+    DimStampedInfo fFtmControlTriggerRates;
+    DimStampedInfo fFtmControlStaticData;
+    DimStampedInfo fFtmControlFtuList;
+
+    DimStampedInfo fRateScanData;
+
+    DimStampedInfo fFadControlEventData;
+
+    DimSubscriptions(DimInfoHandler *h) :
+        fMcp                   ("MCP"),
+        fDataLogger            ("DATA_LOGGER"),
+        fDriveControl          ("DRIVE_CONTROL"),
+        fMagicWeather          ("MAGIC_WEATHER"),
+        fFeedback              ("FEEDBACK"),
+        fBiasControl           ("BIAS_CONTROL"),
+        fFtmControl            ("FTM_CONTROL"),
+        fFadControl            ("FAD_CONTROL"),
+        fFscControl            ("FSC_CONTROL"),
+        fRateControl           ("RATE_CONTROL"),
+        fRateScan              ("RATE_SCAN"),
+        fChatServer            ("CHAT_SERVER"),
+        //---
+        fMcpConfiguration      ("MCP/CONFIGURATION",               (void*)NULL, 0, h),
+        //---
+        fDriveControlPointing  ("DRIVE_CONTROL/POINTING_POSITION", (void*)NULL, 0, h),
+        fDriveControlTracking  ("DRIVE_CONTROL/TRACKING_POSITION", (void*)NULL, 0, h),
+        fDriveControlSource    ("DRIVE_CONTROL/SOURCE_POSITION",   (void*)NULL, 0, h),
+        //---
+        fFscControlTemperature ("FSC_CONTROL/TEMPERATURE",         (void*)NULL, 0, h),
+        fFscControlHumidity    ("FSC_CONTROL/HUMIDITY",            (void*)NULL, 0, h),
+        //---
+        fMagicWeatherData      ("MAGIC_WEATHER/DATA",              (void*)NULL, 0, h),
+        //---
+        fFeedbackDeviation     ("FEEDBACK/DEVIATION",              (void*)NULL, 0, h),
+        fFeedbackCalibration   ("FEEDBACK/CALIBRATION",            (void*)NULL, 0, h),
+        //---
+        fBiasControlVoltage    ("BIAS_CONTROL/VOLTAGE",            (void*)NULL, 0, h),
+        fBiasControlCurrent    ("BIAS_CONTROL/CURRENT",            (void*)NULL, 0, h),
+        //---
+        fFadConnections        ("FAD_CONTROL/CONNECTIONS",         (void*)NULL, 0, h),
+        fFadEvents             ("FAD_CONTROL/EVENTS",              (void*)NULL, 0, h),
+        //---
+        fFtmControlTriggerRates("FTM_CONTROL/TRIGGER_RATES",       (void*)NULL, 0, h),
+        fFtmControlStaticData  ("FTM_CONTROL/STATIC_DATA",         (void*)NULL, 0, h),
+        fFtmControlFtuList     ("FTM_CONTROL/FTU_LIST",            (void*)NULL, 0, h),
+        //---
+        fRateScanData          ("RATE_SCAN/DATA",                  (void*)NULL, 0, h),
+        //---
+        fFadControlEventData   ("FAD_CONTROL/EVENT_DATA",          (void*)NULL, 0, h)
+
+    {
+    }
+
+    const State GetState(const DimState &s) const
+    {
+        return fNetwork.GetState(s.name(), s.state());
+    }
+};
+
+// ========================================================================
+// ========================================================================
+// ========================================================================
 
 
@@ -359,4 +575,6 @@
     vector<float> fFtmPatchThresholds;
 
+    bool fFtmControlFtuOk;
+
     uint64_t  fRateScanDataId;
     deque<float> fRateScanDataHist;
@@ -364,166 +582,8 @@
     // ------------- Initialize variables before the Dim stuff ------------
 
-    DimServiceInfoList fNetwork;
-
-    class DimState : public DimInfoHandler
-    {
-    public:
-        DimState(const string &n, const string s="STATE") :
-            server(n), info(make_pair(Time(), -4)),
-            dim((n+"/"+s).c_str(), (void*)NULL, 0, this) { }
-
-        string server;
-        pair<Time, int> info;
-        string msg;
-
-        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 ? -4 : dim.getQuality());
-
-            msg = disconnected ? "" : dim.getString();
-        }
-
-        const Time &time() const { return info.first; }
-        const int  &state() const { return info.second; }
-
-        bool online() const { return info.second>-4; }
-
-        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 out;
-            out << "V" << info.second/100 << 'r' << info.second%100;
-            return out.str();
-        }
-    };
-
-    class DimControl : public DimState
-    {
-        typedef function<void(const DimData &)> callback;
-        map<string, callback> fCallbacks;
-    public:
-        DimControl() : DimState("DIM_CONTROL") { }
-
-        void AddCallback(const string &script, const callback &cb)
-        {
-            fCallbacks[script] = cb;
-        }
-
-        void infoHandler()
-        {
-            DimInfo *curr = getInfo(); // get current DimInfo address
-            if (!curr || curr != &dim)
-                return;
-
-            DimState::infoHandler();
-
-            // Evaluate msg
-            const size_t p0 = msg.find_first_of(':');
-            if (p0==string::npos)
-                return;
-
-            const size_t p1 = msg.find_last_of('[');
-            if (p1==string::npos)
-                return;
-
-            const size_t p2 = msg.find_first_of(':', p0+1);
-
-            const size_t p3 = p2==string::npos || p2>p1 ? p1-1 : p2;
-
-            const string file = msg.substr(p0+2, p3-p0-2);
-
-            const auto func = fCallbacks.find(file);
-            if (func==fCallbacks.end())
-                return;
-
-            // Call callback
-            func->second(DimData(curr));
-        }
-    };
-
-
-
-    DimVersion fDim;
-    DimControl fDimControl;
-    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 fDimFscControlTemperature;
-    DimStampedInfo fDimFscControlHumidity;
-
-    DimStampedInfo fDimMagicWeatherData;
-
-    DimStampedInfo fDimFeedbackDeviation;
-    DimStampedInfo fDimFeedbackCalibration;
-
-    DimStampedInfo fDimBiasControlVoltage;
-    DimStampedInfo fDimBiasControlCurrent;
-
-    DimStampedInfo fDimFadConnections;
-    DimStampedInfo fDimFadEvents;
-
-    DimStampedInfo fDimFtmControlTriggerRates;
-    DimStampedInfo fDimFtmControlStaticData;
-
-    DimStampedInfo fDimRateScanData;
-
-    DimStampedInfo *fDimFadControlEventData;
+    DimSubscriptions *fDim;
 
     // -------------------------------------------------------------------
 
-    const State GetState(const DimState &s) const
-    {
-        return fNetwork.GetState(s.name(), s.state());
-    }
 
     // -------------------------------------------------------------------
@@ -891,5 +951,5 @@
         }
 
-        if (fDimBiasControl.state()==BIAS::kVoltageOn)
+        if (fDim->fBiasControl.state()==BIAS::kVoltageOn)
             WriteBinary(d, "biascontrol-voltage", val, 10, 65);
         else
@@ -1156,4 +1216,39 @@
     }
 
+    void HandleFtmControlFtuList(const DimData &d)
+    {
+        if (!CheckDataSize(d, "FtmControl:FtuList", sizeof(FTM::DimFtuList)))
+            return;
+
+        const FTM::DimFtuList &sdata = d.ref<FTM::DimFtuList>();
+
+        ostringstream out;
+        out << d.time.JavaDate() << '\n';
+
+        int cnt = 0;
+        for (int i=0; i<4; i++)
+        {
+            out << kHtmlWhite << '\t';
+            for (int j=0; j<10; j++)
+                if (sdata.IsActive(i*10+j))
+                {
+                    if (sdata.fPing[i*10+j]==1)
+                    {
+                        out << '*';
+                        cnt++;
+                    }
+                    else
+                        out << sdata.fPing[i*10+j];
+                }
+                else
+                    out << '-';
+            out << '\n';
+        }
+
+        fFtmControlFtuOk = cnt==40;
+
+        ofstream(fPath+"/ftu.txt") << out.str();
+    }
+
     void HandleFadControlEventData(const DimData &d)
     {
@@ -1219,7 +1314,10 @@
         rms = sqrt(rms/num-avg*avg);
 
-        fFscControlTemperatureHist.push_back(avg-fMagicWeatherHist[kTemp].back());
-        if (fFscControlTemperatureHist.size()>300)
-            fFscControlTemperatureHist.pop_front();
+        if (fMagicWeatherHist[kTemp].size()>0)
+        {
+            fFscControlTemperatureHist.push_back(avg-fMagicWeatherHist[kTemp].back());
+            if (fFscControlTemperatureHist.size()>300)
+                fFscControlTemperatureHist.pop_front();
+        }
 
         const Statistics stat(fFscControlTemperatureHist);
@@ -1285,5 +1383,5 @@
     {
         ostringstream out;
-        out << d.time.JavaDate() << '\t' << fDimControl.online() << '\n';
+        out << d.time.JavaDate() << '\t' << fDim->fControl.online() << '\n';
         switch (d.qos)
         {
@@ -1305,37 +1403,39 @@
             return;
 
-        if (HandleService(curr, fDimMcpConfiguration,       &StateMachineSmartFACT::HandleMcpConfiguration))
-            return;
-        if (HandleService(curr, fDimMagicWeatherData,       &StateMachineSmartFACT::HandleMagicWeatherData))
-            return;
-        if (HandleService(curr, fDimDriveControlPointing,   &StateMachineSmartFACT::HandleDriveControlPointing))
-            return;
-        if (HandleService(curr, fDimDriveControlTracking,   &StateMachineSmartFACT::HandleDriveControlTracking))
-            return;
-        if (HandleService(curr, fDimDriveControlSource,     &StateMachineSmartFACT::HandleDriveControlSource))
-            return;
-        if (HandleService(curr, fDimFeedbackDeviation,      &StateMachineSmartFACT::HandleFeedbackDeviation))
-            return;
-        if (HandleService(curr, fDimFeedbackCalibration,    &StateMachineSmartFACT::HandleFeedbackCalibration))
-            return;
-        if (HandleService(curr, fDimBiasControlVoltage,     &StateMachineSmartFACT::HandleBiasControlVoltage))
-            return;
-        if (HandleService(curr, fDimBiasControlCurrent,     &StateMachineSmartFACT::HandleBiasControlCurrent))
-            return;
-        if (HandleService(curr, fDimFadConnections,         &StateMachineSmartFACT::HandleFadConnections))
-            return;
-        if (HandleService(curr, fDimFadEvents,              &StateMachineSmartFACT::HandleFadEvents))
-            return;
-        if (HandleService(curr, fDimFtmControlTriggerRates, &StateMachineSmartFACT::HandleFtmControlTriggerRates))
-            return;
-        if (HandleService(curr, fDimFtmControlStaticData,   &StateMachineSmartFACT::HandleFtmControlStaticData))
-            return;
-        if (HandleService(curr, *fDimFadControlEventData,   &StateMachineSmartFACT::HandleFadControlEventData))
-            return;
-        if (HandleService(curr, fDimFscControlTemperature,  &StateMachineSmartFACT::HandleFscControlTemperature))
-            return;
-        if (HandleService(curr, fDimFscControlHumidity,     &StateMachineSmartFACT::HandleFscControlHumidity))
-            return;
-        if (HandleService(curr, fDimRateScanData,           &StateMachineSmartFACT::HandleRateScanData))
+        if (HandleService(curr, fDim->fMcpConfiguration,       &StateMachineSmartFACT::HandleMcpConfiguration))
+            return;
+        if (HandleService(curr, fDim->fMagicWeatherData,       &StateMachineSmartFACT::HandleMagicWeatherData))
+            return;
+        if (HandleService(curr, fDim->fDriveControlPointing,   &StateMachineSmartFACT::HandleDriveControlPointing))
+            return;
+        if (HandleService(curr, fDim->fDriveControlTracking,   &StateMachineSmartFACT::HandleDriveControlTracking))
+            return;
+        if (HandleService(curr, fDim->fDriveControlSource,     &StateMachineSmartFACT::HandleDriveControlSource))
+            return;
+        if (HandleService(curr, fDim->fFeedbackDeviation,      &StateMachineSmartFACT::HandleFeedbackDeviation))
+            return;
+        if (HandleService(curr, fDim->fFeedbackCalibration,    &StateMachineSmartFACT::HandleFeedbackCalibration))
+            return;
+        if (HandleService(curr, fDim->fBiasControlVoltage,     &StateMachineSmartFACT::HandleBiasControlVoltage))
+            return;
+        if (HandleService(curr, fDim->fBiasControlCurrent,     &StateMachineSmartFACT::HandleBiasControlCurrent))
+            return;
+        if (HandleService(curr, fDim->fFadConnections,         &StateMachineSmartFACT::HandleFadConnections))
+            return;
+        if (HandleService(curr, fDim->fFadEvents,              &StateMachineSmartFACT::HandleFadEvents))
+            return;
+        if (HandleService(curr, fDim->fFtmControlTriggerRates, &StateMachineSmartFACT::HandleFtmControlTriggerRates))
+            return;
+        if (HandleService(curr, fDim->fFtmControlStaticData,   &StateMachineSmartFACT::HandleFtmControlStaticData))
+            return;
+        if (HandleService(curr, fDim->fFtmControlFtuList,      &StateMachineSmartFACT::HandleFtmControlFtuList))
+            return;
+        if (HandleService(curr, fDim->fFadControlEventData,    &StateMachineSmartFACT::HandleFadControlEventData))
+            return;
+        if (HandleService(curr, fDim->fFscControlTemperature,  &StateMachineSmartFACT::HandleFscControlTemperature))
+            return;
+        if (HandleService(curr, fDim->fFscControlHumidity,     &StateMachineSmartFACT::HandleFscControlHumidity))
+            return;
+        if (HandleService(curr, fDim->fRateScanData,           &StateMachineSmartFACT::HandleRateScanData))
             return;
     }
@@ -1354,5 +1454,5 @@
     void PrintState(const DimState &state) const
     {
-        const State rc = GetState(state);
+        const State rc = fDim->GetState(state);
 
         Out() << state.time().GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
@@ -1372,20 +1472,20 @@
     int Print() const
     {
-        Out() << fDim.time().GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
-        Out() << kBold << "DIM_DNS: " << fDim.version() << endl;
-
-        PrintState(fDimMcp);
-        PrintState(fDimControl);
-        PrintState(fDimDataLogger);
-        PrintState(fDimDriveControl);
-        PrintState(fDimFadControl);
-        PrintState(fDimFtmControl);
-        PrintState(fDimBiasControl);
-        PrintState(fDimFeedback);
-        PrintState(fDimRateControl);
-        PrintState(fDimFscControl);
-        PrintState(fDimMagicWeather);
-        PrintState(fDimRateScan);
-        PrintState(fDimChatServer);
+        Out() << fDim->fDNS.time().GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
+        Out() << kBold << "DIM_DNS: " << fDim->fDNS.version() << endl;
+
+        PrintState(fDim->fMcp);
+        PrintState(fDim->fControl);
+        PrintState(fDim->fDataLogger);
+        PrintState(fDim->fDriveControl);
+        PrintState(fDim->fFadControl);
+        PrintState(fDim->fFtmControl);
+        PrintState(fDim->fBiasControl);
+        PrintState(fDim->fFeedback);
+        PrintState(fDim->fRateControl);
+        PrintState(fDim->fFscControl);
+        PrintState(fDim->fMagicWeather);
+        PrintState(fDim->fRateScan);
+        PrintState(fDim->fChatServer);
 
         return GetCurrentState();
@@ -1397,5 +1497,5 @@
             return kHtmlWhite+"\t&mdash;\n";
 
-        if (&state==&fDimControl)
+        if (&state==&fDim->fControl)
         {
             ostringstream out;
@@ -1404,5 +1504,5 @@
         }
 
-        const State rc = GetState(state);
+        const State rc = fDim->GetState(state);
 
         // Sate not found in list, server online (-3: offline; -2: not found)
@@ -1434,5 +1534,5 @@
         //poll_one();
 
-        if (fDim.state()==0)
+        if (fDim->fDNS.state()==0)
             return kStateDimNetworkNA;
 
@@ -1444,9 +1544,9 @@
 
         ostringstream out;
-        out << now.JavaDate() << '\t' << fDimControl.online() << '\n';
+        out << now.JavaDate() << '\t' << fDim->fControl.online() << '\n';
         out << setprecision(3);
 
         // -------------- System status --------------
-        if (fDimMcp.state()>=5) // Idle
+        if (fDim->fMcp.state()>=5) // Idle
         {
             string col = kHtmlBlue;
@@ -1455,17 +1555,17 @@
                 fMcpConfigurationState!=11 &&  // Trigger On
                 fMcpConfigurationState!=12)    // Taking Data*/
-            if (fDimMcp.state()!= 5 &&  // Idle
-                fDimMcp.state()!=11 &&  // Trigger On
-                fDimMcp.state()!=12)    // Taking Data
+            if (fDim->fMcp.state()!= 5 &&  // Idle
+                fDim->fMcp.state()!=11 &&  // Trigger On
+                fDim->fMcp.state()!=12)    // Taking Data
                 col = kHtmlYellow;
             else
-                if (fDimFadControl.state()==FAD::kWritingData)
+                if (fDim->fFadControl.state()==FAD::kWritingData)
                     col = kHtmlGreen;
 
             out << col << '\t';
 
-            if (fDimRateControl.state()!=5 && fDimRateScan.state()!=5)
+            if (fDim->fRateControl.state()!=5 && fDim->fRateScan.state()!=5)
             {
-                switch (fDimMcp.state()/*fMcpConfigurationState*/)
+                switch (fDim->fMcp.state()/*fMcpConfigurationState*/)
                 {
                 // kStateIdle
@@ -1483,12 +1583,12 @@
             }
             else
-                if (fDimRateControl.state()==5/*kStateSettingGlobalThreshold*/)
+                if (fDim->fRateControl.state()==5/*kStateSettingGlobalThreshold*/)
                     out << "Calibrating threshold";
                 else
 
-                    if (fDimRateScan.state()==5/*kStateSettingGlobalThreshold*/)
+                    if (fDim->fRateScan.state()==5/*kStateSettingGlobalThreshold*/)
                         out << "Rate scan in progress";
 
-            if (fDimMcp.state()>10 && fDimRateControl.state()!=5)
+            if (fDim->fMcp.state()>10 && fDim->fRateControl.state()!=5)
             {
                 if (fMcpConfigurationMaxEvents>0 || fMcpConfigurationMaxTime>0 || fMcpConfigurationState==12)
@@ -1536,8 +1636,8 @@
 
         // ------------------ Drive -----------------
-        if (fDimDriveControl.state()>=5)   // Armed, Moving, Tracking
+        if (fDim->fDriveControl.state()>=5)   // Armed, Moving, Tracking
         {
             const double dev = fDriveControlTrackingDevHist.size()>0 ? fDriveControlTrackingDevHist.back() : 0;
-            const State rc = GetState(fDimDriveControl);
+            const State rc = fDim->GetState(fDim->fDriveControl);
             string col = kHtmlGreen;
             if (rc.index==6) // Moving
@@ -1557,5 +1657,5 @@
             out << fDriveControlPointingZd  << '\t';
             out << fDriveControlPointingAz  << '\t';
-            if (fDimDriveControl.state()==7)
+            if (fDim->fDriveControl.state()==7)
             {
                 out << fDriveControlSourceName  << '\t';
@@ -1571,5 +1671,5 @@
 
         // ------------------- FSC ------------------
-        if (fDimFscControl.state()>1 && fFscControlTemperatureHist.size()>0)
+        if (fDim->fFscControl.state()>1 && fFscControlTemperatureHist.size()>0)
         {
             out << kHtmlGreen << '\t' << fFscControlTemperatureHist.back() << '\n';
@@ -1579,5 +1679,5 @@
 
         // --------------- MagicWeather -------------
-        if (fDimMagicWeather.state()==3 && fMagicWeatherHist[kWeatherBegin].size()>0)
+        if (fDim->fMagicWeather.state()==3 && fMagicWeatherHist[kWeatherBegin].size()>0)
         {
             /*
@@ -1608,5 +1708,5 @@
 
         // --------------- FtmControl -------------
-        if (fDimFtmControl.state()==FTM::kTriggerOn)
+        if (fDim->fFtmControl.state()==FTM::kTriggerOn)
         {
             string col = kHtmlGreen;
@@ -1622,11 +1722,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 (fDim->fBiasControl.state()==BIAS::kRamping     ||
+            fDim->fBiasControl.state()==BIAS::kOverCurrent ||
+            fDim->fBiasControl.state()==BIAS::kVoltageOn   ||
+            fDim->fBiasControl.state()==BIAS::kVoltageOff)
+        {
+            const bool off = fDim->fBiasControl.state()==BIAS::kVoltageOff;
+            const bool oc  = fDim->fBiasControl.state()==BIAS::kOverCurrent;
 
             string col = fBiasControlVoltageMed>3?kHtmlGreen:kHtmlWhite;
@@ -1637,12 +1737,12 @@
 
             // Bias in overcurrent => Red
-            if (fDimBiasControl.state()==BIAS::kOverCurrent)
+            if (fDim->fBiasControl.state()==BIAS::kOverCurrent)
                 col = kHtmlRed;
 
             // MCP in ReadyForDatataking/Configuring/Configured/TriggerOn/TakingData
             // and Bias not in "data-taking state' => Red
-            if (fDimMcp.state()>5 &&
-                fDimBiasControl.state()!=BIAS::kVoltageOn &&
-                fDimBiasControl.state()!=BIAS::kVoltageOff)
+            if (fDim->fMcp.state()>5 &&
+                fDim->fBiasControl.state()!=BIAS::kVoltageOn &&
+                fDim->fBiasControl.state()!=BIAS::kVoltageOff)
                 col = kHtmlRed;
 
@@ -1650,5 +1750,5 @@
 
             // Feedback is currently calibrating => Blue
-            if (fDimFeedback.state()==13)
+            if (fDim->fFeedback.state()==13)
             {
                 out << kHtmlBlue << '\t';
@@ -1686,25 +1786,25 @@
 
         out.str("");
-        out << now.JavaDate() << '\t' << fDimControl.online() << '\n';
-
-        if (fDim.state()==0)
+        out << now.JavaDate() << '\t' << fDim->fControl.online() << '\n';
+
+        if (fDim->fDNS.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(fDimControl,      0);
-            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);
+            out << kHtmlGreen << '\t' << fDim->fDNS.version() << '\n';
+
+            out << GetStateHtml(fDim->fMcp,          4);
+            out << GetStateHtml(fDim->fControl,      0);
+            out << GetStateHtml(fDim->fDataLogger,   1);
+            out << GetStateHtml(fDim->fDriveControl, 2);
+            out << GetStateHtml(fDim->fFadControl,   FAD::kConnected);
+            out << GetStateHtml(fDim->fFtmControl,   FTM::kConnected);
+            out << GetStateHtml(fDim->fBiasControl,  BIAS::kConnected);
+            out << GetStateHtml(fDim->fFeedback,     4);
+            out << GetStateHtml(fDim->fRateControl,  4);
+            out << GetStateHtml(fDim->fFscControl,   2);
+            out << GetStateHtml(fDim->fMagicWeather, 2);
+            out << GetStateHtml(fDim->fRateScan,     4);
+            out << GetStateHtml(fDim->fChatServer,   1);
         }
 
@@ -1720,44 +1820,5 @@
         fMcpConfigurationMaxEvents(0),
         fRateScanDataId(0),
-        //---
-        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"),
-        //---
-        fDimMcpConfiguration      ("MCP/CONFIGURATION",               (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),
-        //---
-        fDimFscControlTemperature ("FSC_CONTROL/TEMPERATURE",         (void*)NULL, 0, this),
-        fDimFscControlHumidity    ("FSC_CONTROL/HUMIDITY",            (void*)NULL, 0, this),
-        //---
-        fDimMagicWeatherData      ("MAGIC_WEATHER/DATA",              (void*)NULL, 0, this),
-        //---
-        fDimFeedbackDeviation     ("FEEDBACK/DEVIATION",              (void*)NULL, 0, this),
-        fDimFeedbackCalibration   ("FEEDBACK/CALIBRATION",            (void*)NULL, 0, this),
-        //---
-        fDimBiasControlVoltage    ("BIAS_CONTROL/VOLTAGE",            (void*)NULL, 0, this),
-        fDimBiasControlCurrent    ("BIAS_CONTROL/CURRENT",            (void*)NULL, 0, this),
-        //---
-        fDimFadConnections        ("FAD_CONTROL/CONNECTIONS",         (void*)NULL, 0, this),
-        fDimFadEvents             ("FAD_CONTROL/EVENTS",              (void*)NULL, 0, this),
-        //---
-        fDimFtmControlTriggerRates("FTM_CONTROL/TRIGGER_RATES",       (void*)NULL, 0, this),
-        fDimFtmControlStaticData  ("FTM_CONTROL/STATIC_DATA",         (void*)NULL, 0, this),
-        //-
-        fDimRateScanData          ("RATE_SCAN/DATA",                  (void*)NULL, 0, this),
-        //-
-        fDimFadControlEventData(0)
+        fDim(0)
     {
         // State names
@@ -1771,9 +1832,8 @@
             ("");
 
-        fDimControl.AddCallback("dotest.dim", bind(&StateMachineSmartFACT::HandleDoTest, this, placeholders::_1));
     }
     ~StateMachineSmartFACT()
     {
-        delete fDimFadControlEventData;
+        delete fDim;
     }
     int EvalOptions(Configuration &conf)
@@ -1785,10 +1845,8 @@
         }
 
-        // First move all the dim services to another class so that
-        // they can be instatiated all at once _after_ path was set
-        //fPath = conf.Get<string>("path");
-
-        // Pixel map is needed to deal with this service
-        fDimFadControlEventData=new DimStampedInfo("FAD_CONTROL/EVENT_DATA", (void*)NULL, 0, this);
+        fPath = conf.Get<string>("path");
+
+        fDim = new DimSubscriptions(this);
+        fDim->fControl.AddCallback("dotest.dim", bind(&StateMachineSmartFACT::HandleDoTest, this, placeholders::_1));
 
         return -1;
