esrf

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

#%TITLE% MKS_PR4000.MAC
#%NAME%
# Macros for controlling MKS PR4000 dual channel power supply
# and readout for flow and pressure.
#
# The communication is done through a serial line that has to
# configured in SPEC config first.
#
# Currently multi controllers are not supported.
#

constant MKS_EOC "\r"
global MKS_SL

#%UU% serial_line
#%MDESC%
#  Select the SPEC serial line to use.
# 
def mks_setup '{

  if($# != 1) {
    print "Usage: $0 serial_line"
    print "Ex: $ 1"
    exit
  }
    
  MKS_SL = int($1)
  if(_mks_cmd("?ID") == "") {
    print "Error: no MKS PR4000 found"
    MKS_SL = -1
    exit
  }

  # switch on remote mode
  mks_remonteon
}'


#%UU%
#%MDESC%
#  Switch on remote control, disable controller front panel
#
def mks_remoteon '{
  _mksremote(1)
}'

#%UU%
#%MDESC%
#  Switch off remote control, enable controller front panel
#
def mks_remoteoff '{
  _mksremote(0)
}'

#%IU%(action)
#%MDESC%
#  Switch remote control on or off, depending if action 
#  given is 1 or 0.
#  Can be called without any action.
#  Returns non null if remote control is on
#
def _mks_remote(action) '{
  if(!(whatis("action") & 0x08000000)) {
    _mks_cmd(sprintf("RT,%s",action?"ON":"OFF"))
  }

  return (index(_mks_cmd("?RT"), "ON") ? 1 : 0)
}'


#%UU% channel [value]
#%MDESC%
# Change the setpoint on the given channel
#
def mks_setpoint '{
  local ch
  local sp
  local val

  if($# < 1) {
    print "Usage: $0 channel [value]"
    print "Ex: $0 1 1.2"
    exit
  }

  ch = int($1)
  _mks_checkchannel(ch)

  if($# == 2) {
    sp = $2
    val = _mks_setpoint(ch, sp)
  } else {
    val = _mks_setpoint(ch)
  }

  printf("current setpoint: %f\n", val)
}'


#%IU%(channel, value)
#%MDESC%
# Change the setpoint on the given channel.
# Can be called without any value.
# Returns the current setpoint.
#
def _mks_setpoint(ch, sp) '{
  local ans
  local val

  _mks_checkchannel(ch)

  if(!(whatis("sp") & 0x08000000)) {
    _mks_cmd(sprintf("SP%d,%f", ch, sp))
  }

  ans = _mks_cmd(sprintf("?SP%d", ch))
  if(sscanf(ans, "%f", val) != 1) {
    print "Error: unable to parse setpoint"
    exit
  }

  return val
}'

#%UU% channel
#%MDESC%
# Print the current flow rate on the given channel
#
def mks_read '{
  local ch
  local val

  if($# < 1) {
    print "Usage: $0 channel"
    print "Ex: $0 1"
    exit
  }

  ch = int($1)
  _mks_checkchannel(ch)

  val = _mks_read(ch)
  printf("current flow    : %f\n", val)
}'


#%IU%(channel)
#%MDESC%
# Returns the current flow rate on the given channel.
#
def _mks_read(ch) '{
  local ans
  local val

  _mks_checkchannel(ch)

  ans = _mks_cmd(sprintf("AV%d", ch))
  if(sscanf(ans, "%f", val) != 1) {
    print "Error: unable to parse current flow rate"
    exit
  }

  return val
}'

#%UU% channel
#%MDESC%
# Wait until the current flow rate is at least 90% of the setpoint
# WARNING: no timeout, use <cltr-c>
#
def mks_wait '{
  local ch

  if($# < 1) {
    print "Usage: $0 channel"
    print "Ex: $0 1"
    exit
  }

  ch = int($1)
  _mks_wait(ch, 1)
    
}'


#%IU%(channel)
#%MDESC%
# Returns the current flow rate on the given channel.
#
def _mks_wait(ch, verbose) '{
  local ans
  local val
  local sp

  _mks_checkchannel(ch)

  sp = _mks_setpoint(ch)
  if(verbose) { printf("current setpoint: %f\n", sp) }
  sp *= 0.9

  if(verbose) { printf("waiting...") }
  while(1) {
    val = _mks_read(ch)
    if(val > sp) {
      break
    }
    if(verbose) { printf(".") }
    sleep(.1)
  }
}'

#%UU% channel
#%MDESC%
# Close the valve on the given channel
#
def mks_valveclose '{

  if($# != 1) {
    print "Usage: $0 channel"
    print "Ex: $0 1"
  }

  mks_valve $1 CLOSE
}'


#%UU% channel
#%MDESC%
# Open the valve on the given channel
#
def mks_valveopen '{

  if($# != 1) {
    print "Usage: $0 channel"
    print "Ex: $0 1"
  }

  mks_valve $1 OPEN
}'


#%UU% channel [OPEN|CLOSE]
#%MDESC%
# Control the valve on the given channel
#
def mks_valve '{
  local ch
  local action
  local val
  local sta

  if($# < 1) {
    print "Usage: $0 channel [OPEN|CLOSE]"
    print "Ex: $0 1 OPEN"
  }
  ch = int($1)
  _mks_checkchannel(ch)

  if($# == 2) {
    action = "$2"
    if((action != "OPEN") && (action != "CLOSE")) {
      print "Error: action must be \"OPEN\" or \"CLOSE\""
      exit
    }
 
    val = (action == "OPEN") ? 1 : 0
    sta = _mks_valve(ch, val)
  } else {
    sta = _mks_valve(ch)
  }

  printf("valve is: %s\n", (sta ? "OPEN" : "CLOSED"))
}'


#%IU%(channel, action)
#%MDESC%
# Change the valve state on the given channel.
# Can be called without any action.
# Returns non null if the valve is open.
#
def _mks_valve(ch, action) '{

  _mks_checkchannel(ch)

  if(!(whatis("action") & 0x08000000)) {
    _mks_cmd(sprintf("VL%d,%s", ch, (action?"ON":"OFF")))
  }

  return (index(_mks_cmd(sprintf("?VL%d", ch)), "ON") ? 1 : 0)
}'


#%IU%(channel)
#%MDESC%
#
def _mks_checkchannel(ch) '{
  if((ch != 1) && (ch != 2)) {
    print "Error: invalid chanel, must be 1 or 2"
    exit
  }
}'


#%IU%(cmd)
#%MDESC%
# Send the given command to the controller and returns its 
# answer or ".error."
# 
def _mks_cmd(cmd) '{
  local sl
  local ans
  local len

  sl = MKS_SL
  if((sl == -1) || (whatis("MKS_SL") & 0x08000000)) {
    print "Error: missing serial line initialization"
    print "Hint: use \"mkssetup\""
    return ".error."
  }
  
  ser_par(sl, "flush")

  if(index(cmd, MKK_EOC) == 0) {
    cmd = sprintf("%s%s", cmd, MKS_EOC)
  }

  ser_put(sl, cmd)

  ans = ser_get(sl, MKS_EOC)
  len = length(ans)
  if(substr(ans, len) == MKS_EOC) {
    ans = substr(ans, 0, len-1)
  }

  return ans
}'

#%IU%
#%MDESC%
# MACRO COUNTER: 
# Called by spec after reading the config file
#
def mks_sp_config(num,type,p1,p2,p3) '{

 if(type=="ctrl") {
   MKS_SL = mks_sp_ADDR
   return
 }

 if(type=="cnt") {
   return
 }
}'

#%IU%
#%MDESC%
# MACRO COUNTER: 
# Called by spec on counter operation.
#
def mks_sp_cmd(num,key,p1,p2) '{
 local mne
 local ch

 if (key == "counts") {
  mne = cnt_mne(num)
  ch  = counter_par(num, "channel")
  S[num]=_mks_setpoint(ch)
 }
}'

#%IU%
#%MDESC%
# MACRO COUNTER: 
# Called by spec after reading the config file
#
def mks_read_config(num,type,p1,p2,p3) '{

 if(type=="ctrl") {
   MKS_SL = mks_sp_ADDR
   return
 }

 if(type=="cnt") {
   return
 }
}'

#%IU%
#%MDESC%
# MACRO COUNTER: 
# Called by spec on counter operation.
#
def mks_read_cmd(num,key,p1,p2) '{
 local mne
 local ch

 if (key == "counts") {
  mne = cnt_mne(num)
  ch  = counter_par(num, "channel")
  S[num]=_mks_read(ch)
 }
}'

#%MACROS%
#%IMACROS%
#%AUTHOR% MP BLISS (Original Apr/2015).
# %BR%$Revision: 1.1 $ / $Date: 2015/06/02 05:25:21 $
#%TOC%