Index: trunk/FACT++/src/smartfact.cc
===================================================================
--- trunk/FACT++/src/smartfact.cc	(revision 14160)
+++ trunk/FACT++/src/smartfact.cc	(revision 14161)
@@ -9,4 +9,6 @@
 #include "Database.h"
 #endif
+
+#include <sys/stat.h> //for file stats
 
 #include "Dim.h"
@@ -358,4 +360,7 @@
 class StateMachineSmartFACT : public StateMachineDim
 {
+public:
+    static bool fIsServer;
+
 private:
     enum states_t
@@ -391,4 +396,6 @@
     deque<string> fMcpConfigurationHist;
 
+    bool fLastRunFinishedWithZeroEvents;
+
     enum weather_t { kWeatherBegin=0, kTemp = kWeatherBegin, kDew, kHum, kPress, kWind, kGusts, kDir, kWeatherEnd = kDir+1 };
     deque<float> fMagicWeatherHist[kWeatherEnd];
@@ -427,6 +434,5 @@
 
     deque<float> fFtmControlTriggerRateHist;
-    uint32_t     fFtmControlNewRunStarted;
-    uint32_t     fFtmControlTriggerRateTooLow;
+     int32_t     fFtmControlTriggerRateTooLow;
 
     float fFtmPatchThresholdMed;
@@ -748,4 +754,6 @@
             out << "</#><br/>";
             fMcpConfigurationHist.push_back(out.str());
+
+            fLastRunFinishedWithZeroEvents = fFadControlNumEvents==0;
         }
 
@@ -1284,11 +1292,10 @@
         }
 
-        const double crate = d.Get<float>(20);     // Camera rate
+        const float *crate = d.Ptr<float>(20); // Camera rate
 
         // New run started
-        if (crate<0)
-        {
-            fFtmControlNewRunStarted     = 0;
-            fFtmControlTriggerRateTooLow = 0;
+        if (*crate<0)
+        {
+            fFtmControlTriggerRateTooLow = -1;
             return GetCurrentState();
         }
@@ -1298,17 +1305,15 @@
         // by the MCP. Hence, we get a warning. So we have to require
         // two consecutive low rates.
-        if (crate<0.1)
+        if (*crate<0.1)
             fFtmControlTriggerRateTooLow++;
         else
             fFtmControlTriggerRateTooLow=0;
 
-        fFtmControlNewRunStarted++;
-
-        const float *brates = d.Ptr<float>(24);                  // Board rate
-        const float *prates = d.Ptr<float>(24+40*sizeof(float)); // Patch rate
+        const float *brates = crate + 1; // Board rate
+        const float *prates = brates+40; // Patch rate
 
         // Store a history of the last 60 entries
-        fFtmControlTriggerRateHist.push_back(crate);
-        if (fFtmControlTriggerRateHist.size()>60)
+        fFtmControlTriggerRateHist.push_back(*crate);
+        if (fFtmControlTriggerRateHist.size()>300)
             fFtmControlTriggerRateHist.pop_front();
 
@@ -1325,9 +1330,9 @@
         out << setprecision(3);
         out << d.GetJavaDate() << '\n';
-        out << HTML::kWhite << '\t' << crate << '\n';
+        out << HTML::kWhite << '\t' << *crate << '\n';
 
         ofstream(fPath+"/trigger.data") << out.str();
 
-        const Statistics bstat(vector<float>(brates, brates+40));
+        const Statistics bstat(vector<float>(brates, brates+ 40));
         const Statistics pstat(vector<float>(prates, prates+160));
 
@@ -1572,9 +1577,9 @@
         const float *ptr = d.Ptr<float>(4);
 
-        double avg =   0;
+        double avg =0;
         int num = 0;
 
         for (const float *t=ptr; t<ptr+4; t++)
-            if (*t>0)
+            if (*t>0 && *t<=100)
             {
                 avg += *t;
@@ -1582,5 +1587,5 @@
             }
 
-        fFscControlHumidityAvg = avg/num;
+        fFscControlHumidityAvg = num>0 ? avg/num : 0;
 
         return GetCurrentState();
@@ -2044,5 +2049,5 @@
 
         newerr |= SetError(bias_on && fFeedbackCalibration.size()>0 && fBiasControlCurrentMed>80,
-                           "Median current exceeds 80&micro;A/pix");
+                           "Median current exceeds 80&micro;A/pix exceeds 80&micro;A/pix");
         newerr |= SetError(bias_on && fFeedbackCalibration.size()>0 && fBiasControlCurrentMax>100,
                            "Maximum current exceeds 100&micro;A/pix");
@@ -2059,5 +2064,5 @@
                            "Sensor temperature exceeds outside temperature by more than 8&deg;C");
 
-        newerr |= SetError(fFtmControlNewRunStarted>0 && fFtmControlTriggerRateTooLow>1 && fDimMcp.state()==MCP::State::kTakingData,
+        newerr |= SetError(fFtmControlTriggerRateTooLow>2 && fDimMcp.state()==MCP::State::kTakingData,
                            "Trigger rate below 100mHz during data taking");
 
@@ -2072,4 +2077,9 @@
                            fFeedbackCalibration.size()==0,
                            "Bias voltage switched on, but bias crate not calibrated");
+
+        newerr |= SetError(fLastRunFinishedWithZeroEvents,
+                           "Last run finshed, but contained zero events.");
+
+        fLastRunFinishedWithZeroEvents = false;
 
         // FTM in Connected instead of Idle --> power cyclen
@@ -2343,5 +2353,5 @@
         {
             string col = HTML::kGreen;
-            if (fFtmControlTriggerRateHist.size()>0 && fFtmControlNewRunStarted>0)
+            if (fFtmControlTriggerRateHist.size()>0)
             {
                 if (fFtmControlTriggerRateHist.back()<15)
@@ -2474,5 +2484,5 @@
 
 public:
-    StateMachineSmartFACT(ostream &out=cout) : StateMachineDim(out, "SMART_FACT"),
+    StateMachineSmartFACT(ostream &out=cout) : StateMachineDim(out, fIsServer?"SMART_FACT":""),
         fLastAstroCalc(boost::date_time::neg_infin),
         fPath("www/smartfact/data"),
@@ -2481,4 +2491,5 @@
         fMcpConfigurationMaxTime(0),
         fMcpConfigurationMaxEvents(0),
+        fLastRunFinishedWithZeroEvents(false),
         fTngWeatherDustTime(Time::none),
         fBiasControlVoltageMed(0),
@@ -2614,13 +2625,40 @@
         fDatabase = conf.Get<string>("source-database");
 
+        struct stat st;
+        if (stat(fPath.c_str(), &st))
+        {
+            Error(fPath+" does not exist!");
+            return 2;
+        }
+
+        if ((st.st_mode&S_IFDIR)==0)
+        {
+            Error(fPath+" not a directory!");
+            return 3;
+        }
+
+        if ((st.st_mode&S_IWUSR)==0)
+        {
+            Error(fPath+" has no write permission!");
+            return 4;
+        }
+
+        if ((st.st_mode&S_IXUSR)==0)
+        {
+            Error(fPath+" has no execute permission!");
+            return 5;
+        }
+
         ostringstream out;
         out << Time().JavaDate() << '\n';
 
-        ofstream(fPath+"/errorhist.data") << out.str();
-        ofstream(fPath+"/error.data")     << out.str();
+        ofstream(fPath+"/errorhist.data")    << out.str();
+        ofstream(fPath+"/error.data")        << out.str();
 
         return -1;
     }
 };
+
+bool StateMachineSmartFACT::fIsServer = false;
 
 // ------------------------------------------------------------------------
@@ -2631,4 +2669,5 @@
 int RunShell(Configuration &conf)
 {
+    StateMachineSmartFACT::fIsServer = !conf.Get<bool>("client");
     return Main::execute<T, StateMachineSmartFACT>(conf);
 }
@@ -2641,4 +2680,5 @@
         ("path",            var<string>("www/smartfact/data"), "Output path for the data-files")
         ("source-database", var<string>(), "Database link as in\n\tuser:password@server[:port]/database.")
+        ("client",          po_bool(false), "For a standalone client choose this option.")
         ;
 
