#%TITLE% K2701.mac
#%NAME%
# Macros to work with a Keithley 2701 via a tcp/ip socket interface.
#%CATEGORY% Multimeter, temperature
#%DESCRIPTION%
# The keithley 2701 is a multichannel multimeter with a socket interface.
# Different kind of thermocouples measuring, voltage, current, resistance
# and frequency are possible.
#%BR% %BR%
# These macros have been tested only with thermocouples of type K and
# 4-wire pt100. Even if the code could, in principle, support other
# types of measuring, precise configuration may be necessary.
#%BR% %BR%
# This device is not recommended for fast measuring. At the ESRF an alternative
# solution is to use wago modules. Typical overhead measuring times for
# a Keithley 2701 are around 200 ms for one channel, around 400 ms
# for a three channel configuration compared with just a few ms for wago modules.
# Nevertheless this device presents at least two advantages. One is the
# flexibility and easyness of its setup. The second one is that some features
# are available that are not available with wago: for example, the higher
# accuracy obtained with a 4wire pt100, instead of only 3-wire supported by
# the corresponding wago module.
#%BR% %BR%
# The keithley tcp/ip socket connection is a single client connection. This
# would, in principle, stops several application configuring measuring channels
# on the device at the same time as only one can have an open socket to the
# device. It is possible to have a multi-client setup by using a Socketserver
# proxy device server (check your bliss contact to set it up). Nevertheless,
# as clients may have different measuring configurations, a conflict could quickly
# arise. Multiple clients MUST use exactly the same channel configuration.
#
#%EXAMPLE%
#%PRE%
# k2701setup k2701-1 id06/k2701/1
# k2701setup k2701-2 keithid32a:1394
#
# k2701add kt1 k2701-1 101 TEMP_K
# k2701add kt2 k2701-1 102 TEMP_K
# k2701add kt3 k2701-1 101 TEMP_PT100
# k2701add kvolt k2701-2 101 VOLT
#
# k2701init
#%PRE%
#%END%
global K2701CTRL K2701CTRLPAR
global K2701CHANS K2701PAR
global K2701READ
global K2701_NO_READ
K2701_NO_READ = -999
#%UU% cntlname device
#%MDESC%
# Defines a keithley 2701 controller in the system.
# Parameter ident is an arbitrary name to identify the
# controller later.
#%BR% %BR%
# Parameter device can take two forms:
#%DL%
# %DT%socket %DD%host:port (ex: keythid06a:1394 )
# %DT%server %DD%tango devname (ex: id06/k2701/1)
#%XDL%
#%BR% %BR%
# The socket naming is simple and does not require any extra software
# on the other hand k2701 devices only support one simultaneous
# client to talk to it.
#%BR% %BR%
# If you want to have it configured at the same time in more than
# one spec application or GUI, the second option must be used. For
# this it is necessary to run a tango server that needs to be
# configured and started beforehand.
#
def k2701setup '{
if ($# != 2) {
print "Usage: $0 ident device"
exit
}
K2701CTRL["$1"] = "$1"
K2701CTRLPAR["$1"]["dev"] = "$2"
if ( index("$2",":") > 0 ) {
K2701CTRLPAR["$1"]["socket"] = "socket"
} else {
K2701CTRLPAR["$1"]["socket"] = "tango"
}
setup_tail("k2701_ctrl","$1")
}'
#%UU% <mne> <ctrl-ident> <ch> <readtype>
#%MDESC%
# Add a counter on one Keithley 2701 controller previously
# defined with k2701setup
#%BR% %BR%
# Parameters are:
#%DL%
# %DT%mne: %DD%counter mnemonic where counts will be read
# %DT%ctrl-ident: %DD%ident given in previous k2701setup
# %DT%ch: %DD%channel in controller for this counter
# %DT%readtype: %DD%one of the following:
# %DT% %DD%
# TEMP:PT100,
# TEMP:K,
# CURR:AC,
# CURR:DC,
# VOLT:AC,
# VOLT:DC,
# RES,
# FREQ,
#%XDL%
def k2701add '{
if ($#!=4) {
print "$0 <mne> <ctrl-ident> <ch> <readtype>"
exit
}
cntnum = cnt_num("$1")
K2701CHANS["$1"] = cntnum
K2701PAR["$1"]["ctrl"] = "$2"
K2701PAR["$1"]["channel"] = int($3)
K2701PAR["$1"]["readtype"] = "$4"
K2701PAR["$1"]["enable"] = 1
setup_tail("k2701_","$1")
}'
#%IU%
#%MDESC%
# Performs clean up on unsetup (take away k2701add from setup)
def k2701_unsetup '{
local mne
mne = "$1"
cdef("","",mne,"delete")
for (ky in K2701PAR[mne]) {
delete K2701PAR[mne][ky]
}
delete K2701CHANS[mne]
}'
#%IU%
#%MDESC%
# Performs clean up on ctrl unsetup (take away k2701setup from setup)
def k2701_ctrlunsetup '{
local ctrl
ctrl = "$1"
split(K2701CTRLPAR[ctrl]["chans"], chans, ",")
cdef("","",ctrl,"delete")
for (chan in chans) {
mne = chans[chan]
K2701PAR[mne]["enable"] = 0
}
for (ky in K2701CTRLPAR[ctrl]) {
delete K2701CTRLPAR[ctrl][ky]
}
delete K2701CTRL[mne]
}'
#%UU%
#%MDESC%
# Initializes controllers. Includes a reset after configuration
def k2701init '{
local mnes mne mneno ctrl
local nb_use_chan nb_total_chan
# fill up lists of channels per controller
k2701channels
for (ctrl in K2701CTRL) {
nb_total_chan = split( K2701CTRLPAR[ctrl]["chans"], mnes, ",")
if (nb_total_chan == 0 ) {
print "No channel defined for controller " ctrl
continue
}
nb_use_chan = 0
for (mneno in mnes) {
mne = mnes[mneno]
if ( K2701PAR[mne]["enable"] ) {
nb_use_chan += 1
}
}
if (nb_use_chan != 0) {
k2701_resetctrl( ctrl )
}
for (mneno in mnes) {
local cdefstr
mne = mnes[mneno]
k2701_confchan( mne )
cdefstr = sprintf("k2701_chget %s\n",mne)
cdef("user_getcounts",cdefstr,mne,0x2)
}
if (nb_use_chan != 0) {
k2701_confctrl( ctrl )
cdef("user_getcounts",sprintf("k2701_ctrlget %s\n",ctrl),ctrl,0x10)
}
}
}'
#%IU%
#%MDESC%
def k2701channels '{
local ctrls ctrl mne
for (ctrl in K2701CTRL) {
K2701CTRLPAR[ctrl]["chans"] = ""
}
for (mne in K2701CHANS) {
ctrl = K2701PAR[mne]["ctrl"]
if ( whatis( sprintf("K2701CTRLPAR[\'%s\'][\'chans\'", ctrl)) == 0 ) {
sprintf("Wrong K2701 controller (%s) for counter %s. Disabled\n", ctrl, mne)
K2701PAR[mne]["enable"] = 0
continue
}
if (K2701CTRLPAR[ctrl]["chans"] == "") {
K2701CTRLPAR[ctrl]["chans"] = mne
} else {
K2701CTRLPAR[ctrl]["chans"] = K2701CTRLPAR[ctrl]["chans"] "," mne
}
}
}'
#%IU%
def k2701_resetctrl( ctrl ) '{
local nbchan chlist
_k2701_reset(ctrl)
}'
#%IU%
def k2701_confctrl( ctrl ) '{
local nbchan chlist allchan chno
nbchan = split( K2701CTRLPAR[ctrl]["chans"], allchan, ",")
_k2701_trig(ctrl, nbchan)
_k2701_form(ctrl)
chlist = ""
for (chno=0;chno<nbchan;chno++) {
chan = K2701PAR[ allchan[chno] ]["channel"]
if (chlist == "") {
chlist = chan
} else {
chlist = chlist "," chan
}
}
_k2701_route(ctrl, chlist)
}'
#%IU%
def k2701_confchan( mne ) '{
local readtype channel ctrl
ctrl = K2701PAR[mne]["ctrl"]
readtype = K2701PAR[mne]["readtype"]
channel = K2701PAR[mne]["channel"]
if (readtype == "TEMP_PT100") {
_k2701_config_pt100(ctrl, channel)
} else if (readtype == "TEMP_K") {
_k2701_config_tc(ctrl, channel, "K")
} else if (readtype == "VOLTAC") {
_k2701_config_voltac(ctrl, channel)
} else if (readtype == "VOLTDC") {
_k2701_config_voltdc(ctrl, channel)
} else if (readtype == "CURRAC") {
_k2701_config_currac(ctrl, channel)
} else if (readtype == "CURRDC") {
_k2701_config_currdc(ctrl, channel)
} else if (readtype == "RES") {
_k2701_config_res(ctrl, channel)
} else if (readtype == "FREQ") {
_k2701_config_freq(ctrl, channel)
} else {
print "Unkown readtype for k2701 channel. Disabled"
K2701PAR[mne]["enable"] = 0
}
}'
#%UU%
#%MDESC%
# Not implemented yet
def k2701show '{
# Show current config
}'
#%IU%
#%MDESC% resets a controller
def _k2701_reset(ctrl) '{
k2701send( ctrl, "*RST; *CLS; :ABORT; INIT:CONT OFF;")
}'
#%IU%
#%MDESC% gets a small improvement in speed
def _k2701_speed(ctrl) '{
k2701send( ctrl, ":DISP:ENAB OFF;:SYST:AZER:STAT OFF")
}'
#%IU%
#%MDESC%
def _k2701_config_voltdc(ctrl,chlist) '{
k2701send( ctrl, sprintf("FUNC \'VOLT:DC\', (@%s)", chlist))
}'
#%IU%
#%MDESC%
def _k2701_config_voltac(ctrl,chlist) '{
k2701send( ctrl, sprintf("FUNC \'VOLT:AC\', (@%s)", chlist))
}'
#%IU%
#%MDESC%
def _k2701_config_currdc(ctrl,chlist) '{
k2701send( ctrl, sprintf("FUNC \'CURR:DC\', (@%s)", chlist))
}'
#%IU%
#%MDESC%
def _k2701_config_currac(ctrl,chlist) '{
k2701send( ctrl, sprintf("FUNC \'CURR:AC\', (@%s)", chlist))
}'
#%IU%
#%MDESC%
def _k2701_config_res(ctrl,chlist) '{
k2701send( ctrl, sprintf("FUNC \'RES\', (@%s)", chlist))
}'
#%IU%
#%MDESC%
def _k2701_config_freq(ctrl,chlist) '{
k2701send( ctrl, sprintf("FUNC \'FREQ\', (@%s)", chlist))
}'
#%IU%
#%MDESC%
def _k2701_config_tc(ctrl,chlist,tc_type) '{
kcmds["0"] = sprintf("FUNC \'TEMP\', (@%s)", chlist)
kcmds["1"] = sprintf("UNIT:TEMP C,(@%s)", chlist)
kcmds["2"] = sprintf("SENS:TEMP:TRAN TC,(@%s)", chlist)
kcmds["3"] = sprintf("SENS:TEMP:TC:TYPE %s,(@%s)", tc_type, chlist)
# kcmds["4"] = sprintf("SENS:TEMP:NPLC 1,(@%s)", chlist)
k2701send( ctrl, kcmds,4 )
}'
#%IU%
#%MDESC%
def _k2701_config_pt100(ctrl,chlist) '{
local kcmds
kcmds["0"] = sprintf("FUNC \'TEMP\', (@%s)", chlist)
kcmds["1"] = sprintf("UNIT:TEMP C,(@%s)", chlist)
kcmds["2"] = sprintf("SENS:TEMP:TRAN FRTD,(@%s)", chlist)
kcmds["3"] = sprintf("SENS:TEMP:FRTD:TYPE PT100, (@%s)", chlist)
kcmds["4"] = sprintf("SENS:TEMP:NPLC 1,(@%s)", chlist)
k2701send( ctrl, kcmds,5 )
}'
#%IU%
#%MDESC%
def _k2701_trig(ctrl, nbchan) '{
local kcmds
kcmds["0"] = "TRIG:COUN 1"
kcmds["1"] = sprintf("SAMP:COUN %d", nbchan)
kcmds["2"] = "TRIG:SOUR IMM"
kcmds["3"] = "TRIG:DEL 0.100"
k2701send( ctrl, kcmds , 4)
}'
#%IU%
#%MDESC%
def _k2701_form(ctrl) '{
k2701send( ctrl,"FORM:ELEM CHAN,READ,UNIT")
}'
#%IU%
#%MDESC%
def _k2701_routopen(ctrl,chlist) '{
k2701send( ctrl,"ROUT:OPEN:ALL")
}'
#%IU%
#%MDESC%
def _k2701_route(ctrl,chlist) '{
local kcmds
kcmds["0"] = sprintf("ROUT:SCAN (@%s)", chlist )
kcmds["1"] = "ROUT:SCAN:TSO IMM"
kcmds["2"] = "ROUT:SCAN:LSEL INT"
k2701send( ctrl, kcmds, 3 )
}'
#%IU%
#%MDESC%
def k2701_ctrlget '{
local allans
ctrl = "$1"
unglobal K2701READ
global K2701READ
# -- slower version --
# allans = k2701read( ctrl, "READ?")
allans = k2701read( ctrl, "INIT;FETCH?")
# If we sent k2701 at init time we should get readings in the form value, chan, value, chan...
nb_fields = split( allans, fields, ",")
if (nb_fields == 0) {
tty_cntl("md")
printf("No reading from k2701 controller\n")
printf(" - whole line from controller is: %s\n", allans)
tty_cntl("me")
}
for ( nf = 0; nf < nb_fields; nf+=2) {
nn = sscanf( fields[nf+1], "%d", chnum )
# clean spurious minus sign at beginning of string
cleanval = k2701_cleanminus( fields[nf] )
nv = sscanf( cleanval, "%f", chval )
if (nn == 0 || nv == 0) {
printf("unknown reading from k2701 (value=%s) (chan=%s)\n", fields[nf], fields[nf+1])
printf("Whole line from controller is: %s\n", allans)
} else {
K2701READ[ctrl][chnum] = chval
}
}
}'
#%IU%
def k2701_chget '{
local mne ctrl chan ctval
# reading is done with k2701_ctrlget.. assign to counters
mne = cnt_mne($1)
ctrl = K2701PAR[mne]["ctrl"]
chan = K2701PAR[mne]["channel"]
if ( K2701READ[ctrl][chan] == 0) {
K2701READ[ctrl][chan] = K2701_NO_READ
}
ctval = K2701READ[ctrl][chan]
S[$1] = ctval
}'
#%IU%
#%MDESC%
# Sends one or several commands. No answer expected
def k2701send( ctrl, kcmds, nbcmds ) '{
local socktype sockdev
socktype = K2701CTRLPAR[ctrl]["socket"]
sockdev = K2701CTRLPAR[ctrl]["dev"]
if (nbcmds == 0 || nbcmds == "") {
_k2701_write( kcmds, sockdev, socktype )
} else {
for(ii=0;ii<nbcmds;ii++) {
_k2701_write( kcmds[ii], sockdev, socktype )
}
}
}'
#%IU%
#%MDESC%
# Sends one command. Returns answer
def k2701read(ctrl, cmd) '{
local socktype sockdev
socktype = K2701CTRLPAR[ctrl]["socket"]
sockdev = K2701CTRLPAR[ctrl]["dev"]
return _k2701_read(cmd, sockdev, socktype)
}'
#%IU%
#%MDESC%
# Sends one command through socket. No answer expected
def _k2701_write( cmd, sockdev, socktype ) '{
cmd = sprintf("%s\r\n",cmd)
if ( socktype == "socket") {
sock_put( sockdev, cmd )
} else if ( socktype == "tango") {
esrf_io(sprintf("tango:%s", sockdev), "Write", cmd)
}
}'
#%IU%
#%MDESC%
# Sends one command through selected socket. Returns answer
def _k2701_read( cmd , sockdev, socktype) '{
if (socktype == "") socktype = "socket"
cmd = sprintf("%s\r\n",cmd)
if ( socktype == "socket") {
sock_put( sockdev, cmd )
return sock_get( sockdev )
} else if ( socktype == "tango") {
return esrf_io(sprintf("tango:%s", sockdev), "Writeread", cmd)
}
}'
#%IU%
#%MDESC%
# Clean spurious minus sign at the beginning of response string
def k2701_cleanminus( instr ) '{
local outstr
outstr = instr
while (1) {
minidx = index( outstr, "-")
if (minidx == 1) {
# is there a second one?
if ( index( substr(outstr,2) , "-") == 1) { # yes
outstr = substr(outstr,2)
} else { # no. thats it
return outstr
}
} else { # no minus sign
return outstr
}
}
}'
#%MACROS%
#%IMACROS%
#%TOC%
#%AUTHOR% V.Rey BLISS/ESRF (2008)
|