Index: /fact/tools/PyDimCtrl/factdimserver.py
===================================================================
--- /fact/tools/PyDimCtrl/factdimserver.py	(revision 13811)
+++ /fact/tools/PyDimCtrl/factdimserver.py	(revision 13812)
@@ -29,4 +29,8 @@
         self.reg_msg_cb()
         self.user_func = None
+        self.__delay_between_cmds = 1.0
+        seld.__delay_between_services = 1.0
+        self.__last_cmd_send = -1*float('inf')
+        self.__last_service_got = -1*float('inf')
 
     def _cmd(self, cmdstr, *args):
@@ -42,5 +46,9 @@
             desc = 'I'
             args=(1,)
+        while not time.time() - self.__last_cmd_send > self.__delay_between_cmds:
+            time.sleep(0.5)
+        self.__last_cmd_send = time.time()
         pydim.dic_sync_cmnd_service(cmdstr, args, desc, timeout=None)
+        
 
 
@@ -50,4 +58,9 @@
         full_srv_name = self.name+'/'+service.upper()
         desc = services[self.name][full_srv_name][0]
+
+        while not time.time() - self.__last_service_got > self.__delay_between_services:
+            time.sleep(0.5)
+        self.__last_service_got = time.time()
+
         return pydim.dic_sync_info_service(full_srv_name, desc)
 
Index: /fact/tools/PyDimCtrl/pyfactctrl.py
===================================================================
--- /fact/tools/PyDimCtrl/pyfactctrl.py	(revision 13811)
+++ /fact/tools/PyDimCtrl/pyfactctrl.py	(revision 13812)
@@ -1,4 +1,249 @@
 #!/usr/bin/python -tti
 from factdimserver import *
+
+# List of Wobble Positions
+source_list = { '1ES 1218+304' : [( 0.6, -5), (0.6, 175)] ,\
+    'Crab' : [(0.6, 50), (0.6, -130)], \
+    'Mrk 421' : [(0.6, 90),(0.6, -90)] \
+    'Mrk 501' : [(0.6, 90),(0.6, -90)] }
+
+def TakeFullSet( source = 'Crab', verbose = True):
+    msg = MSG( verbose )
+    drs_calib_done = False      # Drs Calib is only done in the 1st wobble pos
+    
+    if not source in source_list:
+        raise ValueError('source not in source_list')
+        msg("Possible sources are:")
+        for src in source_list.keys():
+            msg(src)
+        return False
+    
+    
+    # set is a list of wobble positions, stored as 2-tuple
+    for set in source_list(source):
+        # wobble is a 2-tuple: (Shift, Angle)
+        for wobble in set:
+            TrackSource( source, wobble[0] , wobble[1] , CalmDownTime=45)
+
+            if not drs_calib_done:
+                TakeDrsAmplitudeCalibration( roi=1024 )
+                TakeDrsTimeCalibration( mode='upshifted' )
+                AddDrsAmplitudeCalibration( roi=300 )
+                drs_calib_done = True
+
+            VoltageOn( mode='current' )
+            for i in range(4):
+                msg("Taking Data Run "+str(i+1)+" of 4")
+                TakeDataRun()
+            VoltageOff()
+
+    StopTracking()
+    return True
+
+#=========== TRACKING =========================================================
+def TrackSource( Shift=0.6, Angle=50, SrcName='Crab', CalmDownTime = None, verbose=True):
+    drive = drive_control
+    msg = MSG( verbose )
+    SrcName += '\0'
+
+    if not StopTracking( timeout = 5, verbose = False ):
+        msg.fail('Cannot start Tracking, because I cannot Stop the Drive')
+        return False
+    
+    drive.track_source( Shift, Angle, SrcName)
+
+    if CalmDownTime != None:
+        if not WaitToCalmDown( CalmDownTime, verbose = True):
+            msg.fail("a problem in WaitToCalmDown(). drive state: "+drive.sts)
+            return False:
+    
+    msg.ok('Tracking Source '+SrcName + ' Angle:'+str(Angle)+' Shift:'+str(Shift))
+    return True
+
+def WaitToCalmDown( CalmDownTime = 45, time_until_moving = 10, time_until_tracking = 40, verbose = True):
+    """ before calling this function, one should call TrackSource()
+        this function waits until Drive is in state 'Tracking' 
+        and then sleeps *CalmDownTime* seconds in order to give 
+        the Drive time to calm down.
+        
+    """
+    drive = drive_control
+    msg = MSG(verbose)
+
+    starttime = time.time()
+    while not drive.stn == 6: #Moving
+        if time.time() - starttime > time_until_moving:
+            msg.fail("DRIVE not in Moving after "+str(time_until_moving))
+            return False
+        time.sleep(0.5)
+    msg.ok("Drive is Moving, waiting for Tracking")
+        
+    starttime = time.time()
+    while not drive.stn == 7: #Tracking
+        if time.time() - starttime > time_until_tracking:
+            msg.fail("DRIVE not in Tracking after "+str(time_until_tracking))
+            return False
+        time.sleep(0.5)
+    msg.ok("Drive is Tracking, waiting to calm down...")
+    
+    time.sleep(CalmDownTime)
+    msg.ok("Drive hopefully has calmed down")
+    return True
+
+def StopTracking( timeout = 3, verbose = True ):
+    msg = MSG(verbose)
+    drive = drive_control
+    starttime = time.time()
+    while not drive.stn == 5:
+        if time.time() - starttime > timeout:
+            msg.fail('Did not get DRIVE into Armed state within '+str(timeout)+' seconds')
+            return False
+
+        if drive.stn < 5:
+            msg.fail('DRIVE in state'+drive.sts+" I don't know how to STOP")
+        if drive.stn >= 256:
+            msg.fail('DRIVE in state'+drive.sts+" I don't know how to STOP")
+
+        if drive.stn in [6,7]:
+            drive.stop()
+            time.sleep(0.5)
+
+    msg.ok('DRIVE Stopped: current state:'+drive.sts)
+    return True
+
+#=========== DRS CALIBRATION ==================================================
+def TakeDrsAmplitudeCalibration( roi = None, verbose = True):
+    """ Takes DRS Amplitude Calibration
+        *roy* integer: 300, 1024 or 
+        *roy* string : 'both'
+        in case of both, the roi=300 calibration is done last.
+        
+        after each complete AmpliteCalibration a 4th pedestal run of the same 
+        roi is taken, for crosschecking.
+        """
+    msg = MSG( verbose )
+    bias = bias_control
+    fad = fad_control
+    if not roi in [300,1024,'both']:
+        raise ValueError("roi must be 300,1024 or the string 'both'")
+
+
+    bias.set_zero_voltage()
+    if not bias.wait(7, 10):
+        msg.warn("bias has not switched of after 10sec")
+        return False
+
+    fad.start_drs_calibration()
+    Take( -1, 1000, 'drs-pedestal')
+    Take( -1, 1000, 'drs-gain')
+    if roi == 300:
+        Take( -1, 1000, 'pedestal')
+        fad.set_file_format(2)
+        Take( -1, 1000, 'pedestal')
+    elif roi == 1024:
+        Take( -1, 1000, 'drs-pedestal')
+        fad.set_file_format(2)
+        Take( -1, 1000, 'drs-pedestal')
+    elif roi == 'both':
+        Take( -1, 1000, 'drs-pedestal')
+        fad.set_file_format(2)
+        Take( -1, 1000, 'drs-pedestal')
+        fad.reset_secondary_drs_baseline()
+        Take( -1, 1000, 'pedestal')
+        fad.set_file_format(2)
+        Take( -1, 1000, 'pedestal')
+
+
+def TakeDrsTimeCalibration( mode = 'upshifted', verbose = True):
+    """ Takes DRS Time Calibration
+        *mode* can be 'upshifted', 'old' or 'both'
+    """
+    msg = MSG( verbose )
+    bias = bias_control
+    fad = fad_control
+    if not mode in ['upshifted', 'old', 'both']:
+        raise ValueError("mode must be: 'upshifted','old' or 'both'")
+
+    bias.set_zero_voltage()
+    if not bias.wait(7, 10):
+        msg.warn("bias has not switched of after 10sec")
+        return False
+
+    fad.set_file_format(2)
+    if mode == 'old':
+        Take(-1, 1000, 'drs-time')
+    if mode == 'upshifted':
+        Take(-1, 1000, 'drs-time-upshifted')
+    if mode == 'both':
+        Take(-1, 1000, 'drs-time')
+        Take(-1, 1000, 'drs-time-upshifted')
+
+
+
+def AddDrsAmplitudeCalibration( roi = None, verbose = True):
+    """ Adds a DRS Amplitude Calibration,
+        do not call, in case you did not *Take* one before
+        *roy* integer: 300, 1024
+        
+        after each complete AmpliteCalibration a 4th pedestal run of the same 
+        roi is taken, for crosschecking.
+        """
+    msg = MSG( verbose )
+    bias = bias_control
+    fad = fad_control
+    if not roi in [300,1024]:
+        raise ValueError("roi must be 300,1024")
+
+    if not bias.stn == 'VoltageOff':
+        msg.fail('a DRS amplitude calibration should not be taken with Voltage On')
+        return False
+
+    fad.reset_secondary_drs_baseline()
+    if roi == 300
+        Take( -1, 1000, 'pedestal')
+        fad.set_file_format(2)
+        Take( -1, 1000, 'pedestal')
+    elif roi == 1024:
+        Take( -1, 1000, 'drs-pedestal')
+        fad.set_file_format(2)
+        Take( -1, 1000, 'drs-pedestal')
+        
+    return True
+
+
+#============ BIAS VOLTAGE ====================================================
+def VoltageOn( mode = None, Watchdog = None, verbose = True):
+    """ High Level Method for switching on the bias Voltage
+        can be called, in whatever state the bias and the feedback might be.
+        In case the voltage is on and the feedback is already in the mode
+        requested, nothing happens.
+        In all other cases, the method will perform the needed steps to switch
+        on the bias voltage, the way the user requested
+    """
+    msg = MSG( verbose )
+    bias = bias_control
+    fb = feedback
+
+    if not mode in ['temperature', 'current', 'feedback']:
+        raise ValueError("mode must be 'temperature', 'current' or 'feedback'")
+
+    
+    
+    bias.set_global_dac(1)
+    if not bias.wait(9, 10):
+        msg.warn("bias not in Voltage ON after 10sec")
+        return False
+    if not bias.wait(5, 10):
+        msg.warn("bias not Ramping after 10sec")
+        return False
+    if not bias.wait(9, 30):
+        msg.warn("bias not fully ramped up after 30sec")
+        return False
+
+    msg("waiting 45sec...")    
+    time.sleep(45)
+    return True
+
+
 
 def IsReadyForDataTaking( verbose = True ):
@@ -41,19 +286,4 @@
 
     return ok
-
-def StopTracking( verbose = True ):
-    msg = MSG()
-    msg.output = verbose
-
-    # defining a shortcut 
-    drive = drive_control
-
-    drive.stop()
-    if not drive.wait(5, 10):
-        msg.warn("drive did not reach state 5 after 10 seconds")
-        msg.warn( drive.state()[0].rstrip('\x00') )
-        return False
-
-    return True
 
 def TakeDataRun( verbose = True ):
@@ -73,44 +303,4 @@
         msg.warn("FAD did not return to Connected, after 330 seconds")
         return False
-    return True
-
-def TrackSource( Shift=0.6, Angle=50, SrcName='Crab', verbose=True):
-    drive = drive_control
-    msg = MSG( verbose )
-    SrcName += '\0'
-
-    timeout  = 3
-    starttime = time.time()
-    while not drive.stn == 5:
-        if time.time() - starttime > timeout:
-            msg.fail('Did not get DRIVE into Armed state')
-            return False
-
-        if drive.stn < 5:
-            msg.fail('DRIVE in state'+drive.sts+" I don't what to do.")
-        if drive.stn >= 256:
-            msg.fail('DRIVE in state'+drive.sts+" I don't what to do.")
-
-        if drive.stn in [6,7]:
-            drive.stop()
-            time.sleep(0.5)
-
-    drive.track_source( Shift, Angle, SrcName)
-    return True
-
-def WaitForTracking( CalmDownTime = 30, verbose = True):
-    drive = drive_control
-    msg = MSG(verbose)
-
-    starttime = time.time()
-    time_out = 10
-
-    while not drive.stn == 7: #Tracking
-        if time.time() - starttime > time_out:
-            msg.fail("DRIVE not in Tracking after Timeout")
-            return False
-
-    msg.ok("Drive is Tracking, waiting to calm down...")
-    time.sleep(CalmDownTime)
     return True
 
@@ -178,29 +368,4 @@
     return True
 
-def Take1218( verbose = True):
-
-    TrackSource( Shift=0.6, Angle=-5, SrcName='1ES 1218+304')
-    WaitForTracking( CalmDownTime = 45, verbose = True)
-
-    TakeDrsAmplitudeCalibration( roi=1024 )
-    TakeDrsTimeCalibration( mode='upshifted' )
-    TakeDrsAmplitudeCalibration( roi=300 )
-
-    VoltageOn( mode='current' )
-    for i in range(4):
-        msg("Taking Data Run "+str(i+1)+" of 4")
-        TakeDataRun()
-    VoltageOff()
-
-    TrackSource( Shift=0.6, Angle=175, SrcName='1ES 1218+304')
-    WaitForTracking( CalmDownTime = 45, verbose = True)
-
-    VoltageOn( mode='current' )
-    for i in range(4):
-        msg("Taking Data Run "+str(i+1)+" of 4")
-        TakeDataRun()
-    VoltageOff()
-
-    drive_control.stop()
 
 def BlinkenLights(verbose = True):
@@ -473,95 +638,4 @@
 
 #==============================================================================
-def TakeDrsAmplitudeCalibration( roi = None, verbose = True):
-    """ Takes DRS Amplitude Calibration
-        *roy* integer: 300, 1024 or 
-        *roy* string : 'both'
-        in case of both, the roi=300 calibration is done last.
-        
-        after each complete AmpliteCalibration a 4th pedestal run of the same 
-        roi is taken, for crosschecking.
-        """
-    msg = MSG( verbose )
-    bias = bias_control
-    fad = fad_control
-    if not roi in [300,1024,'both']:
-        raise ValueError("roi must be 300,1024 or the string 'both'")
-
-
-    bias.set_zero_voltage()
-    if not bias.wait(7, 10):
-        msg.warn("bias has not switched of after 10sec")
-        return False
-
-    fad.start_drs_calibration()
-    Take( -1, 1000, 'drs-pedestal')
-    Take( -1, 1000, 'drs-gain')
-    if roi == 300:
-        Take( -1, 1000, 'pedestal')
-        fad.set_file_format(2)
-        Take( -1, 1000, 'pedestal')
-    elif roi == 1024:
-        Take( -1, 1000, 'drs-pedestal')
-        fad.set_file_format(2)
-        Take( -1, 1000, 'drs-pedestal')
-    elif roi == 'both':
-        Take( -1, 1000, 'drs-pedestal')
-        fad.set_file_format(2)
-        Take( -1, 1000, 'drs-pedestal')
-        fad.reset_secondary_drs_baseline()
-        Take( -1, 1000, 'pedestal')
-        fad.set_file_format(2)
-        Take( -1, 1000, 'pedestal')
-
-
-def TakeDrsTimeCalibration( mode = None, verbose = True):
-    """ Takes DRS Time Calibration
-        *mode* can be 'upshifted', 'old' or 'both'
-    """
-    msg = MSG( verbose )
-    bias = bias_control
-    fad = fad_control
-    if not mode in ['upshifted', 'old', 'both']:
-        raise ValueError("mode must be: 'upshifted','old' or 'both'")
-
-    bias.set_zero_voltage()
-    if not bias.wait(7, 10):
-        msg.warn("bias has not switched of after 10sec")
-        return False
-
-    fad.set_file_format(2)
-    if mode == 'old':
-        Take(-1, 1000, 'drs-time')
-    if mode == 'upshifted':
-        Take(-1, 1000, 'drs-time-upshifted')
-    if mode == 'both':
-        Take(-1, 1000, 'drs-time')
-        Take(-1, 1000, 'drs-time-upshifted')
-
-
-def VoltageOn( mode = None, Watchdog = None, verbose = True):
-    msg = MSG( verbose )
-    bias = bias_control
-    fb = feedback
-
-    if not mode in ['temperature', 'current', 'feedback']:
-        raise ValueError("mode must be 'temperature', 'current' or 'feedback'")
-    
-    
-    bias.set_global_dac(1)
-    if not bias.wait(9, 10):
-        msg.warn("bias not in Voltage ON after 10sec")
-        return False
-    if not bias.wait(5, 10):
-        msg.warn("bias not Ramping after 10sec")
-        return False
-    if not bias.wait(9, 30):
-        msg.warn("bias not fully ramped up after 30sec")
-        return False
-
-    msg("waiting 45sec...")    
-    time.sleep(45)
-    return True
-
 # standard watchdog:
 def std_bias_watchdog( state, verbose=True ):
