Zugvorrichtung, P03 (argparse)

#!/usr/bin/env python
#
## script for BT Conrad S. - sweep scan using phyton
##
## usage:
##
## 1) adjust motors / devices acording to current device onnections
##    see line 128 (at moment) - proxy connects to tango devices
##
## 2) copy this script into "online" foler and make it
##    executable for P03user (i.e. as p03user do)
##    a) cp cs_sweep.py /gpfs/current/raw/online/
##    b) cd /gpfs/current/raw/online/
##       chmod u+x cs_sweep.py
##
## 4) script can now be excecuted from within online folder by
##    [from fresh terminal window: cd /gpfs/current/raw/online/ and then]
##    ./cs_sweep.py [opt_args]
##
##   !!! Do NOT stop reading here !!!
##
##  The script writes its oputput into the directory from where it was called
##  with a filename having the extension ".dat"
##
##  When called without arguments, it takes the defaults defined in here,
##  e.g. for filename and motor movement ranges
##
##  The script can be called with optional args allowing to change the defaults
##  Note: You can pass one or multiple args.
##        If an argument is missing, the default is taken
##        Order of arguments doesn't matter
##
##  Opt args are:
##
##    -p (or aquivalent --prefix):   the filename prefix for the output file
##                                   a 5 digit counter will be added automatically
##    -sx (or aquivalent --startX):  the start position of 1st motor
##    -ex (or aquivalent --stopX):   the stop position of 1st motor
##    -sy (or aquivalent --startY):  the start position of 2nd motor
##    -ey (or aquivalent --stopY):   the stop position of 2nd motor
##     -l (or aquivalent --loopMax): the maximum number of loops (before script
##                                   ends by itself)
##    -d (or aquivalent --debug):    NOT needed - just some additional screen
##                                   output I used when writing the stuff
##
##
##  Hence, script calls can be e.g. like this
##
##  ./cs_sweep.py -p=dummy
##
##  (output file should be named dummy, i.e. dummy_<5 digit counter>.dat,
##   and defaults for all other actions implied)
##
## or
##
##  ./cs_sweep.py -p=dummy -l=3 -sx=2
##  (output file should be named dummy, number of loops should be 3 and
##   1st motor starting position to use is 2. defaults for all other actions implied)
##
## or
##
##  ./cs_sweep.py -p=dummy -l=2 -sx=2 -ex=4 -sy=3 -ey=6
##
##  (output file should be named dummy, number of loops should be 2,
##   1st motor should move from 2 to 4 and 2nd motor should move from 3 to 6.)
##
## The script runs until the max. number of loops defined is reached or
## can be stopped with the 'space bar'
##
##
## history
##
## ver 0.0 - the first - script for test environment
##           * T.K. + W.O. + A.R., Oct 14, 2016
##
## ver 0.1 - modifications according to P03 BL and enhancements, Oct 14, 2016 by A.R./FSEC
##           * argument parsing added
##           * shutter control added
##           * comments added
##
import time, sys
import PyTango
import HasyUtils
import argparse

class breakLoop( Exception): pass

## here we define the optional arguments and their defaults
## the --<name> defines the name of the variable used laten in the script
## e.g. --prefix results that a variable args.prefix exists
##      (args.prefix because of the args = parser.... call lateron)
parser = argparse.ArgumentParser(description='CS sweep scan')
parser.add_argument('-p','--prefix', type=str, default="cs_sweep_p03",
 help='the filename prefix for the output file (counter will be added)')
parser.add_argument('-l','--loopMax', type=int, default=10,
 help='the maximum number of loops (defaults to 10)')
parser.add_argument('-sx','--startX', type=int, default=0,
 help='the start position of 1st motor (exp_mot<NN>) (defaults to 0)')
parser.add_argument('-ex','--stopX', type=int, default=1,
 help='the stop position of 1st motor (defaults to 1)')
parser.add_argument('-sy','--startY', type=int, default=0,
 help='the start position of 2nd motor (exp_mot<NN>) (defaults to 0)')
parser.add_argument('-ey','--stopY', type=int, default=-1,
 help='the stop position of 2nd motor (defaults to 0)')
parser.add_argument('-d','--debug', type=int, default=0,
 help='a debug flag (defaults to 0)')
args = parser.parse_args()

out = None

# print something to the screen if set
if args.debug == 1:
    print( "prefix: %s, startX: %g, stopX: %g, startY: %g, stopY: %g, loopMax: %g\n" % ( args.prefix,
                                    args.startX, args.stopX, args.startY,
				    args.stopY, args.loopMax))

## establish proxy connects to devices involved
## use motor 26 as X (still defined as diode_x in online as of Oct. 14)
## use motor 25 as Y (still defined as diode_y in online as of Oct. 14)
## assign ADCs 1 and 2 (for the 0-10V signals Conrad will provide)
## use P03 vfcadc01 (the diode on primary BS)
## use output register 1 'oreg1 in online', i.e. connected to fast shutter at momentt
## W.O. to adjust
##
try:
    diode_x = PyTango.DeviceProxy( "p03/motor/expmi.26")
    diode_y = PyTango.DeviceProxy( "p03/motor/expmi.25")
    adc_kraft = PyTango.DeviceProxy( "p03/adc/exp.01")
    adc_weg = PyTango.DeviceProxy( "p03/adc/exp.02")
    i0 = PyTango.DeviceProxy( "p03/vfc/exp.01")
    fshttr = PyTango.DeviceProxy( "p03/register/exp.out01")
except:
    print( "failed to create the proxies")
    sys.exit( 255)

## definition to put single line to screen and into file
def recordData():
    print( "%g %g %g %g %g" % ( diode_x.position,
                               diode_y.position,
                               adc_kraft.value, 
                               adc_weg.value, 
                               i0.value))
    out.write( "%g %g %g %g %g %f\n" % ( diode_x.position,
                                         diode_y.position,
                                         adc_kraft.value, 
                                         adc_weg.value, 
                                         i0.value, time.time()))
    if HasyUtils.inkey() == 32:
        return False
    return True
    
## definition for call (moving into starting position)
##
def moveToStart():
    if( diode_x.state() != PyTango.DevState.ON or
        diode_y.state() != PyTango.DevState.ON): 
        print( "state != ON")
        return False
    diode_x.position = args.startX
    diode_y.position = args.startY
    while( diode_x.state() == PyTango.DevState.MOVING or
           diode_y.state() == PyTango.DevState.MOVING): 
        time.sleep(0.5)
        print( "moving to start %g %g" % (diode_x.position, diode_y.position))
        if HasyUtils.inkey() == 32:
            print( "terminated by space-bar")
            return False
    return True

## make use of hasyutils and create a decent filename from the prefix given
## this also adds the 5 digit counter
##
fName = HasyUtils.createScanName( args.prefix)

if args.debug == 1:
    print( "fName: %s\n" % ( fName))

## move to strating position or die
##
ret = moveToStart()
if not ret:
    sys.exit( 255)

## create the output file (in the current directory)
##
out = open( fName + ".dat", "w")
out.write("!\n")
out.write("! Started at %s %f\n" % (HasyUtils.getDateTime(), time.time()))
out.write("! recording %s %s %s %s %s time\n" % (diode_x.name(),diode_y.name(),adc_kraft.name(),adc_weg.name(),i0.name()))
out.write("!\n")

## open the fast shutter (i.e. set register to low)
##
fshttr.value=0

## now loop until max num of loops is reached or space bar is pressed to abort
## data logging time reolution is currently 0.2s (I wouldn't go too low,
## maybe down to 0.05 (?) you may try ....)
## W.O. to adjust
##
try:
    for i in range( args.loopMax):
        out.write( "! sweep %d\n" % i)
        print( "! sweep %d/%d \n" % (i, args.loopMax))
        diode_x.position = args.stopX
        diode_y.position = args.stopY
        while( diode_x.state() == PyTango.DevState.MOVING or
               diode_y.state() == PyTango.DevState.MOVING): 
            time.sleep(0.2)
            if not recordData():
                raise breakLoop
        diode_x.position = args.startX
        diode_y.position = args.startY
        while( diode_x.state() == PyTango.DevState.MOVING or
               diode_y.state() == PyTango.DevState.MOVING): 
            time.sleep(0.2)
            if not recordData():
                raise breakLoop
except breakLoop:
    ## close fast shutter
    fshttr.value=1
    print( "The eagle has landed!")

## close file            
##
out.close()

## close fast shutter (in case of normal termination and to be save at all)
##
fshttr.value=1