#%TITLE% ELMETER_MH.MAC
#%NAME% %B%elmeter_mh.mac%B% - Electrometer Macro Counter
#%DESCRIPTION%
# The macro set offers the possibility to set-up the electrometer TANGO
# attributes as macro counter.%BR%
# The macro counter controller defined in spec config is called %B%elmeter%B%
# and has as the ADDR the device server device (e.g. d29/elmeter/all)
# For each controller the %B%type%B% additional parameter shoud be
# configured (e.g.CONPAR:type = K_6485). Each counter should have a
# parameter %B%device%B% (e,g, CNTPAR:device = d29/keithley/wb) which is the
# one used to controll one counter only (for start, gain setting etc.) and
# an optional parameter %B%autorange%B% (e.g. CNTPAR:autorange = 1) which
# indicates if the automatic range should be set.
#%END%
need spec_utils.mac
#%IU% (hwn, type, unit, module, chan)
#%MDESC% Called after reading the config file. If return the string ".error.",
#spec will consider the channel unusable.
def elmeter_config(hwn, type, unit, module, chan) '{
global ELMETER_PARAMS ELMETER_DATA
global ELMETER_CH[]
global ELMETER_CTRL[] ELMETER_IDX[]
if (ELMETER_PARAMS["debug"] != 0) {
tty_cntl("md");printf ("elmeter_config type -> %s\n", type);tty_cntl("me")
tty_cntl("md");printf ("elmeter_config hardware %s\n", hwn);tty_cntl("me")
printf("unit %d, module %d, chan %d\n", unit, module, chan)
}
if (type == "ctrl") {
unglobal ELMETER_CH
global ELMETER_CH []
if (get_index(elmeter_ADDR,unit) == -1)
return ".error."
ELMETER_CTRL[unit] = elmeter_ADDR
return
}
if (type == "mot") {
return
}
if (type == "cnt") {
if (counter_par(hwn,"device_id") != "elmeter")
return ".error."
if (elmeter_getpropsc(hwn) == -1)
return ".error."
elm_cdefs(hwn)
}
}'
#%IU% (hwn, key, p1, p2)
#%MDESC% Execute the command %B%key%B% for the counter %B%hwn%B%, with
#parameters %B%p1%B% and %B%p2%B% if needed. The keys used are as follows:%BR%
#%B%"start_one"%B% and %B%"prestart_all"%B% - start the counting
#Parameters: p1 - counting time.%BR%
#Parameters: p2 - 2 (count to a time preset - tcount()).%BR%
#%B%"counts"%B% - return the current counts.
#Parameters:none.%BR%
#%B%"get_status%B%" - only used for polling counter
#Parameters:none.%BR%
#%B%"halt_all%B%" - stop the counting and read the controller (all the
#counters in one go)
#Parameters: p1 - controller unit number.%BR%
#Return the string ".error.", spec will consider the channel unusable.
def elmeter_cmd(hwn, key, p1, p2, unit) '{
local dev attr ret _pos add_attr l_data nb_data
global ESRF_ERR
if (ELMETER_PARAMS["debug"] != 0) {
tty_cntl("md");printf ("elmeter_cmd %s\n", key);tty_cntl("me")
}
if (key == "prestart_all") {
if (ELMETER_PARAMS["debug"] != 0) {
printf (" --------> mne %s, cnt_time %f, cnt_mode %d, unit %d\n",\
hwn, p1, p2, unit)
}
if (hwn == "..") {
for (i in ELMETER_CH) {
ret = elm_start(i,p1)
if (ret == -1) {
return ".error."
}
}
}
} else if (key == "start_one") {
if (ELMETER_PARAMS["debug"] != 0)
printf (" --------> start for device %d\n", hwn)
if (p2 == 0) {
#do nothing if counter
return
}
} else if (key == "halt_all") {
if (ELMETER_PARAMS["debug"] != 0){
printf(" --------> halt all ctrl %d\n", p1)
}
elm_stopall()
ret = elm_read(p1) # p1 = controller number
if (ret == -1) {
return ".error."
}
else {
split(ret, l_data)
for (nb_data in l_data)
ELMETER_DATA[p1][nb_data] = l_data[nb_data]
}
} else if (key == "halt_one") {
if (ELMETER_PARAMS["debug"] != 0)
printf(" --------> halt all counter %d\n", hwn)
} else if (key == "counts") {
if (ELMETER_PARAMS["debug"] != 0) {
printf(" --------> read counter %d (%s)\n", hwn, cnt_mne(hwn))
printf(" --------> unit:%d index: %d ", counter_par(hwn,"unit"), counter_par(hwn,"index"))
print " --> ELMETER_DATA="
print ELMETER_DATA
}
if (counter_par(hwn,"type") == "K_6482"){
ret = ELMETER_DATA[counter_par(hwn,"unit")][counter_par(hwn,"channel")]
}
else{
ret = ELMETER_DATA[counter_par(hwn,"unit")][counter_par(hwn,"index")]
}
return ret
}
}'
#%IU% (hwn, key, action, p1)
#%MDESC% Get/set the corresponding electrometer counter par
def elmeter_par(hwn, key, action, p1) '{
local ret elm_dev
if (key == "device")
return ""
elm_dev = counter_par(hwn, "device")
if (key == "acq_afap") {
TANGO_ERR = "-1"
if (action == "get") {
ret = tango_get(elm_dev, key)
} else {
ret = tango_put(elm_dev, key, p1)
}
if (TANGO_ERR != "0") {
tty_cntl("md")
print_tango_err()
tty_cntl("me")
return(-1)
} else {
return ret
}
}
}'
#%IU% (ctrl,unit)
#%MDESC% Get the index in the list of devices, served by the %B%ctrl%B%
# controller device server.
def get_index(ctrl,unit) '{
global ELMETER_IDX[]
local idx[] i j
if (ELMETER_PARAMS["debug"] != 0)
printf ("Calling get index for controller %s, unit %d\n", ctrl, unit)
TANGO_ERR = "-1"
tango_io(ctrl,"timeout",10)
tango_io(ctrl, "GetDevicesList", idx)
if (TANGO_ERR != "0") {
print_tango_err()
return(-1)
}
for (i in idx) {
ELMETER_IDX[unit][i] = tolower(idx[i])
}
}'
#%IU% (ctn)
#%MDESC% Get the counter properties. Save it as a index counter parameter.
def elmeter_getpropsc(ctn) '{
local dev key i unit
global ELMETER_PARAMS
if (ELMETER_PARAMS["debug"] != 0) {
tty_cntl("md");printf ("elmeter_getpropsc %d\n", ctn);tty_cntl("me")
}
if (counter_par(ctn,"controller") != "MAC_CNT") {
counter_par(ctn,"disable",1)
return(-1)
}
unit = counter_par(ctn,"unit")
dev = counter_par(ctn,"device")
for (i in ELMETER_IDX[unit]) {
if (tolower(dev) == ELMETER_IDX[unit][i]) {
counter_par(ctn,"index", i, "add")
if (counter_par(ctn,"type") == "K_6482")
ELMETER_CTRL[unit][dev] = 0
S[ctn] = 0
break
}
}
ELMETER_CH[ctn] = ctn
counter_par(ctn,"counting",0,"add")
TANGO_ERR = "-1"
tango_io(dev,"timeout",10)
if (TANGO_ERR != "0") {
print_tango_err()
counter_par(ctn,"disable",1)
return(-1)
}
return(elm_autorange_status(ctn))
}'
#%IU% (hwn,p1)
#%MDESC% Start the %B%hwn%B% counting for %B%p1%B% seconds.
def elm_start(hwn,p1) '{
local ret dev unit type
if (counter_par(hwn,"disable") != 0)
return(0)
if (counter_par(hwn,"counting") == 1)
return(0)
dev = counter_par(hwn,"device")
unit = counter_par(hwn,"unit")
type = counter_par(hwn,"type")
if ((type == "K_6482") && (ELMETER_CTRL[unit][dev] == 1))
return(0)
TANGO_ERR = "-1"
ret = tango_io(dev,"StartAcq",p1)
if (TANGO_ERR != "0") {
tty_cntl("md")
printf ("counter %s:",cnt_mne(hwn))
print_tango_err()
tty_cntl("me")
counter_par(hwn,"counting",0)
return(-1)
}
counter_par(hwn,"counting",1)
if (type == "K_6482")
ELMETER_CTRL[unit][dev] = 1
return(ret)
}'
#%IU% ()
#%MDESC% Stop all the configured counters.
def elm_stopall() '{
local i
for (i in ELMETER_CH) {
elm_stop(i)
}
}'
#%IU% (hwn)
#%MDESC% Stop the %B%hwn%B% counting.
def elm_stop(hwn) '{
local dev
dev = counter_par(hwn,"device")
if (counter_par(hwn,"counting") == 1) {
tango_io(dev,"WaitAcq")
counter_par(hwn,"counting",0)
if (counter_par(hwn,"type") == "K_6482")
ELMETER_CTRL[counter_par(hwn,"unit")][dev] = 0
}
}'
#%IU% (p1)
#%MDESC% Read the %B%p1%B% controller. Mark all the read counters as not counting.
def elm_read(p1) '{
local ret vals[] ii
if (ELMETER_CTRL[p1] == 0)
return(-1)
TANGO_ERR = "-1"
tango_io(ELMETER_CTRL[p1], "Read", vals)
if (TANGO_ERR != "0") {
tty_cntl("md")
print_tango_err()
tty_cntl("me")
return(-1)
}
if (ELMETER_PARAMS["debug"] != 0) {
print(" ----> READ, vals=")
print(vals)
}
# Build a string containing read values.
ret = ""
for (ii in vals){
# Now spec is iterating in the good order...
ret = sprintf ("%s %g", ret, vals[ii])
}
for (ii in ELMETER_CH) {
if (ELMETER_CTRL[p1] == elmeter_ADDR) {
counter_par(ii, "counting", 0)
}
}
if (ELMETER_PARAMS["debug"] != 0) {
printf(" -----> read ret value = %s\n", ret)
}
return (ret)
}'
#### Autorange ####
#%IU% (hwn)
#%MDESC% Stop the %B%hwn%B% counter autorange.
def elm_autorange_off(hwn) '{
return(elm_autorange_set(hwn, 0))
}'
#%IU% (hwn)
#%MDESC% Start the %B%hwn%B% counter autorange.
def elm_autorange_on(hwn) '{
return(elm_autorange_set(hwn, 1))
}'
#%IU% (hwn)
#%MDESC% Get the %B%hwn%B% counter autorange status (1 if autorange, 0 if not)
def elm_autorange_status(hwn) '{
local ret
TANGO_ERR = "-1"
ret = tango_get(counter_par(hwn,"device"), "autorange")
ELMETER_PARAMS[hwn]["autorange"] = ret
if (TANGO_ERR != "0") {
tty_cntl("md")
print_tango_err()
tty_cntl("me")
#disable the counter if error
counter_par(hwn,"disable",1)
return(-1)
}
counter_par(hwn, "disable", 0)
return(ret)
}'
#%IU% (hwn,stat)
#%MDESC% Set the %B%hwn%B% counter autorange on (%B%stat%B%=1) or off (stat = 0).
def elm_autorange_set(hwn, stat) '{
local ret autor
if (counter_par(hwn,"disable") != 0)
return(stat)
autor = ELMETER_PARAMS[hwn]["autorange"]
ELMETER_PARAMS[hwn]["saved_autorange"] = autor
ELMETER_PARAMS[hwn]["autorange"] = stat
TANGO_ERR = "-1"
ret = tango_put(counter_par(hwn,"device"),"autorange",stat)
if (TANGO_ERR != "0") {
tty_cntl("md")
ELMETER_PARAMS[hwn]["autorange"] = autor
print_tango_err()
tty_cntl("me")
return(-1)
}
elm_autorange_status(hwn)
}'
def elm_autorange_restore(hwn) '{
return(elm_autorange_set(hwn, ELMETER_PARAMS[hwn]["saved_autorange"]))
}'
#### Autorange end ####
#### Range get/set ####
#%IU% (value)
#%MDESC% Convert 2e-xxx to xxx
def _pow2int(value) '{
local ii res
ii = 0
res = value
while(res < 1) {
ii++
res *= 10
}
return(ii)
}'
#%UU% <[c_mne]>
#%MDESC% Get the %B%c_mne%B% counter range.
def elm_getrange '{
local c_mne rr val jj
val = 0
c_mne = "$1"
if (!c_mne) {
# Read ALL ranges
for (jj in ELMETER_CH) {
rr = _elm_getrange(jj)
if (rr != -1) {
val = _pow2int(rr)
}
if (elm_autorange_status(jj) == 1) {
printf ("\n%s autorange set, current range is %g\n", cnt_mne(jj), rr)
} else {
printf ("\n%s range is set to: %d (max input current %g A)\n", \
cnt_mne(jj), val, rr)
}
}
} else {
cntnum = cnt_num(c_mne)
if (cntnum == -1) {
eprintf ("Invalid counter mnemonic %s, exiting...\n", "$1")
exit
}
rr = _elm_getrange(cntnum)
if (rr != -1) {
val = _pow2int(rr)
}
if (elm_autorange_status(cntnum) == 1) {
printf ("\n%s autorange set, current range is %g\n", c_mne, rr)
} else
printf ("\n%s range is set to: %d (max input current %g A)\n", \
c_mne, val, rr)
}
}'
#%IU% (hwn)
#%MDESC% Get the %B%hwn%B% counter range.
def _elm_getrange(hwn) '{
local ret
TANGO_ERR = "-1"
ret = tango_get(counter_par(hwn,"device"), "range")
if (TANGO_ERR != "0") {
tty_cntl("md")
print_tango_err()
tty_cntl("me")
# Disable the counter in case of error.
counter_par(hwn, "disable", 1)
return(-1)
}
counter_par(hwn, "disable", 0)
return(ret)
}'
#%UU% [cntmne range]
#%MDESC% Set the %B%cntmne%B% counter %B%range%B% - allowed values:
#2 (corersponds to 20mA + 5% = 21mA maximum input current)
#to 9 (2nA + 5% = 2.1nA maximum input current). Note that setting the
#range stops the autorange mode!
def elm_setrange '{
local cntmne rr
cntnum = cnt_num("$1")
if (cntnum == -1) {
eprintf ("Invalid counter mnemonic %s, exiting...\n", "$1")
exit
}
rr = int($2)
if ((rr < 2) || (rr > 9)) {
eprintf ("Invalid range number. Please give new value (2 to 9)")
rr = int(input(": "))
}
rr = sprintf ("2e-%d", rr)
if (_elm_setrange(cntnum, rr) == 0)
printf ("\nRange set to: %d (max input current %g A)\n", $2, (rr+rr*0.05))
else
eprintf ("Attention! Range not set and counter %s disabled\n", "$1")
}'
#%IU% (hwn, range)
#%MDESC% Set the %B%hwn%B% counter %B%range%B% - allowed values: 2e-2 to 2e-9
#Note that setting the range stops the autorange mode!
def _elm_setrange(hwn, rr) '{
TANGO_ERR = "-1"
tango_put(counter_par(hwn,"device"),"range", rr)
if (TANGO_ERR != "0") {
tty_cntl("md")
print_tango_err()
tty_cntl("me")
#disable the counter if error
counter_par(hwn,"disable",1)
return(-1)
}
ELMETER_PARAMS[hwn]["autorange"] = 0
counter_par(hwn,"disable",0)
return(0)
}'
#### Range get/set end ####
#### Rate get/set ####
#%UU% <[counter_mnemonic]>
#%MDESC% Get the %B%c_mne%B% counter rate.
def elm_getrate '{
local c_mne rr val jj
val = 0
c_mne = "$1"
if (!c_mne) {
# Read ALL rates
for (jj in ELMETER_CH) {
rr = _elm_getrate(jj)
if (rr != -1) {
printf ("\n %s rate is set to: %g (sampling time : %gms)\n", cnt_mne(jj), rr, rr*20)
}
}
} else {
cntnum = cnt_num(c_mne)
if (cntnum == -1) {
eprintf ("Invalid counter mnemonic %s, exiting...\n", "$1")
exit
}
rr = _elm_getrate(cntnum)
if (rr != -1) {
printf ("\nRate is set to: %g (sampling time : %gms)\n", rr, rr*20)
}
}
}'
#%IU% (hwn)
#%MDESC% Read the %B%hwn%B% counter rate.
def _elm_getrate(hwn) '{
local ret
TANGO_ERR = "-1"
ret = tango_get(counter_par(hwn, "device"), "rate")
if (TANGO_ERR != "0") {
tty_cntl("md")
print_tango_err()
tty_cntl("me")
return(-1)
}
return(ret)
}'
#%UU% [cntmne rate]
#%MDESC% Set the %B%cntmne%B% counter %B%rate%B% - allowed values:
#0.01 to 5 (corresponding to 0.2ms to 100ms sampling time).
def elm_setrate '{
local cntnum rr
cntnum = cnt_num("$1")
if (cntnum == -1) {
eprintf ("Invalid counter mnemonic %s, exiting...\n", "$1")
exit
}
rr = $2
if ((rr < 0.01) || (rr > 5)) {
eprintf ("Invalid rate number. Please give new value (0.01 to 5)")
rr = input(": ")
}
if (_elm_setrate(cntnum, rr) == 0)
printf ("\nCounter %s rate set to: %g (sampling time:%gms)\n", "$1", rr, rr*20)
else
eprintf ("Attention! Cannot set counter %s rate!\n", "$1")
}'
#%IU% (hwn, rate)
#%MDESC% Set the %B%hwn%B% counter %B%rate%B% - allowed values: 0.01 to 5
def _elm_setrate(hwn, rr) '{
TANGO_ERR = "-1"
tango_put(counter_par(hwn,"device"),"rate", rr)
if (TANGO_ERR != "0") {
tty_cntl("md")
print_tango_err()
tty_cntl("me")
return(-1)
}
return(0)
}'
#### Rate get/set end ####
#%IU% (hwn)
#%MDESC% Set some %B%hwn%B% counter defs to be used whith scans.
def elm_cdefs(hwn) '{
local cnt
#cnt = counter_par(hwn,"unit")
if (counter_par(hwn,"autorange") == 1) {
cnt = hwn
cdef ("user_prescan_head", sprintf("elm_autorange_off(%d);",cnt),sprintf ("_elm%d_",cnt),0x20)
cdef ("user_scan_tail", sprintf("elm_autorange_restore(%d);",cnt),sprintf ("_elm%d_",cnt),0x20)
cdef ("_cleanup3", sprintf("elm_autorange_restore(%s);",cnt),sprintf ("_elm%d_",cnt),0x20)
}
}'
#%UU%
#%MDESC% Removes all cdef and globals for all the electrometer macro counters.
def elm_unsetup '{
local jj
for (jj in ELMETER_CH) {
_elm_unsetup(jj)
}
unglobal ELMETER_PARAMS ELMETER_DATA
unglobal ELMETER_CH
unglobal ELMETER_CTRL ELMETER_IDX
}'
#%IU% (cnt)
#%MDESC% removes cdef and globals for counter number %B%cnt%B%.
def _elm_unsetup(cnt) '{
cdef ("user_prescan_head","", sprintf ("_elm%d_", cnt), "delete")
cdef ("user_scan_tail", "", sprintf ("_elm%d_", cnt), "delete")
cdef ("_cleanup3", "", sprintf ("_elm%d_", cnt), "delete")
delete ELMETER_CH[cnt]
delete ELMETER_PARAMS[cnt]["autorange"]
}'
######## bench macros ########
#%IU% (cmd, nb, tt)
#%MDESC% Do a bench of the command %B%cmd%B%, %B%nb%B% times. Subtracs the
#count time %B%tt%B% if needed. Return the mean execution time value.
def bench_ct(cmd,nb,tt) '{
global float array TT[nb]
local i
local oldtime tunits tlabel
for (i = 0; i<nb; i++) {
oldtime=time()
eval(cmd)
oldtime = time()-oldtime
if (oldtime > 60) {
tunits = 60; tlabel="min."
munits = 1e5
} else if (oldtime > 1) {
tunits = 1; tlabel="sec."
munits = 1e3
} else {
tunits = 0.001; tlabel="msec."
munits = 1e0
}
if (tt)
tt = S[0]
TT[i] = ((oldtime - tt)/tunits) * munits
}
return(array_op("sum", TT)/nb)
}'
######## bench macros END ########
#%IMACROS%
#%TOC%
#%DEPENDENCIES% spec_utils.mac %BR%
#%AUTHOR% A.Beteva%BR%
#$Revision: 2.9 $ $Date: 2020/03/10 17:50:10 $
#%END%
#%LOG%
#$Log: elmeter_mh.mac,v $
#Revision 2.9 2020/03/10 17:50:10 guilloud
#fix order of index list of devices (l. 311) + debug
#(+ quote typo)
#
#Revision 2.7 2020/03/08 15:10:14 guilloud
#formating + fix TANGO_ERR
#
#Revision 2.6 2016/05/10 09:21:15 ahoms
#Add As-Fast-As-Possible "acq_afap" mode Tango attr. control as counter_par
#
#Revision 2.5 2015/09/01 12:54:57 beteva
#changed the type parameter from controller to device to be able to mix different Keithleys in the same device
#
#Revision 2.3 2014/05/15 14:13:40 beteva
#Added elm_unsetup (remove configured electrometer(s)).
#Changed getrange to read the autorange state systematically.
#
#Revision 2.2 2014/05/12 12:08:02 beteva
#Added elm_autorange_set and elm_autorange_restore commands.
#Add cdefs only if the counter has autorange property set to 1.
#
#Revision 2.1 2014/05/06 12:41:55 beteva
#Added Set/Get rate commands. Corrected typo in setrange.
#
#Revision 2.0 2014/04/30 12:53:38 beteva
#Changed range and autorange handling from commands to attributes
#(as from v1.5 of the device server).
#Now elm_getrange reads all availble counter with no input parameter.
#
#Revision 1.8 2014/04/02 11:50:39 guijarro
#replaced StopAcq by WaitAcq
#
#Revision 1.7 2013/10/08 13:52:33 beteva
#changed TANGO_ERR = "" to TANGO_ERR = "-1"
#
#Revision 1.6 2013/05/16 11:16:22 lagier
#fixed ELMETER_CH global declaration as an array.
#
#Revision 1.5 2013/04/24 12:27:04 beteva
#added elm_getrange/elm_setrange macros
#
#Revision 1.4 2012/07/30 11:59:55 beteva
#moved the search for index from the controller to the counter config;
#changed autorange_* to elm_autorange_*.
#
#Revision 1.3 2012/05/09 11:59:29 beteva
#Add an extra check in the get_index to avoid calls to otehr macro counters
#
#Revision 1.2 2012/04/25 12:31:41 beteva
# Disable a counter if tango error at setup. Corrected a typo.
#
#Revision 1.1 2012/01/26 14:53:26 beteva
#Initial revision
#
|