Index: /trunk/FACT++/src/smartfact.cc
===================================================================
--- /trunk/FACT++/src/smartfact.cc	(revision 13698)
+++ /trunk/FACT++/src/smartfact.cc	(revision 13699)
@@ -48,4 +48,6 @@
     Time fLastUpdate;
 
+    string fPath;
+
     // ----------------------------- Data storage -------------------------
 
@@ -84,4 +86,6 @@
     deque<float> fFtmControlTriggerRateHist;
 
+    vector<float> fFtmPatchThresholds;
+
     uint64_t  fRateScanDataId;
     deque<float> fRateScanDataHist;
@@ -100,4 +104,5 @@
         string server;
         pair<Time, int> info;
+        string msg;
 
         DimStampedInfo dim;
@@ -117,4 +122,6 @@
             info = make_pair(Time(tsec, tms*1000),
                              disconnected ? -2 : dim.getQuality());
+
+            msg = disconnected ? "" : dim.getString();
         }
 
@@ -146,7 +153,7 @@
                 return "Offline";
 
-            ostringstream msg;
-            msg << "V" << info.second/100 << 'r' << info.second%100;
-            return msg.str();
+            ostringstream out;
+            out << "V" << info.second/100 << 'r' << info.second%100;
+            return out.str();
         }
     };
@@ -186,4 +193,5 @@
 
     DimStampedInfo fDimFtmControlTriggerRates;
+    DimStampedInfo fDimFtmControlStaticData;
 
     DimStampedInfo fDimRateScanData;
@@ -241,5 +249,5 @@
         const char *ptr = reinterpret_cast<char*>(val.data());
 
-        ofstream fout("www/"+fname+".bin");
+        ofstream fout(fPath+"/"+fname+".bin");
         fout << offset << '\n';
         fout << offset+scale << '\n';
@@ -309,5 +317,5 @@
         out << "#ffffff\t" << stat.max << '\n';
 
-        ofstream("www/"+name+".txt") << out.str();
+        ofstream(fPath+"/"+name+".txt") << out.str();
 
         WriteBinary("magicweather-"+name+"-hist", fMagicWeatherHist[i], max-min, min);
@@ -344,5 +352,5 @@
 
 
-        ofstream("www/magicweather.txt") << out.str();
+        ofstream(fPath+"/magicweather.txt") << out.str();
 
         WriteWeather(d, "temp",  kTemp,   -5,   35);
@@ -381,5 +389,5 @@
         out << az << '\n';
 
-        ofstream("www/drive-pointing.txt") << out.str();
+        ofstream(fPath+"/drive-pointing.txt") << out.str();
     }
 
@@ -389,7 +397,7 @@
             return;
 
-        const double zd  = d.get<double>(4*8) * M_PI / 180;
-        const double dzd = d.get<double>(6*8) * M_PI / 180;
-        const double daz = d.get<double>(7*8) * M_PI / 180;
+        const double zd  = d.get<double>(3*8) * M_PI / 180;
+        const double dzd = d.get<double>(5*8) * M_PI / 180;
+        const double daz = d.get<double>(6*8) * M_PI / 180;
 
         // Correct:
@@ -399,4 +407,5 @@
         const double dev = cos(dzd) - sin(zd+dzd)*sin(zd)*(1.-cos(daz));
         fDriveControlTrackingDev = acos(dev) * 180 / M_PI * 3600;
+
         if (fDriveControlTrackingDev<0.01)
             fDriveControlTrackingDev=0;
@@ -428,5 +437,5 @@
         out << "#ffffff\t" << wang << '\n';
 
-        ofstream("www/drive.txt") << out.str();
+        ofstream(fPath+"/drive.txt") << out.str();
     }
 
@@ -448,4 +457,5 @@
             return;
 
+        const float *ptr = d.ptr<float>();
         vector<float> dev(ptr+416, ptr+416+320);
 
@@ -471,5 +481,4 @@
         out << kHtmlWhite << '\t' << stat.max << '\n';
         ofstream("www/feedback.txt") << out.str();
-
     }
 
@@ -495,5 +504,8 @@
         }
 
-        WriteBinary("biascontrol-voltage", val, 75);
+        if (fDimBiasControl.state()==BIAS::kVoltageOn)
+            WriteBinary("biascontrol-voltage", val, 10, 65);
+        else
+            WriteBinary("biascontrol-voltage", val, 75);
 
         ostringstream out;
@@ -504,5 +516,5 @@
         out << kHtmlWhite << '\t' << stat.avg << '\n';
         out << kHtmlWhite << '\t' << stat.max << '\n';
-        ofstream("www/voltage.txt") << out.str();
+        ofstream(fPath+"/voltage.txt") << out.str();
 
     }
@@ -518,8 +530,13 @@
             v[i] = d.ptr<uint16_t>()[i] * 5000./4096;
 
+        const bool cal = fFeedbackCalibration.size()>0 && fBiasControlVoltageVec.size()>0;
+
         // Calibrate the data (subtract offset)
-        if (fFeedbackCalibration.size()>0 && fBiasControlVoltageVec.size()>0)
+        if (cal)
             for (int i=0; i<320; i++)
+            {
                 v[i] -= fBiasControlVoltageVec[i]/fFeedbackCalibration[i]*1e6;
+                v[i] /= fPixelMap.hv(i).group() ? 5 : 4;
+            }
 
         // Get the maximum of each patch
@@ -532,5 +549,5 @@
 
         // Write the 160 patch values to a file
-        WriteBinary("biascontrol-current", val, 500);
+        WriteBinary("biascontrol-current", val, 100);
 
         const Statistics stat(v, 0, 3);
@@ -542,18 +559,46 @@
         // Store a history of the last 60 entries
         fBiasControlCurrentHist.push_back(fBiasControlCurrentMed);
-        if (fBiasControlCurrentHist.size()>60)
+        if (fBiasControlCurrentHist.size()>360)
             fBiasControlCurrentHist.pop_front();
 
         // write the history to a file
-        WriteBinary("biascontrol-current-hist", fBiasControlCurrentHist, 500);
+        WriteBinary("biascontrol-current-hist", fBiasControlCurrentHist, 100);
+
+        const string col0 = cal ? kHtmlGreen : kHtmlWhite;
+
+        string col1 = col0;
+        string col2 = col0;
+        string col3 = col0;
+        string col4 = col0;
+
+        if (cal && stat.min>65)
+            col1 = kYellow;
+        if (cal && stat.min>80)
+            col1 = kRed;
+
+        if (cal && stat.med>65)
+            col2 = kYellow;
+        if (cal && stat.med>80)
+            col2 = kRed;
+
+        if (cal && stat.avg>65)
+            col3 = kYellow;
+        if (cal && stat.avg>80)
+            col3 = kRed;
+
+        if (cal && stat.max>65)
+            col4 = kYellow;
+        if (cal && stat.max>80)
+            col4 = kRed;
 
         ostringstream out;
         out << setprecision(3);
         out << d.time.JavaDate() << '\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();
+        out << col0 << '\t' << (cal?"yes":"no") << '\n';
+        out << col1 << '\t' << stat.min << '\n';
+        out << col2 << '\t' << stat.med << '\n';
+        out << col3 << '\t' << stat.avg << '\n';
+        out << col4 << '\t' << stat.max << '\n';
+        ofstream(fPath+"/current.txt") << out.str();
     }
 
@@ -591,5 +636,5 @@
         out << "#ffffff\t" << fFtmControlTriggerRateCam << '\n';
 
-        ofstream("www/trigger.txt") << out.str();
+        ofstream(fPath+"/trigger.txt") << out.str();
 
         const Statistics bstat(vector<float>(brates, brates+40));
@@ -602,5 +647,5 @@
         out << kHtmlWhite << '\t' << bstat.avg << '\n';
         out << kHtmlWhite << '\t' << bstat.max << '\n';
-        ofstream("www/boardrates.txt") << out.str();
+        ofstream(fPath+"/boardrates.txt") << out.str();
 
         out.str("");
@@ -610,5 +655,26 @@
         out << kHtmlWhite << '\t' << pstat.avg << '\n';
         out << kHtmlWhite << '\t' << pstat.max << '\n';
-        ofstream("www/patchrates.txt") << out.str();
+        ofstream(fPath+"/patchrates.txt") << out.str();
+    }
+
+    void HandleFtmControlStaticData(const DimData &d)
+    {
+        if (!CheckDataSize(d, "FtmControl:StaticData", 740))
+            return;
+
+        const uint16_t *ptr = d.ptr<uint16_t>(260);
+        vector<uint16_t> vec(ptr, ptr+160);
+
+        WriteBinary("ftmcontrol-thresholds", vec, 1000);
+
+        const Statistics stat(vec);
+
+        ostringstream out;
+        out << d.time.JavaDate() << '\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(fPath+"/thresholds.txt") << out.str();
     }
 
@@ -694,5 +760,5 @@
         out << "#ffffff\t" << stat.max << '\n';
 
-        ofstream("www/fsc.txt") << out.str();
+        ofstream(fPath+"/fsc.txt") << out.str();
 
         WriteBinary("fsccontrol-temperature-hist",
@@ -765,4 +831,6 @@
             return;
         if (HandleService(curr, fDimFtmControlTriggerRates, &StateMachineSmartFACT::HandleFtmControlTriggerRates))
+            return;
+        if (HandleService(curr, fDimFtmControlStaticData,   &StateMachineSmartFACT::HandleFtmControlStaticData))
             return;
         if (HandleService(curr, *fDimFadControlEventData,   &StateMachineSmartFACT::HandleFadControlEventData))
@@ -828,4 +896,11 @@
         const State rc = GetState(state);
 
+        if (rc.index==-2 && state.state()>-2)
+        {
+            ostringstream out;
+            out << kWhite << '\t' << state.state() << '\n';
+            return out.str();
+        }
+
         //ostringstream msg;
         //msg << kHtmlWhite << '\t' << rc.name << " [" << rc.index << "]\n";
@@ -884,5 +959,12 @@
             {
                 if (fMcpConfigurationState==12)
-                    out << fMcpConfigurationMaxTime-(Time()-fMcpConfigurationRunStart).total_seconds() << 's';
+                {
+
+                    const uint32_t dt = (Time()-fMcpConfigurationRunStart).total_seconds();
+                    if (dt>fMcpConfigurationMaxTime)
+                        out << "---";
+                    else
+                        out << fMcpConfigurationMaxTime-dt << 's';
+                }
                 else
                     out << "[" << fMcpConfigurationMaxTime << "s]";
@@ -987,14 +1069,23 @@
         {
             string col = fBiasControlVoltageMed>3?kHtmlGreen:kHtmlWhite;
-            if (fBiasControlCurrentMax>280)
+            if (fBiasControlCurrentMax>65)
                 col = kHtmlYellow;
-            if (fBiasControlCurrentMax>350)
+            if (fBiasControlCurrentMax>80)
                 col = kHtmlRed;
 
-            if (fFeedbackCalibration.size()==0)
-                col = kHtmlBlue;
+            // Bias in overcurrent => Red
             if (fDimBiasControl.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))
+                col = kHtmlRed;
+
+            const bool cal = fFeedbackCalibration.size();
+
+            // Feedback is currently calibrating => Blue
             if (fDimFeedback.state()==13)
             {
@@ -1007,5 +1098,9 @@
                 out << col << '\t';
                 out << fBiasControlCurrentMed << '\t';
-                out << fBiasControlCurrentMax << '\t';
+                if (cal)
+                    out << fBiasControlCurrentMax;
+                else
+                    out << "&mdash; ";
+                out << '\t';
             }
             out << fBiasControlVoltageMed << '\n';
@@ -1017,5 +1112,5 @@
         // ------------------------------------------
 
-        ofstream("www/fact.txt") << out.str();
+        ofstream(fPath+"/fact.txt") << out.str();
 
         // ==========================================
@@ -1031,5 +1126,5 @@
 
             out << GetStateHtml(fDimMcp,          4);
-            out << GetStateHtml(fDimControl,      0);
+            out << kHtmlWhite << '\t' << (fDimControl.state()>-2?fDimControl.msg:"---") << "\n";
             out << GetStateHtml(fDimDataLogger,   1);
             out << GetStateHtml(fDimDriveControl, 2);
@@ -1045,5 +1140,5 @@
         }
 
-        ofstream("www/status.txt") << out.str();
+        ofstream(fPath+"/status.txt") << out.str();
 
         return kStateRunning;
@@ -1052,4 +1147,5 @@
 public:
     StateMachineSmartFACT(ostream &out=cout) : StateMachineDim(out, "SMART_FACT"),
+        fPath("www/smartfact/data"),
         fMcpConfigurationMaxTime(0),
         fMcpConfigurationMaxEvents(0),
@@ -1088,4 +1184,5 @@
         //---
         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),
@@ -1121,4 +1218,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);
@@ -1142,5 +1243,6 @@
     po::options_description control("Smart FACT");
     control.add_options()
-        ("pixel-map-file", var<string>("FACTmapV5a.txt"), "Pixel mapping file. Used here to get the default reference voltage.")
+        ("pixel-map-file", var<string>("FACTmapV5a.txt"), "Pixel mapping file. Used here to get the default reference voltage")
+        ("path",           var<string>("www/smartfact"),  "Output path for the data-files")
         ;
 
