esrf

Beamline Instrument Software Support
SPEC Macro documentation: [ Macro Index | BCU Home ]

#%TITLE% I400.MAC
#
#%NAME%
#  Macros for operating the PTC (pyramid technical consultants inc.) I400 4-channel electrometer
#
#%CATEGORY%  Detection, BPM
#   
#%OVERVIEW%
#  This macro set allows to control I400 units in %B%spec%B% and configure
#  their signal inputs as pseudocounters. 
#  %BR%
#  More than one I400 unit can be operated through this macro set.
#
#%EXAMPLE%
#  %DL%
#  %DT%i400setup mydev 0 c1=curr1 c2=curr2 c3=curr3 c4=curr4
#  %DD%Configures an I400 unit connected to the spec serial line #0 and
#      associates its four input channels to the pseudocounters
#      curr1, curr2, curr3 and curr4.
#  %DT%icplussetup bpm0 2 cx=beamX cy=beamY
#  %DD%Configures an I400 unit connected through the serial line #2 and
#      associates normalised current differences to the pseudocounters
#      beamX and beamY.
#  %DT%i400show
#  %DD%Display the list of I400 units currently configured.
#  %XDL%
#
#%SETUP%
#  Serial line in spec %B%config%B% has to be set as %B%raw%B%, %B%19200%B% baud
#  %BR%
#  The mode rotary switch on the I400 unit has to be set to 8.
#%END%

#%UU% <i4name> <serline> [<parameter>=<value> ...]
#%MDESC%
#  Configures a I400 connected to <serline> with the name <i4name>.
#  The following optional parameters can be also set.
#  %UL%
#  %LI%Valid parameters:%DL%
#    %DT%address=<addr>
#    %DD%This parameter allows to address a particular unit when the serial 
#        line is shared by several IC-PLUS units. By default, the address
#        is read from the unit assuming only one unit on the serial line.
#    %DT% c1=<cnt_mne>
#    %DT% c2=<cnt_mne>
#    %DT% c3=<cnt_mne>
#    %DT% c4=<cnt_mne>
#    %DD%If <cnt_mne> is a valid counter mnemonic, it gets configured as
#        a pseudocounter loaded with the current in the corresponding
#        channel (1 to 4).
#        The "Scale Factor" value in the %B%spec%B% config file applies.
#    %DT% ci=<cnt_mne>
#    %DD%If <cnt_mne> is a valid counter mnemonic, it gets configured as
#        a pseudocounter loaded with sum of all channels
#        ci= c1+c2+c3+c4
#        The "Scale Factor" value in the %B%spec%B% config file applies.
#    %DT% cx=<cnt_mne>
#    %DT% cy=<cnt_mne>
#    %DD%If <cnt_mne> is a valid counter mnemonic, it gets configured as
#        a pseudocounter loaded with the normalised current difference:
#%BR%		cx= ((c2+c3)-(c1+c4))/(c1+c2+c3+c4)
#%BR%		cy= ((c1+c2)-(c3+c4))/(c1+c2+c3+c4)
#%BR%	 (x,y) defined for a geometry like:
#%BR%		y
#%BR%		^ c1 | c2
#%BR%		|---------> x
#%BR%		| c4 | c3 
#%BR%	The "Scale Factor" value in the %B%spec%B% config file applies.
#    %DT%samples[=1]
#    %DD%Sets the number of sub-samples per integration period
#    %XDL%
#  %XUL%
#
def i400setup '{
    local ret

    if (ret= _i400_setup("$*")) {
        if (SETUP) print "ERROR in line: $0 $*"
        if (ret < 0) {
	    print "Usage: $0 name serline [parameter=value ...]"
	    if (yesno("\nDisplay online help", 0))
	        eval ("help local i400")
        }
    }
}'

def _i400_init() '{
    global I400_GAIN[]

    I400_GAIN[1]["range"]= 1e-9
    I400_GAIN[1]["period"]= 1e-1
    I400_GAIN[1]["capa"]= 0

    I400_GAIN[2]["range"]= 1e-8
    I400_GAIN[2]["period"]= 1e-2
    I400_GAIN[2]["capa"]= 0

    I400_GAIN[3]["range"]= 1e-7
    I400_GAIN[3]["period"]= 1e-1
    I400_GAIN[3]["capa"]= 1

    I400_GAIN[4]["range"]= 1e-6
    I400_GAIN[4]["period"]= 1e-2
    I400_GAIN[4]["capa"]= 1

    I400_GAIN[5]["range"]= 1e-5
    I400_GAIN[5]["period"]= 1e-3
    I400_GAIN[5]["capa"]= 1

    I400_GAIN[6]["range"]= 1e-4
    I400_GAIN[6]["period"]= 1e-4
    I400_GAIN[6]["capa"]= 1
}'

#%IU%
def _i400_setup(args) '{
    global I400_PAR[]

    local ipar npar pars[] setval[] tarr[]
    local name sdev addr
    local cname cnum defname

    _i400_init()

    npar= split(args, pars)
    for (ipar=0; ipar<npar; ipar++) {
        if (split(pars[ipar], tarr, "=") > 1) {
	    setval[tarr[0]]= tarr[1]
	    delete pars[ipar]
	}
	else if (ipar>1) {
	    setval[pars[ipar]]= "yes"
	    delete pars[ipar]
	}
    }

    if (!((0 in pars)&&(1 in pars))) {
	printf("I400 ERROR: bad setup parameters\n")
	return (-1)
    }

    name= pars[0]
    sdev= pars[1]

    if (name + 0 == name) {
	printf("I400 ERROR: Bad name\n")
	return (-1)
    }
    if (sdev + 0 != sdev) {
        printf("I400 ERROR: Bad serial unit\n")
	return (-1)
    }

    if (I400_PAR["setup_n"] != SETUP_N) {
        list_init I400_PAR
        I400_PAR["setup_n"] = SETUP_N
    }

    list_add(I400_PAR, name)
    I400_PAR[name]["serline"]= sdev + 0
    addr= ("address" in setval)? setval["address"]+0 : -1
    delete setval["address"]
    I400_PAR[name]["address"]= addr

    if (_i400_initcom(name)<0) {
	return (1)
    }

    if ("samples" in setval) {
	I400_PAR[name]["samples"]= setval["samples"]
	delete setval["samples"]
    } else {
	I400_PAR[name]["samples"]= 1
    }
   
    if ("capacitor" in setval) {
        _i400_setcapacitor(name, setval["capacitor"])
	delete setval["capacitor"]
    }

    if ("gain" in setval) {
	_i400_setgain(name, setval["gain"])
	delete setval["gain"]
    }

    _i400_initdata
    for (cname in I400_DATA) {
	I400_PAR[name][cname]= -1
        if (cname in setval) {
	    if ((cnum= cnt_num(setval[cname]))!=-1) {
	        I400_PAR[name][cname]= cnum
	        I400_PAR[name]["pseudo"]= 1
	    } else {
		printf("I400 WARNING: counter <%s> is not valid\n", cname)
	    }
	    delete setval[cname]
        }
    }
    if (I400_PAR[name]["pseudo"]) {
	defname= "i4_" name
	cdef("user_prepcount", sprintf("_i400_prepcount(\"%s\")\n", name), defname)
	cdef("user_getcounts", sprintf("_i400_getcounts(\"%s\")\n", name), defname)
    }

    setup_tail("i400", name)

    ipar= ""
    for (ipar in setval) {
	printf("I400 ERROR: Invalid parameter <%s> \n", ipar)
    }
    if (ipar != "")
	return (-1)

    return (0)
}'

#%UU% <i4name> <samples>
#%MDESC% 
# Sets the number of sub-samples taken during intergration period
# for the i400 unit <i4name>
#
def i400samples '{
    local name samp
    if ($#!=2) {
	print "Usage: $0 <name> <samples>"
	exit
    }
    name= "$1"
    if (list_check(I400_PAR, name)<=0) {
	printf("I400 ERROR: wrong i400 name <%s>\n", name)
    } else {
	samp= ($2+0)>0 ? ($2+0) : 1
	I400_PAR[name]["samples"]= samp
    }
}'

def i400gainlist '{
    local ig
    printf("\nI400 GAIN settings:\n")
    printf("GAIN  CAPAC  PERIOD      RANGE\n")
    for (ig=1; ig<7; ig++) {
	printf("%4d  %-5.5s  %8.3g s  %8.3g A\n", ig, I400_GAIN[ig]["capa"] ? "HIGH" : "LOW", \
			I400_GAIN[ig]["period"], I400_GAIN[ig]["range"])
    }
    printf("\n")
}'

def i400gain '{
    local name gain

    if (($#!=1)&&($#!=2)) {
	print "Usage: $0 <name> [<gain>]"
	exit
    }

    name= "$1"
    if (list_check(I400_PAR, name)<=0) {
	printf("I400 ERROR: wrong i400 name <%s>\n", name)
    } else {
        if ($#==2) {
	    gain= $2 + 0
	    if ((gain<0)||(gain>6)) {
		printf("I400 ERROR: gain values ranges from 1 to 6\n")
	    } else {
		_i400_setgain(name, gain)
	    }
	} else {
	    gain= _i400_getgain(name)
	    if (gain) {
	        printf("Current Gain is : %d\n", gain)
	        printf("- Capacitor = %s\n", I400_GAIN[gain]["capa"])
		printf("- Period    = %g s\n", I400_GAIN[gain]["period"])
		printf("- Range     = %g A\n", I400_GAIN[gain]["range"])
	    } else {
		printf("Gain is not set.")
	    }
        }
    }
}'

def _i400_setgain(name, gain) '{
    local cap per
    if (gain>0) {
        _i400_setcapacitor(name, I400_GAIN[gain]["capa"])
        _i400_setperiod(name, I400_GAIN[gain]["period"])
    }
    I400_PAR[name]["gain"]= gain
}'

def _i400_getgain(name) '{
    return I400_PAR[name]["gain"]
}'

def _i400_setperiod(name, per, samp) '{
    local cmd
    if (samp>0) {
        cmd= sprintf("CONF:GAT:INT:PER %g %d", per, samp)
    } else {
	cmd= sprintf("CONF:GAT:INT:PER %g", per)
    }
    if (_i400_io(name, cmd)<0) {
	printf("I400 ERROR: Fail to set acquisition period\n")
	return (-1)
    }
    return (0)
}'
    
#%UU% <i4name> <capacitor>
#%MDESC%
# Sets feedback capacitor to low value (0) or high value (1)
#
def i400capacitor '{
    local name cap
    if (($#!=1)&&($#!=2)) {
	print "Usage: $0 <name> [<capacitor>]"
	exit
    }
    name= "$1"
    if (list_check(I400_PAR, name)<=0) {
	printf("I400 ERROR: wrong i400 name <%s>\n", name)
    } else {
	if ($#==2) {
	    cap= $2 + 0
	    if ((cap<0)||(cap>1)) {
	        printf("I400 ERROR: capacitor can either 0 (low) or 1 (high)\n")
            } else {
	        _i400_setcapacitor(name, cap)
            }
        } else {
	    cap= _i400_getcapacitor(name)
	    printf("I400 module <%s> capacitor is %s (%d).\n", name, cap?"HIGH":"LOW", cap)
	}
    }
}'

#%IU%
def _i400_setcapacitor(name, cap) '{
    local cmd
    cmd= sprintf("CONF:CAP %d", cap>0 ? 1 : 0)
    if (_i400_io(name, cmd)<0) {
	printf("I400 ERROR: Fail to set capacitor\n")
	return (-1)
    }
    return (0)
}'

#%IU%
def _i400_getcapacitor(name) '{
    local ret cap val
    if ((ret=_i400_io(name, "CONF:CAP?"))<0) {
	printf("I400 ERROR: failed to read capacitor\n")
	return (-1)
    }
    if (sscanf(ret, "%d,%f F", cap, val)!=2) {
	printf("I400 ERROR: failed to parse capacitor value\n")
	return (-1)
    }
    return (cap)
}'
    
    
#%UU%
#%MDESC%
# Shows the list of I400 units configured
#
def i400show '{
    local nb ii name

    nb= list_n(I400_PAR)
    if (!nb) {
	printf("\nNO I400 device configured.\n")
    }
    else {
	printf("\nName      SL  Addr  Samples\n")
        printf("--------  --  ----  -------\n")
	for (ii=1; ii<=nb; ii++) {
	    name= list_item(I400_PAR, ii)
	    printf("%-8.8s  %2d  %4d  %7d\n", name, I400_PAR[name]["serline"], \
		   I400_PAR[name]["address"], I400_PAR[name]["samples"])
	}
    }
}'

#%IU%    
def _i400_initdata '{
    global I400_DATA[]
    I400_DATA["c1"]= -1.
    I400_DATA["c2"]= -1.
    I400_DATA["c3"]= -1.
    I400_DATA["c4"]= -1.
    I400_DATA["ci"]= -1.
    I400_DATA["cx"]= -1.
    I400_DATA["cy"]= -1.
    I400_DATA["ci12"]= -1.
    I400_DATA["cd12"]= -1.
}'

#%IU% [<i4name>]
#%MDESC%
# Unsetup given i400 unit or all units
#
def i400unsetup '{
    local ncfg icfg
    if ($#==1) {
	_i400_unsetup("$1")
    } else {
	ncfg= list_n(I400_PAR)
	for (icfg=1; icfg<=ncfg; icfg++)
	    _i400_unsetup(list_item(I400_PAR, icfg))
    }
    if (list_n(I400_PAR)==0) {
	unglobal I400_PAR I400_DATA
    }
}'

#%IU%
def _i400_unsetup(name) '{
    local defname
    defname= "i4_" name
    cdef("", "", defname, "delete")
    list_remove(I400_PAR, name)
}'

#%IU%
def _i400_prepcount(name) '{
    local period samples cmd minper

    I400_PAR[name]["started"]= 0

    if (I400_PAR[name]["gain"]>0) {
	period= I400_GAIN[I400_PAR[name]["gain"]]["period"]
	if (COUNT_TIME < period) {
	    printf("I400 WARNING: Integration time should be greater than %g s. with gain %d\n", period, I400_PAR[name]["gain"])
	}
    }
    else {
        period= COUNT_TIME
        minper= 1e-4*I400_PAR[name]["samples"]
        if (period < minper) {
	    printf("I400 WARNING: Integration time cannot be lower than %g s. with %d samples\n", minper, I400_PAR[name]["samples"])
	    period= minper
        }
        if (period > 65.0) {
	    printf("I400 WARNING: Integration time cannot be greater than 65 s.\n")
	    period= 65.
        }
        samples= I400_PAR[name]["samples"]
        _i400_setperiod(period, samples)
    }

    if (_i400_io(name, sprintf("TRIG:POIN %d", I400_PAR[name]["samples"]))<0) {
	printf("I400 ERROR: failed to set trigger point\n")
        return (-1)
    }
    if (_i400_io(name, "INIT")<0) {
	printf("I400 ERROR: Fail to start acquisition period\n")
	return (-1)
    }
    I400_PAR[name]["started"]= 1
}'

#%IU%
def _i400_getcounts(name) '{
    local cname cnum

    if (_i400_read(name)==-1) {
	printf("I400 ERROR> Failed to read I400 values\n")
	_i400_initdata
    }
    for (cname in I400_DATA) {
        cnum= I400_PAR[name][cname]
	if ((cnum!=-1)&&(!counter_par(cnum, "disable"))) {
	    S[cnum]= I400_DATA[cname] / counter_par(cnum, "scale")
        }
    }
}'

#%IU%
def _i400_read(name) '{
    local data[] dstr
    local per c1 c2 c3 c4 ov

    _i400_initdata

    if (!I400_PAR[name]["started"])
	return (0)

    if ((dstr=_i400_io(name, "FETC:CURR?"))==-1) {
	printf("I400 ERROR: Failed to read data\n")
	return (-1)
    }
    # --- dstr = 1.0000e-02 S,5.7983e-12 A,-1.2207e-12 A,1.2207e-12 A,1.8311e-12 A,0
    if (sscanf(dstr, "%f S,%f A,%f A,%f A,%f A,%d", per, c1, c2, c3, c4, ov)!=6) {
	printf("I400 ERROR: Failed to parse data\n")
	return (-1)
    }
    I400_PAR[name]["period"]= per
    if (ov) {
	printf("I400 ERROR: over range byte set\n")
	return (-1)
    }
    I400_DATA["c1"]= c1
    I400_DATA["c2"]= c2
    I400_DATA["c3"]= c3
    I400_DATA["c4"]= c4

    I400_DATA["ci12"]= I400_DATA["c1"]+I400_DATA["c2"]
    if (I400_DATA["ci12"]!=0) {
	I400_DATA["cd12"]= (I400_DATA["c1"]-I400_DATA["c2"])/I400_DATA["ci12"]
    } else {
	I400_DATA["cd12"]= -1.
    }
    I400_DATA["ci"]= I400_DATA["c1"]+I400_DATA["c2"]+I400_DATA["c3"]+I400_DATA["c4"]
    if (I400_DATA["ci"]!=0) {
	I400_DATA["cx"]= ((I400_DATA["c2"]+I400_DATA["c3"])-(I400_DATA["c1"]+I400_DATA["c4"]))/I400_DATA["ci"]
	I400_DATA["cy"]= ((I400_DATA["c1"]+I400_DATA["c2"])-(I400_DATA["c3"]+I400_DATA["c4"]))/I400_DATA["ci"]
    } else {
	I400_DATA["cx"]= -1.
	I400_DATA["cy"]= -1.
    }

    return (0)
}'

#%IU%
def _i400_initcom(name) '{
    local addr

    if (_i400_io(name, "\r")<0) {
	printf("I400 ERROR: serial access failed\n")
        return (-1)
    }

    addr= I400_PAR[name]["address"]
    if (addr==-1) {
	addr= _i400_io(name, "#?") + 0
	if (addr < 0) {
	    printf("I400 ERROR: cannot get device address\n")
	    return (-1)
	}
	I400_PAR[name]["address"]= addr
    }

    if (_i400_io(name, sprintf("#%d", addr), 1)<0) {
	printf("I400 ERROR: failed to select device by address\n")
	return (-1)
    }
    if (_i400_io(name, "TRIG:SOUR INT")<0) {
	printf("I400 ERROR: failed to set internal trigger\n")
	return (-1)
    }
    return (0)
}'

#%IU%
def _i400_io(name, com, noack) '{
    local rep str sdev
    sdev= I400_PAR[name]["serline"]
    ser_par(sdev, "flush")
    
    ser_put(sdev, str=com "\n")
    rep= ser_get(sdev, "\n")
    rep= substr(rep, 1, length(rep)-1)
    if (rep != com) {
	printf("I400 ERROR: command not echoed\n")
	return (-1)
    }
    if (!noack) {
        rep= ser_get(sdev, "\r\n")
        rep= substr(rep, 1, length(rep)-2)
        if (index(com, "?")) {
	    return (rep)
        } else {
	    if (rep!="OK") {
	        printf("I400 ERROR: command <%s> failed\n", com)
	        return (-1)
	    }
        }
    }
    return (0)
}'
#%IMACROS%
#%MACROS%
#%AUTHOR% EP, BLISS
#  $Revision: 1.2 $ / $Date: 2008/09/26 12:40:30 $
#%TOC%
#%END%
#%LOG%
#$Log:$