Index: /trunk/FACT++/src/ratecontrol.cc
===================================================================
--- /trunk/FACT++/src/ratecontrol.cc	(revision 15036)
+++ /trunk/FACT++/src/ratecontrol.cc	(revision 15037)
@@ -34,4 +34,15 @@
 {
 private:
+    struct config
+    {
+        uint16_t fCalibrationType;
+        uint16_t fTargetRate;
+        uint16_t fMinThreshold;
+        uint16_t fAverageTime;
+        uint16_t fRequiredEvents;
+    };
+
+    map<string, config> fRunTypes;
+
     bool fTriggerOn;
 
@@ -50,4 +61,7 @@
     uint16_t fThresholdMin;
     uint16_t fThresholdReference;
+
+    uint16_t fAverageTime;
+    uint16_t fRequiredEvents;
 
     deque<pair<Time,float>> fCurrents;
@@ -395,5 +409,5 @@
         while (!fCurrents.empty())
         {
-            if (time-fCurrents.front().first<boost::posix_time::seconds(10))
+            if (time-fCurrents.front().first<boost::posix_time::seconds(fAverageTime))
                 break;
 
@@ -409,5 +423,5 @@
 
         // We want at least 8 values for averaging
-        if (fCurrents.size()<8)
+        if (fCurrents.size()<fRequiredEvents)
             return GetCurrentState();
 
@@ -425,6 +439,5 @@
         rms = sqrt(rms-avg*avg);
 
-        fThresholdMin = 36.0833*pow(avg, 0.638393)+184.037;
-        fThresholdReference = fThresholdMin;
+        fThresholdMin = max(uint16_t(36.0833*pow(avg, 0.638393)+184.037), fThresholdReference);
         fThresholds.assign(160, fThresholdMin);
 
@@ -488,4 +501,39 @@
 
         return RateControl::State::kSettingGlobalThreshold;
+    }
+
+    int CalibrateRun(const EventImp &evt)
+    {
+        const string name = evt.GetText();
+
+        const auto it = fRunTypes.find(name);
+        if (it==fRunTypes.end())
+        {
+            Error("CalibrateRun - Run-type '"+name+"' not found.");
+            return GetCurrentState();
+        }
+
+        const config &conf = it->second;
+
+        switch (conf.fCalibrationType)
+        {
+        case 0:
+            Info("No calibration requested.");
+            return RateControl::State::kGlobalThresholdSet;
+
+        case 1:
+            fThresholdReference = conf.fMinThreshold;
+            fTargetRate = conf.fTargetRate;
+            return Calibrate();
+
+        case 2:
+            fThresholdReference = conf.fMinThreshold;
+            fAverageTime = conf.fAverageTime;
+            fRequiredEvents = conf.fRequiredEvents;
+            return CalibrateByCurrent();
+        }
+
+        Error("CalibrateRun - Calibration type "+to_string(conf.fCalibrationType)+" unknown.");
+        return GetCurrentState();
     }
 
@@ -623,4 +671,8 @@
             ("Set the global threshold from the median current");
 
+        AddEvent("CALIBRATE_RUN", "C")
+            (bind(&StateMachineRateControl::CalibrateRun, this, placeholders::_1))
+            ("Start a threshold calibration as defined in the setup for this run-type");
+
         AddEvent("STOP", RateControl::State::kSettingGlobalThreshold, RateControl::State::kGlobalThresholdSet, RateControl::State::kInProgress)
             (bind(&StateMachineRateControl::StopRC, this))
@@ -646,4 +698,13 @@
     }
 
+    bool CheckConfig(Configuration &conf, const string &name, const string &sub)
+    {
+        if (conf.HasDef(name, sub))
+            return true;
+
+        Error("Neither "+name+"default nor "+name+sub+" found.");
+        return false;
+    }
+
     int EvalOptions(Configuration &conf)
     {
@@ -653,4 +714,59 @@
         fThresholdMin       = 300;
         fTargetRate         =  75;
+
+        fAverageTime        =  10;
+        fRequiredEvents     =   8;
+
+        // ---------- Setup run types ---------
+        const vector<string> types = conf.Vec<string>("run-type");
+        if (types.size()==0)
+            Warn("No run-types defined.");
+        else
+            Message("Defining run-types");
+
+        for (auto it=types.begin(); it!=types.end(); it++)
+        {
+            Message(" -> "+ *it);
+
+            if (fRunTypes.count(*it)>0)
+            {
+                Error("Run-type "+*it+" defined twice.");
+                return 1;
+            }
+
+            if (!CheckConfig(conf, "calibration-type.", *it))
+                return 2;
+
+            config c;
+            c.fCalibrationType = conf.GetDef<uint16_t>("calibration-type.",  *it);
+
+            switch (c.fCalibrationType)
+            {
+            case 0:
+                break;
+
+                // Calibrate by rate
+            case 1:
+                if (!CheckConfig(conf, "target-rate.",   *it) ||
+                    !CheckConfig(conf, "min-threshold.", *it))
+                    return 3;
+                c.fTargetRate   = conf.GetDef<uint16_t>("target-rate.",    *it);
+                c.fMinThreshold = conf.GetDef<uint16_t>("min-threshold.", *it);
+                break;
+
+                // Calibrate by current
+            case 2:
+                if (!CheckConfig(conf, "min-threshold.",   *it) ||
+                    !CheckConfig(conf, "average-time.",    *it) ||
+                    !CheckConfig(conf, "required-events.", *it))
+                    return 4;
+                c.fMinThreshold    = conf.GetDef<uint16_t>("min-threshold.",   *it);
+                c.fAverageTime     = conf.GetDef<uint16_t>("average-time.",    *it);
+                c.fRequiredEvents  = conf.GetDef<uint16_t>("required-events.", *it);
+                break;
+            }
+
+            fRunTypes[*it] = c;
+        }
 
         return -1;
@@ -678,4 +794,16 @@
 
     conf.AddOptions(control);
+
+    po::options_description runtype("Run type configuration");
+    runtype.add_options()
+        ("run-type",           vars<string>(),   "Name of run-types (replace the * in the following configuration by the case-sensitive names defined here)")
+        ("calibration-type.*", vars<uint16_t>(), "Calibration type (0: none, 1: by rate, 2: by current)")
+        ("target-rate.*",      vars<uint16_t>(), "Target rate for calibration by rate")
+        ("min-threshold.*",    vars<uint16_t>(), "Minimum threshold which can be applied in a calibration")
+        ("average-time.*",     vars<uint16_t>(), "Time in seconds to average the currents for a calibration by current.")
+        ("required-events.*",  vars<uint16_t>(), "Number of required current events to start a calibration by current.");
+    ;
+
+    conf.AddOptions(runtype);
 }
 
