Index: trunk/FACT++/src/smartfact.cc
===================================================================
--- trunk/FACT++/src/smartfact.cc	(revision 13497)
+++ trunk/FACT++/src/smartfact.cc	(revision 13498)
@@ -1,4 +1,2 @@
-#include <valarray>
-
 #include "Dim.h"
 #include "Event.h"
@@ -19,4 +17,5 @@
 #include "HeadersFAD.h"
 #include "HeadersBIAS.h"
+#include "HeadersFTM.h"
 
 namespace ba    = boost::asio;
@@ -41,5 +40,35 @@
     };
 
+    // ------------------------- Internal variables -----------------------
+
     PixelMap fPixelMap;
+
+    Time fLastUpdate;
+
+    // ----------------------------- Data storage -------------------------
+
+    enum weather_t { kTemp = 0, kDew, kHum, kPress, kWind, kGusts, kDir };
+    float fMagicWeatherData[7];
+
+    vector<float> fFeedbackCalibration;
+    vector<float> fBiasControlVoltageVec;
+
+    float  fBiasControlVoltageMed;
+    float  fBiasControlCurrentMed;
+    float  fBiasControlCurrentMax;
+
+    deque<float> fBiasControlCurrentHist;
+
+    float  fDriveControlPointingZd;
+    string fDriveControlPointingAz;
+    float  fDriveControlTrackingDev;
+    string fDriveControlSourceName;
+
+    float  fFtmControlTriggerRateCam;
+    deque<float> fFtmControlTriggerRateHist;
+
+    uint8_t fFadControlEventCounter;
+
+    // ------------- Initialize variables before the Dim stuff ------------
 
     DimServiceInfoList fNetwork;
@@ -50,4 +79,5 @@
     pair<Time, int> fStatusFeedback;
     pair<Time, int> fStatusBiasControl;
+    pair<Time, int> fStatusFtmControl;
     pair<Time, int> fStatusFadControl;
 
@@ -69,23 +99,9 @@
     DimStampedInfo fDimBiasControlCurrent;
 
+    DimStampedInfo fDimFtmControl;
+    DimStampedInfo fDimFtmControlTriggerRates;
+
     DimStampedInfo fDimFadControl;
     DimStampedInfo *fDimFadControlEventData;
-
-    Time fLastUpdate;
-
-    enum weather_t { kTemp = 0, kDew, kHum, kPress, kWind, kGusts, kDir };
-    float fMagicWeatherData[7];
-
-    vector<float> fFeedbackCalibration;
-    vector<float> fBiasControlVoltageVec;
-
-    float  fBiasControlVoltageMed;
-    float  fBiasControlCurrentMed;
-    float  fBiasControlCurrentMax;
-
-    float  fDriveControlPointingZd;
-    string fDriveControlPointingAz;
-    float  fDriveControlTrackingDev;
-    string fDriveControlSourceName;
 
     // -------------------------------------------------------------------
@@ -133,4 +149,26 @@
     }
 
+
+    // -------------------------------------------------------------------
+
+    template<class T>
+        void WriteBinary(const string &fname, const T &t, double scale, double offset=0)
+    {
+        vector<uint8_t> val(t.size(), 0);
+        for (uint64_t i=0; i<t.size(); i++)
+        {
+            float range = nearbyint(128*(t[i]+offset)/scale); // [-2V; 2V]
+            if (range>127)
+                range=127;
+            if (range<0)
+                range=0;
+            val[i] = (uint8_t)range;
+        }
+
+        const char *ptr = reinterpret_cast<char*>(val.data());
+
+        ofstream fout("www/"+fname+".bin");
+        fout.write(ptr, val.size()*sizeof(uint8_t));
+    }
 
     // -------------------------------------------------------------------
@@ -271,38 +309,60 @@
             return;
 
+        // Convert dac counts to uA
         vector<float> v(320);
         for (int i=0; i<320; i++)
-            v[i] = d.ptr<uint16_t>()[i];
-
+            v[i] = d.ptr<uint16_t>()[i] * 5000./4096;
+
+        // Calibrate the data (subtract offset)
         if (fFeedbackCalibration.size()>0 && fBiasControlVoltageVec.size()>0)
             for (int i=0; i<320; i++)
                 v[i] -= fBiasControlVoltageVec[i]/fFeedbackCalibration[i]*1e6;
 
-        vector<uint8_t> val(160, 0);
+        // Get the maximum of each patch
+        vector<float> val(160, 0);
         for (int i=0; i<160; i++)
-        {
-            const float I = max(v[i*2], v[i*2+1]);
-
-            float range = nearbyint(128*I/1000); // [0, 1000uA]
-            if (range>127)
-                range=127;
-            if (range<0)
-                range=0;
-            val[i] = (uint8_t)range;
-        }
-
+            val[i] = max(v[i*2], v[i*2+1]);
+
+        // Write the 160 patch values to a file
+        WriteBinary("biascontrol-current", val, 1000);
+
+        // Now sort them to determine the median
         sort(v.begin(), v.end());
 
         // Exclude the three crazy channels
-        fBiasControlCurrentMed = (v[159]+v[160])/2 * 5000./4096;
-        fBiasControlCurrentMax = v[316]            * 5000./4096;
-
-        const char *ptr = reinterpret_cast<char*>(val.data());
-
-        ofstream fout("www/biascontrol-current.bin");
-        fout.write(ptr, 160*sizeof(uint8_t));
-    }
-
-    uint8_t fEventCounter;
+        fBiasControlCurrentMed = (v[159]+v[160])/2;
+        fBiasControlCurrentMax = v[316];
+
+        // Store a history of the last 60 entries
+        fBiasControlCurrentHist.push_back(fBiasControlCurrentMed);
+        if (fBiasControlCurrentHist.size()>60)
+            fBiasControlCurrentHist.pop_front();
+
+        // write the history to a file
+        WriteBinary("biascontrol-current-hist", fBiasControlCurrentHist, 1000);
+    }
+
+    void HandleFtmControlTriggerRates(const DimData &d)
+    {
+        if (!CheckDataSize(d, "FtmControl:TriggerRates", 24+160+640+8))
+            return;
+
+        fFtmControlTriggerRateCam = d.get<float>(20);
+
+        const float *brates = d.ptr<float>(24);     // Board rate
+        const float *prates = d.ptr<float>(24+160); // Patch rate
+
+        // Store a history of the last 60 entries
+        fFtmControlTriggerRateHist.push_back(fFtmControlTriggerRateCam);
+        if (fFtmControlTriggerRateHist.size()>60)
+            fFtmControlTriggerRateHist.pop_front();
+
+        WriteBinary("ftmcontrol-triggerrate-hist",
+                    fFtmControlTriggerRateHist, 100);
+        WriteBinary("ftmcontrol-boardrates",
+                    vector<float>(brates, brates+40), 50);
+        WriteBinary("ftmcontrol-patchrates",
+                    vector<float>(prates, prates+160), 10);
+    }
 
     void HandleFadControlEventData(const DimData &d)
@@ -311,5 +371,5 @@
             return;
 
-        if (fEventCounter++%30)
+        if (fFadControlEventCounter++%30)
             return;
 
@@ -328,19 +388,5 @@
         }
 
-        vector<uint8_t> val(160, 0);
-        for (int i=0; i<160; i++)
-        {
-            float range = nearbyint(64*dat[i]/2000)+64; // [-2V; 2V]
-            if (range>127)
-                range=127;
-            if (range<0)
-                range=0;
-            val[i] = (uint8_t)range;
-        }
-
-        const char *ptr = reinterpret_cast<char*>(val.data());
-
-        ofstream fout("www/fadcontrol-eventdata.bin");
-        fout.write(ptr, 160*sizeof(int8_t));
+        WriteBinary("fadcontrol-eventdata", dat, 4000, 2000);
     }
 
@@ -353,13 +399,15 @@
             return;
 
-        if (HandleService(curr, fDimMagicWeatherData,     &StateMachineSmartFACT::HandleMagicWeatherData))
-            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, *fDimFadControlEventData, &StateMachineSmartFACT::HandleFadControlEventData))
+        if (HandleService(curr, fDimMagicWeatherData,       &StateMachineSmartFACT::HandleMagicWeatherData))
+            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, fDimFtmControlTriggerRates, &StateMachineSmartFACT::HandleFtmControlTriggerRates))
+            return;
+        if (HandleService(curr, *fDimFadControlEventData,   &StateMachineSmartFACT::HandleFadControlEventData))
             return;
 
@@ -369,4 +417,6 @@
             return;
         if (UpdateState(curr, fDimBiasControl, fStatusBiasControl))
+            return;
+        if (UpdateState(curr, fDimFtmControl, fStatusFtmControl))
             return;
         if (UpdateState(curr, fDimFadControl, fStatusFadControl))
@@ -468,5 +518,5 @@
         }
         else
-            out << kWhite << "\t\t\t\t\t\n";
+            out << kWhite << "\n";
 
         // --------------- MagicWeather -------------
@@ -494,5 +544,19 @@
         }
         else
-            out << kWhite << "\t\t\n\n";
+            out << kWhite << "\n\n";
+
+        // --------------- FtmControl -------------
+        if (fStatusFtmControl.second>=FTM::kIdle)
+        {
+            string col = kGreen;
+            if (fFtmControlTriggerRateCam<15)
+                col = kYellow;
+            if (fFtmControlTriggerRateCam>100)
+                col = kRed;
+
+            out << col << '\t' << fFtmControlTriggerRateCam << '\n';
+        }
+        else
+            out << kWhite << '\n';
 
         // --------------- BiasControl -------------
@@ -516,5 +580,5 @@
         }
         else
-            out << kWhite << "\t\t\t\n";
+            out << kWhite << "\n";
 
 
@@ -528,4 +592,6 @@
 public:
     StateMachineSmartFACT(ostream &out=cout) : StateMachineDim(out, "SMART_FACT"),
+        fFadControlEventCounter(0),
+        //---
         fStatusDim         (make_pair(Time(), -2)),
         fStatusDriveControl(make_pair(Time(), -2)),
@@ -533,27 +599,29 @@
         fStatusFeedback    (make_pair(Time(), -2)),
         fStatusBiasControl (make_pair(Time(), -2)),
+        fStatusFtmControl  (make_pair(Time(), -2)),
         fStatusFadControl  (make_pair(Time(), -2)),
         //---
-        fDim                    ("DIS_DNS/VERSION_NUMBER",          (void*)NULL, 0, this),
+        fDim                      ("DIS_DNS/VERSION_NUMBER",          (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),
+        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),
-        fDimMagicWeatherData    ("MAGIC_WEATHER/DATA",              (void*)NULL, 0, this),
+        fDimMagicWeather          ("MAGIC_WEATHER/STATE",             (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),
+        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),
+        fDimBiasControl           ("BIAS_CONTROL/STATE",              (void*)NULL, 0, this),
+        fDimBiasControlVoltage    ("BIAS_CONTROL/VOLTAGE",            (void*)NULL, 0, this),
+        fDimBiasControlCurrent    ("BIAS_CONTROL/CURRENT",            (void*)NULL, 0, this),
         //---
-        fDimFadControl          ("FAD_CONTROL/STATE",               (void*)NULL, 0, this),
-        fDimFadControlEventData(0),
-        //---
-        fEventCounter(0)
+        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)
     {
         // State names
