#%TITLE% TFOC.MAC
#
#%NAME%
# TFOC.MAC - Manages the transfocator device through WAGO DAC and I/O
#
#%DESCRIPTION%
#
#%END%
#
constant TFFILE BLISSADM"/local/spec/userconf/tfoc.dat"
constant TFDAC "dac_ch"
constant TFLIM "lim_ch"
constant TFENA "ena_ch"
constant TFLSON 0
constant TFLSOFF 1
constant TFTIMEOUT 40
#%UU% <edit|show|update>
#%MDESC%
# edit : create or modify a configuration%BR%
# show : print current configuration loaded%BR%
# update: load configuration from file%BR%
#
def tfsetup '{
local usage action
if (!$#) {
_tfsetup_usage("$0")
exit
}
action = "$1"
if (action == "show") { _tfsetup_show(); return }
if (action == "new") { _tfsetup_new(); return }
if (action == "edit") { _tfsetup_edit(); return }
if (action == "update") { _tfsetup_read(); return }
_tfsetup_usage("$0")
}'
#%IU%
#%MDESC%
#
def _tfsetup_usage(arg) '{
print
print "Usage : ",arg," <edit|show|update>"
print " edit : create or modify a configuration"
print " show : print current configuration loaded"
print " update: load configuration from file"
}'
#%IU%()
#%MDESC%
#
def _tfsetup_cfgfile() '{
local dirs[]
local n
n = split(TFFILE, dirs, "/")
return(dirs[n-1])
}'
#%IU%()
#%MDESC%
#
def _tfsetup_edit() '{
local fname
fname = _tfsetup_cfgfile()
if (!file_info(TFFILE, "isreg")) {
print "WARNING: configuration file \""fname"\" is missing, creating it"
_tfsetup_new()
}
print "Editing \""fname"\" ... "
unix(sprintf("%s %s", SEDITOR, TFFILE))
_tfsetup_read()
}'
#%IU%()
#%MDESC%
#
def _tfsetup_new() '{
local blabla
if (file_info(TFFILE, "isreg")) {
if (yesno("Configuration file alredy exists. Do you want to delete it",0)) {
unix(sprintf("\\rm -i %s", TFFILE))
}
}
blabla = \
"# Configuration file for Transfocator control through Wago box\n" \
"# A single instance can be declared in this file.\n" \
"#\n" \
"# Syntax: \n" \
"# wagoname <wcidxxx>\n" \
"# vin <+volts>\n" \
"# vout <-volts>\n" \
"# vstop <+volts>\n" \
"# naxes <number>\n" \
"# "TFDAC" <string>\n" \
"# "TFLIM" <string>\n" \
"# "TFENA" <string>\n" \
"#\n" \
"# <actuator1> <desc_text> <N/R>\n" \
"# <actuator2> <desc_text> <N/R>\n" \
"# ....\n" \
"# <actuatorN> <desc_text> <N/R>\n" \
"#\n" \
"# Notes: \n" \
"# <wcidxxx> is the WAGO box hostname\n" \
"# vin is positive voltage to apply to move piezo in beam\n" \
"# vout is negative voltage to apply to move piezo out beam\n" \
"# the higher these values are, the faster the piezo moves\n"\
"# naxes is the number of piezos controlled by the WAGO box\n" \
"# "TFDAC" WAGO logical channel configured for DACs\n" \
"# "TFLIM" WAGO logical channel configured for switches inputs\n" \
"# "TFENA" WAGO logical channel configured for enable ouput\n" \
"# <actuatorN> is the actuator position, from 1 to <naxes>\n" \
"# a position not given is considered as empty\n" \
"# <desc_text> is description text of the actuator, within quotes\n" \
"# <N/R> is the N/R ratio of the actuator, ex: 4/0.2\n" \
"#\n" \
"wagoname wcidxxx\n" \
"vin +8\n" \
"vout -8\n" \
"naxes 20\n" \
TFDAC" xxxx\n" \
TFLIM" xxxx\n" \
TFENA" xxxx\n" \
"\n" \
"#Actuator \"Description Text\" N/R\n" \
"1 \"alignement pinhole\" 0\n" \
"3 \"2D 1 x R=1.5mm\" 1/1.5\n" \
"4 \"2D 1 x R=1.0mm\" 1/1.0\n" \
fprintf(TFFILE, "%s", blabla)
close(TFFILE)
if (!file_info(TFFILE, "isreg")) {
print "ERROR: Can\'t create file: " TFFILE
exit
}
}'
#%IU%()
#%MDESC%
#
def _tfsetup_show() '{
tfshow
}'
#%IU%()
#%MDESC%
#
def _tfsetup_read() '{
global TFMAIN[]
global TFDESC[]
global TFN[]
global TFR[]
local line
local lineraw
local arg
local wcname
local vin
local vout
local vstop
local naxes
local fname
local dac_ch
local lim_ch
local ena_ch
local i
local c
#
# Minimum check on configuration file
#
fname = _tfsetup_cfgfile()
if (!file_info(TFFILE, "isreg")) {
print "ERROR: configuration file \""fname"\" is missing"
print "HINT : use \"fsetup edit\" to create it"
return(-1)
}
#
# Configuration parameters initialization
#
for(i in TFMAIN) { delete TFMAIN[i] }
for(i in TFDESC) { delete TFDESC[i] }
for(i in TFN) { delete TFN[i] }
for(i in TFR) { delete TFR[i] }
wcname = ""
vin = 0
vout = 0
vstop = 0
naxes = 0
dac_ch = ""
lim_ch = ""
ena_ch = ""
#
# Configuration file parsing
#
print "Reading \""fname"\" ..."
getline(TFFILE, "close")
while ((line = getline(TFFILE)) != -1) {
lineraw = ""
sscanf(line, "%[^\n\r]", lineraw)
line = ""
if (sscanf(lineraw, " %[^#]", line) != 1)
continue
sscanf(line, " %s", c)
if (c == "wagoname") {
arg = substr(line,length(c)+1)
sscanf(arg,"%s",wcname)
if(!length(wcname)) {
print "ERROR: missing WAGO box name"
return(-1)
}
} else if (c == "vin") {
arg = substr(line,length(c)+1)
if(!sscanf(arg,"%d",vin)) {
print "ERROR: invalid \""c"\" parameter"
return(-1)
}
} else if (c == "vout") {
arg = substr(line,length(c)+1)
if(!sscanf(arg,"%d",vout)) {
print "ERROR: invalid \""c"\" parameter"
return(-1)
}
} else if (c == "vstop") {
arg = substr(line,length(c)+1)
if(!sscanf(arg,"%d",vstop)) {
print "ERROR: invalid \""c"\" parameter"
return(-1)
}
} else if (c == "naxes") {
arg = substr(line,length(c)+1)
if(!sscanf(arg,"%d",naxes)) {
print "ERROR: invalid \""c"\" parameter"
return(-1)
}
} else if (c == TFDAC) {
arg = substr(line,length(c)+1)
sscanf(arg,"%s",dac_ch)
if(!length(dac_ch)) {
print "ERROR: missing WAGO channel name"
return(-1)
}
} else if (c == TFLIM) {
arg = substr(line,length(c)+1)
sscanf(arg,"%s",lim_ch)
if(!length(lim_ch)) {
print "ERROR: missing WAGO channel name"
return(-1)
}
} else if (c == TFENA) {
arg = substr(line,length(c)+1)
sscanf(arg,"%s",ena_ch)
if(!length(ena_ch)) {
print "ERROR: missing WAGO channel name"
return(-1)
}
} else {
local desc
local nr_str
local beg end
local n r
beg = index(line,"\"")+1
end = index(substr(line,beg),"\"")+beg
sscanf(substr(line,0,beg-1),"%d",i)
desc = substr(line,beg,end-beg-1)
nr_str = substr(line,end+1)
sscanf(nr_str,"%f/%f",n,r)
# TODO: add some checks on values here
TFDESC[i] = desc
TFN[i] = n
TFR[i] = r
}
} # end of while(getline)
#
# Configuraion parameters verification
#
if(!length(wcname)) {
print "ERROR: missing WAGO box name"
print "HINT : add field \"wagoname\" to configuration"
return(-1)
}
if(!(wcname in WAGO)) {
print "ERROR: invalid or unconfigured WAGO box name"
print "HINT : use \"wagosetup\" first"
return(-1)
}
if(vin<=0) {
print "ERROR: invalid voltage for piezo in beam motion"
print "HINT : give a positive value from 0 to +10"
return(-1)
}
if(vout>=0) {
print "ERROR: invalid voltage for piezo out beam motion"
print "HINT : give a positive value from -10 to 0"
return(-1)
}
if(naxes<=0) {
print "ERROR: invalid number of piezos controlled by the WAGO box"
print "HINT : add field \"naxes\" to configuration"
return(-1)
}
if(!length(lim_ch)) {
print "ERROR: missing WAGO channel name \""TFLIM"\""
print "HINT : add field to configuration"
return(-1)
}
if(!length(dac_ch)) {
print "ERROR: missing WAGO channel name \""TFDAC"\""
print "HINT : add field to configuration"
return(-1)
}
if(!length(ena_ch)) {
print "ERROR: missing WAGO channel name \""TFENA"\""
print "HINT : add field to configuration"
return(-1)
}
if(!index(WAGO[wcname]["ldevs"],dac_ch)) {
print "ERROR: invalid WAGO channel name \""dac_ch"\""
print "HINT : check WAGO Devise Server resources"
return(-1)
}
if(!index(WAGO[wcname]["ldevs"],lim_ch)) {
print "ERROR: invalid WAGO channel name \""lim_ch"\""
print "HINT : check WAGO Devise Server resources"
return(-1)
}
if(!index(WAGO[wcname]["ldevs"],ena_ch)) {
print "ERROR: invalid WAGO channel name \""ena_ch"\""
print "HINT : check WAGO Devise Server resources"
return(-1)
}
#
# Store new configuration
#
TFMAIN["wcname"] = wcname
TFMAIN["vin"] = vin
TFMAIN["vout"] = vout
TFMAIN["vstop"] = vstop
TFMAIN["naxes"] = naxes
TFMAIN["dac_ch"] = dac_ch
TFMAIN["lim_ch"] = lim_ch
TFMAIN["ena_ch"] = ena_ch
}'
#%UU% ["all"|"in"|"out"]
#%MDESC%
# Without argument, it shows the position of configured actuators.%BR%
# With "all", it shows even the unconfigured actuators.%BR%
# Finally only the actuationrs "in" the beam or "out" can be displayed.
#
def tfshow '{
local i
local todo
local lim[]
local naxes
local axis
local pos
todo = "min"
if($#>=1) { todo = "$1" }
if((todo!="min") && (todo!="all") && (todo!="in") && (todo!="out")) {
print "Usage : $0 [\"all\"|\"in\"|\"out\"]"
exit
}
# get all limitswitches values
if(_tfgetls(lim) == -1) { exit }
printf("%-15s %-20s %-10s %-3s\n",\
"Actuator", \
"Description", \
"N/R", \
"Pos")
# TODO: add a check on TFMAIN
naxes=TFMAIN["naxes"]
for(i=0;i<naxes;i++) {
axis = i+1
if((todo!="all") && !(axis in TFDESC)) { continue }
pos="???"
if(lim[2*i]==TFLSON && lim[2*i+1]==TFLSOFF) {pos="IN"}
if(lim[2*i]==TFLSOFF && lim[2*i+1]==TFLSON) {pos="OUT"}
if((todo=="in") && (pos!="IN")) { continue }
if((todo=="out") && (pos!="OUT")) { continue }
printf("%-15s %-20s %-10s %-3s\n",\
sprintf("%2d 0x%05x",axis,(1<<i)), \
TFDESC[axis], \
sprintf("%.0f/%.1f",TFN[axis],TFR[axis]), \
pos)
}
}'
#%IU%(array)
#%MDESC%
# Fill the two cells array. The first value is
# a bit pattern value corresponding to the limitswitches values.
# The actuator positive switch is activated, the corresponding bit is set.
# In all other switch value cases (negative on, both on, both off),
# the bit is clear.
# The second value returned is a bit pattern with bit set when the
# corresponding actuator limitswitches are in-coherent (both on, both off)
#
def _tfgetls_pattern(bps) '{
local i
local lim[]
local naxes
local bp
local bp_sta
# get all limitswitches values
_tfgetls(lim)
# TODO: add a check on TFMAIN
naxes=TFMAIN["naxes"]
for(i=0,bp=0,bp_sta=0;i<naxes;i++) {
if(lim[2*i]==TFLSON && lim[2*i+1]==TFLSOFF) { bp |= (1<<i) }
if(lim[2*i]==TFLSON && lim[2*i+1]==TFLSON) { bp_sta |= (1<<i) }
if(lim[2*i]==TFLSOFF && lim[2*i+1]==TFLSOFF) { bp_sta |= (1<<i) }
}
bps[0] = bp
bps[1] = bp_sta
return
}'
#%IU%(array)
#%MDESC%
# Fill the array with all limitswitches values.
# Return the array size or -1 in case or error.
#
def _tfgetls(ls) '{
local n
if(!("lim_ch" in TFMAIN) || !("naxes" in TFMAIN)) {
print "ERROR: bad internal array configuration"
print "HINT : use \"fsetup\" first"
return(-1)
}
n=wago_readch(TFMAIN["lim_ch"], ls)
if(n != TFMAIN["naxes"]*2) {
print "ERROR: bad number of WAGO limitswitches channels"
print "HINT : use \"fsetup\" first"
return(-1)
}
return(n)
}'
#%IU%(array)
#%MDESC%
# Fill the array with all WAGO DACs values.
# Return the array size or -1 in case or error.
#
def _tfgetdacs(dacs) '{
local n
if(!("dac_ch" in TFMAIN) || !("naxes" in TFMAIN)) {
print "ERROR: bad internal array configuration"
print "HINT : use \"fsetup\" first"
return(-1)
}
n=wago_readch(TFMAIN["dac_ch"], dacs)
if(n != TFMAIN["naxes"]) {
print "ERROR: bad number of WAGO DACs channels"
print "HINT : use \"fsetup\" first"
return(-1)
}
return(n)
}'
#%IU%(array)
#%MDESC%
# Write the array of values to all WAGO DACs.
#
def _tfsetdacs(dacs) '{
if(!("dac_ch" in TFMAIN) || !("naxes" in TFMAIN)) {
print "ERROR: bad internal array configuration"
print "HINT : use \"fsetup\" first"
return(-1)
}
wago_writech(TFMAIN["dac_ch"], dacs)
return(0)
}'
#%UU% actuator
#%MDESC%
# Move the specified actuator, numbered from 1, in the beam.
#
def tfin '{
local naxes
local axis
local bps[]
local bp_beg
local bp_sta
if($#!=1) {
print "Usage : $0 actuator"
exit
}
axis = $1
# TODO: add a check on TFMAIN
naxes = TFMAIN["naxes"]
if((axis<1) || (axis>naxes)) {
print "ERROR: invalid actuator, must be within [1:"naxes"]"
exit
}
# get the current state of all actuators
_tfgetls_pattern(bps)
bp_beg = bps[0]
bp_sta = bps[1]
# trigger the motion
_tfset(bp_beg |= (1<<(axis-1)))
}'
#%UU% actuator|"all"
#%MDESC%
# Move the specified actuator, numbered from 1, or "all" the
# actuators out of the beam.
#
def tfout '{
local naxes
local axis
local bps[]
local bp_beg
local bp_sta
if($#!=1) {
print "Usage : $0 actuator|\"all\""
exit
}
# handle the case of all the actuators have to be moved out
if("$1"=="all") {
_tfset(0x00)
return
}
# get the axis number
axis = $1
# TODO: add a check on TFMAIN
naxes = TFMAIN["naxes"]
if((axis<1) || (axis>naxes)) {
print "ERROR: invalid actuator, must be within [1:"naxes"]"
exit
}
# get the current state of all actuators
_tfgetls_pattern(bps)
bp_beg = bps[0]
bp_sta = bps[1]
# trigger the motion
_tfset(bp_beg &= ~(1<<(axis-1)))
}'
#%UU% bit_pattern
#%MDESC%
# Move all the actuators according to the bit pattern passed.
# If the bit is set then the corresponding actuator is moved in the beam.
# If the bit is clear then the actuator is moved out.
# The bit pattern can be passed as "0xNNNN"
#
def tfset '{
local bp
bp = 0
if($#!=1) {
print "Usage : $0 bit_pattern"
exit
}
# get the bit pattern value
if(!sscanf("$1","0x%x",bp)) {
if(!sscanf("$1","%d",bp)) {
print "ERROR: argument must be an integer"
exit
}
}
# trigger the motions
_tfset(bp)
}'
#%UU%
#%MDESC%
# Abort any motion on all actuators
#
def tfabort '{
local dacs[]
local naxes
local i
# TODO: add a check on TFMAIN
naxes = TFMAIN["naxes"]
for(i=0;i<naxes;i++) { dacs[i]=0 }
_tfsetdacs(dacs)
}'
#%IU%(bit_pattern)
#%MDESC%
# Move all the actuators according to the bit pattern passed.
# If the bit is set then the corresponding actuator is moved in the beam.
# If the bit is clear then the actuator is moved out.
# %BR%Return -1 in case of error, 0 otherwise
#
def _tfset(bp_end) '{
local bpm
local dacs[]
local bp_beg
local bp_sta
local bps[]
local tomove
local naxes
local vin
local vout
local vstop
local i
# TODO: add a check on TFMAIN
naxes = TFMAIN["naxes"]
vin = TFMAIN["vin"]
vout = TFMAIN["vout"]
vstop = TFMAIN["vstop"]
# check the bit pattern value
bpm = (1<<naxes)-1
if((bp_end<0) || (bp_end>bpm)) {
print "ERROR: invalid integer, must be within [0:"sprintf("0x%x",bpm)"]"
return(-1)
}
# check if a motion is requested on unconfigured axis
for(i=0;i<naxes;i++) {
if((1<<i) & bp_end) {
if(!((i+1) in TFDESC)) {
print "ERROR: try to move unconfigured axis:",i+1
exit
}
}
}
# get the current state of all actuators
_tfgetls_pattern(bps)
bp_beg = bps[0]
bp_sta = bps[1]
# get the current DAC values
if(_tfgetdacs(dacs) == -1) { return(-1) }
# calculate motions needed (include actuators inbetween switches)
for(i=0, tomove=0;i<naxes;i++) {
if((((bp_beg>>i) & 0x01) != ((bp_end>>i) & 0x01)) || \
(((i+1) in TFDESC) && (bp_sta&(1<<i)))) {
dacs[i] = (bp_end & (1<<i)) ? vin : vout
tomove |= (1<<i)
printf("Moving actuator %2d 0x%05x : %-3s\n", \
i+1, \
(1<<i), \
(dacs[i]==vin)?"IN":"OUT")
}
}
# enable PIEZO controller
tfenable
# start all motions simultaneously
_tfsetdacs(dacs)
t_beg = time()
# wait for the end of all motions and stop them one by one
while(tomove) {
# get the current state of all actuators
_tfgetls_pattern(bps)
bp_beg = bps[0]
bp_sta = bps[1]
# an actuator may not reach its limitswitch
if((time()-t_beg)>TFTIMEOUT) {
print "ERROR: "TFTIMEOUT"sec timeout waiting for end of motion, aborting"
tfabort
tfdisable
return(-1)
}
# detect end of motion
for(i=0;i<naxes;i++) {
if(((bp_beg>>i) & 0x01) == ((bp_end>>i) & 0x01)) {
# to save time, do not stop a non moving actuator
if(!(tomove & (1<<i))) { continue }
# do not stop until the limitswitch is reached
if(bp_sta & (1<<i)) { continue }
# stop motion only on concerned actuator
dacs[i] = vstop
tomove &= ~(1<<i)
_tfsetdacs(dacs)
printf("Stop actuator %2d 0x%05x\n", \
i+1, \
(1<<i))
}
}
# do not overload the WAGO box
sleep(.1)
}
# disable PIEZO controller
tfdisable
# normal end
return(0)
}'
#%UU%
#%MDESC%
# Enable the piezo controller
#
def tfenable '{ _tfcontrol(1) }'
#%UU%
#%MDESC%
# Disable the piezo controller
#
def tfdisable '{ _tfcontrol(0) }'
#%UU%
#%MDESC%
# Reset the piezo controller
#
def tfreset '{ _tfcontrol(-1) }'
#%IU%(action)
#%MDESC%
#action = 1 -> enable axis%BR%
#action = 0 -> disable axis%BR%
#action = -1 -> reset axis%BR%
#
def _tfcontrol(action) '{
local enable_axis
local array enable[2]
# TODO: Add check on TFMAIN
enable_axis = TFMAIN["ena_ch"]
if (action == -1) {
enable[0] = 1
wago_writech(enable_axis, enable)
sleep(.2)
enable[0] = 0
wago_writech(enable_axis, enable)
sleep(.5)
enable[0] = 1
wago_writech(enable_axis, enable)
} else if (action == 1) {
enable[0] = 1
wago_writech(enable_axis, enable)
sleep(.5)
} else if (action == 0){
enable[0] = 0
wago_writech(enable_axis, enable)
}
return(0)
}'
#%MACROS%
#%IMACROS%
#%SETUP%
# The Wago controllers must be declared in the setup file by means of the
# %B%wagosetup%B% macro (see help in %B%wagocore.mac%B%).
# This requires that the the device server Wagods must be properly configured
# to access to the Wago controllers.%BR%
#
#%AUTHOR% R.Hino, M.Perez, (Original 5/2010).
# $Revision: 1.4 $ / $Date: 2010/06/22 06:25:19 $
#%TOC%
|