Index: trunk/FACT++/src/biasctrl.cc
===================================================================
--- trunk/FACT++/src/biasctrl.cc	(revision 11992)
+++ trunk/FACT++/src/biasctrl.cc	(revision 11993)
@@ -69,5 +69,6 @@
     vector<int16_t>  fCurrent;     // Current in ADC units (12bit = 5mA)
 
-    uint16_t fVoltMax;
+    uint16_t fVoltMaxAbs;
+    uint16_t fVoltMaxRel;
 
     virtual void UpdateA()
@@ -82,18 +83,30 @@
     bool CheckChDac(const string &cmd, uint16_t dac, uint16_t ch=0)
     {
+        ostringstream str;
+        str << cmd << " - ";
+
+        if (ch>=kNumChannels)
+        {
+            str << "Channel " << ch << " out of range [0,416].";
+            Error(str);
+            return false;
+        }
+
         if (dac>kMaxDac)
         {
-            Error(cmd+" - DAC value out of range.");
-            return false;
-        }
-        if (dac>fVoltMax)
-        {
-            Error(cmd+" - DAC value exceeds fVoltMax.");
-            return false;
-        }
-
-        if (ch>=kNumChannels)
-        {
-            Error(cmd+" - Channel out of range.");
+            str << "DAC value " << dac << " out of range [0,4095].";
+            Error(str);
+            return false;
+        }
+        if (dac>fVoltMaxAbs)
+        {
+            str << "DAC value " << dac << " exceeds allowed absolute maximum of " << fVoltMaxAbs;
+            Error(str);
+            return false;
+        }
+        if (dac>fVoltGapd[ch]+fVoltMaxRel)
+        {
+            str << "DAC value " << dac << " exceeds allowed channel maximum of " << fVoltGapd[ch] << " + " << fVoltMaxRel;
+            Error(str);
             return false;
         }
@@ -152,4 +165,11 @@
         const uint16_t error  = (answer[2]>>4)&0xf;
         const uint16_t board  =  answer[2]&0xf;
+
+        // 0x10 00 7f
+        //   status = 0
+        //   wrap   = 1
+        //   ddd    = 0
+        //   error  = not present
+        //   board  = 15
 
         /*
@@ -376,5 +396,17 @@
         if (command==kCmdChannelSet && fIsRamping)
         {
-            ScheduleRampStep();
+            bool oc = false;
+            for (int ch=0; ch<kNumChannels; ch++)
+                if (fPresent[ch/kNumChannelsPerBoard] && fCurrent[ch]<0)
+                    oc = true;
+
+            if (oc)
+            {
+                Warn("OverCurrent detected - ramping stopped.");
+                fIsRamping = false;
+            }
+            else
+                ScheduleRampStep();
+
             fCounter[3]++;
         }
@@ -1025,4 +1057,9 @@
     }
 
+    uint16_t GetRampStepVolt() const
+    {
+        return fRampStep*90./4096;
+    }
+
     bool IsRamping() const { return fIsRamping; }
 
@@ -1246,13 +1283,31 @@
     }
 
-    void SetVoltMax(float max)
-    {
-        fVoltMax = max*4096/90;
-        if (fVoltMax>4095)
-            fVoltMax = 4095;
+    void SetVoltMaxAbs(float max)
+    {
+        fVoltMaxAbs = max*4096/90;
+        if (fVoltMaxAbs>4095)
+            fVoltMaxAbs = 4095;
         if (max<0)
-            fVoltMax = 0;
-    }
-
+            fVoltMaxAbs = 0;
+    }
+
+    void SetVoltMaxRel(float max)
+    {
+        fVoltMaxRel = max*4096/90;
+        if (fVoltMaxRel>4095)
+            fVoltMaxRel = 4095;
+        if (max<0)
+            fVoltMaxRel = 0;
+    }
+
+    uint16_t GetVoltMaxAbs() const
+    {
+        return fVoltMaxAbs * 90./4096;
+    }
+
+    uint16_t GetVoltMaxRel() const
+    {
+        return fVoltMaxRel * 90./4096;
+    }
 
 /*
@@ -1846,15 +1901,22 @@
         fBias.SetSyncDelay(conf.Get<uint16_t>("sync-delay"));
 
-        const float maxv = conf.Get<float>("volt-max");
-        if (maxv>90)
+        ostringstream str;
+        str << "Ramping in effective steps of " << fBias.GetRampStepVolt() << "V with a cyle time of " << time << "ms";
+        T::Message(str);
+
+        // --------------------------------------------------------------------------
+
+        const float maxabsv = conf.Get<float>("volt-max-abs");
+        const float maxrelv = conf.Get<float>("volt-max-rel");
+        if (maxabsv>90)
         {
             T::Error("volt-max exceeds 90V.");
             return 2;
         }
-        if (maxv>75)
+        if (maxabsv>75)
             T::Warn("volt-max exceeds 75V.");
-        if (maxv<70)
+        if (maxabsv<70)
             T::Warn("volt-max below 70V.");
-        if (maxv<0)
+        if (maxabsv<0)
         {
             T::Error("volt-max negative.");
@@ -1862,5 +1924,12 @@
         }
 
-        fBias.SetVoltMax(maxv);
+        fBias.SetVoltMaxAbs(maxabsv);
+        fBias.SetVoltMaxRel(maxrelv);
+
+        ostringstream str1, str2;
+        str1 << "Effective maximum allowed absolute voltage " << fBias.GetVoltMaxAbs() << "V";
+        str2 << "Effective maximum allowed relative voltage " << fBias.GetVoltMaxAbs() << "V w.r.t to G-APD reference voltage";
+        T::Message(str1);
+        T::Message(str2);
 
         // --------------------------------------------------------------------------
@@ -1908,5 +1977,6 @@
         ("update-interval", var<uint16_t>(3000), "Interval between two current requests in milliseconds")
         ("sync-delay",      var<uint16_t>(333),  "Delay between sending the inital 0's after a newly established connection to synchronize the output stream in milliseconds")
-        ("volt-max",        var<float>(75),      "Upper limit for the voltage which can be applied in Volts")
+        ("volt-max-abs",    var<float>(75),      "Absolte upper limit for the voltage (in Volts)")
+        ("volt-max-rel",    var<float>(2.5),     "Relative upper limit for the voltage w.r.t. the G-APD reference voltage (in Volts)")
         ;
     // FIXME: Add a bit for OC... there is no -0
