#%TITLE% ICE.MAC
#
#%NAME%
# Macros to control ISG ICEPAP motor controller as a macro motor
# and to configure macro counters to read DRIVERs temperatures.
# Replacing the old "icepap.mac" set of macros.
#
#%CATEGORY% Positioning, Isg
#
#%DESCRIPTION%
#%DL%
#%DT%Configuring macro motors %DD%
# %DL%
# %DT% 1)
# You must have an entry in "MOTORS" table for each icepap MASTER
# %DL%
# %DT% -
# The "DEVICE" field must be set to string "icepap"
# %DT% -
# The "ADDR" must be set to the MASTER network name.
# The communication port can optionaly be specified also
# (ex: "isgtmp5:5000")
# %DT% -
# The "NUM" should be set to 159
# %DT% -
# The "TYPE" field must be set to "Macro Motors"
# %XDL%
# %DT% 2)
# For each axis you must define a motor with:
# %DL%
# %DT% -
# The "Controller" field set to "MAC_MOT"
# %DT% -
# The "Unit" field, numbered from 0,
# must be set to the MOTORS entry.
# %DT% -
# The "Module" field, numbered from 0,
# must be set to the ICEPAP rack number (seen on
# the red 7 segments display of the left hand of each rack)
# %DT% -
# The "Chan" field, numbered from 1,
# must be set to the DRIVER address
# NOTE: to configure a linked axis, the "Chan" field must be set
# to 9 and the "Module" to whatever value.
# %DT% -
# Example: "0/1/2" refers to the first icepap controller declared,
# the rack having the number "1" on its display,
# the 2nd DRIVER of this rack
# %XDL%
# %XDL%
#
#
#%DT%Configuring macro counters to read a DRIVER ENCODER POSITION%DD%
# %DL%
# %DT% 1)
# You must have a "SCALER" define with "icepapenc" as "DEVICE" and
# "Macro Counter" as "TYPE".
# %DT% 2)
# You must define a counter with "MAC_CNT" as "Device".
# %DL%
# %DT% -
# The "Unit" field must be set to the SCALER entry.
# %DT% -
# The "Chan" field must be set to the DRIVER address (ex: 5 for
# the 5th DRIVER of crate 0 or ex: 23 for the 3rd DRIVER of crate 2)
# %DT% -
# The "encoder" parameter can be set to one of the following values.
# Typically this parameter is set in config "custom parameters"
# screen for a counter. Hint: type "p" to get in.
# %DL%
# %DT% -
# "abs" Read the SSI absolute encoder
# %DT% -
# "absuXX" Read the unsigned SSI XX bits absolute encoder
# %DT% -
# "inc" Read the incremental encoder (DEFAULT)
# %DT% -
# "inpos" Read the DRIVER front panel input
# %DT% -
# "motor" Read the motor phase position
# %XDL%
# %XDL%
# %XDL%
#
#
#%DT%Configuring macro counters to read a single DRIVER TEMPERATURE %DD%
# %DL%
# %DT% 1)
# You must have a "SCALER" define with "icepapcnt" as "DEVICE" and
# "Macro Counter" as "TYPE".
# %DT% 2)
# You must define a counter with "MAC_CNT" as "Device".
# %DL%
# %DT% -
# The "Unit" field must be set to the SCALER entry.
# %DT% -
# The "Chan" field must be set to the DRIVER address (ex: 5 for
# the 5th DRIVER of crate 0 or ex: 23 for the 3rd DRIVER of crate 2)
# %XDL%
# %XDL%
#
#
#%DT%Configuring macro counters to read several DRIVERs TEMPERATUREs %DD%
# %DL%
# %DT% 1)
# You must have a "SCALER" define with "icepapcalc" as "DEVICE" and
# "Macro Counter" as "TYPE"
# %DT% 2)
# For each counter declared:
# %DL%
# %DT% -
# The "Device" field set to "MAC_CNT"
# %DT% -
# The "Unit" field must be set to the SCALER entry.
# %DT% -
# The "Chan" field is not used.
# %DT% -
# The "Misc 1" parameter (type "s" to access it) is the
# crate number (ex: 0)
# %DT% -
# The "Misc 2" parameter is the type of calculation
# done on the DRIVERs temperatures of the crate. Possible values are
# "max", "min", "avg"
# %XDL%
# %XDL%
#
#
#%DT%Configuring macro counters to read a single DRIVER internal parameter %DD%
# %DL%
# %DT% 1)
# You must have an entry in "SCALER" table for each icepap MASTER
# %DL%
# %DT% -
# The "DEVICE" field must be set to string "icepapmeas"
# %DT% -
# The "ADDR" must be set to the MASTER network name.
# The communication port can optionaly be specified also
# (ex: "isgtmp5:5000")
# %DT% -
# The "NUM" should be set to 159
# %DT% -
# The "TYPE" field must be set to "Macro Counter"
# %XDL%
# %DT% 2)
# You must define a counter with "MAC_CNT" as "Device".
# %DL%
# %DT% -
# The "Unit" field must be set to the SCALER entry.
# %DT% -
# The "Chan" field must be set to the DRIVER address (ex: 5 for
# the 5th DRIVER of crate 0 or ex: 23 for the 3rd DRIVER of crate 2)
# %DT% -
# An extra parameter called "cmd" must be set to the command
# to be used to get the DRIVER internal parameter (ex: "meas vm"
# "meas i" etc)
# %XDL%
# %XDL%
#
#
#%DT%Extra motor_par() parameters %DD%
# %DL%
# %DT% motor_par(motor,"power")%DD%
# Return "1" if the power is enabled on the speficied motor
# %DT% motor_par(motor,"power",1)%DD%
# Try to enable the the power the speficied motor and return the result
# %DT% motor_par(motor,"jog_speed")%DD%
# Returns the current speed if the motor is in never ending motion
# or returns "0" if it's stop or in normal operation mode.
# %DT% motor_par(motor,"jog_speed",speed)%DD%
# Sets the speed for the never ending motion. If the motor is
# already moving in this mode, its speed will be changed on the fly.
# If the new speed has not the same sign that the current one, the
# motor will first deccelerate until stopping and then starts rotating
# in the other direction with the new speed.
# %DT% motor_par(motor,"jog_speed",0)%DD%
# Cancel a never ending motion.
# %DT% motor_par(motor,"jog_modulo",steps)%DD%
# Optional parameter, used to set the motor position when canceling
# never ending motion.
# %DT% motor_par(motor,"closed_loop")%DD%
# Returns nonzero if the closed loop is active
# %DT% motor_par(motor,"closed_loop",1)%DD%
# Activate or desactivate the closed loop for the specified motor
# %DT% motor_par(motor,"reset_closed_loop")%DD%
# Reset the closed loop error (resynchronize axis position with encoder)
# Returns non null on success.
# %DT% motor_par(motor,"home_active")%DD%
# Returns nonzero if logical home signal is active
# %DT% motor_par(motor,"high_lim_set")%DD%
# Returns nonzero if positive limitswitch is active
# %DT% motor_par(motor,"low_lim_set")%DD%
# Returns nonzero if negative limitswitch is active
# %DT% motor_par(motor,"keepusable",1)%DD%
# Keep the motor usable even if power could not be switched on during
# reconfig. Typically this parameter is set in config "additional
# optional parameters" screen for a motor. Hint: type "p" to get in
# %XDL%
#
#%XDL%
#
#%END%
#
#
# ----------------------- MACRO MOTOR implementation -----------------------
#
constant ICEPAP_LOCKFILE "/users/blissadm/local/spec/userconf/icepap_lock"
constant ICEPAP_TIMEOUT 3
global ICEPAP_STOPCODE[]
ICEPAP_STOPCODE[0] = "last motion stopped normally"
ICEPAP_STOPCODE[1] = "STOP signal received"
ICEPAP_STOPCODE[2] = "ABORT signal received"
ICEPAP_STOPCODE[3] = "Limit+ activated"
ICEPAP_STOPCODE[4] = "Limit- activated"
ICEPAP_STOPCODE[6] = "axis disabled"
ICEPAP_STOPCODE[8] = "internal failure"
ICEPAP_STOPCODE[9] = "motion failure"
ICEPAP_STOPCODE[10]= "power overload"
ICEPAP_STOPCODE[11]= "driver overheating"
ICEPAP_STOPCODE[12]= "close loop error"
ICEPAP_STOPCODE[13]= "control encoder error"
ICEPAP_STOPCODE[15]= "external abort"
#%IU% [personal msg]
#%MDESC%
# Switch on or off the print of debug messages
#
def icepapdebug '{
global ICEPAP[]
if(ICEPAP["debug"]) {
rdef icepap__debug \'#\$#\'
print "ICEPAP debug mode is OFF"
ICEPAP["debug"]=0
} else {
rdef icepap__debug \'print "ICEPAP:" \'
print "ICEPAP debug mode is ON"
ICEPAP["debug"]=1
}
}'
#%UU% [on|off]
#%MDESC%
# Switch on (default) brief messages on motors powering error
# during the reconfig.
#
def icepap_brief_messages '{
global ICEPAP[]
local todo arg
todo = 1
if($# == 1) {
arg = "$1"
if((arg == "on") || (arg == "ON")) {
todo = 1
} else if((arg == "off") || (arg == "OFF")) {
todo = 0
} else {
p "Usage: $0 [on|off]"
exit
}
}
printf("ICEPAP error messages will be: %s", (todo?"BRIEF":"NORMAL"))
ICEPAP["brief_messages"] = todo
}'
#%IU%
#%MDESC%
# Reset socket communication and MASTER FIFOs
#
def icepap_fiforst(dev) '{
_icepap_wr(dev,"","_FIFORST")
}'
#%IU%
#%MDESC%
# Called on <Ctrl-C>
#
def icepap_cleanup(dev) '{
# give time to sockets
sleep(.02)
# very dangerous with multiple clients
# icepap_fiforst(dev)
sock_par(dev,"flush")
}'
#%IU%
#%MDESC%
# Needed to initialize debug print out macro the first time the
# file is loaded.
def icepapdebug_init '{
if(!(whatis("ICEPAP") & 0x05000000)) {
global ICEPAP[]
ICEPAP["debug"]=1
icepapdebug
}
}'
icepapdebug_init
#%IU%(string, case)
#%MDESC%
# Convert to lower (case==1) or to upper (case==0) case the string passed
#
def icepap__tocase(str, case) '{
string array str_a[length(str)]
local l
str_a = str
l = length(str)-1
for(;l>=0;l--) {
if(case)
str_a[l]=str_a[l]+(str_a[l]>=asc("A") && str_a[l]<=asc("Z"))*0x20;
else
str_a[l]=str_a[l]-(str_a[l]>=asc("a") && str_a[l]<=asc("z"))*0x20;
}
return(sprintf("%s", str_a))
}'
#%IU%(string)
#%MDESC%
# Return the lower string of the string passed
#
def icepap__tolower(str) '{return((str!="")?icepap__tocase(str, 1):"")}'
#%IU%(string)
#%MDESC%
# Return the upper string of the string passed
#
def icepap__toupper(str) '{return((str!="")?icepap__tocase(str, 0):"")}'
#%IU%(string)
#%MDESC%
#
def icepap_trim(str) '{
local b l
l = length(str)
if(l == 0) {
return ""
}
string array str_a[l]
str_a = str
l = l-1
for(;(l>=0)&&(str_a[l]==0x20);l--);
for(b=0;(b<l)&&(str_a[b]==0x20);b++);
return(substr(str,b+1,(l-b)+1))
}'
#%IU%(x)
#%MDESC%
# Return a well rounded integer as opposed to int() which always
# round down
#
def icepap_round(x) '{ if (x>=0) return int(x+0.5); else return int(x-0.5) }'
#%IU%(ans)
#%MDESC%
# Check if the answer given contains an ERROR and if yes
# request the error message
#
def icepap_chkerr(dev,ans) '{
if(index(ans,"ERROR") == 1) {
ans= _icepap_wrrd(dev,0,"?ERR 1")
print ans;
}
}'
#%IU%
#%MDESC%
#
def icepap_config(num,type,p1,p2,p3) '{
global ICEPAP[]
global ICEPAP_CAT[]
local dev
local i j
local ans
local hrev lrev
local n tt[]
local m aa[]
local mne
local silent
# p1==controller index p2==number of motors supported
if(type=="ctrl") {
silent = 1
icepap__debug "config(): new controller"
if (p1 == 0) { for(i in ICEPAP) { delete ICEPAP[i] } }
ICEPAP["dev"]=""
# get the MASTER
dev=icepap_ADDR
if(dev=="") {
_icepap_err
printf("missing ADDR field\n")
return
}
if(index(dev,":") == 0) { dev=sprintf("%s:5000",dev) }
ICEPAP["dev"][p1]=dev
ICEPAP["dev"]=dev
# if the MASTER is switched off, disable all the associated motors
ans=_icepap_query(dev,0,"?ID", silent)
if(ans == "") { return ".error." }
# get the system version
hrev = 0
lrev = 0
ICEPAP[dev]["hrev"]=0
ICEPAP[dev]["lrev"]=0
ans=_icepap_query(dev,"","?VER")
if(sscanf(ans,"%d.%d",hrev,lrev) == 2) {
ICEPAP[dev]["hrev"]=hrev
ICEPAP[dev]["lrev"]=lrev
}
# try to guess if the firmware supports group motions
ICEPAP[dev]["groups"]=(((hrev>=1)&&(lrev >= 22)) || (hrev>=2))?"YES":"NO"
# try to guess if the firmware supports linked axis
ans=_icepap_query(dev,"","?LINKED",silent)
n =split(ans,tt,"\r\n")
ICEPAP[dev]["linked"]=(!index(ans,"ERROR"))?"YES":"NO"
# get linked axis configured if any (expecting a multilines answer)
if((ICEPAP[dev]["linked"] == "YES") && (n>=3)) {
ICEPAP[dev]["linked_list"]=""
for(i=0;i<n;i++) {
if(index(tt[i],"\$")) {
continue
}
m = split(tt[i],aa)
mne = (m>0)?aa[0]:"???"
if(m<1) {
_icepap_err
printf("bad configured linked axis \"%s\" on \"%s\"\n", \
mne,dev)
continue
}
ICEPAP[dev]["linked_list"]=ICEPAP[dev]["linked_list"] mne " "
ICEPAP[mne]["linked_addr"]=""
for(j=1;j<m;j++) {
ICEPAP[mne]["linked_addr"]=ICEPAP[mne]["linked_addr"] aa[j] " "
}
ICEPAP[mne]["linked_addr"]=icepap_trim(ICEPAP[mne]["linked_addr"])
ICEPAP[mne]["linked"] ="YES"
}
ICEPAP[dev]["linked_list"]=icepap_trim(ICEPAP[dev]["linked_list"])
}
}
# p1==unit p2==module p3==channel
if(type=="mot") {
local mne
local dev
local addr
local i
local ret
local addr
local silent
# get the motor mnemonic string
mne=motor_mne(num)
# get the MASTER
ICEPAP[mne]["dev"]=""
dev=motor_par(num,"address")
if(dev==0) { return }
if(index(dev,":") == 0) { dev=sprintf("%s:5000",dev) }
ICEPAP[mne]["dev"]=dev
# initialize global settings
ICEPAP[mne]["addr"]=p2*10+p3
addr=ICEPAP[mne]["addr"]
ICEPAP[mne]["jog_velocity"]=0
ICEPAP[mne]["stop_code"]=0
# check if it is linked axis (invalid addresses:9, 19, etc)
if((addr%10)==9 || addr==0) {
if(ICEPAP[mne]["linked"] != "YES") {
_icepap_err
printf("unusable motor: \"%s\"\n",mne)
printf("Hint: change address in config or configure linked axe\n")
motor_par(num,"disable",1)
return ".error."
}
# for a linked axis the mnemonic is used as identification for the DSP
ICEPAP[mne]["addr"]=mne
# update globals concerning this linked axis
if(_linkedstat(num)) {
motor_par(num,"disable",1)
return ".error."
}
# switch on, at once, the power on all concerned motors
ans=_icepap_query(dev,"#",sprintf("POWER ON %s", mne))
if(index(ans,"ERROR"))
{
_icepap_err
printf("unusable motor: \"%s\" ",mne)
if(ICEPAP["brief_messages"]) {
printf("Hint: use \"icepap_diagnostic %s\"\n", mne)
} else {
printf("\n")
_icepap_print_info(dev,addr,mne)
}
motor_par(num,"disable",1)
return ".error."
}
# the afterward commands are not implemented in DSP for linked axis:
# ?ACTIVE
# ?CFG ACTIVE
# ?PCLOOP
return
}
# check if it is menber of a linked axis
if(ICEPAP[dev]["linked"] == "YES") {
silent = 1
ans=_icepap_query(dev,addr,"?CFG LNKNAME",silent)
if(index(ans,"ERROR"))
{
_icepap_err
printf("unusable motor: \"%s\" ",mne)
if(ICEPAP["brief_messages"]) {
printf("Hint: use \"icepap_diagnostic %s\"\n", mne)
} else {
printf("\n")
_icepap_print_info(dev,addr,mne)
}
motor_par(num,"disable",1)
return ".error."
}
n=split(ans,tt)
ICEPAP[mne]["linked_member"] = (n>1)?"YES":"NO"
ICEPAP[mne]["linked_name"] = tt[1]
if(n>1) {
printf("ICEPAP WARNING: disabling \"%s\" used for linked axis \"%s\"\n",\
mne, tt[1])
motor_par(num,"disable",1)
# all the powering sequence is done the linked axis, so give up here
return
}
}
# check if the DRIVER is configured and active
ans=_icepap_query(dev,addr,"?ACTIVE")
if(ans != "NO") {
if (ans != "YES")
{
_icepap_err
printf("unusable motor: \"%s\"\n",mne)
motor_par(num,"disable",1)
return ".error."
}
}
else
{
ans=_icepap_query(dev,addr,"?CFG ACTIVE")
if(ans != "ACTIVE YES") {
_icepap_err
printf("not configured active driver for motor: \"%s\"\n",mne)
printf("Hint: use \"icepapcms\" to activate this driver\n")
} else {
_icepap_err
printf("not active driver for motor: \"%s\"\n",mne)
printf("Hint: probably a hardware problem, crate off/on may help\n")
}
motor_par(num,"disable",1)
return ".error."
}
# check if the DSP will handle a closed loop
ICEPAP[mne]["pcloop"]="OFF"
ans=_icepap_query(dev,addr,"?PCLOOP")
if(index(ans,"ON")) { ICEPAP[mne]["pcloop"]="ON" }
# check if the DC dead band and settling time are well set in the config
if(ICEPAP[mne]["pcloop"]=="ON")
{
# NOTE 13Dec29: this interdiction could be discuessed, perhaps the user
# wants to know the current axis position even when there is closed loop
if(motor_par(num,"mode") == "maxe_e")
{
_icepap_err
printf("closed loop incompatible with \"maxe_e\" for motor: \"%s\"\n",mne)
printf("Hint: use remove motor parameter \"mode\"\n")
return ".error."
}
if(motor_par(num,"dc_settle_time") != 0)
{
printf("ICEPAP WARNING: settling handled by IcePAP for motor: \"%s\"\n",mne)
printf("ICEPAP WARNING: the \"DC settle time\" should be set to 0\n")
}
if(motor_par(num,"dc_dead_band") != 1)
{
printf("ICEPAP WARNING: settling handled by IcePAP for motor: \"%s\"\n",mne)
printf("ICEPAP WARNING: the \"DC dead band\" should be set to 1\n")
}
}
# switch on the power on the motor, chaud devant
silent = 1
ans=_icepap_query(dev,"#" addr,"POWER ON", silent)
if(index(ans,"ERROR") && motor_par(mne, "keepusable") != 1)
{
_icepap_err
printf("unusable motor: \"%s\" ",mne)
if(ICEPAP["brief_messages"]) {
printf("Hint: use \"icepap_diagnostic %s\"\n", mne)
} else {
printf("\n")
_icepap_print_info(dev,addr,mne)
}
motor_par(num,"disable",1)
return ".error."
}
if(motor_par(num,"mode") == "maxe_e")
{
if(ICEPAP[dev]["hrev"]<2) {
_icepap_err
printf("can not use \"maxe_e\" mode for motor: \"%s\"\n",mne)
printf("Hint: upgrade embedded firmware to version higher than 2.0\n")
return ".error."
}
printf("ICEPAP WARNING: using \"maxe_e\" mode for motor: \"%s\"\n",mne)
}
}
}'
#%IU%
#%MDESC%
#
def icepap_par(num,key,todo,p1) '{
global ICEPAP[]
local mne
local ans
local sta
local dev
# get the motor mnemonic string
mne=motor_mne(num)
# get the MASTER
if(!("dev" in ICEPAP[mne])) { return }
dev=ICEPAP[mne]["dev"]
if(dev=="") { return }
# get the address
if(!("addr" in ICEPAP[mne])) return;
addr=ICEPAP[mne]["addr"]
# return new motor_par() argins handled
if (key == "?" && todo == "get") {
return("power, jog_speed, jog_modulo, closed_loop, reset_closed_loop")
}
#
#
#
if (key == "power") {
# Change the power on the motor, chaud devant
if(todo == "set") {
if(ICEPAP[mne]["linked"] == "YES") {
ans=_icepap_query(dev,"#",sprintf("POWER %s %s",(p1==1?"ON":"OFF"),addr))
} else {
ans=_icepap_query(dev,"#" addr,sprintf("POWER %s",(p1==1?"ON":"OFF")))
}
if(index(ans,"ERROR"))
{
_icepap_print_info(dev,addr,mne)
_icepap_err
printf("unable to power motor: \"%s\"\n",mne)
return
}
}
# Return the current state in any case
if(ICEPAP[mne]["linked"] == "YES") {
ans=_icepap_query(dev,"",sprintf("?POWER %s",addr))
} else {
ans=_icepap_query(dev,addr,"?POWER")
}
return(index(ans,"ON")?1:0)
}
#
#
#
if (key == "jog_modulo") {
if(todo == "set") {
motor_par(num, "jog_modulo_stps", p1, "add")
}
return(motor_par(num, "jog_modulo_stps"))
}
#
#
#
if (key == "jog_speed") {
if(ICEPAP[mne]["linked"] == "YES") {
_icepap_err
printf("JOG motion no implemented for linked axis\n")
return
}
# Change or start a JOG motion
if(todo == "set")
{
local vel
local acc
local cmd
# Just in case the motor had never been moved previously
acc = motor_par(num,"acceleration")
icepap_cmd(num,"acceleration",acc)
# If the rotation sense changes, we have to stop first the motor
# NOTE MP 15Jul13: with firmware >=2.0 this is no more needed
if(((ICEPAP[mne]["jog_velocity"] * p1) <0) && (ICEPAP[dev]["hrev"]<2))
{
# Stop the motion
ans=_icepap_query(dev,"#" addr,"STOP")
if(index(ans,"ERROR"))
{
_icepap_err
printf("unable to stop JOG on motor: \"%s\"\n",mne)
return
}
# Wait for the end of the motion
while(icepap_cmd(num,"get_status") == 0x02) sleep(.01);
# Give some time to DRIVER to refresh its status
sleep(0.1)
}
# Treat the special case of null velocity
# NOTE MP 15Jul13: with firmware >=2.0 a "JOG 0" will block the motor
# in a never ending loop because the status shows an ongoing motion at
# null velocity.
if(p1 == 0) {
cmd = "STOP"
} else {
cmd = sprintf("JOG %d",p1)
}
# Set the new velocity
ICEPAP[mne]["jog_velocity"]=p1
ans=_icepap_query(dev,"#" addr, cmd)
if(index(ans,"ERROR"))
{
_icepap_err
printf("unable to launch JOG on motor: \"%s\"\n",mne)
return
}
}
# Avoid position discrepancy on motion stopped
if((todo == "set") && (p1 == 0))
{
local pos_mm pos_stps
local period_stps
# NOTE MP 21Jun10: wait for the end of motion before reading position
# can not call wait(0x21) because Spec does not know that we are moving
while(icepap_cmd(num,"get_status") == 0x02) sleep(.01);
# Optional period in steps
period_stps = motor_par(num, "jog_modulo_stps")
# NOTE MP 26Oct09: on users request, clear the position to avoid
# huge position values
pos_mm = 0
# Set the current axis position with a period
if(period_stps != 0)
{
pos_stps = icepap_cmd(num,"position") * motor_par(num, "step_size")
pos_stps %= period_stps
pos_mm = pos_stps / motor_par(num, "step_size")
}
# change the axis position
icepap_cmd(num,"set_position", pos_mm)
# NOTE MP 21Jun10: give time to DSP to update DPM, seen with firmware 1.21
sleep(.1)
# NOTE: from "help motors": position discrepancies between spec and the
# motor hardware will be silently resolved in favor of the hardware
read_motors(0x06)
}
# Return the current jog velocity in any case
# NOTE MP 15Oct09: ?V returns the current instantaneous speed which therefore
# can not be the target one if the motor is still accelerating.
# To avoid confusing the user, we return the target one
if(todo == "set")
return(ICEPAP[mne]["jog_velocity"])
# Return the current instantaneous velocity
ans=_icepap_query(dev,addr,"?JOG")
if(index(ans,"ERROR"))
{
_icepap_err
printf("unable to get speed for motor: \"%s\"\n",mne)
return
}
if(sscanf(ans,"%d",vel) != 1)
{
_icepap_err
printf("unable to read speed for motor: \"%s\"\n",mne)
return
}
# NOTE MP 15Oct09: ?JOG returns positive only values, little work-arround
if(ICEPAP[dev]["hrev"]<2) {
if(ICEPAP[mne]["jog_velocity"]<0)
vel *= -1
}
return(vel)
}
#
#
#
if (key == "closed_loop") {
if(todo == "set") {
ans=_icepap_query(dev,"#" addr,sprintf("PCLOOP %s",(p1==1?"ON":"OFF")))
if(index(ans,"ERROR"))
{
_icepap_err
printf("unable to activate closed loop for: \"%s\"\n",mne)
return
}
}
# Return the current state of closed loop
ans=_icepap_query(dev,addr,"?PCLOOP")
return(index(ans,"ON")?1:0)
}
#
#
#
if (key == "reset_closed_loop") {
# get current encoder position
ans = _icepap_query(dev, addr, "?POS MEASURE")
if(index(ans,"ERROR"))
{
_icepap_err
printf("unable to read encoder for: \"%s\"\n",mne)
return(0)
}
# set axis position to same value to remove closed loop discrepancy
# NOTE MP 21Jul14: the axis command does not work with firmware 2.0
# the system command must be used instead
cmd = sprintf("POS %s %s", addr, ans)
ans = _icepap_query(dev, "#", cmd)
if(index(ans,"ERROR"))
{
_icepap_err
printf("unable to reset closed loop error on: \"%s\"\n",mne)
return(0)
}
# switch power on (should re-enable the closed loop)
if(motor_par(num,"power",1) == 0)
{
_icepap_err
printf("unable to switch power on after closed loop reset on: \"%s\"\n",mne)
return(0)
}
# position discrepancies between spec and the
# motor hardware will be silently resolved in favor of the hardware
read_motors(0x06)
# normal end
return(1)
}
#
#
#
if (key == "home_active") {
sta = 0
ans=_icepap_query(dev,"",sprintf("?FSTATUS %s",addr))
if(sscanf(ans,"%x", sta) != 1)
{
_icepap_err
printf("unable to get status for: \"%s\"\n",mne)
return ".error."
}
# get home signal status
return((sta & (1<<20))!=0)
}
#
#
#
if (key == "high_lim_set") {
sta = 0
ans=_icepap_query(dev,"",sprintf("?FSTATUS %s",addr))
if(sscanf(ans,"%x", sta) != 1)
{
_icepap_err
printf("unable to get status for: \"%s\"\n",mne)
return ".error."
}
# get limitswtich status
return(sta & (1<<18))
}
#
#
#
if (key == "low_lim_set") {
sta = 0
ans=_icepap_query(dev,"",sprintf("?FSTATUS %s",addr))
if(sscanf(ans,"%x", sta) != 1)
{
_icepap_err
printf("unable to get status for: \"%s\"\n",mne)
return ".error."
}
# get limitswtich status
return(sta & (1<<19))
}
}'
#%IU%
#%MDESC%
#
def _icepap_prestart_all(dev) '{
global ICEPAP
if(ICEPAP[dev]["groups"] != "YES") { return }
ICEPAP[dev]["tomove"]=""
ICEPAP[dev]["tostat"]=""
}'
#%IU%
#%MDESC%
#
def _icepap_start_all(dev) '{
global ICEPAP
local aux[]
if(ICEPAP[dev]["groups"] != "YES") { return }
# NOTE MP 24Jul12: the start_all should not be call if nothing to move
# but SPEC version 5.10.02-16 do this
if(ICEPAP[dev]["tomove"] == "") { return }
# NOTE MP 01Feb11: avoid group motion for single axis motion
cmd=sprintf("MOVE %s %s",\
(split(ICEPAP[dev]["tostat"],aux)>1)?"GROUP":"",\
ICEPAP[dev]["tomove"])
answ = _icepap_query(dev,"#",cmd)
if (answ != "OK")
{
_icepap_err
printf("unable to start grouped motion\n")
return ".error."
}
}'
#%IU%
#%MDESC%
#
def _icepap_start_one(dev, addr, pos) '{
global ICEPAP
if(ICEPAP[dev]["groups"] != "YES")
{
local cmd
# NOTE MP 31Jan11: even if multi-axes motion exists before group motion
# their behavior as drastically changed with group implementation
# therefore it is better to not use them
cmd=sprintf("MOVE %d",pos)
addr = "#" addr
answ = _icepap_query(dev,addr,cmd)
if (answ != "OK")
{
_icepap_err
printf("unable to start motion for: \"%s\"\n",mne)
return ".error."
}
return
}
ICEPAP[dev]["tomove"] = sprintf("%s %s %d",ICEPAP[dev]["tomove"],addr,pos)
ICEPAP[dev]["tostat"] = sprintf("%s %s", ICEPAP[dev]["tostat"],addr)
}'
# Allows passing arguments (mandatory to avoid SPEC syntax error
# if the argin is not used)
# To use it: cdef("user_icepap_prestart_one","mymacro(\$1)","_gilles")
cdef("user_icepap_prestart_one", "#$*\n", "_icepap")
cdef("user_icepap_prestart_all", "#$*\n", "_icepap")
cdef("user_icepap_abort_one", "#$*\n", "_icepap")
cdef("user_icepap_abort_all", "#$*\n", "_icepap")
cdef("user_icepap_postmove_one", "#$*\n", "_icepap")
#%IU%
#%MDESC%
#
def icepap_cmd(num,key,p1,p2) '{
global ICEPAP[]
local dev
local mne
local addr
#
# Handle actions at controller level
#
if(num == "..") {
dev = icepap_ADDR
if(index(dev,":") == 0) { dev=sprintf("%s:5000",dev) }
if ( key == "prestart_all" ) {
user_icepap_prestart_all dev
return(_icepap_prestart_all(dev))
}
if ( key == "start_all" ) {
return(_icepap_start_all(dev))
}
if ( key == "abort_all" ) {
user_icepap_abort_all dev
}
return
}
# get the motor mnemonic string
mne=motor_mne(num)
# get the MASTER
if(!("dev" in ICEPAP[mne])) { return }
dev=ICEPAP[mne]["dev"]
if(dev=="") { return }
# NOTE MP 2Aug05: when starting from fresh, SPEC calls
# icepap_cmd("position") before calling icepap_config() and
# therefore nothing is usable at that moment
if(!("addr" in ICEPAP[mne])) return;
addr=ICEPAP[mne]["addr"]
#
# return the current motor position in mm or deg
#
if (key == "position") {
local pos
local pos_str
local ans
# In MAXE_E like mode, return the encoder position instead of the indexer one
if(motor_par(num,"mode") == "maxe_e") {
ans = _icepap_query(dev, addr, "?POS MEASURE")
} else {
ans = _icepap_query(dev, "", sprintf("?FPOS %s", addr))
}
# Request the position from DPM not from the DRIVER
if(sscanf(ans,"%d",pos) != 1) {
_icepap_err
printf("unable to get position for: \"%s\"\n",mne)
return ".error."
}
pos_str = sprintf("%.15g", pos / motor_par(num,"step_size"))
icepap__debug sprintf("\"%s\": pos %s",mne,pos_str)
return(pos_str)
}
#
# start a motion (p1==abs pos, p2==rel pos, with pos in mm or deg)
#
if (key == "start_one") {
local pos
local cmd
local v0
local vsr
local a0
local ans
local incrpos
local indeepshit
local poubelle
local maxloops
# minimum check that motion is possible
sta = 0
ans=_icepap_query(dev,"",sprintf("?FSTATUS %s",addr))
if(sscanf(ans,"%x", sta) != 1)
{
_icepap_err
printf("unable to get status for: \"%s\"\n",mne)
return ".error."
}
# get ready status
if(!(sta & (1<<9)))
{
local msg
msg = "(used as shutter??)"
_icepap_err
printf("driver is not ready for: \"%s\" %s\n", \
mne, motor_par(mne, "shutter_mode")?msg:"")
# temporary: for debug purpose only
_icepap_print_info(dev,addr,mne)
return ".error."
}
pos=icepap_round(p1*motor_par(num,"step_size"))
ICEPAP[mne]["target_steps"]=pos
# Erase stop code condition to treat it once
ICEPAP[mne]["stop_code"]=0
if(motor_par(num,"mode") == "maxe_e") {
_icepap_wr(dev, addr, "ESYNC")
}
return(_icepap_start_one(dev,addr,pos))
}
#
# Check if the driver is powered and ready to use
#
if (key == "prestart_one") {
ICEPAP[mne]["wasmoving"] = 1
user_icepap_prestart_one num
}
#
# return the current motor status
#
if (key == "get_status") {
local ret
local ans
local cms
local sta sta_neg sta_pos
ret = 0
sta = 0
ans=_icepap_query(dev,"",sprintf("?FSTATUS %s",addr))
if(sscanf(ans,"%x", sta) != 1)
{
_icepap_err
printf("unable to get status for: \"%s\"\n",mne)
return ".error."
}
# get moving status
#
# NOTE MP 07Jun10: check MOVING and SETTLING status bits
# -the MOVING (10) goes down at the end of the trajectory
# -the SETTLING (11) goes down at the end of close loop algorythm
#
# NOTE MP 21Jun10: during a HOMING sequence, several motions take place,
# therefore the MOVING/SETTLING pair can be unset. But the READY remains
# unset during all the HOMING sequence. To distinguish a non READY axis
# due to error condition from moving condition, the POWER bit
# must also be checked
# -the READY (09) goes down on error or moving
# -the POWERON (23) goes down on error
#
if((sta & (1<<10)) || (sta & (1<<11))) ret |= 0x02;
else if(!(sta & (1<<9)) && (sta & (1<<23))) ret |= 0x02;
# get limitswitches status
if(sta & (1<<19)) ret |= 0x04;
if(sta & (1<<18)) ret |= 0x08;
# check stop code if not moving, of course
#
if(!(ret & 0x02)) {
_icepap_stopcode(num, sta)
_icepap_postmove(num)
}
# NOTE MP 18May17: SPEC standard macros, on <Ctrl-C>, call "sync"
# which detects a shutter motor as not ready and stops it and that
# gets the motor out of shutter mode. To avoid this, SPEC must
# believe that the motor is ready.
#
if(ret & 0x02) {
if(motor_par(num, "shutter_mode")) {
return(0)
}
}
return(ret)
}
#
# verify if settling is OK
#
if (key =="diff_position") {
# the settling is handled by the DSP
if(ICEPAP[mne]["pcloop"]=="ON")
{
local ans
ans=_icepap_query(dev,"",sprintf("?FSTATUS %s",addr))
if(sscanf(ans,"%x", sta) !=1) {
_icepap_err
printf("unable to get status for: \"%s\"\n",mne)
return(0)
}
# by default the motion is finished
ret=0
# get settling bit
if(sta & (1<<11)) { ret=motor_par(num,"dc_dead_band") }
return ret
}
# the settling is handled by SPEC
if(ICEPAP[mne]["pcloop"]=="OFF")
{
local pos
local ans
local poubelle
ans= _icepap_query(dev,"",sprintf("?FPOS %s",addr))
if(sscanf(ans,"%f%s",pos,poubelle) != 1) {
_icepap_err
printf("unable to get position for: \"%s\"\n",mne)
return ".error."
}
# must return the position delta in steps
return (pos-ICEPAP[mne]["target_steps"])
}
}
#
# stop a single motor
#
if (key == "abort_one") {
local answ
cmd=sprintf("STOP %s",addr)
answ = _icepap_query(dev,"#",cmd)
if (answ != "OK") {
_icepap_wr(dev,"","STOP")
}
user_icepap_abort_one num
return
}
#
# set position (p1=mm)
#
if (key == "set_position") {
local fpos tbeg
ans = _icepap_query(dev,"#",\
sprintf("POS %s %d", addr, icepap_round(p1*motor_par(num,"step_size"))))
if(index(ans,"ERROR"))
{
_icepap_err
printf("unable set position for: \"%s\"\n",mne)
return ".error."
}
# give time to the DPM update from concerned DRIVER
# sleep(.1)
tbeg = time()
while(((time()-tbeg) < .3)) {
sscanf(icepap_cmd(num,"position"),"%.15g",fpos)
if(fabs(fpos-p1) < 1e-3) { break }
}
return
}
#
# set acceleration (p1=ms p2=steps/sec^2)
#
if (key == "acceleration") {
ans = _icepap_query(dev,"#",sprintf("ACCTIME %s %f",addr,p1/1000))
if(index(ans,"ERROR"))
{
_icepap_err
printf("unable set acceleration for: \"%s\"\n",mne)
return ".error."
}
}
#
# set base_rate (p1=rate in Hz)
#
if (key == "base_rate") {
return
}
#
# set slew_rate (p1=rate in Hz)
#
if (key == "slew_rate") {
ans = _icepap_query(dev,"#",sprintf("VELOCITY %s %d",addr,p1))
if(index(ans,"ERROR"))
{
_icepap_err
printf("unable set velocity for: \"%s\"\n",mne)
return ".error."
}
}
#
# initiate a home or limit search (p1=string with what to search)
#
if (key == "search") {
local lim
local cmd
if(ICEPAP[mne]["linked"]=="YES") {
_icepap_err
printf("limit search not implemented for linked axis\n")
return ".error."
}
if(p1=="lim+") { cmd = "SRCH" ; lim="LIM+" }
else if(p1=="lim-") { cmd = "SRCH" ; lim="LIM-" }
else if(p1=="lim+edge") { cmd = "SRCH" ; lim="LIM+" }
else if(p1=="lim-edge") { cmd = "SRCH" ; lim="LIM-" }
else if(p1=="home+") { cmd = "HOME" ; lim="+1" }
else if(p1=="home-") { cmd = "HOME" ; lim="-1" }
else
{
_icepap_err
printf("un-supported home or limit search\n")
return ".error."
}
# If already at limit, do nothing
#
# NOTE MP 10Nov08: the default behavior of "LIM+" command is to look for
# a transition of positive limitswitch (i.e. the DRIVER will automatically
# change the motor motion sense if the limitswitch is already active)
# This behavior can be used using "lim+edge" argin.
#
if(p1=="lim+") { if(icepap_cmd(num,"get_status") == 0x08) { return } }
if(p1=="lim-") { if(icepap_cmd(num,"get_status") == 0x04) { return } }
# NOTE MP 10Nov08: the local variables are erased by the recursive call
# to icepap_cmd("get_status"). Bug fixed in release 5.08.03-3
mne = motor_mne(num)
dev = ICEPAP[mne]["dev"]
addr= ICEPAP[mne]["addr"]
addr = "#" addr
ans = _icepap_query(dev,addr,sprintf("%s %s",cmd,lim))
if(index(ans,"ERROR"))
{
_icepap_err
printf("unable to start limit search\n")
return ".error."
}
# NOTE MP 07Jun10: do a polling on ?SRCHSTAT ?HOMESTAT to have
# the found/notfound information from the DSP directly and to be
# able to do some usage of the SRCHPOS and HOMEPOS
#
# from here, spec will do the polling on status until the
# end of the motion.
return
}
}'
#%UU% motor
#%MDESC%
# Print out information on the specified ICEPAP motor
#
def icepap_diagnostic '{
global ICEPAP[]
local mne
local num
local dev addr
if($# == 0) {
p "Usage: $0 motor"
exit
}
mne = "$1"
if(_icepap_ismot(mne)) {
exit
}
dev = ICEPAP[mne]["dev"]
addr = ICEPAP[mne]["addr"]
_icepap_print_info(dev, addr, mne)
}'
#%IU%(dev,addr,mne)
#%MDESC%
#
def _icepap_print_info(dev,addr,mne) '{
local n tt[]
# check if linked axe or linked one
if(ICEPAP[mne]["linked"] == "YES") {
n=split(ICEPAP[mne]["linked_addr"],tt)
for(;n;n--) {
_icepap_print_info_driver(dev,tt[n-1],mne)
}
} else {
_icepap_print_info_driver(dev,addr,mne)
}
}'
#%IU%(dev,addr)
#%MDESC%
# TODO: unify with icepap_info macro
#
def _icepap_print_info_driver(dev,addr,mne) '{
local num
local tab
tab="\t|"
print "\t---------------------------------------------------------"
num = motor_num(mne)
print tab"MOTOR : ",mne
print tab"SYSTEM : ",motor_par(num,"address")
print tab"DRIVER : ",sprintf("%02d",addr)
print tab"POWER : ",_icepap_query(dev,addr,"?power")
print tab"CLOOP : ",_icepap_query(dev,addr,"?pcloop")
print tab"WARNING: ",_icepap_query(dev,addr,"?warning")
print tab"ALARM : ",_icepap_query(dev,addr,"?alarm")
print tab"PWRINFO: "
_icepap_print_tabbed(tab,_icepap_query(dev,addr,"?isg ?pwrinfo"))
print "\t---------------------------------------------------------"
}'
def _icepap_print_tabbed(tab,str) '{
local lines[]
local i,n
n=split(str,lines,"\n")
for(i=0,ret="";i<n;i++) {
print tab,lines[i]
}
}'
#%UU% [hostname|motor]
#%MDESC%
# Print out information on the specified ICEPAP system or on an
# ICEPAP motor configured in the current SPEC session.
#
def icepap_info '{
local todo
local num
if($# == 0) {
p "Usage: $0 [hostname | motor]"
exit
}
# TODO MP : add multiple argins
todo = "$1"
if((num=motor_num(todo)) != -1) {
_icepap_print_info_mot(num)
} else {
_icepap_print_info_system(todo)
}
}'
#%UU% motor | hostname [addr [addr ... ]]
#%MDESC%
# Print out detailed memory information for the specified DRIVERs
# The DRIVER can be specified by their address or by the corresponding
# motor already configured.
# If only an IcePAP system is given, all its DRIVERs will be print out.
#
def icepap_mem_info '{
local todo
local num
local dev addr
local ans i n addrs[]
if($# == 0) {
p "Usage: $0 motor | hostname [addr [addr ... ]]"
exit
}
todo = "$1"
if((num=motor_num(todo)) != -1) {
if(motor_par(num, "device_id") != "icepap") {
_icepap_err
printf("Not an IcePAP motor: \"%s\"\n", "$1")
exit
}
n = 1
dev = motor_par(num,"address")
addrs[0] = motor_par(num,"module")*10
addrs[0] += motor_par(num,"channel")
} else {
dev = "$1"
if($# > 1) {
n = split("$*", addrs)
for(i=1;i<n;i++) { addrs[i-1] = addrs[i] }
n = n - 1
} else {
ans = _icepap_get_addrs(dev)
n = split(ans, addrs)
}
}
for(i=0;i<n;i++) {
_icepap_mem_driver(dev, addrs[i])
}
}'
#%IU%(motor)
#%MDESC%
#
def _icepap_print_info_mot(num) '{
local mne
local ad sw hn i
sw = 15
mne = motor_mne(num)
if(!("dev" in ICEPAP[mne])) {
p "ERROR: unknown motor"
return
}
printf("%*s : %s\n",sw,"motor name",mne)
hn = ICEPAP[mne]["dev"]
if(i=index(hn,":")) { hn = substr(hn,0,i-1) }
printf("%*s : %s\n",sw,"system",hn)
ad = ICEPAP[mne]["addr"]
printf("%*s : %s\n",sw,"address",ad)
printf("%*s : %s\n",sw,"power",motor_par(num,"power")?"ON":"OFF")
printf("%*s : %s\n",sw,"closed loop",motor_par(num,"closed_loop")?"ON":"OFF")
}'
#%IU%(hostname)
#%MDESC%
#
def _icepap_print_info_system(dev) '{
local sw ans silent
local i nm nums[] ns
silent = 1
ans =_icepap_query(dev,0,"?VER", silent)
if(ans == "") {
p "ERROR: unknown or unreachable system"
return
}
sw = 15
printf("%*s : %s\n",sw,"system",dev)
printf("%*s : %s\n",sw,"version",icepap_trim(ans))
# look for motor from this system configured in the current session
for(i=0,nm=0,ns="";i<MOTORS;i++) {
if(!index(motor_par(i,"address"),dev)) { continue }
nums[nm++] = i
ns = sprintf("%s%s ",ns,motor_mne(i))
}
printf("%*s : %s\n",sw,"motors used",nm?ns:"NONE")
}'
#%UU% [hostname|motor]
#%MDESC%
# Check the firmware version(s) of the specificied ICEPAP system or
# ICEPAP motor configured in the current SPEC session.
#
def icepap_firmware_check '{
local todo
local num
if($# == 0) {
p "Usage: $0 [hostname | motor]"
exit
}
todo = "$1"
if((num=motor_num(todo)) != -1) {
_icepap_fw_check_mot(num)
} else {
_icepap_fw_check_system(todo)
}
}'
#%IU%(motor)
#%MDESC%
#
def _icepap_fw_check_mot(num) '{
p "NOT IMPLEMENTED YET"
}'
#%IU%(hostname)
#%MDESC%
#
def _icepap_fw_check_system(dev) '{
local r_saved
local r_master
local r_drivers[]
local n_drivers
local r_failed_new[]
local r_failed_old[]
local s_failed_new
local s_failed_old
local n_failed
local ans
local addrs
local i n a
local cmp cmp_saved
local sw
#
# Collect information
#
printf("collecting data...\r");
# Get the system revisions
r_master = _icepap_fw_controller(dev)
r_saved = _icepap_fw_saved(dev)
# Get the list of modules
ans = _icepap_get_addrs(dev)
n = split(ans, addrs)
for(i=0,n_drivers=0;i<n;i++) {
a = addrs[i]
if(a==0) { continue }
r_drivers[a] = _icepap_fw_driver(dev,a)
n_drivers++
if(cmp = _icepap_fw_compare(r_master,r_drivers[a])) {
if(cmp == 2) {
r_failed_new[a] = cmp
s_failed_new = sprintf("%s %s",a,s_failed_new)
n_failed_new++
}
if(cmp == 1) {
r_failed_old[a] = cmp ;
s_failed_old = sprintf("%s %s",a,s_failed_old)
n_failed_old++
}
n_failed++
}
}
#
# Display results
#
sw = 21
cmp_saved = _icepap_fw_compare(r_master,r_saved)
printf("%*s : %s\n",sw,"system version",r_master)
printf("%*s : %s\n",sw,"check saved", !cmp_saved?"OK":"FAILED")
ans = sprintf("check %d drivers",n_drivers)
printf("%*s : %s\n",sw, ans, !n_failed?"OK":"FAILED")
if(n_failed) {
printf("%*s : %s\n",sw,"found mismatch on", \
sprintf("%d driver%s",n_failed,n_failed==1?"":"s"))
}
if(n_failed_old) {
#printf("%*s : ",sw, "too old drivers")
#for(a in r_failed_old) { printf("%s ", a) }
printf("%*s : %s",sw, "too old drivers", s_failed_old)
printf("\n")
}
if(n_failed_new) {
printf("%*s : ",sw, "too modern drivers")
for(a in r_failed_new) { printf("%s ", a) }
printf("\n")
}
#
# Actions to take
#
if(cmp_saved) {
p ""
p "WARNING: firmware saved not up to date, giving up"
p "HINT : use the command \"icepap_prog\" with flag \"SAVE\" "
exit
}
if((n_failed_new) && (n_failed_new > (n_drivers/2))) {
p ""
p "WARNING: there are too many drivers with too modern firmware,giving up"
p "HINT : use the command \"icepap_prog\" with flag \"ALL\" "
exit
}
if(n_failed_old) {
p ""
p "WARNING: there are drivers with too old firmware"
if(yesno("Do you agree to upgrade all of them",1)) {
# NOTE MP 26Feb13: according to ICEPAP User Manual, the PROG command
# accepts only on module address, therefore, we have to program
# one after the other
for(a in r_failed_old) {
printf("\n%*s : %s\n",sw, "upgrading driver",a)
_icepap_prog(dev,"",a,"FORCE")
}
}
}
if((n_failed_new) && (n_failed_new < (n_drivers/2))) {
p ""
p "WARNING: there are drivers with too modern firmware"
if(yesno("Do you agree to downgrade all of them",0)) {
# NOTE MP 26Feb13: according to ICEPAP User Manual, the PROG command
# accepts only on module address, therefore, we have to program
# one after the other
for(a in r_failed_new) {
printf("\n%*s : %s\n",sw, "downgrading driver",a)
_icepap_prog(dev,"",a,"FORCE")
}
}
}
}'
#%IU%(rev1, rev2)
#%MDESC%
# Compare deux revisions, given as strings, and returns:
# 0 if rev1 equal rev2
# 1 if rev1 > rev2
# 2 if rev1 < rev2
# -1 if invalid revision numbers
#
def _icepap_fw_compare(rev1, rev2) '{
local hrev1 lrev1
local hrev2 lrev2
local ret
if(sscanf(rev1,"%d.%d",hrev1,lrev1) != 2) { return(-1) }
if(sscanf(rev2,"%d.%d",hrev2,lrev2) != 2) { return(-1) }
if(hrev1>hrev2) { return(1) }
if(hrev1<hrev2) { return(2) }
if(lrev1>lrev2) { return(1) }
if(lrev1<lrev2) { return(2) }
return(0)
}'
#%IU%(hostname)
#%MDESC%
# Returns, for the specified system, the firmware version of the CONTROLLER
#
def _icepap_fw_controller(dev) '{
return(_icepap_fw_driver(dev,0))
}'
#%IU%(hostname, addr)
#%MDESC%
# Returns, for the specified system, the firmware version of the DRIVER
# specified by its address.
#
def _icepap_fw_driver(dev, addr) '{
local rev
local ans
# get the system version
rev="0.0"
ans=_icepap_query(dev,addr,"?VER")
if(index(ans,"ERROR")) { return(rev) }
rev=icepap_trim(ans)
return(rev)
}'
#%IU%(hostname, addr)
#%MDESC%
# Print out, for the specified system, detailed memory information of
# the DRIVER specified by its address.
# Returns non null if error occured.
#
def _icepap_mem_driver(dev, addr) '{
local ans
local i n
local pt sz tp
# first get the number of blocks (free and allocated)
ans=_icepap_query(dev,addr,"?MEMORY -1")
if(sscanf(ans, "%d", n) != 1) {
_icepap_err
print "error gathering information"
return(-1)
}
printf("----------------------------------\n")
printf("| %-31s|\n", sprintf("system: %s address: %d", dev, addr))
printf("|--------------------------------|\n")
printf("| %-10s | %4s | %10s |\n", "block addr", "type", "bytes")
printf("|--------------------------------|\n")
for(i=0;i<n;i++) {
ans=_icepap_query(dev,addr,"?MEMORY 0")
sscanf(ans, "%s %d", pt, sz)
if(sz<0) {
sz = -sz
tp = "USED"
} else {
tp = "FREE"
}
printf("| %-10s | %4s | %10d |\n", pt, tp, sz)
}
printf("----------------------------------\n\n")
}'
#%IU%(hostname)
#%MDESC%
# Returns, for the specified system, the firmware version saved in flash
#
def _icepap_fw_saved(dev) '{
local rev
local ans
local i n lines[] elts[]
# get the system version
rev="0.0"
ans=_icepap_query(dev,"","?VER SAVED")
if(index(ans,"ERROR")) { return(rev) }
n=split(ans,lines,"\n")
for(i=0;i<n;i++) {
if(!index(lines[i],"SYSTEM")) { continue }
split(lines[i],elts,":")
rev=icepap_trim(elts[1])
break
}
return(rev)
}'
#%UU% [hostname[:port]]
#%MDESC%
# Reset all the racks of the specified ICEPAP MASTER
#
def icepap_reset'{
global ICEPAP[]
local dev
if($# < 1) {
dev=getval("Icepap MASTER network name",ICEPAP["dev"])
} else {
dev="$1"
}
if(!index(dev,":")) { dev = dev":5000" }
ICEPAP["dev"]=dev
_icepap_wr(dev,"","RESET")
}'
#%IU% axis
#%MDESC%
# CONFIG LOCK:
# Add a lock on the specified axis (ex: 0/2)
#
def icepap_lock '{
local a
local u c
local line
if($# != 1) {
print "USAGE: $0 axis"
print " Ex: $0 0/2"
exit
}
a="$1"
_icepap_lock(a,1)
}'
#%IU% axis
#%MDESC%
# CONFIG LOCK:
# Remove a lock on the specified axis (ex: 0/2)
#
def icepap_unlock '{
local a
local u c
local line
if($# != 1) {
print "USAGE: $0 axis"
print " Ex: $0 0/2"
exit
}
a="$1"
_icepap_lock(a,0)
}'
#%IU%
#%MDESC%
# CONFIG LOCK:
# Check that lock file exist and create empty if not
#
def _icepap_islockfile() '{
if(file_info(ICEPAP_LOCKFILE, "-w") == 0){
printf("ICEPAP WARNING: touching \"%s\"\n",ICEPAP_LOCKFILE)
if(unix(sprintf("touch %s",ICEPAP_LOCKFILE)) != 0) {
_icepap_err
print "error creating file "ICEPAP_LOCKFILE
return(-1)
}
}
close(ICEPAP_LOCKFILE)
if(getline(ICEPAP_LOCKFILE, "open") < 0){
_icepap_err
printf("Can\'t open file \"%s\"\n", ICEPAP_LOCKFILE)
return(-1)
}
return(0)
}'
#%IU%(axis,lock)
#%MDESC%
# CONFIG LOCK:
# Add or remove (lock=1 or 0) a lock on the specified axis (ex: 0/2)
#
def _icepap_lock(arg,lock) '{
local a
local u c
local line
local nline
local found
if(sscanf(arg,"%d/%d",u,c)!=2) {
_icepap_err
print "bad axis syntax (Ex: \"0/2\")"
return(-1)
}
a=sprintf("%d/%d\n",u,c)
if(_icepap_islockfile() != 0)
return(-1);
line =""
nline=""
found=0
while ((line = getline(ICEPAP_LOCKFILE)) != -1)
{
if(lock)
{
if(line == a) {
print "AXIS already locked"
close(ICEPAP_LOCKFILE)
return(-1)
}
} else {
if(line == a) {
printf("ICEPAP : removing lock on axis %s\n",a)
found=1
} else {
nline=sprintf("%s%s",nline,line)
}
}
}
if(lock) {
printf("ICEPAP : adding lock on axis %s\n",a)
fprintf(ICEPAP_LOCKFILE,"%s",a)
close(ICEPAP_LOCKFILE)
return(0)
}
if(found == 0) {
_icepap_err
print "axis was not locked"
close(ICEPAP_LOCKFILE)
return(-1)
}
unix(sprintf("\\rm -f %s",ICEPAP_LOCKFILE))
unix(sprintf("touch %s",ICEPAP_LOCKFILE))
open(ICEPAP_LOCKFILE)
fprintf(ICEPAP_LOCKFILE,"%s",nline)
close(ICEPAP_LOCKFILE)
return(0)
}'
#%IU%(axis)
#%MDESC%
# CONFIG LOCK:
# Return 1 if a lock exist for the specified axis (ex: 0/2)
# Return 0 if there is no lock.
# Return -1 in case of error.
#
def _icepap_islock(arg) '{
local a
local u c
local line
local nline
local found
if(sscanf(arg,"%d/%d",u,c)!=2) {
_icepap_err
print "bad axis syntax (Ex: \"0/2\")"
return(-1)
}
a=sprintf("%d/%d\n",u,c)
if(_icepap_islockfile() != 0)
return(-1);
line =""
found=0
while ((line = getline(ICEPAP_LOCKFILE)) != -1)
{
if(line == a) {
found=1
break
}
}
close(ICEPAP_LOCKFILE)
return(found)
}'
#
# ----------------------- MACRO COUNTER implementation -----------------------
#
#%IU%(hostname:port, address)
#%MDESC%
#
def _icepapcnt_gettemp(dev,addr) '{
local ans
local t
ans= _icepap_query(dev,addr,"?MEAS T")
if(sscanf(ans,"%d",t) != 1) {
_icepap_err
printf("%s: addr: %s: unable to get temp\n",mne,addr)
icepap_chkerr(dev,ans)
icepap_fiforst(dev)
return(0)
}
return(t)
}'
#%IU%
#%MDESC%
#
def icepapcnt_config(num,type,p1,p2,p3) '{
global ICEPAP_CNT[]
local mne
local dev
if(type=="ctrl") {
return
}
# p1 is the unit
# p2 is always 0
# p3 is the channel which is the two digits address
if(type=="cnt") {
mne=cnt_mne(num)
ICEPAP_CNT[mne]["addr"]=p3
# get the MASTER
ICEPAP_CNT[mne]["dev"]=""
dev=counter_par(num,"address")
if(dev==0) {
printf("ICEPAPCNT ERROR: missing ADDR field\n")
return
}
if(index(dev,":") == 0) { dev=sprintf("%s:5000",dev) }
ICEPAP_CNT[mne]["dev"]=dev
}
}'
#%IU%
#%MDESC%
#
def icepapcnt_cmd(num,key,p1,p2) '{
global ICEPAP_CNT[]
local mne
local addr
local dev
if (key == "counts") {
mne=cnt_mne(num)
addr=ICEPAP_CNT[mne]["addr"]
# get the MASTER
if(!("dev" in ICEPAP_CNT[mne])) { return }
dev=ICEPAP_CNT[mne]["dev"]
if(dev=="") { return }
S[num]=_icepapcnt_gettemp(dev,addr)
}
}'
#
# ----------------------- MACRO COUNTER implementation -----------------------
#
#%IU%(<counter_number>, <hostname:port>, <address>)
#%MDESC%
#
def _icepapenc_getpos(counter_num, dev, addr) '{
local ans
local t
local cmd
local typ
# "encoder" parameter is set to "inc" by default in config.
typ = counter_par(counter_num, "encoder")
cmd = ICEPAP_ENCCMD[typ]
ans = _icepap_query(dev,addr,sprintf("?ENC %s", cmd))
if(sscanf(ans, "%lf", t) != 1) {
_icepap_err
printf("counter \"%s\": addr: \"%s\": unable to get enc pos\n", \
cnt_mne(counter_num), addr)
icepap_chkerr(dev, ans)
icepap_fiforst(dev)
return(0)
}
# handle specific case of unsigned SSI encoders
if(typ == "absu") {
t += ((t<0)?(1<<counter_par(counter_num, "ssi")):0)
}
# normal end
return(t)
}'
#%UU% (<counter_mnemonic>)
#%MDESC%
# Returns value of encoder associated to macro-counter
# <encoder_mnemonic>.
# This function is similar to the previous one but provided to be
# user-callable by beeing more user-friendly.
def icepapenc_read(counter_mne) '{
local _dev _addr _res
if(!("dev" in ICEPAP_ENC[counter_mne])) {
printf("counter %s: unable to read encoder\n", counter_mne)
printf("--> check that your icepap macro counter is defined in SPEC config. \n")
return
}
else{
_dev = ICEPAP_ENC[counter_mne]["dev"]
_addr = ICEPAP_ENC[counter_mne]["addr"]
_res = _icepapenc_getpos(cnt_num(counter_mne), _dev, _addr)
return _res
}
}'
#%IU%(counter, hostname:port, address, pos)
#%MDESC%
#
def _icepapenc_setpos(num,dev,addr,pos) '{
local ans
local t
local cmd
local typ
typ = counter_par(num,"encoder")
if(index(typ,"abs")) {
_icepap_err
p "no sense to set the position of an absolute encoder"
return
}
cmd = ICEPAP_ENCCMD[typ]
ans = _icepap_wrrd(dev,sprintf("#%s",addr),sprintf("ENC %s %d",cmd,pos))
if(index(ans,"ERROR"))
{
_icepap_err
print ""ans
return
}
}'
#%UU% counter position
#%MDESC%
#
def icepap_setenc '{
if($#!=2) {
p "Usage: $0 counter position"
exit
}
_icepap_setenc("$1",$2)
}'
#%IU%(counter_mne, position)
#%MDESC%
#
def _icepap_setenc(mne,pos) '{
local addr
local dev
local num
addr=ICEPAP_ENC[mne]["addr"]
dev =ICEPAP_ENC[mne]["dev"]
if(addr == 0) {
_icepap_err
p "\""mne"\" not an ICEPAP encoder counter"
return
}
num = cnt_num(mne)
pos = pos * counter_par(num,"scale")
_icepapenc_setpos(num,dev,addr,pos)
}'
#%IU%
#%MDESC%
#
def icepapenc_config(num,type,p1,p2,p3) '{
global ICEPAP_ENC[]
global ICEPAP_ENCCMD[]
local mne
local dev
if(type=="ctrl") {
ICEPAP_ENCCMD["inc"] = "ENCIN"
ICEPAP_ENCCMD["abs"] = "ABSENC"
ICEPAP_ENCCMD["absu"] = "ABSENC"
ICEPAP_ENCCMD["inpos"] = "INPOS"
ICEPAP_ENCCMD["motor"] = "MOTOR"
ICEPAP_ENCCMD["axis"] = "AXIS"
ICEPAP_ENCCMD["sync"] = "SYNC"
dev = icepapenc_ADDR
ans=_icepap_query(dev,0,"?ID", silent)
if(ans == "")
{ return ".error." }
return
}
# p1 is the unit
# p2 is always 0
# p3 is the channel which is the two digits address
if(type=="cnt") {
mne=cnt_mne(num)
ICEPAP_ENC[mne]["addr"]=p3
# get the MASTER
ICEPAP_ENC[mne]["dev"]=""
dev=counter_par(num,"address")
if(dev==0) {
printf("ICEPAPCNT ERROR: missing ADDR field\n")
return ".error."
}
if(index(dev,":") == 0) { dev=sprintf("%s:5000",dev) }
ICEPAP_ENC[mne]["dev"]=dev
# get the type of encoder to read
typ = counter_par(num,"encoder")
if((typ == -1) || (typ == 0)) {
counter_par(num,"encoder","inc","add")
typ = "inc"
}
# minium check
if((index(typ,"abs") != 1) && !(typ in ICEPAP_ENCCMD)) {
_icepap_err
printf("invalid \"encoder\" parameter for counter \"%s\"", mne)
return ".error."
}
# handle the specific case of unsigned SSI encoders
if((typ != "abs") && index(typ,"absu")) {
local ssi
if(sscanf(typ,"absu%d",ssi) != 1) {
_icepap_err
printf("invalid \"encoder\" parameter \"absu\" for counter \"%s\"", mne)
return ".error."
}
counter_par(num,"encoder","absu")
counter_par(num,"ssi",ssi,"add")
ICEPAP_ENC[mne]["ssi"]=ssi
}
# normal end
ICEPAP_ENC[mne]["typ"]=typ
}
}'
#%IU%
#%MDESC%
#
def icepapenc_cmd(num,key,p1,p2) '{
global ICEPAP_ENC[]
local mne
local addr
local dev
if (num != "..") {
mne=cnt_mne(num)
addr=ICEPAP_ENC[mne]["addr"]
# get the MASTER
if(!("dev" in ICEPAP_ENC[mne])) { return }
dev=ICEPAP_ENC[mne]["dev"]
if(dev=="") { return }
}
if (key == "start_one") {
icepap_cleanup(dev)
}
if (key == "counts") {
return _icepapenc_getpos(num,dev,addr)
}
if (key == "halt_one") {
icepap_cleanup(dev)
}
}'
#
# ----------------------- MACRO COUNTER implementation -----------------------
#
#%IU%
#%MDESC%
#
def icepapcalc_config(num,typ,p1,p2,p3) '{
global ICEPAP_CALC[]
local mne
local crate
local type
local dev
if(typ=="ctrl") {
ICEPAP_CALC["min_crate"]=0
ICEPAP_CALC["max_crate"]=0
return
}
# p1 is the unit
# p2 is always 0
# p3 is the channel which is the two digits address
if(typ=="cnt") {
mne =cnt_mne(num)
crate=counter_par(num,"misc_par_1")
if((crate<0) || (crate>16)) {
p "\tERROR: counter "mne" unusable: invalid crate as \"misc_par_1\""
p "\tHINT: type \"help local icepap\""
return
}
type =counter_par(num,"misc_par_2")
if((type!="min") && (type!="max") && (type!="avg")) {
p "\tERROR: counter "mne" unusable: invalid type as \"misc_par_2\""
p "\tmust be \"max\" \"min\" or \"avg\""
p "\tHINT: type \"help local icepap\""
return
}
ICEPAP_CALC[mne]["crate"]=crate
ICEPAP_CALC[mne]["type"] =type
if(crate>ICEPAP_CALC["max_crate"]) { ICEPAP_CALC["max_crate"]=crate }
if(crate<ICEPAP_CALC["min_crate"]) { ICEPAP_CALC["min_crate"]=crate }
# get the MASTER
ICEPAP_CALC["dev"]=""
dev=counter_par(num,"address")
if(dev==0) {
printf("ICEPAPCALC ERROR: missing ADDR field\n")
return
}
if(index(dev,":") == 0) { dev=sprintf("%s:5000",dev) }
ICEPAP_CALC["dev"]=dev
}
}'
#%IU%
#%MDESC%
#
def icepapcalc_cmd(num,key,p1,p2) '{
global ICEPAP_CALC[]
local mne
local addr
local crate
local type
local t j c
local t_min t_max t_tot t_avg n_tot
local dev
if (key == "prestart_all") {
# get the MASTER
if(!("dev" in ICEPAP_CALC)) { return }
dev=ICEPAP_CALC["dev"]
if(dev=="") { return }
for(crate=ICEPAP_CALC["min_crate"];crate<=ICEPAP_CALC["max_crate"];crate++) {
t_max=0
t_min=0
t_tot=0
n_tot=0
for(j=1;j<=8;j++) {
addr=sprintf("%d%d",crate,j)
t=_icepapcnt_gettemp(dev,addr)
if(!t) { continue }
if(!t_min) { t_min=t }
if(t>t_max) { t_max=t }
if(t<t_min) { t_min=t }
t_tot += t
n_tot++
}
t_avg=t_tot/n_tot
ICEPAP_CALC[crate]["min"]=t_min
ICEPAP_CALC[crate]["max"]=t_max
ICEPAP_CALC[crate]["avg"]=t_avg
ICEPAP_CALC[crate]["n"] =n_tot
}
}
if (key == "counts") {
mne =cnt_mne(num)
type =ICEPAP_CALC[mne]["type"]
crate =ICEPAP_CALC[mne]["crate"]
S[num]=ICEPAP_CALC[crate][type]
}
}'
#
# ----------------------- MACRO COUNTER implementation -----------------------
#
#%IU%
#%MDESC%
#
def icepapmeas_config(num,type,p1,p2,p3) '{
global ICEPAP_MEAS[]
local mne
local dev
local cmd
if(type=="ctrl") {
return
}
# p1 is the unit
# p2 is always 0
# p3 is the channel which is the two digits address
if(type=="cnt") {
mne=cnt_mne(num)
ICEPAP_MEAS[mne]["addr"]=p3
# get the MASTER
ICEPAP_MEAS[mne]["dev"]=""
dev=counter_par(num,"address")
if(dev==0) {
printf("ICEPAPMEAS ERROR: \"%s\": missing ADDR field\n", mne)
return ".error."
}
if(index(dev,":") == 0) { dev=sprintf("%s:5000",dev) }
ICEPAP_MEAS[mne]["dev"]=dev
# get the command to read the DSP internals
cmd=counter_par(num,"cmd")
if(cmd==0) {
printf("ICEPAPMEAS ERROR: \"%s\": missing \"cmd\" parameter\n", mne)
return ".error."
}
ICEPAP_MEAS[mne]["cmd"]=cmd
}
}'
#%IU%
#%MDESC%
#
def icepapmeas_cmd(num,key,p1,p2) '{
global ICEPAP_MEAS[]
local mne
local addr
local dev
local cmd
if (num != "..") {
mne =cnt_mne(num)
addr=ICEPAP_MEAS[mne]["addr"]
dev =ICEPAP_MEAS[mne]["dev"]
cmd =ICEPAP_MEAS[mne]["cmd"]
}
if (key == "start_one") {
icepap_cleanup(dev)
}
if (key == "counts") {
local ans
local t
ans= _icepap_query(dev,addr,"?"cmd)
if(index(ans,"ERROR")) {
printf("ICEPAPMEAS ERROR: \"%s\": unable to get value\n",mne)
return(0)
}
if(sscanf(ans,"%lf",t) != 1) {
printf("ICEPAPMEAS ERROR: \"%s\": addr: %s: unable to get value\n",mne,addr)
icepap_chkerr(dev,ans)
icepap_fiforst(dev)
return(0)
}
return(t)
}
if (key == "halt_one") {
icepap_cleanup(dev)
}
}'
#
# ----------------------- direct accces macros -------------------------
#
#%UU% hostname cmd [args]
#%MDESC%
# Execute the specified command with its args on all
# ICEPAP modules (MASTER, SLAVES and DRIVERS) known by the hostname.
# Note that quotes must be used when cmd includes a hash for the
# acknowledge.
#
def icepap_all '{
local dev
local cmd
local i n
# Minimum check
if($# < 2) {
p "Usage: $0 icepap cmd [args]"
p " ex: $0 iceid131 ?ver info"
p " ex: $0 iceid131 \"\#power\" off"
exit
}
# Get args
dev = "$1"
if(!index(dev,":")) { dev = dev":5000" }
ICEPAP["dev"]=dev
# Get args
i = 1
n = split("$*", args)
for(cmd=args[i++];i<n;i++) {
cmd = cmd " " args[i]
}
_icepap_all(dev, cmd)
}'
#%IU%(hostname, cmd, prefix_string)
#%MDESC%
#
def _icepap_all(dev, cmd, prefix_string, only_slaves, only_drivers) '{
local ans
local addrs
local i n a
local prefix
if(!index(dev,":")) { dev = dev":5000" }
ICEPAP["dev"]=dev
# Optional line prefix
prefix = (prefix_string)?prefix_string:""
# Not needed
cmd = icepap__toupper(cmd)
# Just in case
icepap_fiforst(dev)
# Get the list of modules
ans = _icepap_get_addrs(dev)
n = split(ans, addrs)
# Execute the command on each module
for(i=0;i<n;i++) {
a = addrs[i]
if(only_slaves) {
if(a%10) {
continue
}
}
if(only_drivers) {
if((a%10) == 0) {
continue
}
}
if(substr(cmd,1,1)=="?") {
p prefix,a,_icepap_wrrd(dev,a,cmd);
} else if(substr(cmd,1,1)=="#") {
p prefix,a,_icepap_wrrd(dev,"#" a,substr(cmd,2));
} else {
_icepap_wr(dev,a,cmd);
}
}
}'
#%UU% [option] cmd
#%MDESC%
# Execute the specified command with its args on all
# ESRF ICEPAP systems which follow the naming convention
# (hostname starting with "ice...")
# The option could be "slaves" to execute the command only
# on MASTERS and SLAVES modules.
#
def icepap_all_esrf '{
local cmd args[]
local i n hosts[]
local dev
local slaves_only drivers_only debug_only
# minimum check
if($# < 1) {
p "Usage : $0 [option] cmd [args]"
p "Option: MASTERS | SLAVES | DRIVERS | DEBUG"
p " ex: $0 ?ver info"
p " ex: $0 MASTERS ?ver saved"
exit
}
# Grant access to avoid abusive use
onwiz 0
if(!spec_par("specwiz")) {
exit
}
# by default execute the command on MASTERS, SLAVES and DRIVERS
slaves_only = 0
drivers_only = 0
debug_only = 0
#
i = 0
n = split("$*", args)
for(;;) {
if(icepap__toupper(args[i]) == "DEBUG") {
i++
debug_only = 1
continue
}
if(icepap__toupper(args[i]) == "SLAVES") {
i++
slaves_only = 1
continue
}
if(icepap__toupper(args[i]) == "DRIVERS") {
i++
drivers_only = 1
continue
}
break
}
for(cmd=args[i++];i<n;i++) {
cmd = cmd " " args[i]
}
if(debug_only) {
n = 0
hosts[n++]="iceeu4"
hosts[n++]="icebcu1"
} else {
n = _icepap_get_all_hostnames(hosts)
if(n < 0) {
exit
}
if(n == 0) {
print "nothing to do, giving up"
exit
}
}
for(i=0;i<n;i++) {
host = hosts[i]
dev = host ":5000"
# avoid timeout messages
if(!sock_par(dev, "connect", "silent")) {
continue
}
_icepap_all(host, cmd, host, slaves_only, drivers_only)
sock_par(dev, "close")
}
}'
#%IU% [hostname [hostname [...]]]
#%MDESC%
# Print out the rack ID of all ESRF ICEPAP racks
#
def _icepap_rid_esrf '{
local i j n m hosts[]
local dev host
local ans addrs[] ids[]
local slaves_only
# Grant access to avoid abusive use
onwiz 0
if(!spec_par("specwiz")) {
exit
}
#
slaves_only = 1
#
if($#) {
n = split("$*", hosts)
} else {
n = _icepap_get_all_hostnames(hosts)
}
if(n < 0) {
exit
}
if(n == 0) {
print "nothing to do, giving up"
exit
}
for(i=0;i<n;i++) {
host = hosts[i]
dev = host ":5000"
# avoid timeout messages
if(!sock_par(dev, "connect", "silent")) {
continue
}
ans = _icepap_get_addrs(dev, slaves_only)
m = split(ans, addrs)
for(cmd="?RID", j=0;j<m;j++) {
cmd = sprintf("%s %d", cmd, addrs[j]/10)
}
ans = _icepap_wrrd(dev, "", cmd)
m = split(ans, ids)
for(j=1;j<m;j++) {
printf("%15s %2d %s\n", host, addrs[j-1]/10, ids[j])
}
sock_par(dev, "close")
}
}'
#%IU%(host[])
#%MDESC%
# Fills the given associative array with all ICEPAP hostnames
# found in DNS and which start with "ice..."
# Returns the number of system or -1 if error occured.
#
def _icepap_get_all_hostnames(hosts) '{
local i cmd aux lines[]
local j host
cmd = "host -l \"esrf.fr\" | grep ice | cut -d\' \' -f1"
cmd = cmd " | cut -d\'.\' -f1"
cmd = cmd " | grep -v nice"
if(unix(cmd, aux) != 0) {
_icepap_err
print "error accessing DNS to list IcePAP hostnames"
return(-1)
}
split(aux, lines, "\n")
for(i in lines) {
host = lines[i]
if(substr(host, 0, 3) != "ice") {
continue
}
hosts[j++] = host
}
return(j)
}'
#%IU%(hostname, slaves_only)
#%MDESC%
# Returns the addresses of all ICEPAP modules alive on the
# specficed hostname. The addresses are returned in a single string,
# blank separated.
#
def _icepap_get_addrs(dev, slaves_only) '{
local cmd_ans
local addrs
local rflg
local r
local dflg
local d
local a
addrs = ""
cmd_ans = _icepap_query(dev,"","?SYSSTAT")
if(index(cmd_ans,"ERROR"))
{
printf("ICEPAP: sorry, too old firmware to guess racks present\n")
return(addrs)
}
sscanf(cmd_ans,"%x",rflg)
for(r=0;r<16;r++)
{
if(!(rflg & (1<<r))) { continue }
cmd_ans = _icepap_query(dev,"",sprintf("?SYSSTAT %d",r))
if(index(cmd_ans,"ERROR")) return(addrs)
cmd_ans=substr(cmd_ans,index(cmd_ans," ")+1)
sscanf(cmd_ans,"%x",dflg)
for(d=0;d<=8;d++)
{
if((d!=0) && !(dflg & (1<<(d-1)))) { continue }
a=(d)+(r*10)
addrs = sprintf("%s%d ",addrs,a)
if(slaves_only) {
break
}
}
}
return(addrs)
}'
#%IU%(bliss_package_name)
#%MDESC%
#
def _is_package_installed(pkg) '{
local ll
local cmd
cmd = "rpm --dbpath ~blissadm/admin/RPM -qa"
cmd = sprintf("%s | grep \"%s\"",cmd, pkg)
unix(cmd,ll)
if(ll=="") {
p "ERROR: missing package \"",pkg,"\""
p "HINT : use \"blissinstaller\""
exit
}
}'
#%IU%(icepap_hostname)
#%MDESC%
#
def _is_same_subnetwork(dev) '{
local ll
local cmd
local dev_ip[]
local host_ip[]
cmd = sprintf("nslookup `hostname`")
cmd = sprintf("%s |grep -i \"address\"|grep -v \"#\"|cut -d\':\' -f2",cmd)
unix(cmd, ll)
if(ll=="") {
p "ERROR: unable to get hostname IP, giving up"
exit
}
split(ll, host_ip, ".")
cmd = sprintf("nslookup %s", dev)
cmd = sprintf("%s |grep -i \"address\"|grep -v \"#\"|cut -d\':\' -f2",cmd)
unix(cmd, ll)
if(ll=="") {
p "ERROR: unable to get \""dev"\" IP, giving up"
exit
}
split(ll, dev_ip, ".")
if(dev_ip[2] != host_ip[2]) {
p "ERROR: not on same sub-network than \""dev"\", giving up"
p "HINT : use spec on another machine"
exit
}
}'
#%IU%(firmwares_list)
#%MDESC%
#
def _is_valid_version(dev, ll) '{
local fw_list[]
local fw_n
local fw_cur
local ans
fw_n = split(ll,fw_list)
ans=_icepap_query(dev, "", "?VER")
if(index(ans,"ERROR"))
{
p "ERROR: unable to get icepap system version, giving up"
p "HINT : switch on \""dev"\""
exit
}
fw_cur=icepap_trim(ans)
for(n in fw_list) {
if(fw_list[n] == fw_cur)
return
}
p "ERROR: wrong current firmware version \""fw_cur"\" on \""dev"\""
p "HINT : must be one of these \""ll"\""
exit
}'
#%IU%(icepap_hostname)
#%MDESC%
#
def _is_alive(dev) '{
local silent
local ans
local cmd
local n
cmd = sprintf("ping -c 1 %s > /dev/null",dev)
for(n=5;n;n--) {
if(!unix(cmd)) {
# Linux is up but give time to the embedded program to start
sleep(1)
# Restore SPEC socket connection
if(!index(dev,":")) { dev = dev":5000" }
sock_par(dev,"close")
sock_par(dev,"connect")
# Check that the embedded program started well
silent = 1
ans=_icepap_query(dev,0,"?ID", silent)
if(ans == "") {
p "ERROR: the embedded program is not running on \""dev"\""
p "HINT : reboot it by cycling its power supply (off/on)"
return ".error."
}
# Normal end
return ""
}
sleep(1)
}
p "ERROR: timeout waiting for \""dev"\" to be alive"
return ".error."
}'
#%IU%(dev, addr_list)
#%MDESC%
# Bypass external disable signal on the list of drivers given.
# (this was done with DISDIS command on old firmwares <2.0)
# Works only on firmware >=2.0
#
def _emulate_alldis(dev, addr_list) '{
local ll
local i
split(addr_list, ll)
for(i in ll) {
_emulate_onedis(dev, ll[i])
}
}'
#%IU%(dev, addr)
#%MDESC%
# Bypass external disable signal on the driver given.
# (this was done with DISDIS command on old firmwares <2.0)
# Works only on firmware >=2.0
#
def _emulate_onedis(dev, addr) '{
local ans
local cmd
local signature
ans = _icepap_query(dev, addr, "?MODE")
if(!index(ans,"OPER"))
{
p "ERROR: driver \""addr"\" not in OPER mode, giving up"
exit
}
ans = _icepap_query(dev, addr, "?CONFIG")
signature = ans
cmd = sprintf("%sCONFIG",spec_par("specwiz")?"BD_":"")
ans = _icepap_query(dev, "#"addr, cmd)
if(index(ans,"ERROR"))
{
p "ERROR: unable to enter CONFIG on driver \""addr"\", giving up"
exit
}
cmd = sprintf("%sCFG EXTDISABLE NONE",spec_par("specwiz")?"BD_":"")
ans = _icepap_query(dev, "#"addr, cmd)
if(index(ans,"ERROR"))
{
p "ERROR: unable to change EXTDISABLE on driver \""addr"\", giving up"
exit
}
cmd = sprintf("%sCONFIG \"%s\"",spec_par("specwiz")?"BD_":"", signature)
ans = _icepap_query(dev, "#"addr, cmd)
if(index(ans,"ERROR"))
{
p "ERROR: unable to change CONFIG on driver \""addr"\", giving up"
exit
}
}'
#%UU% hostname
#%MDESC%
# Upgrade the specified icepap system from firmware 1.22 to 2.0
# If called from SPEC wizard mode, the security of the mandatory
# same subnetwork is bypassed.
#
def upgrade_firmware_1_22 '{
local dev
local fname
local addr
local opt
local dis_list
local msg
local i
# Minimum check
if($# < 1) {
p "Usage: $0 hostname"
p " ex: $0 iceid131"
exit
}
dev = "$1"
# Dangerous macro
p "\nWARNING: this macro will upgrade all the firmwares of \"$1\""
if(!yesno("Do you want to continue",0)) {
p "Giving up"
exit
}
p ""
# Check that packages have been upgarded
_is_package_installed("icepapcms-src-1.28")
_is_package_installed("icepap_firmware-src-2.0")
# Check that the system has firmware version 1.22 or 1.225
_is_valid_version(dev, "1.22 1.225")
# Check that we are on the same subnetwork
if(!spec_par("specwiz")) {
_is_same_subnetwork(dev)
}
# Do an inventory of axis with external signal disabled
p "Collectng list of axis with external disable signal bypassed"
dis_list = _icepap_alldis(dev, 1)
# Keep inventory into a file
# Upgrade firmwares
fname = "/users/blissadm/local/userconf/icepap/icepfw_2.0"
addr = "ALL"
opt = "FORCE"
p "Upgrading FPGA/DSP firmwares"
_icepap_prog(dev,fname,addr,opt)
# Upgrade MCPUx firmwares
addr = "MCPU0"
p "Upgrading embedded Linux firmwares"
_icepap_prog(dev,fname,addr,opt)
addr = "MCPU1"
_icepap_prog(dev,fname,addr,opt)
addr = "MCPU2"
_icepap_prog(dev,fname,addr,opt)
# Save new firmware into the icepap system flash
addr = "NONE"
opt = "SAVE"
p "Saving new firmware package into embedded flash"
_icepap_prog(dev,fname,addr,opt)
# Reboot the icepap system to run the new MCPUx and set RDISPOL
p "Reboot the system and wait for its wake up"
_icepap_query(dev,"#","REBOOT")
sleep(20)
if(_is_alive(dev) != "") {
p "HINT : after the reboot run the following macro:"
p sprintf("_emulate_alldis(\"%s\",\"%s\")",dev, dis_list)
exit
}
# Restore external disable signal
p "Restoring external disable signal bypasses"
_emulate_alldis(dev, dis_list)
# Normal end
p "Bravo\! System should be upgraded"
if(i=index(dev,":")) { dev = substr(dev, 0, i-1) }
msg = sprintf("%s", date())
msg = sprintf("%s\nsystem : %s", msg, dev)
msg = sprintf("%s\nupgraded to : 2.0", msg)
msg = sprintf("%s\nDISDIS kept : %s", msg, dis_list)
_icepap_email(sprintf("%s: UPGRADE", dev), msg)
}'
#%UU% hostname
#%MDESC%
# Will try to guess if the DISDIS parameter is really needed on
# each DRIVER of the specified ICEPAP systerm. If not needed, the
# macro will remove it.
# WARNING: this macro is for temporary usage only.
#
def icepap_alldis '{
local dev
local silent
# Minimum check
if($# < 1) {
p "Usage: $0 icepap"
p " ex: $0 iceid131"
exit
}
# Get args
dev = "$1"
ICEPAP["dev"]=dev
silent = 0
_icepap_alldis(dev, silent)
}'
def _icepap_alldis(dev, silent) '{
global ICEPAP[]
local cmd_ans
local rflg
local r
local dflg
local d
local addr
local was_on
local addr_list
local del_list
local msg
local i
# Just in case
if(!index(dev,":")) { dev = dev":5000" }
icepap_fiforst(dev)
# Check if firmware is a valid one
cmd_ans = _icepap_wrrd(dev,"","?SYSSTAT")
if(index(cmd_ans,"ERROR"))
{
printf("ICEPAP: sorry, too old firmware to guess racks present\n")
exit
}
addr_list = ""
del_list = ""
cmd_ans = _icepap_query(dev,"","?SYSSTAT")
sscanf(cmd_ans,"%x",rflg)
for(r=0;r<16;r++)
{
if(!(rflg & (1<<r))) { continue }
cmd_ans = _icepap_query(dev,"",sprintf("?SYSSTAT %d",r))
if(index(cmd_ans,"ERROR")) exit;
cmd_ans=substr(cmd_ans,index(cmd_ans," ")+1)
sscanf(cmd_ans,"%x",dflg)
# Skip COMM or MASTER modules
for(d=1;d<=8;d++)
{
if((d!=0) && !(dflg & (1<<(d-1)))) { continue }
addr=(d)+(r*10)
cmd_ans = _icepap_query(dev,addr,"?DISDIS")
if(index(cmd_ans,"ERROR")) continue;
if(int(cmd_ans) != 1) { continue }
if(!silent) { printf("Found driver with DISDIS set: %02d\n",addr) }
# Keep a record of the current state in any case
cmd_ans=_icepap_query(dev,addr,"?POWER")
was_on =(index(cmd_ans,"ON")?1:0)
if(!silent) { printf("\tPOWER is %s\n",(was_on?"ON":"OFF")) }
# Try to disable DISDIS
if(was_on)
{
cmd_ans=_icepap_query(dev,"#" addr,"POWER OFF")
if(index(cmd_ans,"ERROR"))
{
printf("ERROR: switching off power\n")
printf("Giving up\n")
continue;
}
}
cmd_ans=_icepap_query(dev,"#" addr,"DISDIS 0")
if(index(cmd_ans,"ERROR"))
{
printf("ERROR: removing DISDIS parameter\n")
printf("Giving up\n")
continue;
}
# Try to guess if DISDIS is really needed
cmd_ans=_icepap_query(dev,addr,"?ISG ?PWRINFO")
if(index(cmd_ans,"axis remote disable signal on"))
{
if(!silent) { printf("\tDISDIS needed\n") }
addr_list = sprintf("%s%s ", addr_list, addr)
cmd_ans=_icepap_query(dev,"#" addr,"DISDIS 1")
if(index(cmd_ans,"ERROR"))
{
printf("ERROR: setting DISDIS parameter\n")
}
}
else
{
del_list = sprintf("%s%s ", del_list, addr)
if(!silent) { printf("\tDISDIS not needed, removed !!!!!!!!!!!!!!\n") }
}
# Put back power if needed
if(was_on)
{
if(!silent) { printf("\tPOWER set %s\n",(was_on?"ON":"OFF")) }
cmd_ans=_icepap_query(dev,"#" addr,"POWER ON")
if(index(cmd_ans,"ERROR"))
{
printf("ERROR: switching on power\n")
printf("Giving up\n")
continue;
}
}
}
}
printf("\tDISDIS kept : \"%s\"\n",addr_list)
printf("\tDISDIS deleted : \"%s\"\n",del_list)
# Normal end, return the list of drivers than need DISDIS
if(i=index(dev,":")) { dev = substr(dev, 0, i-1) }
msg = sprintf("%s", date())
msg = sprintf("%s\n%s", msg, dev)
msg = sprintf("%s\nDISDIS kept : %s", msg, addr_list)
msg = sprintf("%s\nDISDIS deleted: %s", msg, del_list)
_icepap_email(sprintf(" %s: DISDIS", dev), msg)
return addr_list
}'
#%UU% [hostname[:port]]
#%MDESC%
# Console implementation to communicate to icepap MASTER
#
def icepap '{
global ICEPAP[]
global ICEPAP_NCOMM
global ICEPAP_HIST[]
global ICEPAP_NHIST
global ICEPAP_CHIST
local dev
local line c fc
local args[]
local i inst
local begline endline
if($# < 1) {
dev=getval("Icepap MASTER network name",ICEPAP["dev"])
} else {
dev="$1"
}
if(!index(dev,":")) { dev = dev":5000" }
ICEPAP["dev"]=dev
cdef("cleanup_once",sprintf("_icepap_close(\"%s\")\n",dev),"ICEPAP")
if(sock_put(dev, "?_help\n") == -1) { exit }
sleep(0.1)
sock_par(dev,"timeout",2)
p "\n" sock_get(dev)
while(1) {
line = ""
inst = 0
printf("\n%d.ICEPAP console> ",ICEPAP_NCOMM);
while(1) {
c = input(-1)
if (c == "\n") {
# handle carriage return
printf("\n")
tty_cntl("cd")
break
}
# handle backspace
if ((c == "\b" || c == "\177") && (line != "")) {
if((length(line)+inst)<=0) {
continue
}
begline = substr(line, 0, length(line)+inst-1)
endline = substr(line, length(line)+inst+1)
line = begline endline
printf("\b%s ",endline)
for(i=0;i>=inst;i--) {
printf("\b")
}
continue
}
# handle arrow keys
if (asc(c) == 27) {
# arrow keys send 3 control chars
sleep(0.05)
c = input(-1)
sleep(0.01)
c = input(-1)
# left arrow
if(asc(c) == 0x44) {
if((length(line)+inst)<=0) {
continue
}
printf("\b")
inst--
}
# right arrow
if(asc(c) == 0x43) {
if(inst>=0) {
continue
}
i = length(line)+inst
for(;i;i--) {
printf("\b")
}
inst++
begline = substr(line, 0, length(line)+inst)
printf(begline)
}
# up arrow
if(asc(c) == 0x41) {
if(ICEPAP_CHIST) {
line = ICEPAP_HIST[--ICEPAP_CHIST]
printf("\r")
tty_cntl("cd")
printf("%d.ICEPAP console> %s",ICEPAP_NCOMM,line);
}
}
# down arrow
if(asc(c) == 0x42) {
if(ICEPAP_CHIST<ICEPAP_NHIST) {
line = ICEPAP_HIST[++ICEPAP_CHIST]
printf("\r")
tty_cntl("cd")
printf("%d.ICEPAP console> %s",ICEPAP_NCOMM,line);
}
}
continue
}
# append new printable character
if (c >= " " && c <= "z") {
printf(c)
if(!inst) {
line = line c
continue
}
begline = substr(line, 0, length(line)+inst)
endline = substr(line, length(line)+inst+1)
line = begline c endline
printf("%s",endline)
for(i=0;i>inst;i--) {
printf("\b")
}
}
sleep(0.01)
}
# keep an history of all entered commands
if(line) {
ICEPAP_HIST[ICEPAP_NHIST]=line
ICEPAP_NHIST++
ICEPAP_CHIST=ICEPAP_NHIST
}
split(line,args)
if(!args[0]) {
continue
}
if(whatis(args[0]) & 0x00000002) {
eval(line)
continue
}
uline = icepap__toupper(line)
if((uline == "QUIT") || (uline == "CLOSE")) {
sock_par(dev,"close")
exit
}
fc = substr(line,1,1)
if((fc!="#") && (fc!=":")) {
line = "#" line
}
# acknowledge of broadcast commands is forbidden
if(fc==":") {
_icepap_wr(dev,"",line)
} else {
ans = _icepap_query(dev,"",line,1)
p icepap_trim(ans)
}
ICEPAP_NCOMM++
}
}'
#%IU%(string, n)
#%MDESC%
# Parse the string to get the ICEPAP device to talk to.
# Try to get as nth argument (starting from 1) in the string,
# if not prompt the user.
#
def _icepap_getdev(str, i) '{
local args[]
local n
local dev
local sl
n=split(str,args)
if(n < i) {
dev=getval("Icepap MASTER network name or SL",ICEPAP["dev"])
} else {
dev=args[i-1]
}
sl = (dev + 0 == dev)?1:0
if(!sl && !index(dev,":")) { dev = dev":5000" }
ICEPAP["dev"]=dev
return(dev)
}'
#%IU%(string, n)
#%MDESC%
# Parse the string to get the ICEPAP tocho file.
# Try to get as nth argument (starting from 1) in the string,
# if not prompt the user.
#
def _icepap_getfname(str, i) '{
local args[]
local n
local fname
local fdir
local uxcom
local aux
local m
local flist[]
local f
n=split(str,args)
if(n < i) {
fdir=sprintf("%s/%s",BLISSADM,"local/userconf/icepap");
if(!file_info(fdir)) {
print "ERROR: missing icepap_firmware, hint: use \"blissinstaller\""
exit
}
uxcom = "cd " fdir "; ls -rt"
unix(uxcom, aux)
m = split(aux, flist, "\n")
for(m--;m;m--)
{
f=flist[m]
if(f=="") continue;
if(file_info(sprintf("%s/%s",fdir,f),"isdir")) continue;
break;
}
fname=sprintf("%s/%s",fdir,flist[m])
fname=getval("Binary program file",fname)
} else {
fname=args[i-1]
}
if(file_info(fname,"-r") == 0) {
print "ERROR: unable to read file \""fname"\""
exit
}
return(fname)
}'
#%IU%(string, n)
#%MDESC%
# Parse the string to get the addr for programming.
# Try to get as nth argument (starting from 1) in the string,
# if not prompt the user.
#
def _icepap_getaddr(str, i) '{
local args[]
local n
local addr
n=split(str,args)
if(n < i) {
addr=getval("What to program (\"ALL\"|\"DRIVERS\"|\"CONTROLLERS\"|\"NONE\"|addr) ",\
"NONE")
} else {
addr=args[i-1]
}
addr = icepap__toupper(addr)
if(addr=="NONE") { addr="" }
return(addr)
}'
#%IU%(string, n)
#%MDESC%
# Parse the string to get the options for programming.
# Try to get as nth argument (starting from 1) in the string,
# if not prompt the user.
# Any remaining argument is also return as option.
#
def _icepap_getopts(str, i) '{
local args[]
local n
local opt
n=split(str,args)
if(n < i) {
opt=getval("Options (\"SAVE\"|\"SL\"|\"FORCE\"|\"NONE\") ","NONE")
} else {
opt=args[i-1]
for(;i<n;i++) { opt=opt " " args[i] }
}
opt = icepap__toupper(opt)
if(opt =="NONE") { opt ="" }
return(opt)
}'
#%IU%(dev, filename, address, options)
#%MDESC%
# Check that the giving programming options are compatible with
# system to upgrade.
# Returns non null if error.
#
def _icepap_checkprog(dev, fname, addr, opts) '{
local tt[]
local ver
local ver_sl
local ret
#
# only old "tochos" can be used over serial line
#
# return if no serial line prog will take place
if(!index(icepap__toupper(opts), "SL")) {
return 0
}
# get firmware version
if(split(fname, tt, "icepfw_") < 2) {
_icepap_err
print "unable to parse firmware file name:"
print fname
return -1
}
ver = icepap_trim(tt[1])
ver_sl = "2.115"
if(_icepap_fw_compare(ver, ver_sl) != 0) {
_icepap_err
printf("only firmware %s can be used over serial line\n", ver_sl)
return -1
}
# get system version
ver = _icepap_fw_controller(dev)
ret = _icepap_fw_compare(ver, ver_sl)
if((ret < 0) || (ret > 1)) {
_icepap_err
printf("upgrade MASTER to at least firmware %s\n", ver_sl)
return -1
}
# normal end
return 0
}'
#%IU%(string, n)
#%MDESC%
# Parse the string to get the rack addresses for programming.
# Try to get as nth argument (starting from 1) in the string,
# if not prompt the user.
# Any remaining argument is also return as option.
#
def _icepap_getracks(str, i) '{
local args[]
local n
local racks
n=split(str,args)
if(n < i) {
racks=getval("List of racks (ex: 0 3)",0)
} else {
racks=args[i-1]
for(;i<n;i++) { racks=racks " " args[i] }
}
racks = icepap__toupper(racks)
return(racks)
}'
#%UU% [hostname[:port] [file] [rack ... ]]
#%MDESC%
# Program a the ICEPAP specified list of racks using the rack back plane
# serial line.
#
def icepap_rprog '{
local dev
local fname
local racks
local sl
local cmd_ans
# Get args or prompt them to the user
dev = _icepap_getdev ("$*", 1)
fname = _icepap_getfname("$*", 2)
racks = _icepap_getracks("$*", 3)
sl = (dev + 0 == dev)?1:0
# Get a connection to ICEPAP
if(!sl) { _icepap_check(dev) }
# Send this with acknowledge to ensure that all DRIVERs mode have changed
cmd = "#MODE PROG"
printf("\tCommand sent : \"%s\"\n", cmd)
if(sl)
{
ser_put(dev,sprintf("%s\n",cmd))
}
else
{
cmd_ans = _icepap_wrrd(dev,"",cmd)
if(!index(cmd_ans,"MODE OK"))
{
_icepap_err
print "unable to switch ICEPAP to programmation mode"
exit
}
}
cmd = sprintf("*RPROG %s",racks)
printf("\tCommand sent : \"%s\"\n", cmd)
if(sl) { ser_put(dev,sprintf("%s\n",cmd)) } else { _icepap_wr(dev,"",cmd) }
# Send the binary data
# _icepap_wrbin(dev,fname)
}'
#%UU% [hostname[:port] [file] [addr] [options]]
#%MDESC%
# Program a the ICEPAP module with the specified binary file
#
def icepap_prog '{
local dev
local fname
local addr
local opt
# Get args or prompt them to the user
dev = _icepap_getdev ("$*", 1)
fname = _icepap_getfname("$*", 2)
addr = _icepap_getaddr ("$*", 3)
opt = _icepap_getopts ("$*", 4)
if(_icepap_checkprog(dev, fname, addr, opt)) {
exit
}
_icepap_prog(dev,fname,addr,opt)
}'
#%IU%(dev,fname,addr,opt)
#%MDESC%
# Program a the ICEPAP module with the specified arguments.
# If no firmware file name is given, the programmatino will used
# the firmware saved in the controller flash.
#
def _icepap_prog(dev,fname,addr,opt) '{
global ICEPAP[]
local sl
local cmd
local cmd_ans
local dest_mcpu
local dest_none
local use_saved
local dodo
# Get a connection to ICEPAP
sl = (dev + 0 == dev)?1:0
if(!sl && !index(dev,":")) { dev = dev":5000" }
if(!sl) { _icepap_check(dev) }
dest_mcpu=index(addr,"MCPU")
dest_none=(addr=="")?1:0
# Minimum check on parameters validity
if(dest_none && opt == "")
{
_icepap_err
print "nothing to do, giving up"
exit
}
# If no firmware file, then use the saved one
use_saved = (fname=="")
# Skip mode handling if no DSP or FPGA is concerned
if(!dest_none && !dest_mcpu)
{
# Send this with acknowledge to ensure that all DRIVERs mode have changed
cmd = "#MODE PROG"
printf("\tCommand sent : \"%s\"\n", cmd)
if(sl)
{
ser_put(dev,sprintf("%s\n",cmd))
}
else
{
cmd_ans = _icepap_wrrd(dev,"",cmd)
if(!index(cmd_ans,"MODE OK"))
{
_icepap_err
print "unable to switch ICEPAP to programmation mode"
exit
}
}
}
cmd = sprintf("%sPROG %s %s",(use_saved?"":"*"),addr, opt)
printf("\tCommand sent : \"%s\"\n", cmd)
if(sl) { ser_put(dev,sprintf("%s\n",cmd)) } else {
_icepap_wr(dev,"",cmd)
}
# Send the binary data
if(!use_saved) { _icepap_wrbin(dev,fname) }
#Skip mode handling if no DSP or FPGA is concerned
#if(!dest_none && !dest_mcpu)
if(!dest_mcpu)
{
ans="?????"
printf("\tState : %-20s\r",ans)
# NOTE MP 08Apr11: should be replaced by an acknowled on *PROG cmd
sleep(1)
cmd="?_PROG"
if(index((_icepap_wrrd(dev,"",cmd)),"ERROR")) { cmd="?PROG" }
for(;index((ans= _icepap_query(dev,"",cmd)),"ACTIVE");sleep(.5))
printf("\tState : %-20s\r",ans);
printf("\tState : %-20s\n",ans)
sleep(2)
}
else
{
ans=" DONE"
printf("\tState :%-20s\n",ans)
}
if(!dest_none && !dest_mcpu)
{
# Give time to the drivers to come back to life
dodo = 5
printf("\tWait for : %dsecs\n", dodo)
sleep(dodo)
cmd = "#MODE OPER"
printf("\tCommand sent : \"%s\"\n", cmd)
if(sl)
{
ser_put(dev,sprintf("%s\n",cmd))
}
else
{
cmd_ans = _icepap_wrrd(dev,"",cmd)
if(!index(cmd_ans,"MODE OK"))
{
_icepap_err
print "unable to switch ICEPAP to operation mode"
exit
}
}
}
# Check if a reboot is needed
cmd="?VER"
if(index((_icepap_wrrd(dev,"",cmd)),"ERROR Reboot is needed"))
{
cmd = "REBOOT"
printf("\tCommand sent : \"%s\"\n", cmd)
printf("NOTE: the connection to \"%s\" will be unusable during 30s\n",dev)
_icepap_wr(dev,"",cmd)
}
}'
#%IU%(dev,fname)
#%MDESC%
# Send the contain of the file to the ICEPAP using the ISG
# binary transfer protocol.
#
def _icepap_wrbin(dev,fname) '{
local sl
local bin_l
local bin_chksum
sl = (dev + 0 == dev)?1:0
bin_l = (file_info(fname,"size")/2) & 0xffffffff
local ushort array icepapfw[bin_l]
fmt_read(fname,"raw",icepapfw)
# 2 words startup mark (ex: 0xa5aa555a)
local ulong array datal[1]
datal[0]=0xa5aa555a
if(sl) { ser_put(dev, datal) } else { sock_put(dev, datal) }
# 2 words for the binary data length
datal[0]=bin_l
if(sl) { ser_put(dev, datal) } else { sock_put(dev, datal) }
# 2 words for the checksum
bin_chksum = (array_op("sum",icepapfw)) & 0xffffffff
printf("\tCheck sum : 0x%08X\n", bin_chksum)
datal[0]=bin_chksum
if(sl) { ser_put(dev, datal) } else { sock_put(dev, datal) }
# chaud devant !!!
printf("\tTransferring : %d words\n", bin_l)
if(sl) { ser_put(dev, icepapfw) } else { sock_put(dev, icepapfw) }
}'
#%IU% [hostname:port]
#%MDESC%
# Reset the MASTER DSP
#
def icepap_mdspreset '{
global ICEPAP[]
local dev
if($# < 1) {
dev=getval("Icepap MASTER network name",ICEPAP["dev"])
} else {
dev="$1"
}
if(!index(dev,":")) { dev = dev":5000" }
ICEPAP["dev"]=dev
sock_put(dev,"_dsprst\n")
print "MASTER DSP reseted"
}'
#%IU% [hostname:port [driver]]
#%MDESC%
# Program one or all DRIVER DSP numbered from 1 to 8
# using the backplane serial line and the DDSP programm taken
# from MDSP flash (no binary transferred)
#
def icepap_ddsppgm_sl '{
local dev
local board
if($# < 1) {
dev=getval("Icepap MASTER network name","isgtmp5:5000")
} else {
dev="$1"
}
_icepap_check(dev)
# Ya un couillon au clavier ?
board=0
if($# < 2) {
board=getval("Icepap DRIVER to program from 1 to 8 (0 for all)",board)
} else {
board=$2
}
if((board<0) || (board>8))
{
print "ICEPAP: invalid channel/board "board" (valid: 1 to 8 or 0 for all)"
return
}
# ok, on peut bosser
if (board) { p "\tProgramming board: "board }
else { p "\tProgramming all boards" }
sock_put(dev,sprintf("PROG %d\n",board))
p "\tBe patient....."
p "\tHint: check messages on DSP serial line console of MASTER"
}'
#%IU%(hostname:port)
#%MDESC%
# Do not touch, needed by the "raleur"
#
def _icepap_check(dev) '{
local ans
# Allo? Gaston? Tes la?
sock_par(dev,"close")
if(!sock_par(dev,"connect"))
{
_icepap_err
print "communication program not running on MASTER"
print "Hint: reset MASTER or run \"icepap_sock\" on ",dev
exit
}
sock_par(dev,"timeout",ICEPAP_TIMEOUT)
ans=_icepap_query(dev,"","?_SOCKPING")
if(ans != "OK") {
_icepap_err
print "bad response from MASTER"
print "Hint: reset MASTER or run \"icepap_sock\" on ",dev
exit
}
}'
#%IU%(hostname:port)
#%MDESC%
#
def _icepap_close(dev) '{
sock_put(dev,"_SOCKCLOSE\n");
sock_par(dev,"close");
}'
#%IU%
#%MDESC%
#
def _icepap_err '{
tty_cntl("md")
printf("ICEPAP ERROR: ")
tty_cntl("me")
}'
#%IU%
#%MDESC%
#
def _icepap_warn '{
tty_cntl("md")
printf("ICEPAP WARNING: ")
tty_cntl("me")
}'
#%IU%(num, status)
#%MDESC%
#
def _icepap_postmove(num) '{
global ICEPAP[]
local mne
mne = motor_mne(num)
if(ICEPAP[mne]["wasmoving"] == 0) { return }
ICEPAP[mne]["wasmoving"] = 0
user_icepap_postmove_one num
}'
#%IU%(num, status)
#%MDESC%
# Decode stop reason for the driver status given.
# No action, print only for diagnostic
#
def _icepap_stopcode(num, sta) '{
global ICEPAP[]
local stop_code
local mne
# Stop code implemented on bits 14-17
stop_code = (sta & ((1<<14)|(1<<15)|(1<<16)|(1<<17))) >> 14
# Normal case is code 0
if(!stop_code) { return(0) }
# Ignore limitswitches
if((stop_code==3) || (stop_code==4)) { return(0) }
# Treat the stop code only once
mne = motor_mne(num)
if(stop_code == ICEPAP[mne]["stop_code"]) { return(1) }
ICEPAP[mne]["stop_code"]=stop_code
# Abnormal stop case
_icepap_warn
printf("\"%s\": abnormal stop condition: %s\n", \
mne, _icepap_stopcode2str(mne, stop_code))
return(1)
}'
#%IU%(mne, stop_code)
#%MDESC%
# Returns a string describing the given stop code for the given motor.
#
def _icepap_stopcode2str(mne, stop_code) '{
global ICEPAP[]
global ICEPAP_STOPCODE[]
local dev
if(stop_code in ICEPAP_STOPCODE) {
return(ICEPAP_STOPCODE[stop_code])
}
# After firmware release 3.03 the stop code bit has been
# reused for other stop conditions that can be retrieved
# with a new command
dev = ICEPAP[mne]["dev"]
if((stop_code == 5) && (ICEPAP[dev]["hrev"] < 3)) {
return("closed loop settling timeout")
}
if(stop_code == 5) {
local addr ans
local ext_stop_code
# NOTE MP 22thNov2016:
# currently there is no way to get stop code for a linked axis
if(ICEPAP[mne]["linked"] == "YES") {
return("use \"linkedstat\" for details")
}
addr = ICEPAP[mne]["addr"]
ans = _icepap_query(dev, addr, "?STOPCODE")
if(index(cmd_ans,"ERROR")) {
return("close loop settling timeout")
}
if(sscanf(ans, "%x", ext_stop_code) != 1) {
return("unknown (error on ?STOPCODE)")
}
# the four first bits are repeating the information already
# present in the stop code bits of the status
ext_stop_code &= 0x00F0
ext_stop_code >>= 4
if(ext_stop_code == 1) {
return("close loop settling timeout")
}
if(ext_stop_code == 2) {
return("external hold signal active")
}
}
return("unknown")
}'
#%IU%(dev,addr,cmd)
#%MDESC%
#
def _icepap_wr(dev, addr, cmd) '{
local str
global ICEPAP_HISTORY[]
if(addr != "" && addr != "#") str=addr":"cmd; else str=cmd;
if (addr == "#") str = "#" str
icepap__debug dev ":==>" str
_icepap_hist_add(dev, str)
str=str"\n"
sock_par(dev,"flush")
sock_put(dev,str);
}'
#%IU%(ans)
#%MDESC%
# Returns the last valid char of the IcePAP answer.
# The terminator chars are ignored.
#
def _icepap_lastchar(ans) '{
local c
local idx
for(idx=length(ans);idx;idx--) {
c=substr(ans, idx, 1)
if(c!="\r" && c!="\n")
break;
}
return(c)
}'
#%IU%(dev,addr,cmd)
#%MDESC%
#
def _icepap_wrrd(dev,addr,cmd) '{
local ret
local ans
local mline
local eoa
ret = ""
_icepap_wr(dev,addr,cmd)
# MP: TO BE REMOVED when all firmwares will be >=2.0
if(ICEPAP[dev]["hrev"]<2) {
# NOTE MP 10Apr14: warning, long answers could be truncated
ret=sock_get(dev)
} else {
# handle multilines answers
for(mline=0;;) {
ans=sock_get(dev, "\n");
if(_icepap_lastchar(ans) == "\$") {
mline = (mline == 0)
}
# little optimization for most common case, non multilines answers
if(ret=="") {
ret = ans
} else {
ret = sprintf("%s%s", ret, ans)
}
if(mline == 0) {
break
}
}
}
icepap__debug dev ":<==" ret
_icepap_hist_append(ret)
return(ret)
}'
#%IU%(dev,addr,cmd,silent)
#%MDESC%
#
def _icepap_query(hn,addr,cmd,silent) '{
local dev
local ans[]
local cmd_ans
local len_ans
local lc
local n
local ret
local i
ret=""
dev=sprintf("%s%s",hn, index(hn,":")?"":":5000")
cmd_ans=_icepap_wrrd(dev,addr,cmd)
for(;;) {
len_ans=length(cmd_ans)
lc = substr(cmd_ans,len_ans,1)
if((lc=="\n") || (lc=="\r")) {
cmd_ans=substr(cmd_ans,0,len_ans-1)
continue
}
break
}
n=split(cmd_ans,ans)
if(n<1) {
if(!silent) {
_icepap_err
printf("bad answer from IcePAP\n")
}
return(cmd_ans)
}
if(index(ans[1],"ERROR")) {
if(!silent) {
_icepap_err
printf("%s\n",cmd_ans)
}
return(cmd_ans)
}
# NOTE MP 13Dec18: some commands are still not ISG protocol compliant
# not echoing the command before the answer itself,
# for instance the ?_sockping
ret=(n>1)?substr(cmd_ans,index(cmd_ans," ")+1):""
ret=substr(cmd_ans,index(cmd_ans," ")+1)
return(ret)
}'
#%IU%()
#%MDESC%
# Temporary patch
#
def _icepap_patch(dev, addr) '{
local slave
local dest
print "WARNING: icepap ",dev,"MASTER DSP being reset (",addr,")"
# Reset the MASTER DSP only, DRIVERs not affected
_icepap_wr(dev,"","_DSPRST")
# Give a minimum time to DSP to reset (and to DRIVERs to come back)
# or check that it is alive
sleep(3)
# Reaffect a CAN address to the DRIVER
# slave=int(addr/10)*10
# If the DRIVER is in the MASTER rack, the CAN address is already given
# if(slave != 0)
# {
# _icepap_wr(dev,slave,"RESET")
# sleep(10)
# }
}'
#%IU%()
#%MDESC%
# Temporary email after patch
#
def _icepap_patch_email() '{
dest = "perez@esrf.fr jclement@esrf.fr"
unix(sprintf("echo \"%s\" |mailx -s \"ERROR on %s session %s\" %s",\
_icepap_hist_dump(),\
SPECBL,\
SPEC,\
dest))
}'
#%IU%(message)
#%MDESC%
# Send an email with the specificied patch
#
def _icepap_email(subject, str) '{
dest = "perez@esrf.fr jclement@esrf.fr"
unix(sprintf("echo \"%s\" |mailx -s \"%s: session: \\\"%s\\\"\" %s",\
str,\
subject,\
SPEC,\
dest))
}'
#%IU%()
#%MDESC%
# Init the ICEPAP history if needed
#
def _icepap_hist_init() '{
global ICEPAP_HISTORY[]
if(!("size" in ICEPAP_HISTORY)) {
ICEPAP_HISTORY["size"]=1000
ICEPAP_HISTORY["end"] =0
}
}'
#%IU%(dev,cmd)
#%MDESC%
# Add to the ICEPAP history an entry
#
def _icepap_hist_add(dev, cmd) '{
global ICEPAP_HISTORY[]
local n
local tab
tab = " "
_icepap_hist_init()
n = ICEPAP_HISTORY["end"] + 1
if(n >= ICEPAP_HISTORY["size"]) { n = 0}
ICEPAP_HISTORY[n] = sprintf("%s%s%s%s%s",date(),tab,dev,tab,cmd)
ICEPAP_HISTORY["end"] = n
}'
#%IU%(str)
#%MDESC%
# Append a string to the last line in the ICEPAP history
#
def _icepap_hist_append(str) '{
global ICEPAP_HISTORY[]
local n
n = ICEPAP_HISTORY["end"]
ICEPAP_HISTORY[n] = sprintf("%s -> %s",ICEPAP_HISTORY[n], str)
}'
#%IU%()
#%MDESC%
# Return a string with the history of commands sent to ICEPAP systems
#
def _icepap_hist_dump() '{
global ICEPAP_HISTORY[]
local n
local i
local s
local ret
ret = ""
_icepap_hist_init()
s = ICEPAP_HISTORY["size"]
for(n=ICEPAP_HISTORY["end"];(n in ICEPAP_HISTORY) && (i<s);i++)
{
ret = sprintf("%s%s\n",ret,ICEPAP_HISTORY[n])
n--
if(n<0) { n = s - 1 }
}
return ret
}'
#%UU%
#%MDESC%
# Print out the history of commands sent to ICEPAP systems
#
def icepap_history '{
print _icepap_hist_dump()
}'
#%IU%(motor_mne)
#%MDESC%
# Returns non null if the given motor mne is not an IcePAP one
#
def _icepap_ismot(mne, silent) '{
local num
if((num=motor_num(mne)) == -1) {
if(!silent) {
_icepap_err
printf("Invalid motor \"%s\"\n", mne)
}
return(-1)
}
if(motor_par(num, "device_id") != "icepap") {
if(!silent) {
_icepap_err
printf("Not an IcePAP motor: \"%s\"\n", mne)
}
return(-1)
}
return(0)
}'
#
# ----------------------- test macros -------------------------
#
#%IU%(dev,src_addr,dst_addr)
#%MDESC%
# Will copy the source driver configuration to the destination one
# (bypass of icepapcms)
# ex: ("iceid207",11,25)
#
def icepap_duplicate_conf(dev,src_addr,dst_addr) '{
local src_conf
local src_arr[]
local n i
local dst_cmd
local dst_err
if(!index(dev,":")) { dev = sprintf("%s:5000",dev) }
src_conf = _icepap_wrrd(dev,src_addr,"?CFG")
n = split(src_conf,src_arr,"\r\n") - 1
dst_addr = "#" dst_addr
for(i=1;i<n;i++) {
dst_cmd = sprintf("_cfg %s", src_arr[i])
dst_err = _icepap_wrrd(dev,dst_addr,dst_cmd)
if(!index(dst_err,"OK")) {
p "ERROR: sending command: "dst_cmd" error: "dst_err
return(-1)
}
}
dst_cmd = "_CFG SAVE"
dst_err = _icepap_wrrd(dev,dst_addr,dst_cmd)
if(!index(dst_err,"OK")) {
p "ERROR: sending command: "dst_cmd" error: "dst_err
return(-1)
}
# normal end
p "ICEPAP configuration of driver "dst_addr" updated"
return(0)
}'
#
# ----------------------- linked axis -------------------------
#
#%IU%_lvcheck_mne(virtual_axis_mne)
#%MDESC%
# Returns non null if the given axis mnemonic is not a valid virtual axis
# composed of real linked axes.
#
def _lvcheck_mne(mne, silent) '{
local num
if(_icepap_ismot(mne, silent)) {
if(!silent) {
_icepap_err
print "invalid motor \""mne"\", not configured"
}
return(-1)
}
num = motor_num(mne)
if(ICEPAP[mne]["linked"] != "YES") {
if(!silent) {
_icepap_err
print "invalid motor \""mne"\", not a virtual axis of linked axes"
}
return(-1)
}
return(0)
}'
#%IU%_lrcheck_mne(real_axis_mne)
#%MDESC%
# Returns non null if the given axis mnemonic is not a real linked axis
# member of a virtual axis.
#
def _lrcheck_mne(mne, silent) '{
# Update global information on virtual axes
_linkedstat()
if(ICEPAP[mne]["linked_member"] != "YES") {
if(!silent) {
_icepap_err
print "invalid motor \""mne"\", not a linked axis"
}
return(-1)
}
return(0)
}'
#%UU% virtual_axis [virtual_axis...]
#%MDESC%
# Display information about the given virtual axis configured
# as a motor in the current SPEC session.
# The list of real axes linked together should not be configured
# but can be accessed through dedicated commands (linkedmv, linkedhome, etc).
#
def linkedstat '{
global ICEPAP[]
local tt[] axes n
local mne i
local wch str
local stpsz
# Retrive the list of axes
if($#<1) {
print "Usage: $0 virtual_axis"
exit
}
# Minimum checks on arguments
n = split("$*", tt)
for(i=0;i<n;i++) {
mne = tt[i]
if(_lvcheck_mne(mne)) { exit }
axes[i] = motor_num(mne)
}
# Print out information
wch = 20
for(i=0;i<n;i++) {
local j m tt
local nam
num = axes[i]
mne = motor_mne(num)
if(_linkedstat(num)) {
exit
}
stpsz = motor_par(mne, "step_size")
printf("%*s : %s\n",wch,"Virtual axis",mne)
printf("%*s : %s\n",wch,"Power is",motor_par(num,"power")?"ON":"OFF")
printf("%*s : %s\n",wch,"Real linked axes",ICEPAP[mne]["linked_names"])
printf("%*s : %s\n",wch,"Indexer steps",ICEPAP[mne]["pos_stps"])
printf("%*s : %s\n",wch,"Indexer in mm",ICEPAP[mne]["pos_stps"]/stpsz)
m = split(ICEPAP[mne]["linked_names"], tt)
for(j=0;j<m;j++) {
nam = tt[j]
printf("\n%*s : %s\n",wch,"Real axis",nam)
printf("%*s : %s\n",wch,"Home switch",ICEPAP[nam]["homesw"])
printf("%*s : %s\n",wch,"Homing",ICEPAP[nam]["homing"])
printf("%*s : %s\n",wch,"Control encoder",ICEPAP[nam]["ctrlenc"])
printf("%*s : %s\n",wch,"Indexer steps",ICEPAP[nam]["pos_stps"])
printf("%*s : %s\n",wch,"Encoder steps",ICEPAP[nam]["enc_stps"])
printf("%*s : %s\n",wch,"Homepos steps",ICEPAP[nam]["homepos_stps"])
printf("%*s : %s\n",wch,"Indexer in mm",ICEPAP[nam]["pos_stps"]/stpsz)
printf("%*s : %s\n",wch,"Encoder in mm",ICEPAP[nam]["enc_stps"]/stpsz)
printf("%*s : %s\n",wch,"Closed loop",ICEPAP[nam]["pcloop"])
stop_code = ICEPAP[nam]["stop_code"]
printf("%*s : %s (%s)\n",wch,"Stop code", \
stop_code, _icepap_stopcode2str(nam, stop_code))
}
}
}'
#%IU%(linked_axis)
#%MDESC%
# Update the global array ICEPAP[] with information about the given
# virtual axis. Returns non null if an error occured.
#
def _linkedstat(num) '{
global ICEPAP[]
local tt[] ttt[] axes n
local mne i
local dev
local ans
local nam str
local tnum err
local silent
local nums[] nnum j
local addr stop_code sta
silent = 1
# If no motor has been given try to guess all virtual axis configured
nnum = 0
if(whatis("num") & 0x08000000) {
for(i=0;i<MOTORS;i++) {
if(_lvcheck_mne(motor_mne(i), silent)) { continue }
nums[nnum++] = i
}
} else {
nums[nnum++] = num
}
for(j=0;j<nnum;j++) {
# Minimum check on argin
mne = motor_mne(nums[j])
if(motor_num(mne) == -1) {
_icepap_err
print "invalid motor \""mne"\""
return(-1)
}
# Retrieve information to access the real axes
dev = ICEPAP[mne]["dev"]
ans = _icepap_query(dev,"",sprintf("?POS %s", mne))
ICEPAP[mne]["pos_stps"] = int(ans)
# Get the list of real axes linked
n = split(ICEPAP[mne]["linked_addr"], tt)
str = ""
for(i=0;i<n;i++) {
# Real axis address on system
addr = tt[i]
# Get real axis name if any
nam = _icepap_query(dev,addr,"?NAME")
# Otherwise invent a name for the real axis
if((nam == "") || (nam=="?NAME")) { nam = sprintf("%s%d",mne,i+1) }
# In theory it is not possible to have the real IcePAP motor
# configured in current SPEC session but another motor could have
# the name name
for(;;) {
err = 0
if((tnum=motor_num(nam)) == -1) { break }
if(motor_par(tnum, "disable") == 1) { break }
# Allow to have the real motor configured
err = 1
if(motor_par(tnum, "device_id") != "icepap") { break }
if(!index(dev, motor_par(tnum, "address"))) { break }
taddr = motor_par(tnum,"module")*10
taddr += motor_par(tnum,"channel")
if(int(taddr) != int(addr)) { break }
# We are sure that the configured and linked axes are the same
_icepap_warn
p "linked axis \""nam"\" configured as normal motor"
err = 0
break
}
if(err){
_icepap_err
print "conflict between configured and linked axis \""nam"\""
return(-1)
}
# Update globals
str = sprintf("%s%s ", str, nam)
ICEPAP[mne]["linked_n"] += 1
ICEPAP[nam]["linked_name"] = mne
ICEPAP[nam]["linked_member"] = "YES"
ICEPAP[nam]["dev"] = dev
ICEPAP[nam]["addr"] = addr
# Check if an home switch is configured on this axis
ans = _icepap_query(dev,addr,"?CFG HOMESRC")
ICEPAP[nam]["homesw"] = index(ans,"NONE")?"NO":"YES"
# Check if a control encoder is configured on this axis
ans = _icepap_query(dev,addr,"?CFG CTRLENC")
ICEPAP[nam]["ctrlenc"] = index(ans,"NONE")?"NO":"YES"
# Get positions in steps
ans = _icepap_query(dev,addr,"?POS")
ICEPAP[nam]["pos_stps"] = int(ans)
ans = _icepap_query(dev,addr,"?POS MEASURE")
ICEPAP[nam]["enc_stps"] = int(ans)
# Get homing information
ans = _icepap_query(dev,addr,"?HOMEPOS", silent)
ICEPAP[nam]["homepos_stps"] = index(ans, "ERROR")?"unavailable":int(ans)
ans = _icepap_query(dev,addr,"?HOMESTAT", silent)
split(ans, ttt)
ICEPAP[nam]["homing"] = ttt[0]
# Get information on closed loop
ans=_icepap_query(dev,addr,"?PCLOOP")
ICEPAP[nam]["pcloop"] = (index(ans,"ON"))?"ON":"OFF"
# Get information on how the last motion finished
ans = _icepap_query(dev, "", sprintf("?FSTATUS %d", addr))
sscanf(ans, "%x", sta)
stop_code = (sta & ((1<<14)|(1<<15)|(1<<16)|(1<<17))) >> 14
ICEPAP[nam]["stop_code"] = stop_code
}
ICEPAP[mne]["linked_names"] = str
}
# Normal end
return(0)
}'
#%UU% virtual_axis position
#%MDESC%
# Synchronizes all real linked axes members of the given virtual axis
# to the give position. No motion will take place.
# The position is given in user units of the virtual axis.
#
def linkedsync '{
local mne
local pos
# Retrieve the arguments
if($#<2) {
print "Usage: $0 motor position"
exit
}
mne = "$1"
pos = $2
# Minimum checks on arguments
if(_lvcheck_mne(mne)) { exit }
# Launch the synchronization
_linkedsync(mne, pos)
}'
#%IU%(virtual_axis_mne, position)
#%MDESC%
# Synchronizes all real linked axes members of the given virtual axis
# to the give position. No motion will take place.
# The position is given in user units of the virtual axis.
# Returns non null if an error occured.
#
def _linkedsync(mne, p1) '{
global ICEPAP[]
local dev
local num
local pos
local ans
local cmd
local par
# Update global information on virtual axes
_linkedstat()
# Retrieve information on axis
dev = ICEPAP[mne]["dev"]
num = motor_num(mne)
# Calculate the target position in steps
pos = icepap_round(p1*motor_par(num,"step_size"))
# Force position on all real linked axes
cmd = sprintf("#POS %s %d", mne, pos)
ans = _icepap_query(dev,"",cmd)
if (ans != "OK")
{
_icepap_err
printf("unable to force position on real linked axes of: \"%s\"\n",mne)
return(-1)
}
# Force motion parameters on all real linked axes
par = motor_par(num, "acceleration")/1000
ans = _icepap_query(dev,"#",sprintf("ACCTIME %s %f",mne,par))
if(index(ans,"ERROR"))
{
_icepap_err
printf("unable set acceleration for: \"%s\"\n",mne)
return(-1)
}
par = motor_par(num, "velocity")
ans = _icepap_query(dev,"#",sprintf("VELOCITY %s %f",mne,par))
if(index(ans,"ERROR"))
{
_icepap_err
printf("unable set velocity for: \"%s\"\n",mne)
return(-1)
}
# Reset control encoder
# TODO: if any?
ans = _icepap_query(dev,"#",sprintf("CTRLRST %s",mne))
if(index(ans,"ERROR"))
{
_icepap_err
printf("unable reset control encoder for: \"%s\"\n",mne)
return(-1)
}
# switch power on (should re-enable the closed loop)
if(motor_par(num,"power",1) == 0)
{
_icepap_err
printf("unable to switch power on: \"%s\"\n",mne)
return(0)
}
# NOTE: from "help motors": position discrepancies between spec and the
# motor hardware will be silently resolved in favor of the hardware
read_motors(0x06)
# Normal end
return(0)
}'
#%UU% ["strict"] real_axis "home+"|"home-" [[real_axis "home+"|"home-"]...]
#%MDESC%
# Launch a homing sequence on the given list of real linked axes.
# If the strict option is given then the first real linked axis that
# finds its home switch will stop the homing sequence of the other axes.
# The macros does not wait for the end of the homing sequence.
#
def linkedhome '{
local mne
local sen
local stc
local tt[] n i
local arg
# Retrieve the arguments
if($#<2) {
print "Usage: $0 [\"strict\"] motor \"home+\"|\"home-\" ..."
exit
}
stc = ("$1" == "strict")?1:0
n = split("$*",tt)
for(i=stc, arg=""; i<n; i+=2) {
mne = tt[i]
sen = tt[i+1]
# Minimum checks on arguments
if(_lrcheck_mne(mne)) { exit }
if((sen != "home+") && (sen != "home-")) {
_icepap_err
printf("un-supported home or limit search \"%s\"\n", sen)
exit
}
arg = sprintf("%s%s %s ",arg, mne, sen)
}
# Launch the homing sequence
_linkedhome(arg, stc?"strict":"")
}'
#%IU%("mne "home+"|"home-" [[mne "home+"|"home-"]...]", mode)
#%MDESC%
# Launch a homing sequence on the given list of real linked axes.
# If the mode option is set to "strict" then the first real linked axis that
# finds its home switch will stop the homing sequence of the other axes.
# The global ICEPAP[] will then contains the name and the home
# position of this real axis.
# The macros does not wait for the end of the homing sequence.
# Returns non null if an error occured.
#
def _linkedhome(arg, mode) '{
global ICEPAP[]
local lim
local dev
local num
local ans
local cmd1 cmd2
local tt[] n i
# Update global information on virtual axes
_linkedstat()
# The homing command can not be launched on the virtual axis but
# only on the real linked axes.
# The STRICT option is to stop all linked axes if any stops.
cmd1 = "#DISPROT ALL"
cmd2 = sprintf("#HOME %s",(mode=="strict")?"STRICT":"")
# Retrieve the arguments
n = split(arg, tt)
for(i=0; i<n; i+=2) {
mne = tt[i]
sen = tt[i+1]
lim = (sen=="home-")?"-1":"+1"
addr = ICEPAP[mne]["addr"]
dev = ICEPAP[mne]["dev"]
cmd1 = sprintf("%s %d", cmd1, addr)
cmd2 = sprintf("%s %d %s", cmd2, addr, lim)
}
# Launch the homing sequence
ans = _icepap_query(dev,"",sprintf("%s ; %s", cmd1, cmd2))
if(index(ans,"ERROR"))
{
_icepap_err
p "unable to dis-protect axes"
return(-1)
}
ans = sock_get(dev,"\n")
if (!index(ans,"OK"))
{
_icepap_err
p "homing sequence launch failed"
p ans
return(-1)
}
# Normal end
return(0)
}'
#%UU% real_axis posititon [[real_axis posititon] ...]
#%MDESC%
# Move the specified real linked axes to absolute positions.
# The positions are given in user units of the virtual axis of which
# the real axes are members.
#
def linkedmv '{
local tt[] i n
local mne
local pos
# Retrieve the arguments
n = split("$*", tt)
if(($#<2) || (n%2)) {
print "Usage: $0 motor position [[motor position] ...]"
exit
}
# Minimum checks on arguments
for(i=0;i<n;i+=2) {
mne = tt[i]
pos = tt[i+1]
if(_lrcheck_mne(mne)) { exit }
}
# Launch the motion
_linkedmv("$*")
}'
#%UU% real_axis relative-posititon [[real_axis relative-posititon] ...]
#%MDESC%
# Move the specified real linked axes to relative positions.
# The positions are given in user units of the virtual axis of which
# the real axes are member.
#
def linkedmvr '{
local tt[] i n
local mne
local pos
# Retrieve the arguments
n = split("$*", tt)
if(($#<2) || (n%2)) {
print "Usage: $0 motor relative-position [[motor relative-position] ...]"
exit
}
# Minimum checks on arguments
for(i=0;i<n;i+=2) {
mne = tt[i]
pos = tt[i+1]
if(_lrcheck_mne(mne)) { exit }
}
# Launch the motion
_linkedmvr("$*")
}'
#%IU%(real_axis_mne, relative_position)
#%MDESC%
def _linkedmvr(arg) '{
# Launch the motion
_linkedmv(arg, 1)
}'
#%IU%("mne posititon [[mne position]...]")
#%MDESC%
# Move the specified real linked axes to absolute positions.
# Returns non null if an error occured.
#
def _linkedmv(arg, rel) '{
global ICEPAP[]
local mne
local p1
local ans
local addr
local dev
local sta
local pos stps
local vmne vnum
local cmd1 cmd2
local sta ret
local tt[] i n
local addrs[] nsta
local sarg
# Update global information on virtual axes
_linkedstat()
# Prepare the commands
cmd1 = "#DISPROT ALL"
cmd2 = "#MOVE"
# For each real axis
n = split(arg, tt)
nsta = 0
for(i=0;i<n;i+=2) {
# Retrieve the arguments
mne = tt[i]
pos = tt[i+1]
# Retrieve information on axis
addr = ICEPAP[mne]["addr"]
dev = ICEPAP[mne]["dev"]
vmne = ICEPAP[mne]["linked_name"]
vnum = motor_num(vmne)
# Prepare stop command
sarg = dev"="
# Minimum check that motion is possible
sta = 0
ans = _icepap_query(dev,"",sprintf("?FSTATUS %d",addr))
if(sscanf(ans,"%x", sta) != 1)
{
_icepap_err
printf("unable to get status for: \"%s\"\n",mne)
return(-1)
}
# Get ready status
if(!(sta & (1<<9)))
{
_icepap_err
printf("driver is not ready for: \"%s\"\n",mne)
# temporary: for debug purpose only
_icepap_print_info(dev,addr,mne)
return(-1)
}
# Calculate the target position in steps
stps = icepap_round(pos*motor_par(vnum,"step_size"))
# Handle relative motions
if(rel) {
local apos
# Get current position
ans= _icepap_query(dev,"",sprintf("?FPOS %s",addr))
if(sscanf(ans,"%d",apos) != 1) {
_icepap_err
printf("unable to get position for: \"%s\"\n",mne)
return(-1)
}
stps += apos
}
cmd1 = sprintf("%s %d", cmd1, addr)
cmd2 = sprintf("%s %d %d", cmd2, addr, stps)
sarg = sprintf("%s %d", sarg, addr)
# Prepare the list of real axis to poll
addrs[nsta++] = addr
}
# Handle the <ctrl-c>
cdef("cleanup_once", sprintf("_linked_stop(\"%s\")\n", sarg), "_linked_icepap")
# Launch the motion
ans = _icepap_query(dev,"",sprintf("%s ; %s", cmd1, cmd2))
if (ans != "OK")
{
_icepap_err
p "unable to dis-protect axis"
_linked_clean_cleanup()
return(-1)
}
ans = sock_get(dev,"\n")
if (!index(ans,"OK"))
{
_icepap_err
p "unable to start motion for"
p ans
_linked_clean_cleanup()
return(-1)
}
# Wait for the end of the motion
for(nret=0x02;nret;sleep(UPDATE)) {
for(i=0,nret=0;i<nsta;i++) {
addr = addrs[i]
if((addr = addrs[i]) == "") { continue }
ret = 0
ans = _icepap_query(dev,"",sprintf("?FSTATUS %s",addr))
if(sscanf(ans,"%x", sta) != 1)
{
_icepap_err
printf("unable to get status for: \"%s\"\n",mne)
_linked_clean_cleanup()
return(-1)
}
if((sta & (1<<10)) || (sta & (1<<11))) ret |= 0x02;
else if(!(sta & (1<<9)) && (sta & (1<<23))) ret |= 0x02;
# get limitswitches status
if(sta & (1<<19)) ret |= 0x04;
if(sta & (1<<18)) ret |= 0x08;
# check stop code if not moving
if(!(ret & 0x02)) {
_icepap_stopcode(num, sta)
delete addrs[i]
}
nret |= ret
}
}
# Normal end
_linked_clean_cleanup()
return(0)
}'
#%IU%()
#%MDESC%
# Needed to avoid side effects on <ctrl-C>
#
def _linked_clean_cleanup() '{
cdef("cleanup_once", "", "_linked_icepap", "delete")
}'
#%IU%("dev=addr [addr...]")
#%MDESC%
# Stop the motion on the speficied axis identified by their address
#
def _linked_stop(sarg) '{
local dev
local args[]
if(split(sarg, args, "=") != 2) {
_icepap_err
printf("major internal error on _linked_stop(\"%s\")\n", sarg)
return(-1)
}
dev = args[0]
printf("ICEPAP WARNING: Aborting motion on \"%s\" for axes:%s\n", \
dev, args[1])
_icepap_wr(dev,"",sprintf("STOP %s", args[1]))
return(0)
}'
#%UU% real_axis [real_axis ...]
#%MDESC%
# In case of closed error on a real linked axis, this macro
# has to be called to resynchronize the motor and its encoder.
# The power will be also put back.
#
def linkedresetclosedloop '{
local tt[] i n
local mne
local pos
# Retrieve the arguments
n = split("$*", tt)
if(n == 0) {
print "Usage: $0 motor [motor ...]"
exit
}
# Minimum checks on arguments
for(i=0;i<n;i++) {
mne = tt[i]
if(_lrcheck_mne(mne)) { exit }
}
# Acces to the real axis
_linkedresetclosedloop("$*")
}'
#%IU%("mne [mne ...]")
#%MDESC%
# Reset closed loop error on the specified real linked axes.
# Returns non null if an error occured.
#
def _linkedresetclosedloop(arg) '{
global ICEPAP[]
local mne
local addr
local dev
local cmd
local ans
local tt[] i n
# Update global information on virtual axes
_linkedstat()
# For each real axis
n = split(arg, tt)
for(i=0;i<n;i++) {
# Retrieve the arguments
mne = tt[i]
# Retrieve information on axis
addr = ICEPAP[mne]["addr"]
dev = ICEPAP[mne]["dev"]
# Get current encoder position
ans = _icepap_query(dev, addr, "?POS MEASURE")
if(index(ans,"ERROR"))
{
_icepap_err
printf("unable to read encoder for: \"%s\"\n",mne)
return(-1)
}
# Set axis position to same value to remove closed loop discrepancy
# NOTE MP 21Jul14: the axis command does not work with firmware 2.0
# the system command must be used instead
cmd = sprintf("DISPROT LINKED %s ; #POS %s %s", addr, addr, ans)
ans = _icepap_query(dev, "", cmd)
if(index(ans,"ERROR"))
{
_icepap_err
printf("unable to reset closed loop error on: \"%s\"\n",mne)
return(-1)
}
# Switch on closed loop on real axes
cmd = sprintf("%s:DISPROT LINKED ; #%s:PCLOOP ON", addr, addr)
ans = _icepap_query(dev, "", cmd)
if(index(ans,"ERROR"))
{
_icepap_err
printf("unable to switch on closed loop, error on: \"%s\"\n",mne)
return(-1)
}
# Switch power on (should re-enable the closed loop)
ans = _icepap_query(dev, "#" addr, "POWER ON")
if(index(ans,"ERROR"))
{
_icepap_err
printf("unable to switch power on for: \"%s\"\n",mne)
return(-1)
}
}
}'
#%UU% real_axis [real_axis ...]
#%MDESC%
# Open the closed loop on the specified real linked axes.
# The power is not touched.
#
def linkedopenclosedloop '{
local tt[] i n
local mne
local pos
# Retrieve the arguments
n = split("$*", tt)
if(n == 0) {
print "Usage: $0 motor [motor ...]"
exit
}
# Minimum checks on arguments
for(i=0;i<n;i++) {
mne = tt[i]
if(_lrcheck_mne(mne)) { exit }
}
# Acces to the real axis
_linkedopenclosedloop("$*")
}'
#%IU%("mne [mne ...]")
#%MDESC%
# Open the closed loop on the specified real linked axes.
# Returns non null if an error occured.
#
def _linkedopenclosedloop(arg) '{
global ICEPAP[]
local mne
local addr
local dev
local cmd
local ans
local tt[] i n
# Update global information on virtual axes
_linkedstat()
# For each real axis
n = split(arg, tt)
for(i=0;i<n;i++) {
# Retrieve the arguments
mne = tt[i]
# Retrieve information on axis
addr = ICEPAP[mne]["addr"]
dev = ICEPAP[mne]["dev"]
cmd = sprintf("%s:DISPROT LINKED ; #%s:PCLOOP OFF", addr, addr)
ans = _icepap_query(dev, "", cmd)
if(index(ans,"ERROR"))
{
_icepap_err
printf("unable to open closed loop error on: \"%s\"\n",mne)
return(-1)
}
}
}'
#%UU% virtual_axis
#%MDESC%
# Synchronizes all real linked axes members of the given virtual axis
# to the give position. No motion will take place.
#
def linkedreset '{
local mne
local pos
# Retrieve the arguments
if($#<1) {
print "Usage: $0 motor"
exit
}
mne = "$1"
# Minimum checks on arguments
if(_lvcheck_mne(mne)) { exit }
# Launch the synchronization
_linkedreset(mne)
}'
#%IU%(virtual_axis_mne)
#%MDESC%
# Synchronizes all real linked axes members of the given virtual axis
# to the give position. No motion will take place.
# Returns non null if an error occured.
#
def _linkedreset(mne) '{
global ICEPAP[]
local dev
local num
local pos
local ans
local cmd
local par
local pos
local i n tt[]
local stop_code
# Retrieve information on axis
dev = ICEPAP[mne]["dev"]
num = motor_num(mne)
# Synchronize the real axes positions with the encoder ones
icepap__debug "synchronize real axes positions with encoder ones"
cmd = sprintf("#ESYNC %s", mne)
ans = _icepap_query(dev,"",cmd)
if (ans != "OK")
{
_icepap_err
printf("unable to sync axes positions with encoders ones for: \"%s\"\n",mne)
return(-1)
}
# Update global information on virtual axes
_linkedstat()
# Calculate the average real axes positions
n = split(ICEPAP[mne]["linked_names"], tt)
pos = 0.0
for(i=0;i<n;i++) {
nam = tt[i]
pos += ICEPAP[nam]["pos_stps"]
}
pos /= n
pos /= motor_par(num, "step_size")
# Check how the real axes stopped
for(i=0;i<n;i++) {
nam = tt[i]
# Save time
if((stop_code = ICEPAP[nam]["stop_code"]) == 0) {
continue
}
# Limit activated
if((stop_code == 3) || (stop_code == 4)) {
icepap__debug "axis \"" nam "\" stopped on limitswitch"
pos = ICEPAP[nam]["pos_stps"]
pos /= motor_par(num, "step_size")
# TODO: what to do if several axes touched their limitswitches?
break
}
}
# Re-align mechanically the real axes
icepap__debug "move real axes to position: " pos "mm"
cmd = ""
for(i=0;i<n;i++) {
nam = tt[i]
cmd = sprintf("%s %s %f", cmd, nam, pos)
}
_linkedmv(cmd)
# Put back the linked axis in operation
_linkedsync(mne, pos)
# Normal end
return(0)
}'
#
# ----------------------- electronic cam -------------------------
#
constant _ECAM_SIGNAL "PULSE LOW HIGH"
constant _ECAM_SOURCE "AXIS MEASURE PARAM SHFTENC TGTENC CTRLENC ENCIN INPOS ABSENC MOTOR"
#%UU% motor source signal {pos_array}|{pos_first pos_last npos}
#%MDESC%
# Configure for the given motor source which kind of signal will be
# generated and at which positions. These ones can be given as
# an array of motor source positions or only as the beginning and
# ending positions with the number of positions.
# Example:
# short array listpos[10]
# array_op("fill", listpos, 100)
# ecamsetup m2 AXIS PULSE listpos
# ecamlist m2
# ecamlist m2 clear
#
def ecamsetup '{
global ICEPAP[]
local mne
local dev
local ans
local addr
local badconf
local bin_typ
local src_typ
local sig_typ
# Minium check on arguments
if($#<4) {
_icepap_err
print "Missing arguments"
print "Usage: $0 source signal {pos_array}|{pos_first pos_last npos}"
print "Source: " _ECAM_SOURCE
print "Signal: " _ECAM_SIGNAL
exit
}
bin_typ = (whatis("$4") & 0x00010000)?1:0
if(!bin_typ && ($#!=6)) {
_icepap_err
print "Missing first/last positions and number of positions"
exit
}
# Minimum check on motor argument
mne = "$1"
if(_icepap_ismot(mne)) { exit }
# Minimum check on source argument
src_typ = icepap__toupper("$2")
if(!index(_ECAM_SOURCE, src_typ)) {
_icepap_err
print "Wrong signal type, must be one of the following:"
print "\""_ECAM_SOURCE"\""
exit
}
# Minimum check on signal type argument
sig_typ = icepap__toupper("$3")
if(!index(_ECAM_SIGNAL, sig_typ)) {
_icepap_err
print "Wrong signal type, must be one of the following:"
print "\""_ECAM_SIGNAL"\""
exit
}
# Check that there is at least one INFOA,B,C line configured
dev = ICEPAP[mne]["dev"]
addr = ICEPAP[mne]["addr"]
for(badconf=1, ch=asc("A");ch<=asc("C");ch++) {
ans = _icepap_query(dev, addr, sprintf("?INFO%c",ch))
if(index(ans, "eCAM")) {
badconf = 0
break
}
}
if(badconf) {
_icepap_err
print "missing one INFOA,B,C line configured to ECAM. Hint: use IcePAPcms"
return(-1)
}
# Call the corresponding setup
_ecamsetup($1, src_typ, sig_typ, $4, $5, $6)
}'
#%UU% motor [clear]
#%MDESC%
# Print out current position list information for the given motor.
# Or remove already loaded position list.
#
def ecamlist '{
global ICEPAP[]
local mne
local dev
local addr
local cmd
local ans
local mod_typ
local tt[] l i n
# Minium check on arguments
if($#<1) {
_icepap_err
print "Missing arguments"
print "Usage: $0 motor [clear]"
exit
}
# Minimum check on motor argument
mne = "$1"
if(_icepap_ismot(mne)) {
_icepap_err
print "Not an IcePAP motor"
exit
}
# Retrieve access to the IcePAP axis
dev = ICEPAP[mne]["dev"]
addr = ICEPAP[mne]["addr"]
# Clear already loaded position list
if($#>1) {
opt = "$2"
opt = icepap__toupper(opt)
if(opt == "CLEAR") {
print "Clearing position list defined for motor \"" mne "\""
cmd = sprintf("ECAMDAT CLEAR")
ans = _icepap_query(dev, "#" addr, cmd)
if(index(ans, "ERROR")) {
return
}
# avoid displaying error on emptied list
return
}
}
# Get global configuraiton
# Ex of answer: AXIS 0 1000 11
cmd = sprintf("?ECAMDAT")
ans = _icepap_query(dev, addr, cmd)
if(index(ans, "ERROR")) {
return
}
# Get the number of positions in the list
n = split(ans, tt)
if(sscanf(tt[n-1], "%d", npos) != 1) {
_icepap_err
print "Invalid answer from DSP, giving up"
return
}
if(!npos) {
print "No position list defined for motor \"" mne "\""
print "Hint: use \"ecamsetup\""
return
}
# Get positions
cmd = sprintf("?ECAMDAT %d 0", npos)
ans = _icepap_query(dev, addr, cmd)
if(index(ans, "ERROR")) {
return
}
print "number of positions:", npos
print "positions list :"
n = split(ans, tt, "\n")
for(i=0;i<n;i++) {
if(index(tt[i], "\$")) {
continue
}
print tt[i]
}
}'
#%IU%(motor, source, signal, posbeg, posend, npos)
#%MDESC%
# Returns non null if an error occured.
#
def _ecamsetup(num, source, signal, posbeg, posend, npos) '{
global ICEPAP[]
local mne
local dev
local addr
local cmd
local ans
local bin_typ
# No verification on parameters, must have been done in the calling macro
mne = motor_mne(num)
dev = ICEPAP[mne]["dev"]
addr = ICEPAP[mne]["addr"]
# Store information
ICEPAP[mne]["ecam_src"] = source
ICEPAP[mne]["ecam_sig"] = signal
ICEPAP[mne]["ecam_bin"] = "NO"
# Guess how the positions have been given
bin_typ = (whatis("posbeg") & 0x00010000)?1:0
# Prepare the DSP command, even if source is optional, always give it
if(!bin_typ) {
cmd = sprintf("ECAMDAT %s %d %d %d", source, posbeg, posend, npos)
ans = _icepap_query(dev, "#" addr, cmd)
if(index(ans, "ERROR")) {
return(-1)
}
} else {
pos_typ = _icepap_array_type(posbeg)
if(index(pos_typ, "ERROR")) {
return(-1)
}
if((pos_typ!="DWORD") && (pos_typ!="FLOAT") && (pos_typ!="DFLOAT")) {
_icepap_err
print "unsupported position array type"
return(-1)
}
cmd = sprintf("*ECAMDAT %s %s", source, pos_typ)
# Send the binary data
silent = 1
ans = _icepap_send_array(dev, "#" addr, cmd, posbeg, silent)
if(index(ans, "ERROR")) {
print ans
return(-1)
}
}
# Normal end
return(0)
}'
#%UU% motor
#%MDESC%
#
def ecamon '{
# Minimum cheks
if($# != 1) {
print "Usage: $0 motor"
exit
}
if(_icepap_ismot("$1")) { exit }
# Action
_ecamaction($1, "ON")
}'
#%UU% motor
#%MDESC%
#
def ecamoff '{
# Minimum cheks
if($# != 1) {
print "Usage: $0 motor"
exit
}
if(_icepap_ismot("$1")) { exit }
# Action
_ecamaction($1, "OFF")
}'
#%IU%(motor, action)
#%MDESC%
# Swith "ON" of "OFF" the electronic cam on the given axis which must
# have been previously configured with "ecamdat" macro.
# Returns non null if an error occured.
#
def _ecamaction(num, action) '{
global ICEPAP[]
local mne
local dev
local addr
local cmd
local ans
# No verification on parameters, must have been done in the calling macro
mne = motor_mne(num)
dev = ICEPAP[mne]["dev"]
addr = ICEPAP[mne]["addr"]
sig = ICEPAP[mne]["ecam_sig"]
# Check that some data have already been configured
# WARNING: ?ECAMDAT does not return ERROR if not configuration already done
# the command retursn unconsistant values. Dont know if these are
# always the same, therfore do not use command ?ECAMDAT
# Desactivate electronic CAM
if(action == "OFF") {
ans = _icepap_query(dev, "#" addr, "ECAM OFF")
return((index(ans, "ERROR"))?-1:0)
}
# Enable electronic CAM
if(action == "ON") {
cmd = sprintf("ECAM %s", sig)
ans = _icepap_query(dev, "#" addr, cmd)
return((index(ans, "ERROR"))?-1:0)
}
# Abnormal end
return(-1)
}'
#
# ----------------------- position list modes -------------------------
#
constant _ICELIST_MODE "NOCYCLIC CYCLIC"
constant _ICELIST_LTRACKSRC "SYNC ENCIN INPOS ABSENC TRIGGER"
#%UU% motor {cyclic|nocyclic} {pos_array}|{pos_first pos_last npos}
#%MDESC%
# Define for the given motor a list of positions that will be used
# cyclicelly or not.
# These positions can be given as
# an array of motor positions or as the beginning/ending positions
# plus the total number of positions.
# The positions are given in steps.
#%BR% Example:
#%BR% long array listpos[11]
#%BR% array_op("fill", listpos, 100)
#%BR% poslistsetup m2 nocyclic listpos
#%BR% poslist m2
#%BR% poslist m2 clear
#%BR% poslistmv m2 2
#
def poslistsetup '{
global ICEPAP[]
local mne
local bin_typ
local mod_typ
# Minium check on arguments
if($#<3) {
_icepap_err
print "Missing arguments"
print "Usage: $0 motor mode {pos_array}|{pos_first pos_last npos}"
print "Mode : " _ICELIST_MODE
exit
}
bin_typ = (whatis("$3") & 0x00010000)?1:0
if(!bin_typ && ($#!=5)) {
_icepap_err
print "Missing first/last positions and number of positions"
exit
}
# Minimum check on motor argument
mne = "$1"
if(_icepap_ismot(mne)) {
_icepap_err
print "Not an IcePAP motor"
exit
}
# Minimum check on source argument
mod_typ = icepap__toupper("$2")
if(!index(_ICELIST_MODE, mod_typ)) {
_icepap_err
print "Wrong list mode, must be one of the following:"
print "\""_ICELIST_MODE"\""
exit
}
# Call the corresponding setup
_poslistsetup($1, mod_typ, $3, $4, $5)
}'
#%UU% motor [clear]
#%MDESC%
# Print out current position list information for the given motor.
# Or remove already loaded position list.
#
def poslist '{
global ICEPAP[]
local mne
local dev
local addr
local cmd
local ans
local mod_typ
local tt[] l i n
local opt
# Minium check on arguments
if($#<1) {
_icepap_err
print "Missing arguments"
print "Usage: $0 motor [clear]"
exit
}
# Minimum check on motor argument
mne = "$1"
if(_icepap_ismot(mne)) {
_icepap_err
print "Not an IcePAP motor"
exit
}
# Retrieve access to the IcePAP axis
dev = ICEPAP[mne]["dev"]
addr = ICEPAP[mne]["addr"]
# Clear already loaded position list
if($#>1) {
opt = "$2"
opt = icepap__toupper(opt)
if(opt == "CLEAR") {
print "Clearing position list defined for motor \"" mne "\""
cmd = sprintf("LISTDAT CLEAR")
ans = _icepap_query(dev, "#" addr, cmd)
if(index(ans, "ERROR")) {
return
}
# avoid displaying error on emptied list
return
}
}
# Get global configuraiton
cmd = sprintf("?LISTDAT")
ans = _icepap_query(dev, addr, cmd)
if(index(ans, "ERROR")) {
return
}
# First is the number of positions in the list
split(ans, tt)
if(sscanf(tt[0], "%d", npos) != 1) {
_icepap_err
print "Invalid answer from DSP, giving up"
return
}
if(!npos) {
print "No position list defined for motor \"" mne "\""
print "Hint: use \"poslistsetup\""
return
}
mod_typ = tt[1]
# Get positions
cmd = sprintf("?LISTDAT %d 0", npos)
ans = _icepap_query(dev, addr, cmd)
if(index(ans, "ERROR")) {
return
}
print "number of positions:", npos
print "list usage :", mod_typ
print "positions list :"
n = split(ans, tt, "\n")
for(i=0;i<n;i++) {
if(index(tt[i], "\$")) {
continue
}
print tt[i]
}
}'
#%IU%(motor, mode, posbeg, posend, npos) or (motor, mode, posarray)
#%MDESC%
# Define for the given motor a list of positions.
# Returns non null if an error occured.
#
def _poslistsetup(num, mode, posbeg, posend, npos) '{
global ICEPAP[]
local mne
local dev
local addr
local cmd
local ans
local bin_typ
local pos_typ
local silent
# No verification on parameters, must have been done in the calling macro
mne = motor_mne(num)
dev = ICEPAP[mne]["dev"]
addr = ICEPAP[mne]["addr"]
# Store information
ICEPAP[mne]["list_mode"] = mode
# Guess how the positions have been given
bin_typ = (whatis("posbeg") & 0x00010000)?1:0
# Prepare the DSP command, even if source is optional, always give it
if(!bin_typ) {
cmd = sprintf("LISTDAT %s %d %d %d", mode, posbeg, posend, npos)
ans = _icepap_query(dev, "#" addr, cmd)
if(index(ans, "ERROR")) {
return(-1)
}
} else {
pos_typ = _icepap_array_type(posbeg)
if(index(pos_typ, "ERROR")) {
return(-1)
}
if((pos_typ!="DWORD") && (pos_typ!="FLOAT") && (pos_typ!="DFLOAT")) {
_icepap_err
print "unsupported position array type"
return(-1)
}
cmd = sprintf("*LISTDAT %s %s", mode, pos_typ)
# Send the binary data
silent = 1
ans = _icepap_send_array(dev, "#" addr, cmd, posbeg, silent)
if(index(ans, "ERROR")) {
print ans
return(-1)
}
}
# Normal end
return(0)
}'
#%UU% motor index
#%MDESC%
# Move the given motor at the position corresponding to the given index
# within a pre-configured positions list.
# The index can be float, then the target position will be interpolated
# inbetween the two nearest pre-configured positions.
# The macro waits for the end of the motion.
#
def poslistmv '{
global ICEPAP[]
local mne
local idx
local silent
# Minium check on arguments
if($#!=2) {
_icepap_err
print "Missing arguments"
print "Usage: $0 motor index"
exit
}
# Minimum check on motor argument
mne = "$1"
if(_icepap_ismot(mne)) {
_icepap_err
print "Not an IcePAP motor"
exit
}
if(sscanf("$2","%f",idx) != 1) {
_icepap_err
print "Wrong arguments, index must be numerical"
exit
}
silent = 0
_poslistmv($1, idx, silent)
}'
#%IU%(motor, index)
#%MDESC%
# Move the given motor at the position corresponding to the given index
# within a pre-configured positions list.
# The index can be float, then the target position will be interpolated
# inbetween the two nearest pre-configured positions.
# The function waits for the end of the motion.
# Returns non null if an error occured.
#
def _poslistmv(num, idx, silent) '{
global ICEPAP[]
local mne
local dev
local addr
local cmd
local ans
local ret
# No verification on parameters, must have been done in the calling macro
mne = motor_mne(num)
dev = ICEPAP[mne]["dev"]
addr = ICEPAP[mne]["addr"]
# Launch the motion
cmd = sprintf("MOVEL %f", idx)
ans = _icepap_query(dev, "#" addr, cmd)
if(index(ans, "ERROR")) {
print ans
return(-1)
}
# Handle the <ctrl-c>
cdef("cleanup_once", sprintf("_poslist_stop(\"%s\")\n", mne), "_poslist_icepap")
# Cosmetics
if(!silent) {
printf("\n")
}
# Wait for the end of the motion
for(ret=0x02;ret;sleep(UPDATE)) {
# Display motor position in user units
if(!silent) {
printf("%f\r",icepap_cmd(num, "position"))
}
ret = icepap_cmd(num, "get_status")
}
# Cosmetics
if(!silent) {
printf("\n")
}
# Position discrepancies between spec and the
# motor hardware will be silently resolved in favor of the hardware
read_motors(0x06)
# Normal end
return(0)
}'
#%IU%(motor)
#%MDESC%
# Stop the motion on the speficied motor
# and resynchronize silently SPEC position
#
def _poslist_stop(mne, silent) '{
local num
if((num=motor_num(mne)) == -1) {
if(!silent) {
_icepap_err
printf("major internal error on _poslist_stop(\"%s\")\n", mne)
}
return(-1)
}
if(!silent) {
printf("\nICEPAP WARNING: Aborting motion on \"%s\"\n", mne)
}
icepap_cmd(num, "abort_one")
# Position discrepancies between spec and the
# motor hardware will be silently resolved in favor of the hardware
read_motors(0x06)
return(0)
}'
#%UU% motor source_signal [start_index]
#%MDESC%
# The given motor will track the given source signal and move
# within the previously loaded list of positions starting from
# the position corresponding to the optional given index in
# the list.
#
def poslisttrackon '{
local src_sig
local dev
local addr
local cmd
local ans
local tt[]
local npos
# Minium check on arguments
if($#<2) {
_icepap_err
print "Missing arguments"
print "Usage : $0 motor source_signal start_index"
print "Signal: " _ICELIST_LTRACKSRC
exit
}
# Minimum check on motor argument
mne = "$1"
if(_icepap_ismot(mne)) {
_icepap_err
print "Not an IcePAP motor"
exit
}
# Retrieve access to the IcePAP axis
dev = ICEPAP[mne]["dev"]
addr = ICEPAP[mne]["addr"]
# Minimum check on source argument
src_sig = icepap__toupper("$2")
if(!index(_ICELIST_LTRACKSRC, src_sig)) {
_icepap_err
print "Wrong source signal, must be one of the following:"
print "\""_ICELIST_LTRACKSRC"\""
exit
}
# Check that a position list has been already loaded
cmd = sprintf("?LISTDAT")
ans = _icepap_query(dev, addr, cmd)
if(index(ans, "ERROR")) {
return
}
split(ans, tt)
if(sscanf(tt[0], "%d", npos) != 1) {
_icepap_err
print "Invalid answer from DSP, giving up"
return
}
if(!npos) {
_icepap_err
print "No position list loaded for motor \"" mne "\""
print "Hint: use macro \"poslistsetup\""
exit
}
if($# == 3) {
_poslisttrackon($1, src_sig, $3)
} else {
_poslisttrackon($1, src_sig)
}
}'
#%UU% motor
#%MDESC%
# The given motor will no more track a signal.
# Its position is silently updated.
#
def poslisttrackoff '{
local mne
# Minium check on arguments
if($#!=1) {
_icepap_err
print "Missing arguments"
print "Usage : $0 motor"
exit
}
# Minimum check on motor argument
mne = "$1"
if(_icepap_ismot(mne)) {
_icepap_err
print "Not an IcePAP motor"
exit
}
_poslisttrackoff($1)
}'
#%IU%(motor, src_sig) or (motor, src_sig, idx)
#%MDESC%
# The given motor will track the given source signal and move
# within the previously loaded list of positions starting from
# the position corresponding to the optional given index in
# the list.
# Returns non null if an error occured.
#
def _poslisttrackon(num, src_sig, idx, silent) '{
global ICEPAP[]
local cmd
local mne
local dev
local addr
local use_idx
# No verification on parameters, must have been done in the calling macro
mne = motor_mne(num)
dev = ICEPAP[mne]["dev"]
addr = ICEPAP[mne]["addr"]
# optional index argin
use_idx = (whatis("idx") & 0x08000000)?0:1
#
if(use_idx) {
cmd = sprintf("POS %s %d", src_sig, idx)
ans = _icepap_query(dev, "#" addr, cmd, silent)
if(index(ans, "ERROR")) {
return
}
}
#
# NOTE MP 14 Mar 2017: the TRIGGER option can not be given with
# a source signal. Therefore we can handle it as another source.
# By the way, the name TRIGGER is not very explicit, AUTO would
# be better as the motor will automatically move from one position
# in the list to another one.
cmd = sprintf("LTRACK %s", src_sig)
ans = _icepap_query(dev, "#" addr, cmd, silent)
if(index(ans, "ERROR")) {
return
}
}'
#%IU%(motor)
#%MDESC%
# The given motor will no more track a signal.
#
def _poslisttrackoff(num, silent) '{
local mne
mne = motor_mne(num)
_poslist_stop(mne, silent)
}'
#
# ----------------------- binary transfers toolkit -------------------------
#
#%IU%(dev, addr, cmd, array, silent)
#%MDESC%
# Send the binary command with its data given in a SPEC data array.
# Supported types for the array are:
# short (16bits)
# ushort (16bits)
# ulong (32bits)
# float (32bits)
# double (64bits)
#
# Example:
# ushort array shdata[4]
# array_op("fill",shdata,2,2)
# _icepap_send_array("isgtmp5","#0","*ISG BINDATA WORD 4",shdata)
#
def _icepap_send_array(dev, addr, cmd, data, silent) '{
local sl
local datas datal
sl = (dev + 0 == dev)? 1 : 0
if((index(dev,":") == 0) && !sl) { dev=sprintf("%s:5000",dev) }
# check argins validity
if (substr(cmd, 1, 1) != "*") {
_icepap_err
print "Bad binary command format"
return
} else if (whatis("data") & 0x0001ffff != 0x00010004) {
_icepap_err
print "Bad binary data array type"
return
}
# guess the data size in words
if((datas = _icepap_array_size(data)) == -1) {
return
}
# if no conversion is needed, then send the data
if(datas == 1) {
return _icepap_send_ushortarray(dev, addr, cmd, data, silent)
}
# convert typed data to binary word array
datal = array_op("rows", data) * array_op("cols", data) * datas
local ushort array dataw[datal]
array_copy(dataw, data)
return _icepap_send_ushortarray(dev, addr, cmd, dataw, silent)
}'
#%IU%(dev, addr, cmd, array, silent)
#%MDESC%
# Send the binary command with its data given in a SPEC ushort data array.
#
def _icepap_send_ushortarray(dev, addr, cmd, dataw, silent) '{
local i
local sl
local ack
local datas
local ulong array datal[3]
local ret
sl = (dev + 0 == dev)? 1 : 0
if((index(dev,":") == 0) && !sl) { dev=sprintf("%s:5000",dev) }
# check argins validity
if(!index(whatis("dataw", "info"), "ushort")) {
_icepap_err
print "Bad binary data array type, must be \"ushort\""
return
}
# prepare binary protocol header
datal[0] = 0xa5aa555a
# preprare data length in words
datas = 1
datal[1] = array_op("rows", dataw) * array_op("cols", dataw) * datas
# the checksum has to be calculated over words
datal[2] = (array_op("sum", dataw)) & 0xffffffff
#for(i=0, datal[2]=0;i<datal[1]/datas;i++){
# datal[2] += data[i] & 0xffff
# if(datas>1) {
# datal[2] += (data[i]>>16) & 0xffff
# }
#}
# make sure acknowledge is properly treated
if(substr(addr, 1, 1) == "#")
ack = 1
if(!silent) {
printf("\tCommand : \"%s\"\n", cmd)
printf("\tData size : %d word%s\n", datas, datas>1?"s":"")
printf("\tData length : %d word%s\n", datal[1], datal[1]>1?"s":"")
printf("\tCheck sum : 0x%08X\n", datal[2])
printf("\tAcknowledge : %s\n", ack?"YES":"NO")
}
# send command line
_icepap_wr(dev, addr, cmd)
# send header
# 2 words startup mark (ex: 0xa5aa555a)
# 2 words for the binary data length
# 2 words for the checksum
sock_put(dev, datal, 3)
# send data block
sock_put(dev, dataw)
# wait for acknowledge
if(ack) {
ret = sock_get(dev, "\n")
return(ret)
} else
return
}'
#%IU%(array)
#%MDESC%
# Returns the size in bytes of the data type of the given array.
# Otherwise -1 if not supported array type
#
def _icepap_array_size(dataw) '{
# guess the data size in words
if(index(whatis("dataw", "info"), "ushort")) { return(1) }
if(index(whatis("dataw", "info"), "short")) { return(1) }
if(index(whatis("dataw", "info"), "ulong")) { return(2) }
if(index(whatis("dataw", "info"), "long")) { return(2) }
if(index(whatis("dataw", "info"), "float")) { return(2) }
if(index(whatis("dataw", "info"), "double")) { return(4) }
_icepap_err
print "Non supported type for data array"
return(-1)
}'
#%IU%(array)
#%MDESC%
# Returns a string corresponding to IcePAP data type
# Otherwise "ERROR" if not supported array type
#
def _icepap_array_type(dataw) '{
# guess the data size in words
if(index(whatis("dataw", "info"), "ushort")) { return("WORD") }
if(index(whatis("dataw", "info"), "short")) { return("WORD") }
if(index(whatis("dataw", "info"), "ulong")) { return("DWORD") }
if(index(whatis("dataw", "info"), "long")) { return("DWORD") }
if(index(whatis("dataw", "info"), "float")) { return("FLOAT") }
if(index(whatis("dataw", "info"), "double")) { return("DFLOAT") }
_icepap_err
print "Non supported type for data array"
return("ERROR")
}'
#%IU%(dev,addr,cmd,array)
#%MDESC%
# NOT IMPLEMENTED YET
#
def _icepap_get_ushortarray(dev, addr, cmd, dataw) '{
local sl
local nwords
local bin_chksum bin_chksum_rd
local ulong array datal[1]
local ret
sl = (dev + 0 == dev)? 1 : 0
if((index(dev,":") == 0) && !sl) { dev=sprintf("%s:5000",dev) }
# check argins validity
if(substr(cmd, 1, 2) != "?*") {
_icepap_err
print "Bad binary request command format"
return
} else if(!index(whatis("dataw", "info"), "ushort")) {
_icepap_err
print "Bad binary data array type, must be \"ushort\""
return
}
# send command line and get its ASCII answer
printf("\tCommand : %s\n", cmd)
_icepap_wr(dev, addr, cmd)
sock_par(dev,"timeout",0.5)
ret = sock_get(dev,"\n")
if(ret=="") {
_icepap_err
print "ERROR missing acknowledge"
return
}
ret = substr(ret,0,length(ret)-1)
printf("\tAnswer : %s\n", ret)
if(index(ret,"ERROR")) {
return
}
# 2 words startup mark (ex: 0xa5aa555a)
sock_get(dev, datal)
# 2 words for the binary data length
sock_get(dev, datal)
nwords = datal[0]
printf("\tData words : %d\n", nwords)
# resize the data array given as argin
ushort array dataw[nwords]
# 2 words for the checksum
sock_get(dev, datal)
bin_chksum_rd = datal[0]
printf("\tCheck sum : 0x%08X\n", bin_chksum_rd)
# data block
sock_par(dev,"timeout",2)
sock_get(dev, dataw)
# check data validity
bin_chksum = (array_op("sum", dataw)) & 0xffffffff
printf("\tData validity : %s\n", (bin_chksum==bin_chksum_rd)?"OK":"ERROR")
return
}'
#%MACROS%
#%IMACROS%
#%AUTHOR% MP BLISS (Original 9/07).
# %BR%$Revision: 1.87 $ / $Date: 2017/09/25 13:32:14 $
#%TOC%
|