Index: fact/tools/PyDimCtrl/ScriptsForPyDimCtrl.py
===================================================================
--- fact/tools/PyDimCtrl/ScriptsForPyDimCtrl.py	(revision 14453)
+++ fact/tools/PyDimCtrl/ScriptsForPyDimCtrl.py	(revision 14454)
@@ -2,12 +2,16 @@
 
 import time
+from factdimserver import *
+import numpy as np
 
 last_drive_kwargs = {}
 last_drive_method = None
 
+bias_calibration = {}
+
 def FadConnectCrate( crate ):
   cratenum = None
 
-  if cate == 'all':
+  if crate == 'all':
     print "connecting to all crates"
     for i in range( 40 ):
@@ -18,5 +22,5 @@
     try:
       cratenum = int(crate)
-    except ValueError e:
+    except ValueError as e:
       print "cannot convert crate parameter to integer. crate=", crate
       print e
@@ -34,5 +38,5 @@
   cratenum = None
 
-  if cate == 'all':
+  if crate == 'all':
     print "connecting to all crates"
     for i in range( 40 ):
@@ -42,5 +46,5 @@
     try:
       cratenum = int(crate)
-    except ValueError e:
+    except ValueError as e:
       print "cannot convert crate parameter to integer. crate=", crate
       print e
@@ -50,4 +54,5 @@
     print "connecting to crate", cratenum
     for i in range(cratenum*10, (cratenum+1)*10 ):
+      print 'disconnecting from i', time.time()
       fad_control.disconnect(i)
     print "... done"
@@ -56,6 +61,6 @@
 
 def IsReadyForDataTaking():
-""" Checking the system statuses if they are ready for data taking
-"""
+  """ Checking the system statuses if they are ready for data taking
+  """
 
   print "--------------------------------------"
@@ -79,9 +84,8 @@
   print "--------------------------------------"
 
-def NotReadyForDataTaking( servers_n_targets = [
-      (feedback, 12),
+def NotReadyForDataTaking( servers_n_targets = [ (feedback, 12),
       (bias_control, 9),
       (fad_control, 4) ] ):
-""" Checking the system statuses if they are ready for data taking
+  """ Checking the system statuses if they are ready for data taking
     return list of servers, which are NOT ready for Data Taking
     so one can use this function like this
@@ -90,5 +94,5 @@
     else:
       # start data taking
-"""
+  """
   not_ready = []
   
@@ -110,7 +114,7 @@
 
 def IsTracking():
-""" Name is misleading, it actually *waits* until Drive is in Tracking
+  """ Name is misleading, it actually *waits* until Drive is in Tracking
   original comment: Checking if Drive is in Status Tracking
-"""
+  """
   
   #return drive_control.stn == 8
@@ -119,7 +123,7 @@
 
 def PrepareBiasForDataTaking():
-""" should have the original behaviour, no new fancy features
+  """ should have the original behaviour, no new fancy features
     check feedback state before switching BIAS ON and ramping up to nominal Voltage
-"""
+  """
 
   start = time()
@@ -165,7 +169,7 @@
 
 def StopTracking():
-""" should have the original behaviour, no new fancy features
+  """ should have the original behaviour, no new fancy features
     stop drivectrl tracking the current source
-"""
+  """
   drive_control.stop()
   drive_control.wait(6) #Armed
@@ -176,7 +180,7 @@
 
 def SwitchOnBias():
-""" should have the original behaviour, no new fancy features
+  """ should have the original behaviour, no new fancy features
     bring Feedback to state CurrentControIdle and switch on Bias
-"""
+  """
   print ' switching on current controll feedback'
   feedback.stop()
@@ -219,7 +223,7 @@
 
 
-def waitForTracking()
-""" Wait for drivectrl to reply that its tracking the given source
-"""
+def waitForTracking():
+  """ Wait for drivectrl to reply that its tracking the given source
+  """
   
   print "...waiting for DRIVE_CONTROL"
@@ -239,11 +243,11 @@
 
 def TakeDataRun():
-""" Take a 5min Data Run
-"""
+  """ Take a 5min Data Run
+  """
   # check if all subsystems are in the correct state  
   IsReadyForDataTaking()
 
   print ' taking Data:FullTriggerArea 5min Run ...'
-  mcp.start( 300, -1, 'data')
+  mcp.start( 300, -1, 'data\0')
 
   print '...waiting for FAD to be in state 8: Writing Data'
@@ -254,11 +258,11 @@
 
 def TakeExtLpRun():
-""" Take a external Lightpulser Run
-"""
+  """ Take a external Lightpulser Run
+  """
   # check if all subsystems are in the correct state
   IsReadyForDataTaking()
 
   print 'taking External Light Pulser with BIAS on 1000 ...'
-  mcp.start(-1, 1000, 'light-pulser-ext')
+  mcp.start(-1, 1000, 'light-pulser-ext\0')
 
   print '...waiting for FAD to be in state 8: Writing Data'
@@ -269,11 +273,11 @@
   
 def TakePedestalOnRun():
-""" Take a Pedestal 1000 run with Bias ON
-"""
+  """ Take a Pedestal 1000 run with Bias ON
+  """
   # check if all subsystems are in the correct state
   IsReadyForDataTaking()
 
   print 'taking External Light Pulser with BIAS on 1000 ...'
-  mcp.start(-1, 1000, 'pedestal')
+  mcp.start(-1, 1000, 'pedestal\0')
 
   print '...waiting for FAD to be in state 8: Writing Data'
@@ -285,7 +289,8 @@
 
 def Take( time, num_events, runtype):
-""" more general version of e.g. TakePedestalOnRun
+  """ more general version of e.g. TakePedestalOnRun
     Note: One has to check, if Ready for *Take* by oneself
-"""
+  """
+  runtype += '\0'
   # check if all subsystems are in the correct state
   #IsReadyForDataTaking()
@@ -302,6 +307,6 @@
 
 def TakeData():
-""" taking a Data Set (1x Pedestal On, 1x LPext, 4x5min DataRun)
-"""
+  """ taking a Data Set (1x Pedestal On, 1x LPext, 4x5min DataRun)
+  """
   # take a Pedestal run
   IsTracking()
@@ -319,6 +324,6 @@
 
 def TakeDrsCalibration():
-""" script for DRS-Calibration before Data taking
-"""
+  """ script for DRS-Calibration before Data taking
+  """
   print 'script for DRS-Calibration before Data taking'
   print 'starting up...'
@@ -388,7 +393,7 @@
 
 def DataTaking1():
-""" Script for taking data when you are tracking wobble position 1
+  """ Script for taking data when you are tracking wobble position 1
     take a DRS CaLibration and physics Data afterwards
-"""
+  """
   # Move Telescope to Wobble Position 1
   print '--------------------------------------'
@@ -415,6 +420,6 @@
 
 def DataTaking2():
-""" Script for taking data when you are tracking wobble position 2
-"""
+  """ Script for taking data when you are tracking wobble position 2
+  """
   # Move Telescope to Wobble Position 2
   print '--------------------------------------'
@@ -438,6 +443,6 @@
 
 def TakeCrab():
-""" Data taking and tracking script for Crab
-"""
+  """ Data taking and tracking script for Crab
+  """
   print '======================================'
   print 'Data taking and tracking script for'
@@ -473,6 +478,6 @@
 
 def TrackCrabWobble1(): 
-""" changing tracking to "Crab" Wobble 1
-"""
+  """ changing tracking to "Crab" Wobble 1
+  """
   print 'moving telescope to wobble position 1'
   print '...waiting for DRIVE_CONTROL'
@@ -483,5 +488,5 @@
   time.sleep(5.)
 
-  drive_control.track_source( 0.6, 50, 'Crab')
+  drive_control.track_source( 0.6, 50, 'Crab\0')
   # we store this command in global vars, so it is increadibly easy, to 
   # do this call again, when needed
@@ -489,5 +494,5 @@
   last_drive_kwargs = { 'wobble_offset' : 0.6,
                           'wobble_angle' : 50,
-                          'source_name' : 'Crab' }
+                          'source_name' : 'Crab\0' }
   # so in case, this call needs to be repeated, just do
   # last_drive_method(**last_drive_kwargs)
@@ -497,6 +502,6 @@
 
 def TrackCrabWobble2(): 
-""" changing tracking to "Crab" Wobble 2
-"""
+  """ changing tracking to "Crab" Wobble 2
+  """
   print 'moving telescope to wobble position 2'
   print '...waiting for DRIVE_CONTROL'
@@ -512,5 +517,5 @@
   last_drive_kwargs = { 'wobble_offset' : 0.6,
                           'wobble_angle' : -130,
-                          'source_name' : 'Crab' }
+                          'source_name' : 'Crab\0' }
   # so in case, this call needs to be repeated, just do
   last_drive_method(**last_drive_kwargs)
@@ -521,7 +526,7 @@
 
 
-def FirstDrsCalib():
-""" performs the everything, which is done in the FirstDrsCalib Script as well . 
-"""
+def FirstDrsCalib( SkipCurrentCalib=False ):
+  """ performs the everything, which is done in the FirstDrsCalib Script as well . 
+  """
   # As a First step we want to calibrate the current, which are read from the bias crate,
   # and not take a DRS calibration, as it is mentioned in the data taking page...
@@ -553,53 +558,54 @@
   print " ...done"
 
-  # in case we reach this line, the voltages are all off, and the feedback does not do anything
-  # So lets do the current calibration, therefor we tell the bias crate to ramp up just 1 single DAC count(~22mV)
-  # the result of this action is, to get bias_ctrl into the state 'VoltageOn'(9), but since we only go one DAC count it shouldn't take long
-  print " setting bias globally to 1 DAC"
-  bias_control.set_global_dac(1)
-
-  time.sleep(2)
-  print " ...waiting for BIAS to be in state 9: VoltageOn"
-  bias_control.wait(9)
-  print " ...done"
-
-  # now we may tell the feedback program to calibrate the currents ...
-  # I do not understand, if I have to explicitely allow the feedback program to generate output,
-  # or if it just produces output...
-  # As far as I understand, the feedback output enable status is the same,
-  # as it was before I send the STOP command... so it is unknown at this point.
-  # and in addition enabling or disabling the output, when STOPed is not possible as far as I know...
-  # I try to enable it anyway.
-  print " enabling output for feedback"
-  feedback.enable_output(1)
-  time.sleep(2)
-  print " ...done"
-
-  print " calibrating bias crate current readings..."
-  feedback.calibrate_currents()
-  time.sleep(5)
-  # in order to find out when the calibration ends, we have to wait for the transistion from state
-  # 'Calibrating'(13) back to 'Connected'(6)
-  print " ...waiting for FEEDBACK to be in state 13: Calibrating"
-  feedback.wait(13)
-  print " ...waiting for FEEDBACK to be in state 6: Connected"
-  feedback.wait(6)
-
-  # Thomas Bretz told me, that the feedback, after this is step has disabled its output
-  # and is in the mode, we might call 'temperature control' even there is no temerature beeing controlled.
-  # I don't know where the voltage is ... in order to perform the calibration, the feedback had to
-  # ramp up to 2V below the operational voltage, i.e. about 1V below the breakdown voltage
-
-  # We want to take a DRS amplitude calibration so we have to ramp down the bias voltage.
-  # this 10sec wait is needed in order for the bias not to disconect all the time...
-  print " ... current calibration done"
-  time.sleep(10)
-
-  print " switching off bias"
-  bias_control.set_zero_voltage()
-  time.sleep(5)
-  print " ...waiting for BIAS to be in state 7: VoltageOff"
-  bias_control.wait(7)
-  print " ...done"
+  if not SkipCurrentCalib:
+    # in case we reach this line, the voltages are all off, and the feedback does not do anything
+    # So lets do the current calibration, therefor we tell the bias crate to ramp up just 1 single DAC count(~22mV)
+    # the result of this action is, to get bias_ctrl into the state 'VoltageOn'(9), but since we only go one DAC count it shouldn't take long
+    print " setting bias globally to 1 DAC"
+    bias_control.set_global_dac(1)
+
+    time.sleep(2)
+    print " ...waiting for BIAS to be in state 9: VoltageOn"
+    bias_control.wait(9)
+    print " ...done"
+
+    # now we may tell the feedback program to calibrate the currents ...
+    # I do not understand, if I have to explicitely allow the feedback program to generate output,
+    # or if it just produces output...
+    # As far as I understand, the feedback output enable status is the same,
+    # as it was before I send the STOP command... so it is unknown at this point.
+    # and in addition enabling or disabling the output, when STOPed is not possible as far as I know...
+    # I try to enable it anyway.
+    print " enabling output for feedback"
+    feedback.enable_output(1)
+    time.sleep(2)
+    print " ...done"
+
+    print " calibrating bias crate current readings..."
+    feedback.calibrate_currents()
+    time.sleep(5)
+    # in order to find out when the calibration ends, we have to wait for the transistion from state
+    # 'Calibrating'(13) back to 'Connected'(6)
+    print " ...waiting for FEEDBACK to be in state 13: Calibrating"
+    feedback.wait(13)
+    print " ...waiting for FEEDBACK to be in state 6: Connected"
+    feedback.wait(6)
+
+    # Thomas Bretz told me, that the feedback, after this is step has disabled its output
+    # and is in the mode, we might call 'temperature control' even there is no temerature beeing controlled.
+    # I don't know where the voltage is ... in order to perform the calibration, the feedback had to
+    # ramp up to 2V below the operational voltage, i.e. about 1V below the breakdown voltage
+
+    # We want to take a DRS amplitude calibration so we have to ramp down the bias voltage.
+    # this 10sec wait is needed in order for the bias not to disconect all the time...
+    print " ... current calibration done"
+    time.sleep(10)
+
+    print " switching off bias"
+    bias_control.set_zero_voltage()
+    time.sleep(5)
+    print " ...waiting for BIAS to be in state 7: VoltageOff"
+    bias_control.wait(7)
+    print " ...done"
 
   # So now we can take the 3 runs, which are called DRS amplitude calibration:
@@ -616,26 +622,34 @@
 
   fad_control.start_drs_calibration()
-  mcp.start(-1, 1000, "drs-pedestal")
-
+  time.sleep(0.5)
+  mcp.start(-1, 1000, "drs-pedestal\0")
+
+  print "...waiting for FAD to be in state 8: Writing Data"
+  fad_control.wait(8)
+  print "...waiting for FAD to be in state 4: Connected"
+  fad_control.wait_nice(4)
+  print "... done"
+
+  print "taking DRS:Gain 1000 ..."
+  mcp.start(-1, 1000, 'drs-gain\0')
+  print "...waiting for FAD to be in state 8: Writing Data"
+  fad_control.wait(8)
+  print "...waiting for FAD to be in state 4: Connected"
+  fad_control.wait_nice(4)
+  print "... done"
+
+  time.sleep(2)
+  if GetDrsCalibGainRms():
+    print
+    print 'First DRS Calib Script will be aborted'
+    print 'operator, please power cycle FACT'
+    return False
+
+  print "taking Pedestal 1000 ..."
+  mcp.start( -1, 1000, 'pedestal\0')
   print "...waiting for FAD to be in state 8: Writing Data"
   fad_control.wait(8)
   print "...waiting for FAD to be in state 4: Connected"
   fad_control.wait(4)
-  print "... done"
-
-  print "taking DRS:Gain 1000 ..."
-  mcp.start(-1, 1000, 'drs-gain')
-  print "...waiting for FAD to be in state 8: Writing Data"
-  fad_control.wait(8)
-  print "...waiting for FAD to be in state 4: Connected"
-  fad_control.wait(4)
-  print "... done"
-
-  print "taking Pedestal 1000 ..."
-  mcp.start( -1, 1000, 'pedestal')
-  print "...waiting for FAD to be in state 8: Writing Data"
-  fad_control.wait(8)
-  print "...waiting for FAD to be in state 4: Connected"
-  fad_control(4)
   print "... done"
 
@@ -647,5 +661,5 @@
   fad_control.set_file_format(2)
 
-  mcp.start(-1, 1000, 'pedestal')
+  mcp.start(-1, 1000, 'pedestal\0')
   print "...waiting for FAD to be in state 8: Writing Data"
   fad_control.wait(8)
@@ -680,5 +694,5 @@
   print "...ramping to nominal voltage"
   print "...waiting for BIAS to be in state 9: VoltageOn"
-  bias_control(9)
+  bias_control.wait(9)
   print "...bias on"
   # here we should wait 45 sec in order for the current control to get enough current readings and temp readings to stabilize..
@@ -691,5 +705,5 @@
   # then the DRS calibration above, and the pedestal run in between have to be changed as well.
   print "taking Pedestal with BIAS on 3000 ..."
-  mcp.start(-1, 3000, 'pedestal')
+  mcp.start(-1, 3000, 'pedestal\0')
   print "...waiting for FAD to be in state 8: Writing Data"
   fad_control.wait(8)
@@ -710,5 +724,5 @@
 
 def Ratescan( ra=None, dec=None, sourcename=None):
-"""
+  """
 # call it by: .x ScriptsForDimCtrl/Ratescan.dim mode=<trackmode> ra=<Right ascension> dec=<Declination> source=<source_name>
 # mode=0: Manual tracking Mode: set tracking in drivectrl manually
@@ -716,5 +730,5 @@
 # mode=2: source Mode: scripts sends tracking command to drivectrl with the given source_name
 
-"""
+  """
   print '======================================'
   print 'RATESCAN'
@@ -730,5 +744,5 @@
     print 'script will wait for drive'
     print 'to be in state tracking'
-  else if None != ra or None != dec:
+  elif None != ra or None != dec:
     try:
       ra = float(ra)
@@ -743,8 +757,9 @@
     print '...Dec = ', dec
     drive_control.track( ra, dec)
-  else if None != sourcename:
+  elif None != sourcename:
     print '...stop tracking'
     StopTracking()
     print '...change tracking of telescope to:', sourcename
+    sourcename += '\0'
     drive_control.track_source( 0, 0, sourcename)
   else:
@@ -792,8 +807,8 @@
 
 def ResetCrate( crate_num ):
-""" Reset Crate
+  """ Reset Crate
     crate_num = 0,1,2 or 3  the number of the crate to reset.
     crate_num = 'all' is NOT YET SUPPORTED
-"""
+  """
   c = int(crate_num)
   
@@ -832,6 +847,107 @@
 
   print '...connecting FAD boards of crate', c
-  FadConnectCrate(C)
+  FadConnectCrate(c)
   print '======================================'
-  print 'Crate-Reset for crate'c'finished'
+  print 'Crate-Reset for crate', c, 'finished'
   print '======================================'
+
+def GetDrsCalibGainRms():
+#drs_calibration(self) method of factdimserver.FAD_CONTROL instance
+#DESC in SERVICE_DESC is empty ?!
+#I:1;I:3;F:1474560;F:1474560;F:1474560;F:1474560;F:1474560;F:1474560;F:163840;F:163840
+  data = fad_control.drs_calibration()
+  N1 = data[0]
+  N3 = data[1:4]
+  OffsetMean = np.array(data[4:4+1024*1440]).reshape(1440,1024)
+  OffsetRms = np.array(data[4+1024*1440:4+1024*1440*2]).reshape(1440,1024)
+  GainMean = np.array(data[4+1024*1440*2:4+1024*1440*3]).reshape(1440,1024)
+  GainRms = np.array(data[4+1024*1440*3:4+1024*1440*4]).reshape(1440,1024)
+
+  gr = GainRms.mean(axis=1)
+  lala = np.zeros(len(gr)/9)
+  for i,v in enumerate(lala):
+    lala[i] = gr[i*9:(i+1)*9].mean()
+
+  # outliers
+  mean = lala.mean()
+  std = lala.std()
+
+  print 'Mean DRS GainRms value:', mean
+  print 'std:', std
+  outs = np.where( lala > mean+7*std)[0]
+  if len(outs) > 0:
+    print 'WARNING possible DRS underflow detected!!!'
+    for out in outs:
+      out = int(out)
+      crate= out/40
+      board = (out-40*crate)/4
+      chip = out-40*crate-4*board
+      print 'possible DRS underflow in DRS:', crate, board, chip, '--> Mean-GainRms:', lala[out]
+      return outs
+  else:
+    return False
+
+import types
+
+def wait_nice(self, state_num, timeout=None):                            
+  if not hasattr(self, 'stn'):
+    raise TypeError(self.name+' has no CMD called STATE')
+  if timeout == None:
+    timeout = float('inf')
+  else:
+    timeout = float(timeout)
+  start = time.time()
+  intermed = time.time()-1.
+  while not self.stn == state_num:
+    time.sleep(0.1)
+    if time.time() - intermed >= 1.:
+      print fad_control.events()[0], 'events @', ftm_control.trigger_rates()[3], 'Hz'
+      intermed = time.time()
+    
+    if time.time() >= start+timeout:
+      return False
+  return True
+
+fad_control.wait_nice = types.MethodType( wait_nice, fad_control) 
+
+
+def GetBiasCalibration():
+  cali = feedback.calibration()
+  bias_calibration['Time'] = time.time()
+  bias_calibration['Calibration'] = cali
+
+def GetBiasCurrent(verbose = False):
+  """ return median, std, max and min current
+  """
+  if 'Time' in bias_calibration:
+    cali = bias_calibration['Calibration']
+  else:
+    GetBiasCalibration()
+    cali = bias_calibration['Calibration']
+
+  r = np.array(cali[2*416:2*416+320])
+
+  bias = bias_control
+
+  I = np.array(bias.current()[0:320], dtype=float)
+  II = I/4096. * 5000
+  V = np.array(bias.voltage()[0:320])
+  if len(sys.argv) > 1:
+      i = int(sys.argv[1])
+  else: i=0
+#  print 'I:', I[i], 'dac\t', II[i], 'uA'
+#  print 'V:', V[i]
+#  print ''
+#  print 'GUI offset:', V[i]/r[i]*1e6
+#  print 'GUI feedback:', II[0] - V[0]/r[0]*1e6
+
+  GUII = II-V/r*1e6
+  if verbose:
+    print 'median', np.median(GUII)
+    print 'mean', GUII.mean()
+   # print 'rms', ((GUII- GUII.mean())**2).sum()
+    print 'std', GUII.std()
+    print 'max', GUII.max()
+    print 'min', GUII.min()
+
+  return GUII.mean(), GUII.std(), GUII.max(), GUII.min()
