esrf

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

#%TITLE% K6221.MAC 
#
#%NAME%
# Macros motors to control KEITHLEY current source K6221 through GPIB
#
#%DESCRIPTION%
# Configure first a macro motor controller with DEVICE field set to
# string "k6221" and ADDR field set to the full GPIB address where
# the controller can be reached (ex: "0:12"). Therefore there 
# must be ONE macro motor controller per K6221%BR%
#
# Then configure a motor using the previous controller, the "channel" 
# is used to select what to control. 0 for "output current" and 1 for
# "compliance voltage"%BR% 
#
# The unit of "current" motor will be amps and the unit
# of "voltage" motor will be volts.
#
#
#%END%
#


#%IU%()
#%MDESC%
# Called by spec after reading the config file
#
def k6221_config(num, type, p1, p2, p3) '{
  local addr
  local ans

  # p1==controller index p2==number of motors supported
  if(type == "ctrl") {
    addr = k6221_ADDR

    # minimum check on controller
    ans  = ""
    ans  = _k6221_cmd(addr, "*IDN?") 
    if(length(ans) == 0) {
      printf("K6221 ERROR: missing K6221 at address \"%s\"\n", addr)
      return ".error."
    }

    if(!index(ans, "KEITHLEY") || !index(ans, "6221")) {
      printf("K6221 ERROR: not a K6221 at address \"%s\"\n", addr)
      return ".error."
    }

    printf("Using KEITHLEY 6221 at address \"%s\"\n", addr)

    print "K6221: setting output current range to \"auto\""
    _k6221_cmd(addr, "SOURCE1:CURRENT:RANGE:AUTO ON")
  }
}'


#%IU%()
#%MDESC%
# Called by spec on motor operation.
# 
def k6221_cmd(num, key, p1, p2) '{
  local mne
  local addr
  local cmd
  local ans
  local isu


  #
  # Handle actions at controller level
  #
  if(num == "..") { 
    return
  }

  #
  # Handle actions at motor level
  #
  mne  = motor_mne(num)
  addr = motor_par(num, "address")
  isu  = motor_par(num, "channel")

  #
  # return the current motor position in mm or deg
  #
  if (key == "position") {
    local pos 
    local cmd

    cmd = sprintf("SOURCE1:CURRENT:%s", isu?"COMPLIANCE?":"LEVEL?")
    ans = _k6221_cmd(addr, cmd)
    if(sscanf(ans, "%f", pos) != 1) {
      print "K6221 ERROR: unable to get ",isu?"voltage":"current"," level"
      return ".error."
    }
    return pos
  }

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

    cmd = sprintf("SOURCE1:CURRENT:%s", isu?"COMPLIANCE":"LEVEL:IMM:AMPL")
    _k6221_error_clear(addr)
    _k6221_cmd(addr, sprintf("%s %f", cmd, p1))
    _k6221_error_print(addr, "unable to set current level")

    return
  }
}'


#%IU%(addr)
#%MDESC%
# Clear any previous error
#
def _k6221_error_clear(addr) '{
    _k6221_cmd(addr, "SYSTEM:CLEAR")
}'


#%IU%(addr, msg, silent)
#%MDESC%
# Retrieve current error and print it out with the optional given
# message except if silent has be requiered.
# Returns non null if there was an error pending.
#
def _k6221_error_print(addr, msg, silent) '{
  local ans
  local ret

  ret = 0
  ans = _k6221_cmd(addr, "SYSTEM:ERROR?")
  if(index(ans, "No error")) {
    return ret
  }

  ret = 1
  if(!silent) {
    local lines[]

    if(msg) {
      print "K6221 ERROR", msg
    }
    if(split(ans, lines, ",") != 2) {
      print "Unable to parse error"
    } else {
      print lines[1]
    }
  } 
  
  return ret
}'

#%UU% motor command
#%MDESC%
# Send the given command to the controller associate to the
# given motor and print out the answer if there is one.
#%BR%Ex: k6221cmd m0 *IDN?
#
def k6221cmd '{
  local mne
  local cmd
  local num
  local addr

  if($# != 2) {
    print "Usage: $0 motor command"
    exit
  }

  mne = "$1"
  cmd = "$2"
  if((num = motor_num(mne)) == -1) {
    print "K6221 ERROR: invalid motor name"
    exit
  }

  if(motor_par(num, "device_id") != "k6221") {
    print "K6221 ERROR: invalid motor, not a \"k6221\" macro motor"
    exit
  }

  addr = motor_par(num, "address")

  print _k6221_cmd(addr, cmd)
}'

#%UU% motor 
#%MDESC%
# Switch on output of the controller associate with given motor.
#
def k6221on '{
  if($# != 1) {
    print "Usage: $0 motor"
    exit
  }
  _k6221_onoff("$1", 1)
}'

#%UU% motor 
#%MDESC%
# Switch off output of the controller associate with given motor.
#
def k6221off '{
  if($# != 1) {
    print "Usage: $0 motor"
    exit
  }
  _k6221_onoff("$1", 0)
}'

#%IU%(mne, state)
#%MDESC%
# Control controller output for the given motor.
#
def _k6221_onoff(mne, state) '{
  local cmd
  local num
  local addr
  

  cmd = "$2"
  if((num = motor_num(mne)) == -1) {
    print "K6221 ERROR: invalid motor name"
    exit
  }

  if(motor_par(num, "device_id") != "k6221") {
    print "K6221 ERROR: invalid motor, not a \"k6221\" macro motor"
    exit
  }

  addr = motor_par(num, "address")
  cmd  = state?"ON":"OFF"
  _k6221_error_clear(addr)
  _k6221_cmd(addr, sprintf("OUTPUT1:STATE %s", cmd))
  _k6221_error_print(addr, sprintf("unable to switch output %s", cmd))
}'


#%IU%(addr, command)
#%MDESC%
# Send the given command to the controller given by its address and returns
# the answer if there is one. Otherwise returns an empty string.
#
def _k6221_cmd(addr, cmd) '{
  local ans

  ans = ""
  gpib_put(addr, cmd)

  # lazy way to guess if the command is a query
  if(index(cmd, "?")) {
    ans = gpib_get(addr, "\n")
  }

  return(ans)
}'


#%MACROS%
#%IMACROS%
#%AUTHOR% MP BLISS (Original 9/2015).
# %BR%$Revision: 1.0 $ / $Date: 2015/09/18 06:17:06 $
#%TOC%