#%TITLE% WAGOCORE.MAC
#%NAME%
# WAGOCORE.MAC - Basic macros and utilities for Wago I/O stations
#
#%OVERVIEW%
# This macro set provides basic functionality and utilities to access
# Wago I/O stations through the device server class Wagods. %BR%
# It also provides a simple way to declare I/O channels as %B%spec%B%
# pseudomotors or pseudocounters.
#
# %BR%
# %BR%
#
#%EXAMPLE%
# %DL%
# %DT%wagosetup wcid33a wcid33d
# %DD%Declares the Wago I/O stations named wcid33a and wcid33d as being
# accessible through this macro set.
# %DT%wagoshow
# %DD%Displays the currently declared Wago stations
# %DT%wread .
# %DD%Reads and prints the values of all the channels currently declared.
# %DT%wread temp[2:4] mirrordac
# %DD%Reads and prints the values of temp[2:4] (3 channels) and mirrordac.
# %DT%wwrite phscreen 1
# %DD%Writes 1 into the output channel phscreen
# %DT%wwrite dac[3,0] 4.6 2.1
# %DD%Writes the value 4.6 in the output channel dac[3] and 2.1 in dac[0].
# %DT%print wago_readch("phscreen")
# %DD%prints the value of the channel phscreen
# %DT%wago_writech("phscreen", 0)
# %DD%Writes 0 into the output channel phscreen
# %DT%wagopseudosetup cnt1 temp[3] cnt2 mirroradc mot3 mirrordac
# %DD%Configures the spec counters cnt1 and cnt2 to be loaded with the Wago
# channels temp[3] and mirroradc, and mot3 is configured as a pseudocounter
# that drives the Wago output mirrordac.
# %XDL%
#
#%DEPENDENCIES%
#
#=============================================================
#=============================================================
# 2018/05/03 - rh
# __wagopseudocheck: included double check of mnemonic to solve
# the issue associated to the new spec version (eval inside
# cnt_num() and motor_num()
#=============================================================
#=============================================================
jtdo("stlist")
#%UU% <wagoname1> [<wagoname2> [...]]
#%MDESC%
# Declares new Wago I/O stations. The corresponding device server(s) must
# be running and the device names be in conformity with the BLISS convention
# (<blname>/<wagoname>/wc).
# %BR%
# All the logical names declared to the device server become accesible through
# this macro set.
# %BR%
# This line must be included in the %B%spec%B% setup file.%BR%
#
def wagosetup '{
local retval
if (retval = _dowagosetup("$*")) {
if (SETUP) print "Error in line: $0 $*"
if (retval < 0) {
print "Usage: $0 wagoname1 [wagoname2 [ ...]]"
if (yesno("\nDisplay online help", 0)) eval("help local wagocore")
}
}
}'
def _dowagosetup(args) '{
global WAGO[] WAGOKEYS[] WAGOPLC[]
local dev ndev devlist[] gooddevs
ndev = split(args, devlist)
if (!ndev) {
if (whatis("_wagosetup") != 0) {
print "WARNING: You are probably using deprecated macros."
print " Check the \'wagocore\' help."
print
}
return(-1)
}
wago__plcinit()
list_test WAGO
gooddev = ""
for (dev in devlist) {
if (_wagoadd(devlist[dev]) == 0)
setup_tail("wago", devlist[dev])
}
return(0)
}'
def wagounsetup '{
local dev ndev devlist[] gooddev
dev = "$1"
_wagoremove(dev)
if (list_n(WAGO) == 0) {
unglobal WAGO WAGOKEYS WAGOPLC
}
}'
#%UU% {<mne> <wagoch>} ...
#%MDESC%
# Declares channels in Wago I/O stations as %B%spec%B% pseudomotors or
# pseudocounters.
# If <mne> is a %B%spec%B% mnemonic and <wagoch> a valid single-channel
# wago name, the channel gets configured as a pseudomotor or pseudocounter
# depending on the type of mnemonic.%BR%
# Pseudomotors only can be assigned to output channels. Pseudocounters can
# be assigned to either input or output channels.%BR%
# In the case of pseudocounters, the scale factor in the config file is applied.%BR%
#
def wagopseudosetup '{
global WAGOPS[] WAGOPSCHAN[]
local parlist[] npars i
local warr[]
local error
if (SETUP && (SETUP_N != WAGOPS["setup_n"])) {
unglobal WAGOPS WAGOPSCHAN
global WAGOPS WAGOPSCHAN
WAGOPS["setup_n"] = SETUP_N
}
if ((npars = split("$*", parlist)) && !(npars % 2)) {
for (i = 0; i < npars; i += 2) {
if (!__wagopseudocheck(parlist[i], parlist[i + 1], warr))
error = 1
}
} else
error = 1
if (error) {
print "Usage: $0 {<mne> <wagoch>} ..."
} else {
local wname macro cdefkey
n = list_n(warr)
for (i = 1; i <= n; i++) {
wname = warr[i]
if (!list_check(WAGOPS, wname)) {
list_add(WAGOPS, wname)
WAGOPS[wname]["ds"] = warr[wname]["ds"]
WAGOPS[wname]["key"] = warr[wname]["key"]
}
cdefkey = sprintf("wago_%s", wname)
if ("counters" in warr[wname]) {
if ("counters" in WAGOPS[wname])
WAGOPS[wname]["counters"] = \
WAGOPS[wname]["counters"] " " warr[wname]["counters"]
else
WAGOPS[wname]["counters"] = warr[wname]["counters"]
macro = sprintf("wago_getcounts(\"%s\", \"%s\", \"%s\", %d, \"%s\")\n", \
WAGOPS[wname]["counters"], warr[wname]["type"], warr[wname]["ds"], warr[wname]["key"], wname)
cdef("user_getcounts", macro, cdefkey)
setup_tail("wagocounter", wname)
}
if ("motors" in warr[wname]) {
if ("motors" in WAGOPS[wname])
WAGOPS[wname]["motors"] = \
WAGOPS[wname]["motors"] " " warr[wname]["motors"]
else
WAGOPS[wname]["motors"] = warr[wname]["motors"]
macro = sprintf("wago_move(\"%s\", \"%s\", \"%s\", %d, \"%s\")\n", \
WAGOPS[wname]["motors"], warr[wname]["type"], warr[wname]["ds"], warr[wname]["key"], wname)
cdef("user_checkall", macro, cdefkey)
macro = sprintf("wago_getangles(\"%s\", \"%s\", \"%s\", %d, \"%s\")\n", \
WAGOPS[wname]["motors"], warr[wname]["type"], warr[wname]["ds"], warr[wname]["key"], wname)
cdef("user_getpangles", macro, cdefkey)
setup_tail("wagomotor", wname)
}
}
}
}'
def __wagopseudocheck(mne, wchan, warr) '{
local charr[] wname iscntr typestr _num _mne
if (mne in WAGOPSCHAN) {
print "Mnemonic \`" mne "\' is already configured."
return(0)
}
typestr = ""
_num = cnt_num(mne)
if ((_num >= 0) && (mne == cnt_mne(_num))){
typestr = "counters"
}
if(typestr == "") {
_num = motor_num(mne)
if ((_num >= 0) && (mne == motor_mne(_num))){
typestr = "motors"
}
}
if(typestr == "") {
print "\`" mne "\' is not a valid mnemonic."
return(0)
}
if (wago__chanrange(wchan, charr) != 1) {
print "Bad Wago channel identifier: \`" wchan "\'"
return(0)
}
wname = charr["name"]
if (!list_check(warr, wname)) {
list_add(warr, wname)
warr[wname]["ds"] = charr["ds"]
warr[wname]["key"] = charr["key"]
warr[wname]["type"] = charr["type"]
}
if (typestr in warr[wname])
warr[wname][typestr] = warr[wname][typestr] " " mne
else
warr[wname][typestr] = mne
WAGOPSCHAN[mne] = charr[0]
return(1)
}'
def wago_move(motors, wtp, wds, wkey, wname) '{
local vals[] motlist[]
local i j motmne motnum
local scale val
split(motors, motlist)
vals[0] = wkey
j = 1
for (i in motlist) {
motmne = motlist[i]
motnum = motor_num(motmne)
if (motnum >= 0 && !motor_par(motnum, "disable")) {
vals[j++] = WAGOPSCHAN[motmne]
val = A[motnum]
scale = motor_par(motnum, "scale")
if(scale > 0) {
val *= scale
}
vals[j++] = val
}
}
if(j > 1) {
if (wago_io(wtp, wds, "DevWritePhys", vals) < 0) {
printf("Error writing Wago logical device \'%s\'.\n", wname)
}
}
}'
def wago_getangles(motors, wtp, wds, wkey, wname) '{
local vals[] motlist[]
local i motmne motnum error
local scale val
if (error = (wago_io(wtp, wds, "DevReadNoCachePhys", wkey, vals) < 0)) {
printf("Error reading Wago logical device \'%s\'.\n", wname)
}
split(motors, motlist)
for (i in motlist) {
motmne = motlist[i]
motnum = motor_num(motmne)
if (motnum >= 0) {
if (!error && !motor_par(motnum, "disable")) {
val = vals[WAGOPSCHAN[motmne]]
scale = motor_par(motnum, "scale")
if(scale > 0) {
val /= scale
}
A[motnum] = val
} else {
A[motnum] = 0
}
}
}
}'
def wago_getcounts(counters, wtp, wds, wkey, wname) '{
local vals[] cntlist[]
local i cntmne cntnum error
if (error = (wago_io(wtp, wds, "DevReadNoCachePhys", wkey, vals) < 0)) {
printf("Error reading Wago logical device \'%s\'.\n", wname)
}
split(counters, cntlist)
for (i in cntlist) {
cntmne = cntlist[i]
cntnum = cnt_num(cntmne)
if (cntnum >= 0) {
if (!error && !counter_par(cntnum, "disable"))
S[cntnum] = vals[WAGOPSCHAN[cntmne]] / counter_par(cntnum, "scale")
else
S[cntnum] = 0
}
}
}'
def wagomotorunsetup '{
local wname cdefkey
wname = "$1"
cdefkey = sprintf("wago_%s", wname)
cdef("user_getpangles", "", cdefkey, "delete")
cdef("user_checkall", "", cdefkey, "delete")
delete WAGOPS[wname]["motors"]
if (!("counters" in WAGOPS[wname]))
list_remove(WAGOPS, wname)
if (list_n(WAGOPS) <= 0)
unglobal WAGOPS WAGOPSCHAN
}'
def wagocounterunsetup '{
local wname cdefkey
p "UNSETUP!!"
wname = "$1"
cdefkey = sprintf("wago_%s", wname)
cdef("user_getcounts", "", cdefkey, "delete")
if (!("motors" in WAGOPS[wname]))
list_remove(WAGOPS, wname)
if (list_n(WAGOPS) <= 0)
unglobal WAGOPS WAGOPSCHAN
}'
def _wagoremove(wcname) '{
local ds e
if (list_check(WAGO, wcname)>0) {
ds = WAGO[wcname]["ds"]
for (e in WAGOKEYS){
if (WAGOKEYS[e]["ds"] == ds) {
delete WAGOKEYS[e]
delete WAGOKEYS[e]["ds"]
delete WAGOKEYS[e]["nch"]
delete WAGOKEYS[e]["type"]
}
}
list_remove(WAGO, wcname)
}
}'
def _wagoadd(wcname) '{
local i n devlist
local mode ds state id
local typ
if (SETUP && (SETUP_N != WAGO["setup_n"])) {
n = list_n(WAGO)
while (n >= 0) {
list_remove(WAGO, n--)
}
WAGO["setup_n"] = SETUP_N
unglobal WAGOKEYS
global WAGOKEYS
}
if (wcname in WAGO) {
if (SETUP) {
print "Wago I/O station " dev " is already configured."
return(0)
} else {
_wagoremove(wcname)
}
}
ds = SPECBL "/" wcname "/wc"
tp = "TACO"
ESRF_ERR = -1
if (int(state = esrf_io(ds, "DevState")) < 0) {
ds = SPECBL "/" wcname "/tg"
tp = "TANGO"
TANGO_ERR = "-1"
if (int(state = tango_io(ds, "State")) < 0) {
print "Wago device server does not respond: " ds
return(-1)
}
}
# State values depends on the DS type
# with TANGO: ON==0 FAULT==8
# with TACO : ON==2 FAULT==11
if (int(state) != (tp=="TACO"?2:0)) {
print "Wago device " ds ": Wrong device state"
return(-1)
}
if ((devlist = wago__getkeys(ds, tp)) == -1)
return(-1)
list_add(WAGO, wcname)
WAGO[wcname]["ds"] = ds
WAGO[wcname]["type"] = tp
WAGO[wcname]["ldevs"] = devlist
WAGO[wcname]["isgmain"] = wc_getversion(wcname)
return(0)
}'
def wago_io(tp, ds, cmd, argin, argout) '{
local ret
if(tp=="TACO" || tp==0) {
ESRF_ERR=-1
if(whatis("argout") & 0x08000000)
ret = esrf_io( ds, cmd, argin)
else
ret = esrf_io( ds, cmd, argin, argout)
} else if(tp=="TANGO") {
TANGO_ERR="-1"
if(whatis("argout") & 0x08000000)
ret = tango_io(ds, cmd, argin)
else
ret = tango_io(ds, cmd, argin, argout)
} else {
ret = -1
}
return(ret)
}'
def wago__getkeys(ds, tp) '{
local nkeys keys[] name nch i namelist
local dummy[]
local ch[] hw[] j
local idx
if ((nkeys = wago_io(tp, ds, "DevGetKeys", keys)) < 0)
return(-1)
namelist = ""
for (i = 0; i < nkeys; i++) {
if ((name = wago_io(tp, ds, "DevKey2Name", keys[i])) == -1 || \
(nch = wago_io(tp, ds, "DevReadPhys", keys[i], dummy)) < 0)
return(-1)
if (!(name in WAGOKEYS)) {
WAGOKEYS[name] = keys[i]
WAGOKEYS[name]["ds"] = ds
WAGOKEYS[name]["nch"] = nch
WAGOKEYS[name]["type"] = tp
namelist = namelist? (namelist " " name) : name
} else {
print "Duplicated logical name: " name \
"in " WAGOKEYS[name]["ds"] " and " ds
return(-1)
}
# Get hardware information on logical device/channel
for(j = 0; j < nch;j++) {
ch[0] = keys[i]
ch[1] = j
if (wago_io(tp, ds, "DevLog2Hard", ch, hw) < 0)
return(-1)
idx = sprintf("%s[%d]", name, j)
WAGOKEYS[idx]["modbus_addr"] = hw[0] # offset in wago memory
WAGOKEYS[idx]["modbus_type"] = hw[1] # Ex: 0x4957 = ("I"<<8)+"W")
WAGOKEYS[idx]["module_name"] = hw[2] # module reference
WAGOKEYS[idx]["module_num"] = hw[3] # module number, 1st==0
WAGOKEYS[idx]["module_ch"] = hw[4] # channel of the module, 1st==0
WAGOKEYS[name]["module_name"] = hw[2]
}
}
return(namelist)
}'
#%UU%
#%MDESC%
# Lists the currently declared Wago I/O stations and the associated logical
# names.%BR%
#
def wagoshow '{
local wcname
local nwago i ldevs[] lname nch lkey
local nd ndevs
local module_name
nwago = list_n(WAGO)
printf("\n%s Wago I/O station(s) declared\n", nwago? nwago : "No")
if (nwago) {
print "--------------------------------\n"
for (i = 1; i <= nwago; i++) {
wcname = WAGO[i]
ndevs = split(WAGO[wcname]["ldevs"], ldevs)
printf("%-10s - %s logical device(s)\n", wcname, ndevs?ndevs:"No")
for (nd = 0; nd < ndevs; nd++) {
lname = ldevs[nd]
nch = WAGOKEYS[lname]["nch"]
lkey = sprintf("%s%s", lname, (nch > 1)?"[0]":"")
module_name = "750-" WAGOKEYS[lkey]["module_name"]
printf("%5s%s%s %s\n", "", lname, nch? sprintf("(%d)", nch):"", module_name)
}
print
}
}
}'
#%UU%
#%MDESC%
# Prints the status of currently declared Wago I/O stations. Usefull to get
# hardware info about wago box and modules%BR%
#
def wagoinfo '{
local wcname
local nwago i ldevs[] lname nch
local nd ndevs
local module_name
nwago = list_n(WAGO)
printf("\n%s Wago I/O station(s) declared\n", nwago? nwago : "No")
if (nwago) {
for (i = 1; i <= nwago; i++) {
wcname = WAGO[i]
printf( "\n---------------- %s ----------------\n", wcname)
ds = WAGO[wcname]["ds"]
print tango_get(ds, "Status")
}
}
}'
def __wread(chlbl) '{
local nchan charr[] name key ds chname tp
local i nval vals[]
if ((nchan = wago__chanrange(chlbl, charr)) > 0) {
name = charr["name"]
key = charr["key"]
ds = charr["ds"]
tp = charr["type"]
nval = wago_io(tp, ds,"DevReadNoCachePhys", key, vals)
if (nval > 0) {
for(i = 0; i < nchan; i++) {
if(WAGOKEYS[name]["nch"] == 1)
chname = name
else
chname = sprintf("%s[%d]", name, charr[i])
printf("%15s - %.10g\n", chname, vals[charr[i]])
}
} else
print "ERROR"
}
}'
#%UU% <logname1> [<logname2> [...]]
#%MDESC%
# Reads the current values of the Wago channels corresponding to the logical
# names in the parameter list.
# The logical names accept subarray syntax.
# A single dot character ('.') represents all the available channels.%BR%
#
def wread '{
local rlist[] nlist nchan
if (!(nlist = split("$*", rlist))) {
print "Usage: $0 <name> <name> ..."
print " $0 ."
exit
}
for (i = 0; i < nlist; i++){
if (rlist[i] == ".") {
for (dev in WAGOKEYS) {
if (WAGOKEYS[dev]["nch"] > 0)
__wread(dev)
}
} else
__wread(rlist[i])
}
}'
#%UU% <logname> <value1> <value2> [...]
#%MDESC%
# Writes the channels corresponding to the logical name <logname>.
# The logical name accepts subarray syntax and must only include output
# channels.
# One must specify values for all the channels.%BR%
#
def wwrite '{
local npar nchan name plist[] charr[] vals[]
npar = split("$*", plist) - 1
if (npar <= 0) {
print "Usage: $0 <name> val0 val1 val2 ... valN"
exit
}
if ((nchan = wago__chanrange(plist[0], charr)) <= 0) {
exit
}
if (npar != nchan) {
print "Wrong number of values to write in " charr["rname"] ": " \
npar " instead of " nchan
exit
}
vals[0] = charr["key"]
for (i = 1; i <= nchan; i++) {
vals[2 * i - 1] = charr[i - 1]
vals[2 * i] = plist[i] + 0
}
wago_io(charr["type"], charr["ds"], "DevWritePhys", vals)
}'
#%UU% (<chid> [, <out_array>])
#%MDESC%
# This macro function reads the current values of the Wago channels
# identified by <chid>.
# <chid> can be either a string or an associative array. %BR%
# In the case of a string, <chid> must be a Wago logic name with optional
# subarray syntax (i.e. "temp[1,4]"). %BR%
# If <chid> is an array, the elements chid[0], ..., chid[n] must contain
# strings with the corresponding logical names of the n channels to read.
# If a logical name is associated to several the physical channels, the
# channel index within the logical name must be specified in chid[i]["ch"].
# %BR%
# If <chid> is a string and refers to only one channel, the function
# returns the corresponding value.
# If <chid> is an associative array or a string that refers to more than
# one channel, the function returns the number of channels actually read
# into the output array <out_arr> that is mandatory in that case.
# If there is an error, the function returns an emty string ("").
# %BR%
def wago_readch(chid, retval) '{
local whischid nch ds key all i tp
local name prevname chan
local chinfo[] vals[]
whischid = whatis("chid")
if (whischid & 0x00200000) {
if (chid in WAGOKEYS) {
nch = WAGOKEYS[chid]["nch"]
key = WAGOKEYS[chid]
ds = WAGOKEYS[chid]["ds"]
tp = WAGOKEYS[chid]["type"]
all = 1
} else {
if ((nch = wago__chanrange(chid, chinfo)) <= 0){
return("")
}
ds = chinfo["ds"]
tp = chinfo["type"]
key = chinfo["key"]
}
if (wago_io(tp, ds, "DevReadNoCachePhys", key, vals) < 0)
return("")
if (nch == 1)
return(vals[all? 0 : chinfo[0]])
if (whatis("retval") & 0x01010000) {
for (i = 0; i < nch; i++)
retval[i] = vals[all? i : chinfo[i]]
return(nch)
} else {
print " Missing or wrong output array."
return("")
}
} else if (whischid & 0x01000000){
if (!(whatis("retval") & 0x01010000)) {
print " Missing or wrong output array."
return("")
}
i = 0
while(i in chid) {
name = chid[i]
if (name == "" || name != prevname) {
if (!(name in WAGOKEYS)) {
print " Bad Wago logic name: \'" name "\'."
return("")
}
nch = WAGOKEYS[name]["nch"]
key = WAGOKEYS[name]
ds = WAGOKEYS[name]["ds"]
tp = WAGOKEYS[name]["type"]
if (wago_io(tp, ds, "DevReadNoCachePhys", key, vals) < 0)
return("")
prevname = name
}
if ("ch" in chid[i]) {
chan = chid[i]["ch"]
if (chan < 0 || chan >= nch) {
print " Wago channels out of bounds: \'" name "[" chan "]\'."
return("")
}
} else {
if (nch != 1) {
print " Wago channel index missing for logic name: \'" name "\'."
return("")
}
chan = 0
}
retval[i] = vals[chan]
i++
}
if (i == 0) {
print " Missing or bad input channel list."
return("")
}
return(i)
} else {
print " Bad Wago channel(s) identifier."
return("")
}
}'
#%UU% (<chid>, <data>])
#%MDESC%
# This macro function writes into the output Wago channels identified
# by <chid>.
# <chid> can be either a string or an associative array.%BR%
# In the case of a string, <chid> must be a Wago logic name with optional
# subarray syntax (i.e. "dac[1,4]").
# %BR%
# If <chid> is an array, the elements chid[0], ..., chid[n] must contain
# strings with the corresponding logical names of the n output channels
# to write.
# If a logical name is associated to several physical channels, the channel
# index within the logical name must be specified in chid[i]["ch"].
# %BR%
# If <chid> is a string and refers to a single output channel, the parameter
# <data> can be a simple numerical value. Otherwise <data> must be an array
# containing all the values to be written.
# The function returns the number of channels written if it completes
# succesfully. It returns 0 if there is an error in the channel
# specification or in the data format, and -1 if the error happens in the
# access to the device server.
# %BR%
def wago_writech(chid, data) '{
local whischid nch ds i j chan tp
local name prevname
local chinfo[] vals[]
whischid = whatis("chid")
if (whischid & 0x00200000) {
if (chid in WAGOKEYS) {
nch = WAGOKEYS[chid]["nch"]
vals[0] = WAGOKEYS[chid]
ds = WAGOKEYS[chid]["ds"]
tp = WAGOKEYS[chid]["type"]
for (i = 0; i < nch; i++)
vals[2 * i + 1] = i
} else {
if ((nch = wago__chanrange(chid, chinfo)) <= 0){
return(0)
}
ds = chinfo["ds"]
tp = chinfo["type"]
vals[0] = chinfo["key"]
for (i = 0; i < nch; i++)
vals[2 * i + 1] = chinfo[i]
}
if (whatis("data") & 0x09010000) {
for (i = 0; i < nch; i++)
vals[2 * (i + 1)] = data[i]
} else {
if (nch > 1) {
print " Missing data array."
return(0)
}
vals[2] = data
}
if (wago_io(tp, ds, "DevWritePhys", vals) < 0)
return(-1)
else
return(nch)
} else if (whischid & 0x01000000){
i = 0
prevname = ""
while(i in chid) {
name = chid[i]
if (name == "" || name != prevname) {
if (!(name in WAGOKEYS)) {
print " Bad Wago logic name: \'" name "\'."
return(0)
}
if (prevname != "") {
local e
if (wago_io(tp, ds, "DevWritePhys", vals) < 0)
return(-1)
for (e in vals) delete vals[e]
}
nch = WAGOKEYS[name]["nch"]
vals[0] = WAGOKEYS[name]
ds = WAGOKEYS[name]["ds"]
tp = WAGOKEYS[name]["type"]
j = 1
prevname = name
}
if ("ch" in chid[i]) {
chan = chid[i]["ch"]
if (chan < 0 || chan >= nch) {
print " Wago channels out of bounds: \'" name "[" chan "]\'."
return(0)
}
vals[j] = chan
} else {
if (nch != 1) {
print " Wago channel index missing for logic name: \'" name "\'."
return(0)
}
vals[j] = 0
}
vals[j + 1] = data[i]
j += 2
i++
}
if (i == 0) {
print " Missing or bad input channel list."
return(0)
}
if (wago_io(tp, ds, "DevWritePhys", vals) < 0)
return(-1)
else
return(i)
} else {
print " Bad Wago channel(s) identifier."
return(0)
}
}'
# taken from /segfs/dserver/include/BlcDsNumbers.h
constant WAGODS_BASE ((5<<26)+(47<<18))
def wago__plcinit() '{
global WAGOPLC[]
WAGOPLC["#addr0"] = 256
WAGOPLC["#max_par"] = 32
WAGOPLC["#max_res"] = 32
WAGOPLC["#err"]["base"] = WAGODS_BASE + 19
WAGOPLC["#err"][1] = "Communication timeout"
WAGOPLC["#err"][2] = "Bad command"
WAGOPLC["#err"][3] = "Bad parameter(s)"
WAGOPLC["#err"][4] = "Bad instance number"
WAGOPLC["#err"][5] = "Instance is not enabled"
WAGOPLC["#err"][6] = "No more instances available"
WAGOPLC["#err"][7] = "Bad Function"
WAGOPLC["#err"][8] = "Bad channel"
WAGOPLC["#err"][9] = "No more channels available"
WAGOPLC["NAME"] = 0x0001
WAGOPLC["ACTIVE"] = 0x0002
WAGOPLC["RESET"] = 0x0003
WAGOPLC["VERSION"] = 0x0004
WAGOPLC["#func"]["INTERLOCK"] = 0x0100
WAGOPLC["ILCK_CREATE"] = 0x0101
WAGOPLC["ILCK_DELETE"] = 0x0102
WAGOPLC["ILCK_ADDCHAN"] = 0x0103
WAGOPLC["ILCK_DELCHAN"] = 0x0104
WAGOPLC["ILCK_GETCONF"] = 0x0105
WAGOPLC["ILCK_SETNAME"] = 0x0106
WAGOPLC["ILCK_GETNAME"] = 0x0107
WAGOPLC["ILCK_GETSTAT"] = 0x0108
WAGOPLC["ILCK_SETFLGS"] = 0x0109
WAGOPLC["ILCK_CLRFLGS"] = 0x010A
WAGOPLC["ILCK_SETTHR"] = 0x010B
WAGOPLC["ILCK_RESET"] = 0x010C
}'
#%UU%
#%MDESC%
#
def wc_comm '{
local i comm npar par[] station
local nres res[]
if ($# < 2) {
print "Usage: $0 <station> <command> <p0> [<p1> <p2> ...]"
exit
}
station = "$1"
npar = $# - 2
par[0] = "$3"
par[1] = "$4"
par[2] = "$5"
par[3] = "$6"
par[4] = "$7"
par[5] = "$8"
if ((nres = wc_sendcomm(station, "$2", npar, par, res)) < 0) {
exit
} else if (!nres) {
if (!silent)
print "OK."
} else {
if (!silent) {
printf("OK. : ")
for (i = 0; i < nres; i++)
printf(" 0x%04X", res[i] & 0xFFFF)
print
}
}
}'
#UU (<wcname>, <command>, <npar>, <par> [, <silent>])
#%MDESC%
#
def wc_getstring(device, comm, npar, par, silent) '{
local nres i c str d
local short array res[WAGOPLC["#max_par"]]
nres = wc_sendcomm(device, comm, npar, par, res, silent)
if (nres < 0)
return(-1)
str = ""
for (i = 0; i < nres; i++) {
if (!(c = sprintf("%c", res[i] >> 8)))
return(str)
str = str c
if (!(c = sprintf("%c", res[i] & 0xFF)))
return(str)
str = str c
}
return(str)
}'
#%UU% (<wcname>, <command>, <npar>, <par>, <res> [, <silent>])
#%MDESC%
#
def wc_sendcomm(device, comm, npar, par, res, silent) '{
local wname i ass_wcd[]
local nres nerr
local lastpar npar_org
if ((wname = list_item(WAGO, device)) < 0) {
if (!silent)
print " Undeclared Wago I/O station: " device
return(-.1)
}
if (int(comm) != comm){
if (comm in WAGOPLC)
comm = WAGOPLC[comm]
else {
if (!silent)
print " Unknown Wago PLC command: " comm
return(-.1)
}
}
ass_wcd[0] = comm
# can not use par because its dimension is passed by spec to esrf_io()
npar_org = npar
for (i = 1, npar = 1; i <= npar_org; i++) {
lastpar = par[i - 1]
# check if a parameter is string
if (int(lastpar) == lastpar) {
ass_wcd[npar++] = int(lastpar)
} else {
local slen c j
slen = length(lastpar)
for (j = 0; j < slen; j += 2) {
c = asc(substr(lastpar, j + 1, 1)) << 8
c |= asc(substr(lastpar, j + 2, 1))
ass_wcd[npar++] = c
}
}
}
# consider commands that have no parameter
if(npar == 0) {
npar = 1
}
local ushort array wcd[npar]
for (i = 0; i < npar; i++)
wcd[i] = ass_wcd[i] & 0xffff
ESRF_ERR = -1
nres = wago_io(WAGO[wname]["type"], WAGO[wname]["ds"], "DevWcComm", wcd, res)
if (nres < 0 && !silent) {
if(WAGO[wcname]["type"] == "TACO") {
nerr = ESRF_ERR - WAGOPLC["#err"]["base"]
printf(" ERROR %d: %s.\n", nerr, WAGOPLC["#err"][nerr])
} else {
nerr = 1
printf(" ERROR : %s.\n", TANGO_ERR)
}
return(-nerr)
}
return(nres)
}'
#%UU% (<wcname>)
#%MDESC%
# Loads and returns the current version of the %B%isgmain%B% program running
# in the controller <wcname>.
# Returns 0 if there is no response.
#
def wc_getversion(wcname) '{
local par[] res[]
if (wc_sendcomm(wcname, "VERSION", 0, par, res, 1) != 1)
return(0)
else
return(res[0])
}'
#%UU% (<logname>, <chlist>)
#%MDESC%
# This macro function parses the logical name in the string <logname> and
# stores the information so obtained in the associative array <chlist>.
# Individual channels or channel ranges within the logical name can be
# specified by using the %B%spec%B% subarray syntax (i.e. "vin[0,4:7]"). %BR%
# If there is an error, the function returns -1, otherwise it returns the
# total number of physical channels n that is also stored in chlist["n"].%BR
# chlist["key"] contains the device server key, and the array elements
# chlist[0] to chlist[n] contain the indexes of the channels.
# Other information available is the device server name in chlist["ds"]
# and the logical name in chlist["name"].
#
def wago__chanrange(rngname, arr) '{
local lname idxrng endstr nch
if (index(rngname, "[")) {
if (sscanf(rngname, " %[^[] [ %[^]] %s", lname, idxrng, endstr) == 1) {
idxrng = ""
sscanf(rngname, " %[^[] [ %s", lname, endstr)
}
if (endstr != "]" || 0) {
print " Wrong Wago channel range syntax: \'" rngname "\'"
return(-1)
}
} else {
sscanf(rngname, " %s", lname)
idxrng = ""
}
if (!(lname in WAGOKEYS)) {
print " Bad Wago logic name: \'" lname "\'"
return(-1)
}
nch = WAGOKEYS[lname]["nch"]
nch = wago__parseindex(idxrng, arr, nch)
if (nch == 0) {
nch = -1
print " Wago channels out of bounds: \'" rngname "\'"
} else if (nch < 0)
print " Wrong Wago subarray syntax: \'" rngname "\'"
arr["n"] = nch
arr["name"] = lname
arr["rname"] = rngname
arr["ds"] = WAGOKEYS[lname]["ds"]
arr["key"] = WAGOKEYS[lname]
arr["type"] = WAGOKEYS[lname]["type"]
return(nch)
}'
def wago__parseindex(str, arr, maxidx) '{
local pos n
n = 0
while(pos = index(str, ",")) {
n = wago__parseindex0(substr(str, 1, pos - 1), arr, n, maxidx)
str = substr(str, pos + 1)
if (n <= 0)
return(n)
}
n = wago__parseindex0(str, arr, n, maxidx)
return(n)
}'
def wago__parseindex0(str, arr, n, maxidx) '{
local pos ch ch1 str1
if (str == "") {
ch = 0
ch1 = maxidx - 1
} else {
if (pos = index(str, ":")) {
str1 = substr(str, pos + 1)
str = substr(str, 1, pos - 1)
}
ch = int(str)
if (str != 0 && str != "" && ch != str)
return(-1)
if (ch < 0) ch = maxidx + ch
if (ch < 0 || ch >= maxidx) return(0)
if (!pos) {
ch1 = ch
} else {
ch1 = int(str1)
if (str1 != 0 && str1 != "" && ch1 != str1)
return(-1)
if (str1 == "") ch1 = maxidx - 1
if (ch1 < 0) ch1 = maxidx + ch1
if (ch1 < 0 || ch1 >= maxidx) return(0)
}
}
while (1) {
arr[n++] = ch
if (ch == ch1)
return(n)
else if (ch < ch1)
ch++
else
ch--
}
}'
def wago__type2code(type) '{return((asc(type) << 8) + asc(substr(type, 2, 1)))}'
def wago__code2type(code) '{return sprintf("%c%c", code >> 8, code & 0x00ff)}'
def wago__hard2log(wcname, channel, type) '{
local short array sqin[2] sqout[2]
local name ds tp
ds = WAGO[wcname]["ds"]
tp = WAGO[wcname]["type"]
sqin[1] = channel
sqin[0] = wago__type2code(type)
if (wago_io(tp, ds, "DevHard2Log", sqin, sqout) != 2) {
print " Warning: can\'t get logical name from \'" wcname "\'."
return(-1)
} else {
name = wago_io(tp, ds, "DevKey2Name", sqout[0])
if (WAGOKEYS[name]["nch"] > 1) {
return(sprintf("%s[%d]", name, sqout[1]))
} else {
return(name)
}
}
}'
def wago__log2hard(chname) '{
local short array sqin[2] sqout[5]
local ds arr[] nch tp
if (int(chname) == chname)
return(chname)
nch = wago__chanrange(chname, arr)
if(nch == 1) {
sqin[0] = arr["key"]
sqin[1] = arr[0]
if (wago_io(arr["type"], arr["ds"],"DevLog2Hard", sqin, sqout) >= 0)
return((sqout[1] << 16) + sqout[0])
} else if (nch > 1)
print " More than one channel in: " chname
return(-1)
}'
def wago__log2scale(chname) '{
local short array sqin[2] sqout[5]
local ds arr[] nch tp
nch = wago__chanrange(chname, arr)
if(nch == 1) {
if(!index(chname, "[")) {
chname = sprintf("%s[0]", chname)
}
if((module = WAGOKEYS[chname]["module_name"])) {
# Default case: 10V over 15bits
scale = 10
# Handle here all exotic modules
if(module == "483")
scale = 30
return(scale / 0x7fff)
}
} else if (nch > 1)
print " More than one channel in: " chname
print " ERROR: missing information on \""chname"\""
print " Hint: run \"wagosetup\""
return(-1)
}'
#%MACROS%
#%SETUP%
#%AUTHOR% M. Perez, P.Fajardo, (Original 3/2005).
# $Revision: 3.6 $ / $Date: 2018/09/24 13:23:31 $
#%TOC%
|