esrf

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

#%TITLE% SLITSET.MAC
#%NAME%
#Macros for operating slits with independent blades.
#
#This macro set allows you to define pseudo motors on slits.
#
#Since version 4.0 (Feb 2006) this macro file allows also to
#define new style calculation macro motors on slits.
#
#To define new style macro motors you must define:
#
#a slit controller in config (one controller will work on one or
#two pair of blades):
#
#%PRE%
#MOTORS       DEVICE    ADDR   <>MODE      NUM               <>TYPE
#  YES       slit                           4         Macro Motors
#%PRE%
#motors in config referring to that controller. Channel assignment
#will decide on the motor role as follow:
#%PRE%
#Channel
# 0   -   gap    
# 1   -   offset 
#%PRE%
#Different pairs of slits can be defined by using additional
#module numbers in the motor unit/module/channel assignment.
#
#Config file
# The following motor parameters have to be associated in config
# file to the channel 0 of the controller/module. 
#
# Example:
#%PRE%
# MOT000 = MAXE:0/0 [...]   psu
# MOT001 = MAXE:0/1 [...]   psd
# MOT002 = MAXE:0/2 [...]   psl
# MOT003 = MAXE:0/3 [...]   psr
# MOT004 = MAXE:0/4 [...]   ssu
# MOT005 = MAXE:0/5 [...]   ssd
#
# MOT006 = MAC_MOT:0/0/0 [....]         psvg
# MOTPAR:blade1 = psu
# MOTPAR:blade2 = psd
# MOT007 = MAC_MOT:0/0/1 [....]         psvo
#
# MOT008 = MAC_MOT:0/1/0 [....]         pshg
# MOTPAR:blade1 = psl
# MOTPAR:blade2 = psr
# MOT009 = MAC_MOT:0/1/1 [....]         psho
#
# MOT010 = MAC_MOT:0/2/0 [....]         ssvg
# MOTPAR:blade1 = ssu
# MOTPAR:blade2 = ssd
# MOT011 = MAC_MOT:0/2/1 [....]         ssvo
#%PRE%
#%OVERVIEW%
#  
#These macros implement pseudomotors for slitsets with independent blades.
#Each set is composed by one or two slits (two or four blades). You will be
#able to use offset and gap motors that will move the corresponding blades.
#The main features are:%BR%
#%UL%
#%LI%Limits are consistently checked on all motors (blades and pseudomotors).
#%LI%The %B%set%B% macro lets change the user position of the pseudomotors as if they were ordinary motors. Actually the user position of the blades are corrected to set the pseudomotors to the desired values.
#%LI%Automatic search of mechanical reference (some additional setup required).
#%LI%A `where' macro that displays the position of the slitset is automatically defined.
#%LI%The unsetup procedure is implemented.
#%XUL%
#
#%EXAMPLE%
#
#  %DL%
#  %DT%slitsetup ps pho phg pr pl pvo pvg pu pd 
#  %DD%Configures a slitset called `ps' that consists of a vertical and a
#  horizontal slit. Two logical motors (`pho' and `phg') are associated to the
#  offset and gap of the slit defined by the blades `pr' and `pl'. In the same
#  way `pvo' and `pvg' are logical motors associated to `pu' and `pd'.
#  %DT%mv phg 1
#  %DD%Moves the horizontal gap to 1 mm.
#  %DT%dscan pho -5 5 80 1
#  %DD%Scans the slit in the horizontal direction (horizontal offset).
#  %DT%wps
#  %DD%Displays the current position of the slits in the set `ps'.
#  %DT%set phg 0
#  %DD%Changes the user position of `pr' and `pl' to zero the gap.
#  %DT%slitshow ps
#  %DD%Displays the current configuration of the slitset `ps'.
#  %DT%slithome ps
#  %DD%Moves the blades of the slitset `ps' to the mechanical reference and
#  set their dials to the values in the configuration file.
#  %DT%slitzero ps
#  %DD%Moves the slitset `ps' to the zero position defined in the
#  configuration file.
#  %XDL%
#%BR%MCD 02/05/11: add a scale factor on the gap or offset, so that
#the resulting gap or offset original value is multiplied by this scale factor.
#%BR%This is implemented when the 
#%BR%     MOTPAR:scale = <a value>
#%BR%is added to the macromotor
#%BR%This is useful in particular when moving the gap executes a rotational
#movement on the plate and we want the gap to reflect the angular rotation.

def slit_config(mne,type,unit,module,chan) '{

   if (type == "ctrl") return

   master = motor_par(mne,"chan0")
   chan   = motor_par(mne,"channel")

   blade1 = motor_par(master,"blade1")
   blade2 = motor_par(master,"blade2")

   if ( motor_num(blade1) == -1 || motor_num(blade2) == -1) {  
      return ".error."
   }

   motor_par(mne, "master",  master, "add")

   if (chan == 0) {

      motor_par(mne,    "role",   "slitgap","add")
      motor_par(mne,    "locked",   0,       "add")
      motor_par(mne,    "setp",    -999,       "add")
      motor_par(mne,    "oldpos",  -999,       "add")
      local myscale
      myscale = motor_par(mne,    "scale")
      if (myscale < 1.0e-8) {
         myscale = 1
      }
      motor_par(mne,    "scalefactor",  myscale,       "add")
      motor_par(master, "slitgap", motor_mne(mne),  "add")

      motor_par(blade1, "master",  mne, "add")
      motor_par(blade2, "master",  mne, "add")
      motor_par(blade1, "oldpos",  -999, "add")
      motor_par(blade2, "oldpos",  -999, "add")

      motor_par(blade1, "role",  "blade1", "add")
      motor_par(blade2, "role",  "blade2", "add")

   } else if (chan == 1) {
      motor_par(mne,    "role",   "slitoff",  "add")
      motor_par(mne,    "locked",  0,          "add")
      motor_par(mne,    "setp",   -999,       "add")
      motor_par(mne,    "oldpos",  -999,       "add")
      motor_par(master, "slitoff", motor_mne(mne), "add")
      local myscale
      myscale = motor_par(mne,    "scale")
      if (myscale < 1.0e-8) {
         myscale = 1
      }
      motor_par(mne,    "scalefactor",  myscale,       "add")
   } else {
      print "Wrong channel assignment for slit motor. Only 0 or 1 accepted"
      return ".error."
   }

   cdef("user_checkall",sprintf("slit_checkmove(%s)\n",master),motor_mne(master),0x01)

   return sprintf("%s %s", blade1, blade2)
}'

def slit_calc(mne,mode,master0) '{
   local role master motnum
   local blade1 blade2 slitoff slitgap
   local bl1num bl2num offnum gapnum

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

   motnum = motor_num(mne)
   role   = motor_par(mne,"role")
   master = motor_par(mne,"master")

   if ( mode == 0) {
      blade1 = motor_par(master, "blade1")
      blade2 = motor_par(master, "blade2")
      bl1num = motor_num(blade1)
      bl2num = motor_num(blade2)
      local scale      
      scale = motor_par(mne,"scalefactor")

      if (role == "slitoff") {
        A[motnum] = ((A[bl1num] - A[bl2num]) / 2.0) * scale
      } else if ( role == "slitgap") {  # role = gap
        A[motnum] = (A[bl1num] + A[bl2num]) * scale
      }

   } else {

      slitoff = motor_par(master, "slitoff")
      slitgap = motor_par(master, "slitgap")
      offnum  = motor_num(slitoff)
      gapnum  = motor_num(slitgap)

      offpos = A[offnum]
      gappos = A[gapnum]

      if ( motor_par(offnum,"locked") ) {
          offpos = motor_par(offnum,"setp")
      }
      if ( motor_par(gapnum,"locked") ) {
          gappos = motor_par(gapnum,"setp")
      }

      if (role == "blade1") {
         A[motnum] = (gappos/2.0)/motor_par(gapnum,"scalefactor") + offpos/motor_par(offnum,"scalefactor")
      } else if (role == "blade2") {  # role = blade2
         A[motnum] = gappos/2.0/motor_par(gapnum,"scalefactor")- offpos/motor_par(offnum,"scalefactor")
      }
   }

   motor_par( motnum,"oldpos", A[motnum])

}'

def slit_checkmove(master) '{

     local slitmots 
     local diff mot motnum

     slitmots["gap"] = motor_num( motor_par(master,"slitgap") )
     slitmots["off"] = motor_num( motor_par(master,"slitoff") )
     slitmots["bl1"] = motor_num( motor_par(master,"blade1") )
     slitmots["bl2"] = motor_num( motor_par(master,"blade2") )

     offnum = slitmots["off"]
     gapnum = slitmots["gap"]

     for ( mot in slitmots )  {
         motnum = slitmots[mot]
         diff   = fabs( A[motnum] - motor_par(motnum,"oldpos") )

         if ( diff > 1.0 / motor_par( motnum, "step_size") ) {
             if ( mot == "bl1" || mot == "bl2") {
                 motor_par( slitmots["gap"], "locked", 0)
                 motor_par( slitmots["off"], "locked", 0)
             } else {
                 if ( mot == "off" ) {  # offset - fix gap
                     if ( motor_par(gapnum,"locked") == 0 ) {
                        motor_par(gapnum,"setp",A[gapnum])
                        motor_par(gapnum,"locked",1)
                     }
                 } else {  #  gap - fix offset
                     if ( motor_par(offnum,"locked") == 0 ) {
                        motor_par(offnum,"setp",A[offnum])
                        motor_par(offnum,"locked",1)
                     }
                 }
                 motor_par(motnum,"locked",0)
             }
         }

     }

}'

def slit '{
   local mne master
   mne    = "$1"
   master = motor_par(mne,"chan0")

   print "Gap    :"  motor_par(master,"slitgap")
   print "Offset :"  motor_par(master,"slitoff")
   print "Blade1 :"  motor_par(master,"blade1")
   print "Blade2 :"  motor_par(master,"blade2")
}'

#%UU% <name> <offs> <gap> <bld1> <bld2> [<offsV> <gapV> <bldV1> <bldV2>]
#%MDESC%
#  Configures a slitset with one or two slits. Each slit consists of two
#  real motors (<bld1>, <bld2>) that move the independent blades and two
#  logical motors <offs> and <gap> associated respectively to the position
#  (offset) and aperture (gap) of the resulting slit. The setup of <bld1>
#  and <bld2> must be such that moving both blades in the positive direction
#  the slit opens. The sign of <offs> is that of the first blade (<bld1>).%BR%
#  More than one slitset can be defined by using different names. A macro
#  called `w<name>' is internally defined for each slitset. This macro
#  displays the current position of the slitset. If a slitset includes two
#  slits, it is assumed that the first one is the horizontal and the second
#  one the vertical.%BR%
#  All the motors must be defined in the configuration file, the logical 
#  motors having their controllers selected to `NONE'.%BR%
def slitsetup '{
   local npar key 

   npar = $# - 1
   if (npar != 4 && npar != 8){
      if (SETUP) print "Error in line: slitsetup $*"
      print "Usage: $0 name offsH gapH bladeH bladeH "\
                          "[offsV gapV bladeV bladeV]"
   } else {
      global SLIT
      key = "slit$1"
      newwhere = "w$1"
      list_test SLIT

      """
      Protect the macro motors from the pseudo motor stuff, 
      if a slitsetup is run. Check for macromotor controller
      It will allow to use the nice wps and slitshow macro
      """
      if (motor_par($2, "controller") != "PSE_MAC_MOT") {
          global SLITPOS
          cdef("user_checkall", "slit_move $*\n", key)
          cdef("user_getpangles", "slit_getangles $*\n", key)
          cdef("user_set", "slit_setuser $*\n", key)
          if (!SETUP)
             cdef("user_config", "slitset_config $*\n", key)
          else
             cdef("user_config", "", key, "delete")
          slitset_config $*
      }
      list_add(SLIT, "$1")
      list_setpar(SLIT, "$1", "param", "$*")
      checkifmacro w$1 slit_where
      if (!error)
         rdef w$1 "slit_where \$# $*"
      else
         print "Macro `w$1\' already defined. No `where slits\' macro."


      # This line is mandatory
      setup_tail("slit", "slit$1 w$1 $1")
   }
}'

#%IU% "slit<name>" "w<name>"
#%MDESC%
#  Undoes the configuration of a slitset.
def slitunsetup '{
   local key
   key = "$1"
   SLIT["$1"] = 0
   cdef("", "", key, "delete")
   list_remove(SLIT, "$3"), "$3"
   if (!SLIT[0]) unglobal SLIT SLITPOS
   checkifmacro $2 slit_where
   if (!error) undef $2
}'

#%IU% <name> <offs> <gap> <bld1> <bld2> [<offsV> <gapV> <bldV1> <bldV2>]
#%MDESC%
#  Checks the validity of the motor mnemonics and enable or disable the
#  whole slitset.
def slitset_config '{
   local npar

   npar = $# - 1
   if (motor_num("$2") < 0 || motor_num("$3") < 0 ||              \
       motor_num("$4") < 0 || motor_num("$5") < 0 || npar==8 && ( \
       motor_num("$6") < 0 || motor_num("$7") < 0 ||              \
       motor_num("$8") < 0 || motor_num("$9") < 0)) {
      print "\nMotor mnemonics for slitset `$1\' are not valid."
      SLIT["$1"] = 0
   } else {
      SLIT["$1"] = 1
      SLIT["MOVED_$2"] = SLIT["MOVED_$3"] = 0
      if (npar == 8) SLIT["MOVED_$6"] = SLIT["MOVED_$7"] = 0
   }
}'

#%IU% <name> <offs> <gap> <bld1> <bld2> [<offsV> <gapV> <bldV1> <bldV2>]
#%MDESC%
def slit_move '
   if (SLIT["$1"]){
      slitset_move($2,$3,$4,$5)
      if ($# == 9) {
         slitset_move($6,$7,$8,$9)
      }
   }

'

#%IU% <name> <offs> <gap> <bld1> <bld2> [<offsV> <gapV> <bldV1> <bldV2>]
#%MDESC%
def slit_getangles '
   if (SLIT["$1"]){
      slitset_getangles($2, $3, $4, $5)
      if ($# == 9) {
         slitset_getangles($6, $7, $8, $9)
      }
   }

'

#%IU% <name> <offs> <gap> <bld1> <bld2> [<offsV> <gapV> <bldV1> <bldV2>] <motor> <position>
#%MDESC%
def slit_setuser '
   if (SLIT["$1"]){
      if (motor2set == $2 || motor2set == $3 || \
          motor2set == $4 || motor2set == $5) {
	if (motor2set == $2 || motor2set == $3) {
          slitset_chgoff $2 $3 $4 $5
	}
        SLIT["MOVED_$2"] = SLIT["MOVED_$3"] = 0
      } else if ($# == 9 && (motor2set == $6 || motor2set == $7 || \
                             motor2set == $8 || motor2set == $9)) {
	if (motor2set == $6 || motor2set == $7) {
          slitset_chgoff $6 $7 $8 $9
	}
        SLIT["MOVED_$6"] = SLIT["MOVED_$7"] = 0
      }
   }
'

#%IU% <offs> <gap> <bld1> <bld2>
#%MDESC%
def slitset_chgoff '
   local dpos 

   dpos = position2set - A[motor2set]
   if (motor2set == $1) {
      chg_offset($3, A[$3]+dpos)
      chg_offset($4, A[$4]-dpos)
   } else {
      chg_offset($3, A[$3]+dpos/2)
      chg_offset($4, A[$4]+dpos/2)
   }
'

#%IU% (<offs>, <gap>, <bld1>, <bld2>)
#%MDESC%
def slitset_move(offs, gap, bld1, bld2) '{
   local blademove gapmove offmove 
   local m_offs m_gap

   offmove = (SLITPOS[offs]!=A[offs])
   gapmove = (SLITPOS[gap]!=A[gap])
   blademove  = (SLITPOS[bld1]!=A[bld1] || SLITPOS[bld2]!=A[bld2])
   if ((offmove || gapmove) && blademove){
      printf("Can\'t move `%s\' and `%s\' simultaneously.\n",\
              offmove?motor_mne(offs):motor_mne(gap),        \
              SLITPOS[bld1]!=A[bld1]?motor_mne(bld1):motor_mne(bld2))
      print "Motion aborted."
      exit
   }

   if (offmove || gapmove || blademove){
      m_offs = sprintf("MOVED_%s", motor_mne(offs))
      m_gap = sprintf("MOVED_%s", motor_mne(gap))
      if (offmove || gapmove){
         old_offs = sprintf("PREV_%s", motor_mne(offs))
         old_gap = sprintf("PREV_%s", motor_mne(gap))
         if (offmove && !gapmove && SLIT[m_offs]) A[gap] = SLIT[old_gap]
         if (gapmove && !offmove && SLIT[m_gap]) A[offs] = SLIT[old_offs]
         SLIT[old_offs] = A[offs]
         SLIT[old_gap] = A[gap]
         A[bld1] = A[gap]/2 + A[offs]
         A[bld2] = A[gap]/2 - A[offs]
      }
      A[offs] = (A[bld1] - A[bld2]) / 2
      A[gap] = A[bld1] + A[bld2]
      SLIT[m_offs] = offmove
      SLIT[m_gap] = gapmove
   }
}'

#%IU% (<offs>, <gap>, <bld1>, <bld2>)
#%MDESC%
def slitset_getangles(offs, gap, bld1, bld2) '{
   local soffs sgap

   soffs = user(offs, 1) - user(offs, 0)
   sgap = user(gap, 1) - user(gap, 0)
   chg_offset(offs, soffs * dial(offs, A[offs])+(user(bld1,0)-user(bld2,0))/2)
   chg_offset(gap, sgap * dial(gap, A[gap])+ user(bld1,0)+user(bld2,0))
   SLITPOS[offs] = A[offs] = (A[bld1]-A[bld2])/2
   SLITPOS[gap]  = A[gap]  = A[bld1]+A[bld2]
   SLITPOS[bld1] = A[bld1]
   SLITPOS[bld2] = A[bld2]
}'

#%IU% 0|1 <name> <offs> <gap> <bld1> <bld2> [<offsV> <gapV> <bldV1> <bldV2>]
#%MDESC%
#  Displays the current position of a slitset. If the first parameter is 1
#  more detailed information is presented.
def slit_where '
   waitmove; get_angles
#   onp
   if (!SLIT["$2"]){
      print "Slit set `$2\' is disabled."
   } else {
      if ($# == 10) {
         slit_disp($1, "Horizontal", $3, $4, $5, $6)
         slit_disp($1, "Vertical", $7, $8, $9, $10)
      } else {
         slit_disp($1, "Slit `$2\'", $3, $4, $5, $6)
      }
   }
#   offp
'

#%IU%  (<format>, <label>, <offs>, <gap>, <bld1>, <bld2>)
#%MDESC%
def slit_disp(format, label, offs, gap, bld1, bld2) '{
   local _offset _gap _blade1 _blade2
   _offset = sprintf("Offset(%s)", motor_mne(offs))
   _gap = sprintf("Gap(%s)", motor_mne(gap))
   _blade1 = sprintf("Blade(%s)", motor_mne(bld1))
   _blade2 = sprintf("Blade(%s)", motor_mne(bld2))
   printf("%10s: %12s %12s %12s %12s\n",label,_offset,_gap,_blade1,_blade2)
   if (format == 1) {
      printf("           %12.4f %12.4f %12.4f %12.4f    High\n",         \
               user(offs, get_lim(offs, 1)), user(gap, get_lim(gap, 1)), \
               user(bld1, get_lim(bld1, 1)), user(bld2, get_lim(bld2, 1)))
   }
   printf("%10s %12.4f %12.4f %12.4f %12.4f   (User)\n", "", \
                                           A[offs], A[gap], A[bld1], A[bld2])
   if (format == 1) {
      printf("           %12.4f %12.4f %12.4f %12.4f    Low\n",          \
               user(offs, get_lim(offs,-1)), user(gap, get_lim(gap,-1)), \
               user(bld1, get_lim(bld1,-1)), user(bld2, get_lim(bld2,-1)))
      print
      printf("           %12.4f %12.4f %12.4f %12.4f    High\n",  \
               get_lim(offs,1),get_lim(gap,1),get_lim(bld1,1),get_lim(bld2,1))
      printf("%10s %12.4f %12.4f %12.4f %12.4f   (Dial)\n", "",    \
      dial(offs,A[offs]),dial(gap,A[gap]),dial(bld1,A[bld1]),dial(bld2,A[bld2]))
      printf("           %12.4f %12.4f %12.4f %12.4f    Low\n",  \
           get_lim(offs,-1),get_lim(gap,-1),get_lim(bld1,-1),get_lim(bld2,-1))
   }
   print
}'

#%IU% (<slitset_name>, <param_array>)
#%MDESC%
#  Loads the parameters of the slitset into an array.
def slit_params(slitset, param) '{
   local nparams
   nparams = split(list_getpar(SLIT, slitset, "param"), param)
   if (nparams < 1) {
      print "Slitset `$1\' is not currently defined."
      exit
   }
   return(nparams)
}'

#%UU% 
#%MDESC%
#  Shows the current position of the configured slitsets.
def slitshow '{
   local N nparams param
   param[0]=0
   waitmove; get_angles
   onp
   if ((N = list_n(SLIT)) == 0){
      print "No slitsets currently configured."
   } else {
      print "Currently configured slitsets:\n"
      for (i=1; i<=N; i++){
         slitset = list_item(SLIT,i)
         nparams = slit_params(slitset, param)
         if (nparams <= 5) {
            printf("%10s  %12s  %12s\n",sprintf("`%s\'",slitset),"Offset","Gap")
            printf("%10s   %12.4f  %12.4f\n", SLIT[slitset]?"(enabled)":"(disabled)",\
               A[motor_num(param[1])], A[motor_num(param[2])])
         } else {
            printf("%10s  %12s  %12s  %12s  %12s\n",sprintf("`%s\'",slitset), \
                    "Horiz. offset", "Horiz. gap", "Vert. offset", "Vert. gap")
            if (SLIT[slitset])
               printf("%10s   %12.4f  %12.4f  %12.4f  %12.4f\n", "(enabled)", \
                      A[motor_num(param[1])], A[motor_num(param[2])], \
                      A[motor_num(param[5])], A[motor_num(param[6])])
            else
               printf("%10s\n", "(disabled)")
         }
         print
      }
   }
   offp
}'

#%IU%
#%MDESC%
#  Lists the slitsets currently configured.%BR%
def slitlist '{
   local i
   if (SLIT[0]) {
      printf("(%d slitset%s currently configured: ", SLIT[0], SLIT[0]>1?"s":"")
      for(i=1; i<=SLIT[0]; i++) printf(" %s,", SLIT[i])
      printf("\b)\n")
   } else 
      print "(No slitsets currently configured.)"
}'

#%UU% <slitset_name>
#%MDESC%
#  Moves the blades to the zero position defined in the configuration file.%BR%
#  The slitset is at `zero position' when the dials of the blades are at the
#  values defined in the configuration file as %B%Generic parameter 3%B%.%BR%
#  This macro moves the blades but does not modify their `user' position.
#  To change the user positions to zero or other desired value, one has to
#  explicitely use the %B%set%B% macro.
def slitzero '{
   if ($# != 1){
      print "Usage:  slitzero slitset"
      slitlist
      exit
   }
   local nparams param
   param[0]=0
   nparams = slit_params("$1", param)
   if (SLIT["$1"]){
      local mot1 mot2 mot3 mot4
      local pos1 pos2 pos3 pos4
      local dummy 
      mot1 = param[3]; mot2 = param[4]
      _chk_slt_home mot1 dummy dummy pos1
      _chk_slt_home mot2 dummy dummy pos2
      pos1 = user(mot1, pos1)
      pos2 = user(mot2, pos2)
      if (nparams > 5) {
         mot3 = param[7]; mot4 = param[8]
         _chk_slt_home mot3 dummy dummy pos3
         _chk_slt_home mot4 dummy dummy pos4
         pos3 = user(mot3, pos3)
         pos4 = user(mot4, pos4)
      }
      waitmove
      get_angles
      A[mot1] = pos1
      A[mot2] = pos2
      if (nparams > 5) {
         A[mot3] = pos3
         A[mot4] = pos4
      }
      move_em
      move_poll
   }
}'

#%UU% <slitset_name>
#%MDESC%
#  Moves the physical motors in the slitset to a mechanical reference
#  and sets the dial positions.%BR%
#  This macro needs special parameters in the configuration file as explained
#  in the %B%%{%<A HREF=#SETUP>%}%SETUP%{%</A>%}%%B% section. 
def slithome '{
   if ($# != 1){
      print "Usage:  slithome slitset"
      slitlist
      exit
   }
   local nparams param
   param[0]=0
   nparams = slit_params("$1", param)
   if (SLIT["$1"]){
      local pseud1 pseud2 pseud3 pseud4 
      local mot1 mot2 mot3 mot4 
      local lim1 lim2 lim3 lim4 
      local pos1 pos2 pos3 pos4
      local protected dummy

      waitmove
      get_angles
      pseud1 = motor_num(param[1]); pseud2 = motor_num(param[2])
      mot1 = param[3]; mot2 = param[4]
      _chk_slt_home mot1 lim1 pos1 dummy
      _chk_slt_home mot2 lim2 pos2 dummy
      if (nparams > 5) {
         pseud3 = motor_num(param[5]); pseud4 = motor_num(param[6])
         mot3 = param[7]; mot4 = param[8]
         _chk_slt_home mot3 lim3 pos3 dummy
         _chk_slt_home mot4 lim4 pos4 dummy
      }
      if (mot1 >= 0 && mot2 >= 0 && mot3 >= 0 && mot4 >= 0){
         protected = mot_prot(pseud1) || mot_prot(pseud2) ||  \
                     mot_prot(mot1) || mot_prot(mot2) 
         if (nparams > 5)
            protected = protected || mot_prot(pseud3) || mot_prot(pseud4) || \
                                     mot_prot(mot3) || mot_prot(mot4)
         if (!spec_par("specwiz") && protected) {
            print "Motors are protected. You must type the password."
            onwiz 0
            if (!spec_par("specwiz"))
               exit
         }
         printf("\nSearching mechanical reference for slitset `$1\' (%s %s)  ",\
                                        param[3], param[4])
         if (nparams > 5) printf("(%s %s)   ", param[7], param[8])
         chg_dial(mot1, lim1)
         chg_dial(mot2, lim2)
         if (nparams > 5) {
            chg_dial(mot3, lim3)
            chg_dial(mot4, lim4)
         }
         while(wait(0x21)){
            local m
            printf("\b%s", substr("-\\|/", (m=++m%4)+1, 1))
            sleep(.05)
         }
         print "\b\b... Done!"
         _chg_slt_dial(mot1, pos1)
         _chg_slt_dial(mot2, pos2)
         getangles
         chg_dial(pseud1, dial(pseud1, (A[mot1]-A[mot2])/2))
         chg_dial(pseud2, dial(pseud2, A[mot1]+A[mot2]))
         if (nparams > 5) {
            _chg_slt_dial(mot3, pos3)
            _chg_slt_dial(mot4, pos4)
            getangles
            chg_dial(pseud3, dial(pseud3, (A[mot3]-A[mot4])/2))
            chg_dial(pseud4, dial(pseud4, A[mot3]+A[mot4]))
         }

         checkifmacro w$1 slit_where
         if (!error){
            print "\nCurrent user position are: (use `w$1 +\' to see dials)\n"
            w$1
         }
      }
   } else print "Slit set `$1\' is disabled."
}'

#%IU% (<motor>, <new_dial>)
#%MDESC%
def _chg_slt_dial(mot, pos) '{
   local oldpos slop

   slop = fabs(motor_par(mot, "slop")/motor_par(mot, "step_size"))
   getdials
   oldpos = A[mot]
   if (fabs(pos-oldpos) > slop) {
      chg_dial(mot, pos)
      getdials
      pos = A[mot]
      printf("  Dial of motor `%s\' reset from %g to %g (%+g mm).\n", \
                                 motor_mne(mot), oldpos, pos, pos-oldpos)
   } else
      printf("  Dial of motor `%s\' unchanged.\n", motor_mne(mot))
}'

#%IU% <motor> <lim> <position> 
#%MDESC%
def _chk_slt_home '{
   local lm mot 

   mot = -1
   for (i=0; i<MOTORS; i++)
      if ($1 == motor_mne(i)) {
         mot = i
         break
      }

   $1 = -1
   if (mot >= 0){
      lm = motor_par(mot, "misc_par_1") 
      $3 = motor_par(mot, "misc_par_2") 
      if ($# > 3){
         $4 = motor_par(mot, "misc_par_3") 
      }
      if (($2 = (lm == 1)?"lim+":(lm == -1)?"lim-":"") == ""){
         printf( \
         "Wrong mechanical reference (Generic parameter 1) for motor `%s\'\n",\
         motor_mne(mot))
      } else {
         $1 = mot
      }
   }
}'

#%IU% (<motor>)
#%MDESC%
# Returns true if <motor> is protected.
def mot_prot(mot) '{
   local stat
   stat = motor_par(mot, "status")
   return (!((stat & 0x0040) && (stat & 0x0080)))
}'

#%MACROS%
#%IMACROS%
#%SETUP%
#  The %B%slitsetup%B% macro has to be executed with the proper parameters
#  and the logical motors must be defined in the configuration file
#  (controller set to `NONE').%BR%
#  In order to use %B%slithome%B% the `generic parameters' 1 and 2 must be
#  properly set up in the configuration file for the blade motors.
#  %B%Generic parameter 1%B% must be set to `1' or `-1' to indicate if the
#  mechanical reference is `lim+' or `lim-' respectively.
#  %B%Generic parameter 2%B% must be set to the desired dial value at the
#  position of the limit switch.%BR%
#  To use %B%slitzero%B% the %B%Generic parameter 3%B% of the blade motors
#  must be set to the dial value at the zero position.
#
#%BUGS%
#  In the present version if a pseudomotor (gap or offset) is moved too
#  close of the software limit, it might occur that when the movement is
#  finished and due to small inaccuracies (encoder discrepancies, etc..)
#  the recalculated position of the pseudomotor is slightly out of limits.
#  If this happens and one tries to move a different motor an error message
#  is issued and the movement is cancelled. Is this happens one should move
#  first the pseudomotor to a valid position (in between the software limits)
#  and then all the other movements will be allowed.%BR%
#  There are two ways to avoid the previous problem. The first and obvious
#  one is not to move a pseudomotor to the limit position. The second one is
#  to set the software limits of the real motors (the blades) to values such
#  that the limits of the pseudomotors will never be reached. This last 
#  solution is the best but it is not always possible or convenient.%BR%
#  If someone thinks that there should be possible to get rid of this annoying
#  behaviour by a third solution consisting on modifying the code, I must
#  say that all the possible solutions I can imagine would weaken or break
#  some other important features of these macros or would complicate excessively
#  the code. What I want to state is that this problem is not simply the
#  result of the laziness of the programmer (what does not necessarily mean
#  that the programmer is no lazy or incompetent).
#
#%AUTHOR% P.Fajardo, (Original 1/96).
#  $Revision: 4.7 $ / $Date: 2014/02/27 17:03:50 $
#%TOC%