Index: /trunk/FACT++/src/smartfact.cc
===================================================================
--- /trunk/FACT++/src/smartfact.cc	(revision 13620)
+++ /trunk/FACT++/src/smartfact.cc	(revision 13621)
@@ -83,4 +83,7 @@
     float  fFtmControlTriggerRateCam;
     deque<float> fFtmControlTriggerRateHist;
+
+    uint64_t  fRateScanDataId;
+    deque<float> fRateScanDataHist;
 
     // ------------- Initialize variables before the Dim stuff ------------
@@ -182,4 +185,6 @@
     DimStampedInfo fDimFtmControlTriggerRates;
 
+    DimStampedInfo fDimRateScanData;
+
     DimStampedInfo *fDimFadControlEventData;
 
@@ -224,5 +229,5 @@
         for (uint64_t i=0; i<t.size(); i++)
         {
-            float range = nearbyint(128*(t[i]+offset)/scale); // [-2V; 2V]
+            float range = nearbyint(128*(t[i]-offset)/scale); // [-2V; 2V]
             if (range>127)
                 range=127;
@@ -240,4 +245,27 @@
     // -------------------------------------------------------------------
 
+    struct Statistics
+    {
+        float min;
+        float max;
+        float med;
+        float avg;
+        //float rms;
+
+        template<class T>
+            Statistics(const T &t)
+        {
+            min = *min_element(t.begin(), t.end());
+            max = *max_element(t.begin(), t.end());
+            avg =  accumulate (t.begin(), t.end(), 0.)/t.size();
+
+            const size_t p = t.size()/2;
+
+            T copy(t);
+            nth_element(copy.begin(), copy.begin()+p, copy.end());
+            med = copy[p];
+        }
+    };
+
     void HandleMcpConfiguration(const DimData &d)
     {
@@ -256,7 +284,5 @@
     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();
+        const Statistics stat(fMagicWeatherHist[i]);
 
         ostringstream out;
@@ -265,11 +291,11 @@
 
         out << "#ffffff\t" << fMagicWeatherHist[i].back() << '\n';
-        out << "#ffffff\t" << *fmin << '\n';
-        out << "#ffffff\t" <<  favg << '\n';
-        out << "#ffffff\t" << *fmax << '\n';
+        out << "#ffffff\t" << stat.min << '\n';
+        out << "#ffffff\t" << stat.avg << '\n';
+        out << "#ffffff\t" << stat.max << '\n';
 
         ofstream("www/"+name+".txt") << out.str();
 
-        WriteBinary("magicweather-"+name+"-hist", fMagicWeatherHist[i], max-min, -min);
+        WriteBinary("magicweather-"+name+"-hist", fMagicWeatherHist[i], max-min, min);
     }
 
@@ -287,9 +313,20 @@
         }
 
+        static const char *dir[] =
+        {
+            "N", "NNE", "NE", "ENE",
+            "E", "ESE", "SE", "SSE",
+            "S", "SSW", "SW", "WSW",
+            "W", "WNW", "NW", "NNW"
+        };
+
+        const uint16_t idx = uint16_t(floor(fmod(fMagicWeatherHist[kDir].back()+360+11.25, 360)/22.5));
+
         ostringstream out;
         out << uint64_t(d.time.UnixTime()*1000) << '\n';
-
-        for (int i=0; i<7; i++)
+        for (int i=0; i<6; i++)
             out << "#ffffff\t" << fMagicWeatherHist[i].back() << '\n';
+        out << "#ffffff\t" << dir[idx] << '\n';
+
 
         ofstream("www/magicweather.txt") << out.str();
@@ -320,5 +357,5 @@
         };
 
-        const uint16_t i = uint16_t(floor(fmod(az+360+11.25, 360)/22));
+        const uint16_t i = uint16_t(floor(fmod(az+360+11.25, 360)/22.5));
         fDriveControlPointingAz = dir[i];
 
@@ -404,12 +441,7 @@
         fBiasControlVoltageVec.assign(d.ptr<float>(), d.ptr<float>()+320);
 
-        vector<float> v(fBiasControlVoltageVec);
-        sort(v.begin(), v.end());
-
-        fBiasControlVoltageMed = (v[159]+v[160])/2;
-
-        //const char *ptr = d.ptr<char>();
-        //ofstream fout("www/biascontrol-voltage.bin");
-        //fout.write(ptr, 320*sizeof(float));
+        const Statistics stat(fBiasControlVoltageVec);
+
+        fBiasControlVoltageMed = stat.med;
 
         vector<float> val(320, 0);
@@ -417,8 +449,18 @@
         {
             const int idx = (fPixelMap.hv(i).hw()/9)*2+fPixelMap.hv(i).group();
-            val[i] = v[i];
+            val[idx] = fBiasControlVoltageVec[i];
         }
 
         WriteBinary("biascontrol-voltage", val, 75);
+
+        ostringstream out;
+        out << setprecision(3);
+        out << uint64_t(d.time.UnixTime()*1000) << '\n';
+        out << kHtmlWhite << '\t' << stat.min << '\n';
+        out << kHtmlWhite << '\t' << stat.med << '\n';
+        out << kHtmlWhite << '\t' << stat.avg << '\n';
+        out << kHtmlWhite << '\t' << stat.max << '\n';
+        ofstream("www/voltage.txt") << out.str();
+
     }
 
@@ -443,5 +485,5 @@
         {
             const int idx = (fPixelMap.hv(i).hw()/9)*2+fPixelMap.hv(i).group();
-            val[idx] = v[i];//max(v[i*2], v[i*2+1]);
+            val[idx] = v[i];
         }
 
@@ -449,10 +491,9 @@
         WriteBinary("biascontrol-current", val, 1000);
 
-        // Now sort them to determine the median
-        sort(v.begin(), v.end());
+        const Statistics stat(v);
 
         // Exclude the three crazy channels
-        fBiasControlCurrentMed = (v[159]+v[160])/2;
-        fBiasControlCurrentMax = v[316];
+        fBiasControlCurrentMed = stat.med;
+        fBiasControlCurrentMax = stat.max;
 
         // Store a history of the last 60 entries
@@ -463,4 +504,13 @@
         // write the history to a file
         WriteBinary("biascontrol-current-hist", fBiasControlCurrentHist, 1000);
+
+        ostringstream out;
+        out << setprecision(3);
+        out << uint64_t(d.time.UnixTime()*1000) << '\n';
+        out << kHtmlWhite << '\t' << stat.min << '\n';
+        out << kHtmlWhite << '\t' << stat.med << '\n';
+        out << kHtmlWhite << '\t' << stat.avg << '\n';
+        out << kHtmlWhite << '\t' << stat.max << '\n';
+        ofstream("www/current.txt") << out.str();
     }
 
@@ -494,6 +544,26 @@
         out << "#ffffff\t" << fFtmControlTriggerRateCam << '\n';
 
-        ofstream fout("www/trigger.txt");
-        fout << out.str();
+        ofstream("www/trigger.txt") << out.str();
+
+        const Statistics bstat(vector<float>(brates, brates+40));
+        const Statistics pstat(vector<float>(prates, prates+160));
+
+        out.str("");
+        out << uint64_t(d.time.UnixTime()*1000) << '\n';
+        out << kHtmlWhite << '\t' << bstat.min << '\n';
+        out << kHtmlWhite << '\t' << bstat.med << '\n';
+        out << kHtmlWhite << '\t' << bstat.avg << '\n';
+        out << kHtmlWhite << '\t' << bstat.max << '\n';
+        ofstream("www/boardrates.txt") << out.str();
+
+        out.str("");
+        out << uint64_t(d.time.UnixTime()*1000) << '\n';
+        out << kHtmlWhite << '\t' << pstat.min << '\n';
+        out << kHtmlWhite << '\t' << pstat.med << '\n';
+        out << kHtmlWhite << '\t' << pstat.avg << '\n';
+        out << kHtmlWhite << '\t' << pstat.max << '\n';
+        ofstream("www/patchrates.txt") << out.str();
+
+
     }
 
@@ -521,7 +591,7 @@
         switch (d.qos)
         {
-        case 0:  WriteBinary("fadcontrol-eventdata", max, 2000, 1000); break;
-        case 1:  WriteBinary("fadcontrol-eventdata", max, 2000,    0); break;
-        default: WriteBinary("fadcontrol-eventdata", max,  250,    0); break;
+        case 0:  WriteBinary("fadcontrol-eventdata", max, 2000, -1000); break;
+        case 1:  WriteBinary("fadcontrol-eventdata", max, 2000,     0); break;
+        default: WriteBinary("fadcontrol-eventdata", max,  250,     0); break;
         }
     }
@@ -566,20 +636,15 @@
             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();
+        const Statistics stat(fFscControlTemperatureHist);
 
         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';
+        out << "#ffffff\t" << min      << '\n';
+        out << "#ffffff\t" << avg      << '\n';
+        out << "#ffffff\t" << max      << '\n';
+        out << "#ffffff\t" << stat.min << '\n';
+        out << "#ffffff\t" << stat.avg << '\n';
+        out << "#ffffff\t" << stat.max << '\n';
 
         ofstream("www/fsc.txt") << out.str();
@@ -587,5 +652,4 @@
         WriteBinary("fsccontrol-temperature-hist",
                     fFscControlTemperatureHist, 30);
-
     }
 
@@ -610,4 +674,21 @@
     }
 
+    void HandleRateScanData(const DimData &d)
+    {
+        if (!CheckDataSize(d, "RateScan:Data", 24+200*40))
+            return;
+
+        const uint64_t id   = d.get<uint64_t>();
+        const float    rate = log10(d.get<float>(20));
+
+        if (fRateScanDataId!=id)
+        {
+            fRateScanDataHist.clear();
+            fRateScanDataId = id;
+        }
+        fRateScanDataHist.push_back(rate);
+
+        WriteBinary("ratescan-hist", fRateScanDataHist, 10, -1);
+    }
 
     // -------------------------------------------------------------------
@@ -619,5 +700,5 @@
             return;
 
-        if (HandleService(curr, fDimMcpConfiguration,       &StateMachineSmartFACT::HandleMcpConfiguration))
+        if (HandleService(curr, fDimMcpConfiguration,       &StateMachineSmartFACT::configuHandleMcpConfiguration))
             return;
         if (HandleService(curr, fDimMagicWeatherData,       &StateMachineSmartFACT::HandleMagicWeatherData))
@@ -642,4 +723,6 @@
             return;
         if (HandleService(curr, fDimFscControlHumidity,     &StateMachineSmartFACT::HandleFscControlHumidity))
+            return;
+        if (HandleService(curr, fDimRateScanData,           &StateMachineSmartFACT::HandleRateScanData))
             return;
     }
@@ -768,6 +851,4 @@
             if (fMcpConfigurationMaxEvents>0 || fMcpConfigurationState==12)
                 out << ']';
-
-
         }
         else
@@ -919,4 +1000,7 @@
 public:
     StateMachineSmartFACT(ostream &out=cout) : StateMachineDim(out, "SMART_FACT"),
+        fMcpConfigurationMaxTime(0),
+        fMcpConfigurationMaxEvents(0),
+        fRateScanDataId(0),
         //---
         fDimMcp                   ("MCP"),
@@ -951,6 +1035,6 @@
         fDimFtmControlTriggerRates("FTM_CONTROL/TRIGGER_RATES",       (void*)NULL, 0, this),
         //-
-        fMcpConfigurationMaxEvents(0),
-        fMcpConfigurationMaxTime(0),
+        fDimRateScanData          ("RATE_SCAN/DATA",                  (void*)NULL, 0, this),
+        //-
         fDimFadControlEventData(0)
     {
