esrf

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

#%TITLE% SC.mac
#%NAME%
#  Macros for Sample changer operation
#
#%CATEGORY% MX, Other hardware
#
#%LOG%
#
#$Log: SC.mac,v $
#Revision 2.30  2013/10/31 12:20:01  guijarro
#more permissive with missing motors regarding setup
#
#Revision 2.29  2012/07/09 14:27:12  beteva
#avoid delete of the minidiff motors when Minikappa Off
#
#Revision 2.28  2011/11/02 10:58:37  guijarro
#fixed SCKappaOn
#added yagin'
#added code to disable safety bath
#
#Revision 2.27  2010/07/07 08:47:22  guijarro
#do not include r_kappa motor in SC sequence
#
#Revision 2.26  2010/06/10 16:16:57  guijarro
#added more time for safety bath to be in
#
#Revision 2.25  2010/01/28 14:00:36  guijarro
#changed minidiff_take_backgrounds to minidiff_take_periodic_backgrounds
#
#Revision 2.24  2008/07/17 14:58:34  rey
#documentation changes
#
#Revision 2.23  2008/05/23 07:24:50  spruce
#wait for 0.5 seconds before checking if the safety bath is in after putting it in
#
#Revision 2.22  2008/04/03 14:36:27  gabadinh
#-added new global variable PY_SC_LOADED_SAMPLE (a python dictionary encoded as a string) to share the current loaded sample information across BlissFramework applications
#
#Revision 2.21  2008/03/18 14:16:01  guijarro
#takes minikappa into account in setup
#
#Revision 2.20  2008/03/11 15:19:00  guijarro
#*** empty log message ***
#
#Revision 2.19  2008/03/11 13:24:17  guijarro
#Lock and Unlock macros disable/enable beamstop as well
#
#Revision 2.18  2007/09/03 15:23:50  guijarro
#move_em replaced by move_poll,
#user_postmove replaced by user_finished1
#
#Revision 2.17  2007/08/21 09:42:40  guijarro
#use _backout instead of bstopz reference position in xml file
#
#Revision 2.16  2007/05/31 08:26:57  gabadinh
#new spec functions to act as wrappers of the SCMoveToLoadingPosition and SCMoveToUnloadingPosition macros
#
#Revision 2.15  2007/05/29 16:23:52  gabadinh
#new global variable SC_MD_FLAGS, storing the current operational state:
#bit 1: sample changer is in use
#bit 2: minidiff can move
#bit 3: sample changer is in loading position
#
#Revision 2.14  2007/05/15 13:53:01  guijarro
#added SCKappaOn and SCKappaOff for minikappa ;
#needs modifications to the minidiff.xml file!!!
#
#Revision 2.13  2006/09/28 11:49:08  guijarro
#added sleep in SCMinidiffGetControl,
#to let time for Wago to really do the job
#before looking at the status again
#
#Revision 2.12  2006/09/12 13:00:54  guijarro
#calls exit if SCMoveToLoadingPosition fails and also gives back control to minidiff
#
#Revision 2.11  2006/09/06 08:01:09  guijarro
#adapted to call minidiff_take_backgrounds
#
#Revision 2.10  2006/05/17 07:27:14  guijarro
#*** empty log message ***
#
#Revision 2.8  2006/04/21 14:18:16  beteva
#added the kappa motor handling
#
#%END%

cdef("prompt_mac",         "SC_prompt_check;\n",    "samplechanger")
cdef("user_checkall",      "SC_minidiff_check();\n",  "samplechanger")
cdef("_SC_minidiff_check", "_SC_minidiff_check0();\n", "_SC_minidiff")
cdef("user_finished1", "SC_safetybath_get\n", "_SC_minidiff")
cdef("user_checkall", "SC_safetybath_check\n",  "_SC_minidiff")
cdef("cleanup_always", "SC_safetybath_get\n","_SC_minidiff")


global MINIDIFF_SETUP 
global MINIDIFF_BSTOPZ_POS
global KAPPA_IN_USE
global SC_MD_FLAGS
global PY_SC_LOADED_SAMPLE

def SC_safetybath_get '{
  global MINIDIFF_BSTOPZ_POS
  local bstopzmot

  bstopzmot = motor_num(MINIDIFF["bstopz"])

  if (bstopzmot < 0) {
    print "invalid motor bstopz in Minidiff Hardware Object"
    exit
  }

  get_angles
  MINIDIFF_BSTOPZ_POS = A[bstopzmot]
}'


def SC_safetybath_check '{
  local bstopzmot t0

  bstopzmot = motor_num(MINIDIFF["bstopz"])

  if (whatis("MINIDIFF_BSTOPZ_POS")&0x0800) {
    SC_safetybath_get
  }

  if (A[bstopzmot] != MINIDIFF_BSTOPZ_POS) {
    _remove_safety_bath
  }
}'


def SCMinidiffSetup '{
  global SC_MD_FLAGS
  global PY_SC_LOADED_SAMPLE
  global SC_NO_SAFETY_BATH

  PY_SC_LOADED_SAMPLE=""
  SC_MD_FLAGS=0
  if (MINIDIFF_SETUP) {
    if (KAPPA_IN_USE) {
      SCKappaOn
    } else {
      SCGetLoadingPosition()
    }
    SCMinidiffOn
    SCInUse 1

    if ($1 == 1) {
      # desactivate safety bath
      rdef SC_safetybath_check ""
      rdef SC_safetybath_get "" 
      rdef _remove_safety_bath ""
      SC_NO_SAFETY_BATH=1 
      cdef("user_finished1", "", "_SC_minidiff", "delete")
      cdef("user_checkall", "",  "_SC_minidiff", "delete")
      cdef("cleanup_always", "","_SC_minidiff", "delete")
    }

    print "Sample Changer properly configured for SPEC"
  } else {
    SCInUse 0
    print "Minidiff setup incomplete: cannot continue with Sample Changer. Please run minidiff_setup."
    exit
  }
}'


def SCKappaOn '{
  global KAPPA_IN_USE
  KAPPA_IN_USE = 1

  for (mne in KAPPA_MNE) {
    if ((mne != "omega")&&(mne!="kappa")&&(mne!="phi")) {
      motmne = KAPPA_MNE[mne]
      MINIDIFF[motmne]=motmne
      MINIDIFF[motmne]["ho"]=sprintf("/%s/%s", SPEC, motmne) 
    }
  }

  SCGetLoadingPosition()
}'


def SCKappaOff '{
  local _OBJ_MINIDIFF[]
  global KAPPA_IN_USE
  KAPPA_IN_USE = 0

  _OBJ_MINIDIFF = xml_readMotorsByRoles(MINIDIFF_HO_NAME)

  for (mne in KAPPA_MNE)  {
    if (mne in _OBJ_MINIDIFF) {
    } else {
      if (mne != "omega") {
        motmne = KAPPA_MNE[mne]
        delete MINIDIFF[motmne]
        delete MINIDIFF[motmne]["ho"]
      }
    }
  }

  SCGetLoadingPosition()
}'


def SCSetLoadingPosition '{
local holderLength, motmne, motnum

  if ($# >= 1) {
    holderLength = $1
  } else {
    motmne = MINIDIFF["phiy"]
    motnum = motor_num(motmne)
    holderLength = A[motnum]    
  }
 
  print "setting loading position with holder length = " holderLength

  _SCSetLoadingPosition(holderLength)
  
  if (yesno("Are you sure you want to save the new reference position ?", 1) == 1) {
    if (_SCWriteMinidiffReferencePosition() == 0) {
      print "Reference position saved."
      unix("mkdir -p ~/SClog")
      on("~/SClog/SC_positions.log");offt
      print date()
      SCShowStatus
      print
      ont; close("~/SClog/SC_positions.log")
    } else {
      print "Warning: could not save reference position !"
    }
  } else {
    print "Warning: reference position is left unsaved."
  }
}'


def _SCSetLoadingPosition(holderLength) '{
local role, motor, motmne, tmp[]

  unglobal MINIDIFF_LOAD_POSITION
  global MINIDIFF_LOAD_POSITION[]
  tmp = asso_keys(MINIDIFF)

  for (role in tmp) {
    if ((role != "zoom")&&(role != "light")&&(role != "camera")) {
      motmne = MINIDIFF[role]
      motnum = motor_num(motmne)
      MINIDIFF_LOAD_POSITION[motmne] = A[motnum]
    }
  }

  # set holder length
  motmne = MINIDIFF["phiy"]
  MINIDIFF_LOAD_POSITION[motmne] = holderLength

  print MINIDIFF_LOAD_POSITION
}'


def _SCWriteMinidiffReferencePosition() '{
local tmp0[], role, motmne, query, queryResult[], path, update, updatesList, updateResult

  tmp0 = asso_keys(MINIDIFF)

  updatesList = "("

  for (role in tmp0) {
    if ((role != "zoom")&&(role != "light")&&(role != "camera")) 
    {
      motmne = MINIDIFF[role]

      if (KAPPA_IN_USE) {
        query = sprintf("xml_read(\"%s\", \"/equipment/referencePositionWithKappa/%s[1]\")", MINIDIFF_HO_NAME, role)
      } else {
        query = sprintf("xml_read(\"%s\", \"/equipment/referencePosition/%s[1]\")", MINIDIFF_HO_NAME, role)
      }
      queryResult = prop_get(HWR_dev, query)
    
      if (!("__error__" in queryResult)) {
        path = queryResult[0]["__path__"]
        update = sprintf("(\"%s\", %s)", path, MINIDIFF_LOAD_POSITION[motmne])

        if (updatesList == "(") {
          updatesList = sprintf("(%s", update)
        } else {
          updatesList = sprintf("%s,%s", updatesList, update)     
        }
      } else {
        print queryResult["__error__"]
        return(-1)
      }
    }    
  }    
  
  updatesList = sprintf("%s)", updatesList)
  query = sprintf("xml_multiwrite(\"%s\", \'%s\')", MINIDIFF_HO_NAME, updatesList)

  updateResult = remote_eval(HWR_dev, query)
  
  if ("__error__" in updateResult) {
    print updateResult["__error__"]
    return(-1) 
  } else {
    return(0)
  }
}'


def SCGetLoadingPosition() '{
  local role, motmne, query, queryResult[], position, tmp0[], tmp[], tmp2[]

  tmp0 = asso_keys(MINIDIFF)

  for (role in tmp0) {
    if ((role != "zoom")&&(role != "light")&&(role != "camera")&&(role != "bstopz")) {
      motmne = MINIDIFF[role]

      if (KAPPA_IN_USE) {
        query = sprintf("xml_read(\"%s\", \"/equipment/referencePositionWithKappa/%s[1]\")", MINIDIFF_HO_NAME, role)
      } else {
        query = sprintf("xml_read(\"%s\", \"/equipment/referencePosition/%s[1]\")", MINIDIFF_HO_NAME, role)
      }
      queryResult = prop_get(HWR_dev, query)
    
      if (!("__error__" in queryResult)) {
        position = queryResult[0]["__value__"]
      
        tmp[motmne] = position
   
        if (KAPPA_IN_USE) {
          query = sprintf("xml_read(\"%s\", \"/equipment/referencePositionWithKappa/%s[1]/@delta\")", MINIDIFF_HO_NAME, role)
        } else {
          query = sprintf("xml_read(\"%s\", \"/equipment/referencePosition/%s[1]/@delta\")", MINIDIFF_HO_NAME, role)
        }
        queryResult = prop_get(HWR_dev, query)
    
        if (!("__error__" in queryResult)) {
          delta = queryResult[0]["__value__"]
      
          tmp2[motmne] = delta
        } else {
          tmp2[motmne] = 0.0001
        }
      }
    }    
  }

  unglobal MINIDIFF_LOAD_POSITION
  unglobal MINIDIFF_DELTAS
  global MINIDIFF_LOAD_POSITION[]
  global MINIDIFF_DELTAS[]

  ass_copy(tmp, MINIDIFF_LOAD_POSITION)
  ass_copy(tmp2, MINIDIFF_DELTAS)

  return(1)
}'


def SCMinidiffOn '{
   cdef("_SC_minidiff_check", "_SC_minidiff_check0()\n","_SC_minidiff")
}'


def SCMinidiffOff '{
   local _yn 
 
   tty_cntl("md")
   print 
   print "*****      THIS ACTION HAS SECURITY IMPLICATIONS         *****"
   print "**  Checking on Sample Changer / Minidiff will be disabled  **"
   tty_cntl("me")   
   
   if (yesno("Do you really want to do it ?",0) == 1) {
     cdef("", "","_SC_minidiff","delete")
   }
}'


def inPosition(motmne) '{
   # *******************************************************
   # * Compare given motor position with loading position, *
   # * taking the tolerance into account ; return 0 if the *
   # * motor is not in the position, 1 otherwise           *
   # *******************************************************
   local delta, motnum, position

   motnum = motor_num(motmne)
   position = MINIDIFF_LOAD_POSITION[motmne]
   delta = MINIDIFF_DELTAS[motmne]

   if (delta <= 0) {
      return(0)
   } else {
      if (motnum < 0) {
        return(0)
      }

      #return 1 if motor position is between position-delta and position+delta
      return(fabs(A[motnum] - position) <= delta)
   }
}'


def SC_minidiff_check() '{
   _SC_minidiff_check
}'


def _SC_minidiff_check0() '{
  # *****************************************************
  # * This macro is called before each motor movement ; *
  # * if the minidiff should not move from the loading  *
  # * position, it prevents Spec from moving the motor  *
  # *****************************************************
  if (SCMinidiffCanMove() == 0) {
    # prevent Spec from moving the Minidiff motors
    SCLockMinidiff
  }
}'


def SCMoveToLoadingPos() '{
   SCMoveToLoadingPosition
   helical_resetpos()
   return SCCanOperate()
}'


def SCMoveToLoadingPosition '{
  if (PIPELINE) { minidiff_take_periodic_backgrounds }
  
  _SCMoveToLoadingPosition $*
}'


def _SCMoveToLoadingPosition '{
  global MINIDIFF_LOAD_POSITION[]
  local motmne, motnum

  wago_writech("swpermit", 0)
  wago_writech("SCcryoctrl", 0)
  if (SCMinidiffCanMove()==1) SCUnlockMinidiff

  if (MINIDIFF_SETUP == 0) { print "no minidiff defined"; exit }

  # the loading position is always re-read from the file ;
  # maybe we can do differently (no re-reading it if MINIDIFF_LOAD_POSITION
  # is already filled ?)
  if ( ( ret = SCGetLoadingPosition()) != 1) {
    # an error occured
    if (asso_len(MINIDIFF_LOAD_POSITION) > 0) {
      print "Cannot get object minidiff. Check hardware repository"
    } else {
      print "No loading position defined ! Aborting."
    }
    exit
  } 

  if ($# >= 1) {
    # set a different holder length
    motmne = MINIDIFF["phiy"]
    MINIDIFF_LOAD_POSITION[motmne] = $1
  }

  get_angles

  _backout()

  for (motmne in MINIDIFF_LOAD_POSITION) {
    motnum = motor_num(motmne)
    A[motnum] = MINIDIFF_LOAD_POSITION[motmne]
  }

  print "Moving minidiff to loading position"
  move_em
	
  print "Moving fluorescence detector out"
  wago_writech("fldin", 0)

  if (WAGOKEYS["laserin"] > 0) {
    print "Removing laser"
    wago_writech("laserin", 0)
  }

  if (WAGOKEYS["scntin"] > 0) {
    print "Removing scintillator"
    wago_writech("scntin", 0)
  }
  if (WAGOKEYS["yag_in"] > 0) {
    print "Removing scintillator"
    yagout 
  }

  move_poll 

  print "Moving light out"
  lightout

  if (SCMotorsInLoadingPosition() == 1) {
    if (!SC_NO_SAFETY_BATH) {
      print "Putting safety screen in"
      wago_writech("safetyin", 1)
      sleep(1)
    }
    if (SCPneumaticsInLoadingPosition(1) == 1) {  
      print "  -- done."

      # give software permit for loading to SC ;
      # as a consequence, it will "lock" (software lock)
      # the minidiff motors (see _SC_minidiff_check macro)
      wago_writech("swpermit", 1)
      wago_writech("SCcryoctrl", 1)
 
      if (SCMinidiffCanMove() == 0) SCLockMinidiff
    } else {
      tty_cntl("md")
      print "Cannot get minidiff to loading position"
      SCShowStatus
      tty_cntl("me")
      SCMinidiffGetControl
      exit
    }
  } else {
    tty_cntl("md")
    print "Cannot get minidiff to loading position"
    SCShowStatus
    tty_cntl("me")
    SCMinidiffGetControl
    exit
  }
}'


def SCMoveToUnloadingPos() '{
   SCMoveToUnloadingPosition
   helical_resetpos()
   return SCCanOperate()
}'


def SCMoveToUnloadingPosition '{
  _SCMoveToLoadingPosition $*
}'


def SCMinidiffGetControl '{
  if (! SC_NO_SAFETY_BATH) { wago_writech("safetyin", 0) }
  wago_writech("swpermit", 0)
  wago_writech("SCcryoctrl", 0)
  sleep(0.5)
  if (SCMinidiffCanMove() == 1) { 
    SCUnlockMinidiff
  } else {
    printf("cannot get control to minidiff: is SC arm parked ?\n")
    exit
  }
}'


def SCLockMinidiff '{
  local motnum

  for (motmne in MINIDIFF_LOAD_POSITION) {
    motnum = motor_num(motmne)
    motor_par(motnum, "disable", 1)
  }

  motnum = motor_num(BEAMSTOP["z"]["motor"])
  motor_par(motnum, "disable", 1)
}'


def SCUnlockMinidiff '{
  local motnum

  for (motmne in MINIDIFF_LOAD_POSITION) {
    motnum = motor_num(motmne)
    motor_par(motnum, "disable", 0)
  }

  motnum = motor_num(BEAMSTOP["z"]["motor"])
  motor_par(motnum, "disable", 0)
}'


def SCInUse '{
  global SC_MD_FLAGS
  if ( $1 == 1 )  {
      wago_writech("SCdisable", 0)
      SC_MD_FLAGS=SC_MD_FLAGS | 1
      SCMinidiffCanMove()
  } else {
      wago_writech("SCdisable", 1)
      SC_MD_FLAGS=SC_MD_FLAGS & ~1
      SCMinidiffGetControl
  }

  SCIsInUse(1)
}'


def SCIsInUse(verbose) '{
  nowis = wago_readch("SCdisable") 
 
  if (verbose==1) {
     if( nowis == 0 )  { using = "" } else { using = "not" }
     print "Sample Changer is " using " being used. "
  } else {
     return( nowis? 0:1)
  }
}'

def SCShowStatus '{
    local motmne, motnum, status 

    get_angles

    print "Current Minidiff signals/positions"
    print "  -- motors :"

    for (motmne in MINIDIFF_LOAD_POSITION) {
      motnum = motor_num(motmne)
      if (inPosition(motmne)) status="ok"; else status=sprintf("invalid (should be %.5g)", MINIDIFF_LOAD_POSITION[motmne])
      printf("%15s   %.5g\t%10s\n", motmne, A[motnum], status)     
    }

    print "  -- wagos (check correct interlock state with \'intlck show\') :"
    wread SCdisable lightin cryoin mdpermit swpermit SCcryoctrl fldin safetyok
    if (WAGOKEYS["laserin"] > 0) wread laserin
    if (WAGOKEYS["scntin"] > 0) wread scntin
}'


def SC_prompt_check '{
  # ***************************************************************
  # * Check minidiff and sample changer and display status        *
  # ***************************************************************
  local msg
  
  if (SCIsInUse(0) == 1) {
     if (SCCanOperate() == 1) {
       msg = "SAMPLE CHANGER CAN LOAD/UNLOAD SAMPLE"
     } else {
       msg = "SAMPLE CHANGER LOCKED"
     }
  } else {
    msg = "SAMPLE CHANGER NOT IN USE"
  }

  if (SCMinidiffCanMove() == 1) {
    msg = sprintf("%s / %s", msg, "MINIDIFF CAN MOVE")
  } else {
    msg = sprintf("%s / %s", msg, "MINIDIFF LOCKED")
  }
  tty_cntl("md");printf("%s", msg);tty_cntl("me")  
}'


def SCMinidiffCanMove() '{
   # **************************************************************
   # Minidiff can move only if sample changer arm is parked,      * 
   # and if the software permit to allow sample loading/unloading *
   # is not set                                                   *
   # **************************************************************
   local SCparked, swpermit
   global SC_MD_FLAGS
   
   SCparked = wago_readch("SCparked")
   swpermit = wago_readch("swpermit")

   if (wago_readch("SCdisable") == 1) {
      SC_MD_FLAGS = SC_MD_FLAGS & ~4
      SC_MD_FLAGS = SC_MD_FLAGS | 2
      return(1)
   }

   if ( (SCparked == 1) && (swpermit == 0) ) {
      #print "Minidiff could move"
      SC_MD_FLAGS = SC_MD_FLAGS & ~4
      SC_MD_FLAGS = SC_MD_FLAGS | 2
      return(1)
   } else {
      #print "Minidiff should not move"
      SC_MD_FLAGS = SC_MD_FLAGS & ~2
      return(0)
   }
}'


def SCPneumaticsInLoadingPosition(waitend) '{
  local inload timeout inittime
  
  inload = 0
  timeout = 6
  inittime = time()

  while (inload == 0) {
    inload = wago_readch("mdpermit") 
    if (waitend == 0) {
      break
    }

    if ((time()-inittime) > timeout) {
      break
    }
  }

  return(inload)
}'


def SCMinidiffInLoadingPosition(waitend) '{
  # ********************************************************
  # * Minidiff is in loading position if all the motors    *
  # * are in the right positions and if the pneumatic      *
  # * devices are out (except safety screen)               *
  # ********************************************************
  if (SCMotorsInLoadingPosition() > 0) {
    return SCPneumaticsInLoadingPosition(waitend)
  } else {
    return 0
  }
}'


def SCMotorsInLoadingPosition() '{
  global MINIDIFF_LOAD_POSITION[]
  local motmne, motnum

  if (asso_len(MINIDIFF_LOAD_POSITION) == 0) {
        # no positions defined ?!
        return(0)
  }

  get_angles

  for (motmne in MINIDIFF_LOAD_POSITION) {
      if (inPosition(motmne) == 0) {
          return(0)
      }
  }

  return(1)
}'


def SCCanOperate() '{
  # ******************************************************
  # * SC can load/unload a sample if minidiff is in load *
  # * position and if it has the software authorization  *
  # ******************************************************
  global SC_MD_FLAGS
  local res

  res = wago_readch("swpermit") && SCMinidiffInLoadingPosition()
  if (res) {
    SC_MD_FLAGS = SC_MD_FLAGS & ~2
    SC_MD_FLAGS = SC_MD_FLAGS | 4
  } else{
    SC_MD_FLAGS = SC_MD_FLAGS & ~4
  }
  return( res )
}'

#%MACROS%
#%IMACROS%
#%TOC%
#%AUTHOR%
#$Revision: 2.30 $$Date: 2013/10/31 12:20:01 $