esrf

Beamline Instrument Software Support
SPEC Macro documentation: [ Macro Index | BCU Home ]

#%TITLE% ICEPAP.MAC 
#
#%NAME%
# Macros to control ISG ICEPAP motor controller as a macro motor
# and to configure macro counters to read DRIVERs temperatures
# (obsolete: use ice.mac instead)
#
#%CATEGORY% Positioning, Obsolete
#
#%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 "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 128
#         %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 must be set to the MOTORS entry.
#         %DT% -
#         The "Module" field must be set to the ICEPAP rack numer (seen on
#         the red 7 segments display of the top left hand card)
#         %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% -
#         Example: "0/1/2" refers to the first icepap controller declared, 
#         and the 2nd DRIVER of the rack having the number "1" on its display.
#         %DT% -
#         The "Generic parameter 1" parameter (type "m" to access it) is the 
#         motor type (ex: "pk267"). For the moment the motor types and
#         their parameters are defined in:
#         ~blissadm/local/spec/userconf/icepap_catalogue
#         %DT% -
#         The "Generic parameter 2" and nexts can be any of the following
#         options: 
#         %DL%
#           %DT% - 
#           "SWOFF" to disable limitswitches
#           %DT% - 
#           "DIRINV" to reverse the motor direction according to limitswitches
#         %XDL%
#       %XDL%
# %XDL%
#
#%DT%Configuring macro counters to read a single DRIVER %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 %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%
#
#%XDL%
#
#%END%
#



print "--------------------------- WARNING ----------------------------"
print "----------------------- OBSOLETE MACROS  -----------------------"
print "--------------- you should use ice.mac instead -----------------"
print "--------------------------- WARNING ----------------------------"



#
# ----------------------- MACRO MOTOR implementation -----------------------
#

constant ICEPAP_CATALOGUE "/users/blissadm/local/spec/userconf/icepap_catalogue"
constant ICEPAP_LOCKFILE  "/users/blissadm/local/spec/userconf/icepap_lock"

#%UU% [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
 }
}'


#%IU%
#%MDESC%
# Reset socket communication and MASTER FIFOs
#
def icepap_fiforst(dev) '{
 _icepap_wr(dev,"","_FIFORST")
 sock_par(dev,"flush")
}'


#%IU%
#%MDESC%
# Call on <Ctrl-C>
#
def icepap_cleanup(dev) '{
  # give time to sockets
  sleep(.05)
  icepap_fiforst(dev)
}'


#%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%
#%MDESC%
# Read the catalogue of motor parameters from a file
#
def icepap_read_cat() '{
 global ICEPAP_CAT[]
 local  l line c
 local  entry motor_ref
 local  param, val

 if(getline(ICEPAP_CATALOGUE, "open") < 0){
  printf("ICEPAP ERROR: Can\'t open file \"%s\"\n", ICEPAP_CATALOGUE)
  return -1
 } 

 # Erase any previous catalogue (cf can not do unglobal+global)
 for(param in ICEPAP_CAT) delete ICEPAP_CAT[param];
 ICEPAP_CAT["nconf"] = 0

 l = 0
 while ((line = getline(ICEPAP_CATALOGUE)) != -1) {
  l++
  c = substr(line, 1, 1)
  if (asc(c) < 32 || c == "#") continue;

  if (sscanf(line,"motor %s",motor_ref) == 1) {
   motor_ref=icepap__toupper(motor_ref)
   icepap__debug "found new catalogue entry: " motor_ref
   ICEPAP_CAT[motor_ref] = ICEPAP_CAT["nconf"]++

   entry=1
   while(entry) {
    line = getline(ICEPAP_CATALOGUE)
    l++
    if((line == -1) || (line == "\n")) {
     icepap__debug "end of entry: " motor_ref
     entry=0
     continue
    }

    c = substr(line, 1, 1)
    if (asc(c) < 32 || c == "#") continue;
   
    if(sscanf(line, "%s %s",param, val) != 2) {
     printf("ICEPAP ERROR: syntax error at line %d in file \"%s\"\n", \
      l, ICEPAP_CATALOGUE)
     return
    }

    param=icepap__toupper(param)
    ICEPAP_CAT[motor_ref][param] = val
   }

  }
 }

 getline(ICEPAP_CATALOGUE, "close")
 return 0
}'


#%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%(device,crate,board,motor_ref,mne)
#%MDESC%
# Set for a motor its parameter according to catalogue. The motor
# is specified by crate and board. The mne field is for debug print out only.
# The device is the network name of the MASTER.
#
def icepap_set_mot(dev,crate,board,motor_ref,mne) '{
  global ICEPAP_CAT[]
  global ICEPAP[]
  local addr ack_addr
  local cmd 
  local cmd_ans
  local param val val_sd
  local ans id err

  if(mne=="") mne="TEST";

  motor_ref=icepap__toupper(motor_ref)

  if(!(motor_ref in ICEPAP_CAT)) {
   printf("ICEPAP ERROR: \"%s\": unknown motor type \"%s\"\n",mne,motor_ref)
   printf("Hint: update file \"%s\"\n", ICEPAP_CATALOGUE)
   return
  }

  if((crate<0) || (crate>15)) {
   print "ICEPAP: \""mne"\": invalid module/crate "crate" (valid: 0 to 15)"
   return
  }
 
  if((board<1) || (board>8)) 
  {
   print "ICEPAP: \""mne"\": invalid channel/board "board" (valid: 1 to 8)"
   return
  }
  addr=crate*10 + board

  ack_addr = "#" addr

  # get a communication to the ICEPAP master 
  ans=_icepap_query(dev,addr,"?ID")
  if(sscanf(ans,"%s",id) != 1) {
   printf("ICEPAP ERROR: %s: addr: %s: unable to get driver ID\n",mne,addr)
   return
  }
  

  # TODO: check that the id has not changed (in case the driver has been
  # physically replaced and need to be reconfigured)
  ICEPAP[mne]["id"]=id
 

  # If SD parameter is not given in catalogue, the default value is 2Volts
  val_sd=2.0


  # clear DRIVER error messages

# MP 30/01/07 TODO
#  _icepap_query(dev,addr,"?FERRMSG")

  # configure low level motor params
  for(param in ICEPAP_CAT[motor_ref]) {
   val=ICEPAP_CAT[motor_ref][param]
   if(param=="SD") {
     val_sd=val
     continue
   }
   cmd=param" "val
   _icepap_wrrd(dev,ack_addr,cmd)
  }


  # enable the axis
  cmd="SD "val_sd
  _icepap_wrrd(dev,ack_addr,cmd)
  _icepap_wrrd(dev,ack_addr,"CLR")
  _icepap_wrrd(dev,ack_addr,"EN")


  # check that the configuration took place correctly
# MP 30/01/07 TODO
#  ans=_icepap_query(dev,addr,"?FERRMSG")
# TODO
#  if(index(ans," FERR") != 1) {
#   printf("ICEPAP ERROR: %s: addr: %s: unable to get first error\n",mne,addr)
#   icepap_fiforst(dev)
#   return
#  } else {
#   err=substr(ans,7)
#   if(err != "OK") {
#    printf("ICEPAP ERROR: %s: addr: %s: error on driver config\n",mne,addr)
#    print err
#    return
#   }
#  }


}'


#%IU%
#%MDESC%
# MACRO MOTOR: 
# Check that spec is not too old to support controller parameters in
# the config file. Return 0 if > = 5.06.04-4
#
def icepap_specver() '{
 local ver subver

 ver[0]=0
 split(VERSION,ver,".")
 split(ver[2],subver,"-")
 p ver
 p subver
 if((int(ver[0])<5)||(int(ver[1])<6)||(int(subver[0])<4)||(int(subver[1])<4)) {
  return -1
 }

 return 0
}'




#%IU%
#%MDESC%
# MACRO MOTOR: 
# Called by spec after reading the config file
#
def icepap_config(num,type,p1,p2,p3) '{
 global ICEPAP[]
 global ICEPAP_CAT[]
 local dev
 local i
 


 # p1==?? p2==number of motors supported
 if(type=="ctrl") {
  icepap__debug "config(): new controller"
  for(i in ICEPAP) { delete ICEPAP[i] }
  ICEPAP["on"] = 0
  ICEPAP["dev"]=""

  if(icepap_read_cat() != 0) {
    return 
  }

  # get the MASTER
  dev=icepap_ADDR
  if(dev=="") {
    printf("ICEPAP ERROR: missing ADDR field\n")
    return 
  }
  if(index(dev,":") == 0) { dev=sprintf("%s:5000",dev) }
  ICEPAP["dev"]=dev

  cdef ("cleanup_always",sprintf("icepap_cleanup(\"%s\");",dev) ,"ICEPAP")
  ICEPAP["on"] = 1
 }

 # p1==unit p2==module p3==channel
 if(type=="mot") {
  local mne
  local motor_ref
  local opts
  local dev
  local addr
  local i
  local ret

  # If the controller was not well configured then give up
  if(ICEPAP["on"] != 1) { return }

  # 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

  # NOTE MP 24Jan05: it is currently not possible to pass a string through p1
  # but SPEC internally stores the "Generic Parmeter" as a string therefore
  # asking it to SPEC with motor_par() is a work arround
  motor_ref=motor_par(num,"misc_par_1")
  icepap__debug "\""mne"\": motor type == misc_par_1: \"" motor_ref"\""


  # check if the configuration of that motor has been locked
  # in this case do not overwrite the configuration
  ret=_icepap_islock(sprintf("%d/%d",p2,p3))
  if(ret == 0)
   icepap_set_mot(dev,p2,p3,motor_ref,mne);
  else if(ret == 1)
   printf("ICEPAP WARNING: motor configuration locked for %s\n",mne);

  ICEPAP[mne]["addr"]=p2*10+p3
  addr=ICEPAP[mne]["addr"]

  _icepap_wr(dev,addr, "ESW 1")
  _icepap_wr(dev,addr, "TDIR 0")

  i=2
  while((opts=motor_par(num,sprintf("misc_par_%d",i++))) != 0)
  {
   opts = icepap__toupper(opts)
   if(opts == "SWOFF")       { _icepap_wr(dev,addr, "ESW 0") }
   else if(opts == "DIRINV") { _icepap_wr(dev,addr,"TDIR 1") }
  }


 }
}'


#%IU%
#%MDESC%
# MACRO MOTOR: 
# Called by spec after reading the config file, after calling _config()
# and only if parameters are set in the config file for a motor.
#
def icepap_par(num,key,todo,p1) '{
 global ICEPAP[]
 local mne

 mne=motor_mne(num)

}'


#%IU%
#%MDESC%
# MACRO MOTOR: 
# Called by spec on motor operation.
# 
def icepap_cmd(num,key,p1,p2) '{
 local dev
 local mne
 local addr

 if(num == "..") { return }

 # If the controller was not well configured then give up
 if(ICEPAP["on"] != 1) { 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 ans

  ans= _icepap_query(dev,addr,"?P")
  if(sscanf(ans,"%f",pos) != 1) {
   printf("ICEPAP ERROR: %s: addr: %s: unable to get position\n",mne,addr)
   return(0)
  }
  pos = pos / motor_par(num,"step_size")
  icepap__debug sprintf("\"%s\": pos      %d",mne,pos)
  return(pos)
 }


 #
 # start a motion (p1==abs pos, p2==rel pos, with pos in mm or deg)
 #
 if (key == "start_one") {
  local pos 
  local cmd
  local stp
  local v0
  local vsr
  local a0

  stp=motor_par(num,"step_size")

  # minimum check on motion parameters
  v0= _icepap_query(dev,addr,"?V0")
  if(v0<=0)
  {
   p "ICEPAP ERROR: base rate must be >0 : "v0
   exit
  }
  vsr= _icepap_query(dev,addr,"?VSR")
  if(vsr<v0)
  {
   p "ICEPAP ERROR: velocity must be >= base rate : "vsr
   exit
  }
  a0= _icepap_query(dev,addr,"?A0")
  if((a0<=0) || (a0>20000))
  {
   p "ICEPAP ERROR: acceleration must be >0 and < 20000stp/sec2 : "a0
   exit
  }



  cmd=sprintf("DIR %d",(p2>0))
  _icepap_wr(dev,addr,cmd)

  pos=fabs(p2)*stp
  if((pos-int(pos)) >= 0.5) pos += 0.5;
  pos=int(pos)
  cmd=sprintf("GO %d",pos)
  _icepap_wr(dev,addr,cmd)

  return
 }

 #
 # Check if the driver is powered and ready to use
 #
 if (key == "prestart_one") {
  local ret
  local ans
  local i

  #
  #TODO: ?OVL != 0 print out warning msg and give up
  #


  return(0)
 }


 #
 # return the current motor status
 #
 if (key == "get_status") {
  local ret
  local ans
  local sta sta_neg sta_pos
  local oldfashion


  oldfashion=1
  if(oldfashion)
  {
  # get moving status
  ret = 0
  sta = 0
  ans=_icepap_query(dev,addr,"?ST")
  if(sscanf(ans,"%d",sta) != 1) {
   printf("ICEPAP ERROR: %s: addr: %s: unable to get status\n",mne,addr)
   return(0);
  }
  if(sta == 1) ret |= 0x02;


  # get limitswitches status
  ans=_icepap_query(dev,addr,"?SW")
  if(sscanf(ans,"%d %d",sta_neg,sta_pos) != 2) {
   printf("ICEPAP ERROR: %s: addr: %s: unable to get limitswitches\n",mne,addr)
   return(0);
  }
  if(sta_neg == 1) ret |= 0x04;
  if(sta_pos == 1) ret |= 0x08;

  }
  else
  {
  # ICEPAP DRIVER DSP needs at least 20mS to update dual RAM
  sleep(0.05)

  ret = 0
  ans=_icepap_query(dev,"",sprintf("?STAT %d",addr))
  if(sscanf(ans,"%d",sta) != 1) {
   printf("ICEPAP ERROR: %s: addr: %s: unable to get status\n",mne,addr)
   return(0);
  }
  # get moving status
  if(sta & (1<<10)) ret |= 0x02;
  # get limitswitches status
  if(sta & (1<<19)) ret |= 0x04;
  if(sta & (1<<18)) ret |= 0x08;
  }



  return(ret)
 }


 #
 # stop a single motor
 #
 if (key == "abort_one") {
  _icepap_wr(dev,addr,"STOP")
  return
 }



 #
 # set position (p1=mm)
 #
 if (key == "set_position") {
  _icepap_wr(dev,addr,sprintf("P %d",p1*motor_par(num,"step_size")))
  return
 }

 #
 # set acceleration (p1=ms p2=steps/sec^2)
 #
 if (key == "acceleration") {
  _icepap_wr(dev,addr,sprintf("A0 %d",p2))
  return
 }


 #
 # set base_rate (p1=rate in Hz)
 #
 if (key == "base_rate") {
  _icepap_wr(dev,addr,sprintf("V0 %d",p1))
  return
 }


 #
 # set slew_rate (p1=rate in Hz)
 #
 if (key == "slew_rate") {
  _icepap_wr(dev,addr,sprintf("VSR %d",p1))
  return
 }

}'




#%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,"",":RACKRST")
}'



#%UU% 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)
}'


#%UU% 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) {
   print "ICEPAP ERROR: error creating file "ICEPAP_LOCKFILE
   return -1
  }
 }
 close(ICEPAP_LOCKFILE)

 if(getline(ICEPAP_LOCKFILE, "open") < 0){
  printf("ICEPAP ERROR: 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) {
  print "ICEPAP ERROR: 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) {
  print "ICEPAP ERROR: 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) {
  print "ICEPAP ERROR: 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%
# MACRO COUNTER: 
# Read the temperature on the specified address
# Returns 0 in case of error
#
def _icepapcnt_gettemp(dev,addr) '{
 local ans
 local t

 ans= _icepap_query(dev,addr,"?TEMP")
 if(sscanf(ans,"%d",t) != 1) {
  printf("ICEPAP ERROR: %s: addr: %s: unable to get temp\n",mne,addr)
  icepap_chkerr(dev,ans)
  icepap_fiforst(dev)
  return(0)
 }
 return(t)
}'


#%IU%
#%MDESC%
# MACRO COUNTER: 
# Called by spec after reading the config file
#
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%
# MACRO COUNTER: 
# Called by spec on counter operation.
#
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%
#%MDESC%
# MACRO COUNTER: 
# Called by spec after reading the config file
#
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%
# MACRO COUNTER: 
# Called by spec on counter operation.
#
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]
 }
}'





#
# ----------------------- direct accces macros -------------------------
#


#%UU% [hostname[:port]]
#%MDESC%
# Console implementation to communicate to icepap MASTER
#
def icepap '{
 global ICEPAP[]
 local dev
 local line c fc
 local ncomm
 local his[]
 local nhis
 local chis
 

 if($# < 1) {
  dev=getval("Icepap MASTER network name",ICEPAP["dev"])
 } else {
  dev="$1"
 }

 if(!index(dev,":")) { dev = dev":5000" }
 ICEPAP["dev"]=dev


 rdef cleanup_once sprintf("_icepap_close(\"%s\")",dev)

 if(sock_put(dev, "help\n") == -1) { exit }
 sleep(0.1)
 sock_par(dev,"timeout",0.1)
 p "\n" sock_get(dev) "\n"
 
 if(sock_put(dev, "sockhelp\n") == -1) { exit }
 sleep(0.1)
 sock_par(dev,"timeout",0.1)
 p "\n" sock_get(dev) "\n"
 
 ncomm = 1
 nhis  = 0
 chis  = 0
 while(1) {
  line = ""
  printf("%d.ICEPAP console> ",ncomm);
  while(1) {
    c = input(-1)
    if (c == "\n") {
      printf("\n")
      tty_cntl("cd")
      break
    } else if ((c == "\b" || c == "\177") && line) {
      line = substr(line, 0, length(line)-1)
      printf("\b \b")
    } else if (asc(c) == 27) {
      sleep(0.01)
      c = input(-1)
      sleep(0.01)
      c = input(-1)
      if(asc(c) == 0x41) {
       if(chis) { 
        line = his[--chis] 
        printf("\r")
        tty_cntl("cd")
        printf("%d.ICEPAP console> %s",ncomm,line);
       }
      } else if(asc(c) == 0x42) {
       if(chis<nhis) { 
        line = his[++chis] 
        printf("\r")
        tty_cntl("cd")
        printf("%d.ICEPAP console> %s",ncomm,line);
       }
      }
    } else if (c >= " " && c <= "z") {
      line = line c
      printf(c)
    }
  }

  line = icepap__toupper(line)

  if(line) {
   his[nhis]=line
   nhis++
   chis=nhis

   line = line "\n"
   sock_put(dev, line)
   ncomm++
   sleep(0.1)
  }


  if((line == "QUIT\n") || (line == "CLOSE\n")) {
   sock_par(dev,"close")
   exit
  }

  fc = substr(line,1,1) 
  if((fc=="?") || (fc=="#"))
  {
   # get answer of query commands
   sock_par(dev,"timeout",2)
   p sock_get(dev) "\n"
  }
  else
  {
   # some commands may have answer even if they are not query commands
   sock_par(dev,"timeout",0.5)
   p sock_get(dev) "\n"
  }

 }
}'





#%UU% [hostname[:port] [file] [addr] [options]]
#%MDESC%
# Program a the ICEPAP module with the specified binary file
#
def icepap_prog '{
 global ICEPAP[]
 local dev
 local fname
 local addr
 local bin_l
 local bin_chksum
 local cmd
 local opt
 local sl
 

 if($# < 1) {
  dev=getval("Icepap MASTER network name or SL",ICEPAP["dev"])
 } else {
  dev="$1"
 }

 sl = (dev + 0 == dev)?1:0

 if(!sl && !index(dev,":")) { dev = dev":5000" }
 ICEPAP["dev"]=dev

 if($# < 2) {
  fname=sprintf("%s/%s",BLISSADM,"local/userconf/icepap/icepapfw0.0")
  fname=getval("Binary program file",fname)
 } else {
  fname="$2"
 }

 if(file_info(fname,"-r") == 0) {
  print "ERROR: unable to read file \""fname"\""
  exit
 } 

 if($# < 3) {
  addr=getval("What to program (\"ALL\"|\"DRIVERS\"|\"COMM\"|\"NONE\"|addr) ",\
     "NONE")
 } else {
  addr="$3"
 }
 addr = icepap__toupper(addr)

 if($# < 4) {
  opt=getval("Options (\"SAVE\"|\"SL\"|\"FORCE\"|\"NONE\") ","SAVE")
 } else {
  opt="$4"
  if($#>4) { opt=opt " $5" }
  if($#>5) { opt=opt " $6" }
  if($#>6) { opt=opt " $7" }
  if($#>7) { opt=opt " $8" }
 }
 opt = icepap__toupper(opt)

 # Get a connection to ICEPAP
 if(!sl) { _icepap_check(dev) }

 bin_l = (file_info(fname,"size")/2) & 0xffffffff

 local ushort array icepapfw[bin_l]
 fmt_read(fname,"raw",icepapfw)



 # ASCII Cmd to inform that binary data is coming
 if(addr=="NONE") { addr="" }
 if(opt =="NONE") { opt ="" }

 cmd = sprintf("*PROG %s %s",addr, opt)
 printf("\tCommand sent  : \"%s\"\n", cmd)
 if(sl) { ser_put(dev,sprintf("%s\n",cmd)) } else { _icepap_wr(dev,"",cmd) }

 # 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\t", bin_l)
 if(sl) { bench ser_put(dev, icepapfw) } else { bench sock_put(dev, icepapfw) }

 if(!sl) { sock_par(dev,"close") }
 print "Binary data transferred"

}'



#%UU% [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"
}'




#%UU% [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"))
 {
  print "ICEPAP ERROR: communication program not running on MASTER"
  print "Hint: reset MASTER or run \"icepap_sock\" on ",dev
  exit
 }
 sock_par(dev,"timeout",3)
 ans=_icepap_wrrd(dev,"","?_SOCKPING")
 if(ans != "OK") {
  print "ICEPAP ERROR: 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,"CLOSE\n");
 sock_par(dev,"close");
}'


#%IU%(dev,addr,cmd)
#%MDESC%
#
def _icepap_wr(dev,addr,cmd) '{
 local str


 if(addr != "" && addr != "#") str=addr":"cmd; else str=cmd;
 if (addr == "#") str = "#" str
 str=str"\n"
 sock_put(dev,str);
}'


#%IU%(dev,addr,cmd)
#%MDESC%
#
def _icepap_wrrd(dev,addr,cmd) '{
 local ret
 
 _icepap_wr(dev,addr,cmd)
 ret=sock_get(dev);
 return(ret)
}'


#%IU%(dev,addr,cmd)
#%MDESC%
#
def _icepap_query(dev,addr,cmd) '{
  local ans[]
  local cmd_ans
  local n
  local ret
  local i


  ret=""

  cmd_ans=_icepap_wrrd(dev,addr,cmd)
  n=split(cmd_ans,ans)
  if(n<2) {
   printf("ICEPAP ERROR: bad answer from ICEPAP\n")
   return(ret)
  }
  
  if(index(ans[1],"ERROR")) {
   printf("ICEPAP ERROR: from ICEPAP: %s\n",cmd_ans)
   return(ret)
  }

  ret=substr(cmd_ans,index(cmd_ans," "))
  return(ret)

}'








#
# ----------------------- test macros -------------------------
#


#%IU% hostname:port crate board
#%MDESC%
# Custom debug sequence 
# (H.GONZALEZ)
#
def icepaptst '{
 local board
 local crate
 local addr
 local usage


 usage ="USAGE: $0 hostname:port crate board\n"
 usage = usage"  hostname:port of MASTER (ex: \"isgtmp5:5000\")\n"
 usage = usage"  crate from 0 to 15 (look a MASTER front panel)\n"
 usage = usage"  board from 1 to 8\n"

 # Ya un couillon au clavier ?
 if($# != 3) 
 { 
  printf("%s",usage)
  exit
 }
 dev  ="$1"
 crate= $2
 board= $3
 
 if((crate<0) || (crate>15) || (board<1) || (board>8)) 
 {
  printf("%s",usage)
  exit
 }
 addr=crate*10 + board

 _icepap_check(dev)

 # ok, on peut bosser
 sock_put(dev,sprintf("%d:?ID\n",addr));
 p sock_get(dev)
 
 sock_put(dev,sprintf("%d:?TEMP\n",addr));
 p sock_get(dev)

 sock_put(dev,sprintf("%d:CLR\n",addr));
 
 
 icepap_set_mot(dev,crate,board,"0.25")

 mvr m$2 $3
 mvr m$2 -$3
 
 icepap_set_mot(dev,crate,board,"0.5")

 mvr m$2 $3
 mvr m$2 -$3
 
 icepap_set_mot(dev,crate,board,"1")

 mvr m$2 $3
 mvr m$2 -$3
 
 icepap_set_mot(dev,crate,board,"2")

 mvr m$2 $3
 mvr m$2 -$3
 
 icepap_set_mot(dev,crate,board,"4")

 mvr m$2 $3
 mvr m$2 -$3
 
}'



#%IU% hostname:port
#%MDESC%
# Intensive test loop on the specified Icepap MASTER (ex: "isgtmp5:5000")
#
def icepap_massacre '{
 global ICEPAP[]
 local dev
 local ans
 local i b

 if($# != 1) {
  dev=getval("Icepap MASTER network name",ICEPAP["dev"])
 } else {
  dev="$1"
 }

 if(!index(dev,":")) { dev = dev":5000" }
 ICEPAP["dev"]=dev

 for(i=0;;i++) {
  p "----------------------- "date()" loop: "i
  p "prog DSP en RAM"
  sock_put(dev,"dsppgm\n")
  sleep(5)
  p "reset DSP == prog DSP en FLASH"
  sock_put(dev,"dsprst\n")
  sleep(3)
  p "reset FIFO == test mailbox + IRQ DSP"
  icepap_fiforst(dev)
  sleep(3)
 
  p "testing FIFO"
  sock_put(dev,"?ID\n")
  ans=sock_get(dev)
  if(sscanf(ans, " ID %d",b) != 1) {
   p "ERROR on FIFO"
   cmd=sprintf("echo \"Error on FIFO\nloop %d\n%s\" | mailx -s \"pb\" jclement@esrf.fr ", i, date())
   unix(cmd)
   exit
  }
  p ans
 }
}'




#%MACROS%
#%IMACROS%
#%AUTHOR% MP BLISS (Original 8/05).
# %BR%$Revision: 1.3 $ / $Date: 2008/07/17 14:29:34 $
#%TOC%