Index: trunk/FACT++/src/smartfact.cc
===================================================================
--- trunk/FACT++/src/smartfact.cc	(revision 13819)
+++ trunk/FACT++/src/smartfact.cc	(revision 13820)
@@ -306,112 +306,124 @@
 
 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));
-        }
-    };
+{
+protected:
+    typedef function<void(const DimData &)> callback;
+
+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;
+
+    callback fCallback;
+
+    void SetCallback(const callback &cb)
+    {
+        fCallback = cb;
+    }
+
+    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();
+
+        if (fCallback)
+            fCallback(DimData(curr));
+    }
+
+    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
+{
+    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
@@ -434,4 +446,6 @@
     DimState   fChatServer;
 
+    DimStampedInfo fControlMessage;
+
     DimStampedInfo fMcpConfiguration;
 
@@ -475,4 +489,6 @@
         fRateScan              ("RATE_SCAN"),
         fChatServer            ("CHAT_SERVER"),
+        //---
+        fControlMessage        ("DIM_CONTROL/MESSAGE",             (void*)NULL, 0, h),
         //---
         fMcpConfiguration      ("MCP/CONFIGURATION",               (void*)NULL, 0, h),
@@ -537,4 +553,6 @@
     // ----------------------------- Data storage -------------------------
 
+    deque<string> fControlMessageHist;
+
     uint32_t fMcpConfigurationState;
      int64_t fMcpConfigurationMaxTime;
@@ -578,5 +596,6 @@
 
     uint64_t  fRateScanDataId;
-    deque<float> fRateScanDataHist;
+    uint8_t   fRateScanBoard;
+    deque<float> fRateScanDataHist[41];
 
     // ------------- Initialize variables before the Dim stuff ------------
@@ -676,4 +695,49 @@
     };
 
+    void HandleControlMessageImp(const DimData &d)
+    {
+        if (d.size()==0)
+            return;
+
+        const string str  = fControlMessageHist.size()>0 ? fControlMessageHist.back() : "<pre>  :  :  </pre> ";
+        const string time = "<pre>"+d.time.GetAsStr("%H:%M:%S")+"</pre> ";
+
+        ostringstream tst;
+        tst << d.qos;
+
+        string msg;
+        msg += str.substr(0, time.length())==time ? "<pre>        </pre> " : time;
+        msg += d.ptr<char>();
+
+        fControlMessageHist.push_back(msg);
+
+        ostringstream out;
+        out << setprecision(3);
+        out << d.time.JavaDate() << '\n';
+        out << "#ffffff\t";
+
+        for (auto it=fControlMessageHist.begin(); it!=fControlMessageHist.end(); it++)
+            out << *it << "<br/>";
+
+        out << '\n';
+
+        ofstream(fPath+"/test.txt") << out.str();
+    }
+
+    void HandleControlMessage(const DimData &d)
+    {
+        if (d.qos==90)
+            HandleControlMessageImp(d);
+    }
+
+    void HandleControlStateChange(const DimData &d)
+    {
+        if (d.qos==-2)
+            fControlMessageHist.clear();
+
+        if (d.qos<0)
+            HandleControlMessageImp(d);
+    }
+
     void HandleMcpConfiguration(const DimData &d)
     {
@@ -729,8 +793,10 @@
         };
 
-        const uint16_t idx = uint16_t(floor(fmod(fMagicWeatherHist[kDir].back()+360+11.25, 360)/22.5));
+
+        const uint16_t idx = uint16_t(floor(fMagicWeatherHist[kDir].back()/22.5+16.5))%16;
+        //const uint16_t idx = uint16_t(floor(fmod(fMagicWeatherHist[kDir].back()/22.5+360+11.25, 360)/22.5))%16;
 
         Astro astro(-(17.+53./60+26.525/3600), 28.+45./60+42.462/3600);
-        Moon  moon(-(17.+53./60+26.525/3600), 28.+45./60+42.462/3600);
+        Moon  moon (-(17.+53./60+26.525/3600), 28.+45./60+42.462/3600);
 
         ostringstream out;
@@ -789,6 +855,6 @@
         };
 
-        const uint16_t i = uint16_t(floor(fmod(az+360+11.25, 360)/22.5));
-        fDriveControlPointingAz = dir[i];
+        const uint16_t idx = uint16_t(floor(az/22.5+16.5))%16;
+        fDriveControlPointingAz = dir[idx];
 
         ostringstream out;
@@ -1366,14 +1432,42 @@
 
         const uint64_t id   = d.get<uint64_t>();
-        const float    rate = log10(d.get<float>(20));
+        const float   *rate = d.ptr<float>(20);
 
         if (fRateScanDataId!=id)
         {
-            fRateScanDataHist.clear();
+            for (int i=0; i<41; i++)
+                fRateScanDataHist[i].clear();
             fRateScanDataId = id;
         }
-        fRateScanDataHist.push_back(rate);
-
-        WriteBinary(d, "ratescan-hist", fRateScanDataHist, 10, -2);
+        fRateScanDataHist[0].push_back(log10(rate[0]));
+
+        double max = 0;
+        for (int i=1; i<41; i++)
+        {
+            fRateScanDataHist[i].push_back(log10(rate[i]));
+            if (rate[i]>max)
+                max = rate[i];
+        }
+
+        fRateScanBoard ++;
+        fRateScanBoard %= 40;
+
+        WriteBinary(d, "ratescan-hist",  fRateScanDataHist[0],                10, -2);
+        WriteBinary(d, "ratescan-board", fRateScanDataHist[fRateScanBoard+1], 10, -2);
+
+        ostringstream out;
+        out << setprecision(3);
+        out << d.time.JavaDate() << '\n';
+        out << "#ffffff\t" << pow(10, fRateScanDataHist[0].back()) << '\n';
+        out << "#ffffff\t" << max << '\n';
+
+        ofstream(fPath+"/ratecan.txt") << out.str();
+
+        out.str("");
+        out << d.time.JavaDate() << '\n';
+        out << "#ffffff\t" << int(fRateScanBoard) << '\n';
+        out << "#ffffff\t" << pow(10, fRateScanDataHist[fRateScanBoard+1].back()) << '\n';
+
+        ofstream(fPath+"/ratecan_board.txt") << out.str();
     }
 
@@ -1436,4 +1530,6 @@
             return;
         if (HandleService(curr, fDim->fFscControlHumidity,     &StateMachineSmartFACT::HandleFscControlHumidity))
+            return;
+        if (HandleService(curr, fDim->fControlMessage,         &StateMachineSmartFACT::HandleControlMessage))
             return;
         if (HandleService(curr, fDim->fRateScanData,           &StateMachineSmartFACT::HandleRateScanData))
@@ -1819,5 +1915,7 @@
         fMcpConfigurationMaxTime(0),
         fMcpConfigurationMaxEvents(0),
+        fFscControlHumidityAvg(0),
         fRateScanDataId(0),
+        fRateScanBoard(0),
         fDim(0)
     {
@@ -1848,4 +1946,5 @@
 
         fDim = new DimSubscriptions(this);
+        fDim->fControl.SetCallback(bind(&StateMachineSmartFACT::HandleControlStateChange, this, placeholders::_1));
         fDim->fControl.AddCallback("dotest.dim", bind(&StateMachineSmartFACT::HandleDoTest, this, placeholders::_1));
 
