esrf

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


"""
#%TITLE% LAKESHORE.MAC
#%NAME%
#   Temperature control macros for the LakeShore model 340 (ID20)
#   Improved for ID18
#%CATEGORY% Temperature
#%DESCRIPTION%
# This macroset contains macros to control and read the temperature from the
# Lakeshore 340 controller. The macroset has three main functions. Firstly, the
# macroset chains onto the counting chain of Spec to allow the temperature or
# sensor resistance to be measured at each counting event. Secondly, macros are
# avaliable to control the main parameters of the controller such as heater range,
# control sensor etc. Finally, macros are provided to enable auto configuration
# from a datafile for standard parameters which are specific to the type of 
# cryostat in use. This will be discussed further below. A list of commands and
# syntaxes is provided below for all functions.%BR%
#%BR%
#Getting Started%BR%
#%BR%
# To start logging the temperature from within Spec the command %B%ontemp%B% should
# be issued. This starts the logging of the temperature at each count command, and
# will record the temperature in the datafile during a scan. 
# The sister command %B%offtemp%B% will stop the logging of the temperature.
# The command %B%lsspec_setup%B% should be run (usually from the setup macro 
# of spec) for temperature counters and %B%lsspec_setup_resistance%B% for 
# sensor units measurements to pair the lakeshore sensor to a spec counter mnemonics.
# Please note that %B%lsspec_setup%B% also sets various global parameters so should
# be run at startup.%BR%
#%BR%
# To switch on and off the temperature control (enable or disable the heater) the
# command %B%onreg%B% and %B%offreg%B% are used. This causes the conrollers control
# loop to be enabled or disabled.%BR%
#%BR%
# To show all relevant parameters for the controller the command %B%lsshow%B% can
# can be used, while %B%showtemp%B% displays all configured sensor temperature and
# resistance or voltage readings. Setpoint ramping is enabled through the command
# %B%onramp%B% and disabled with %B%offramp%B%. The rate of ramping can be changed
# through the command %B%lsramp%B%.%BR% 
#%BR%
#Configuration from File%BR%
#%BR%BR%
# Using this macroset it is possible to send a standard configuration to
# the Lakeshore from a datafile. This is done through two separate macros
# which call the same internal function to load the config into the 
# controller.%BR%
#%BR%
# The macro %B%lssendconfig%B% causes the Lakeshore to be configured by the datafile
# passed to it as the first argument. Each call to this macro causes the controller 
# to be placed in its default state with the control loop disabled. This can 
# therefore cause a disturbance to data collection if this is put into a startup 
# script. For this reason the second macro %B%lsconfig%B% exists. This macro takes
# the same first argument of a datafile to process, but on opening the file and 
# reading the two first lines (see the section on the datafile below) their values
# are compared with the two global variables %B%LS_CONFIG_NAME%B% and
# %B%LS_CONFIG_REVISION%B%. If a match is obtained then the config process is aborted.
# However, if a match is not obtained then the config process is run for the datafile
# specified. This enables a line to be placed in the setup script for the configuration
# in use. If no parameter is passed to the %B%lssendconfig%B% macro then a forced 
# reconfig will start using the previous file.%BR%
#This datafile has a minimal amount of input checking so please
# follow the format fairly strictly. Any line in which the %B%first%B%
# character is a # is skipped and treated as a comment.%BR%
#%BR%
#The first two non comment lines of the datafile are used for identification
# of the config file. The first is intended as an identification string for 
# the cryostat, displex etc. and needs to be unique among your setup. The
# second is intended as version string which is also checked at setup. This
# could for instance be the $Revision: 2.17 $ string if the files are placed under
# a revision control system.%BR%
#%BR%
#The sensor input configuration follows as a block. Each line is a different
# input of the controller. For each line the parameters are separated
# by commas and should contain no spaces. The string consists of the following
# parameters.%BR%
#%DL%
# %DD% Sensor channel. (A, B, C etc.)
# %DD% Sensor type number. (0-12) (see 340 manual)
# %DD% Sensor curve number. (0-60)
# %DD% Serial number of sensor
# %DD% Input Filter. (1 = on, 0 = off)
# %DD% Number of readings to filter.
# %DD% Percentage band for filter (see 340 manual)
#%XDL%
#After the lines for all sensors the string %B%END_SENS%B% should follow.%BR%
# %BR% 
#The heater resistance (in ohms) is indicated on the next line by itself. %BR%
#%BR%
#The setpoint high and low limits follow on the next line with 
# the lower temperature limit first, separated by a comma.%BR%
#%BR%
#The next line consists of the control channel (A, B, C etc.) and setpoint 
# unit setting (1 = Kelvin, 2 = Celsius, 3 = sensor) separated by a comma.%BR%
#%BR% 
#The zone table follows as the last item with each line indicating a 
# separate zone entry. A maximum of 10 lines are permitted (this is governed
# by the 340). The list of entries is ended by the string %B%END_ZONE%B% on 
# the next line. If less than 10 entries are included then the remaining entries
# of the controller are set to zero in the setup procedure. The format of the 
# entries separated by commas is given below:%BR%
#%DL%
# %DD%Upper temperature limit (Kelvin)
# %DD%Proportional (P).
# %DD%Integral (I).
# %DD%Derivative (D).
# %DD%Manual output value (percentage).
# %DD%Heater range (0-5).
#%XDL%
#%BR%
#The file is then ended by the string %B%END%B%.
#
#%BR%
#An example of the file is given below%BR%
# %PRE%
#  #
#  # Zone PID File for ARS Cryofurnace
#  #$Id: lakeshore340.mac,v 2.17 2017/01/31 15:05:19 domingue Exp $#$State: Exp $
#  #
#  # Name
#  ARS_Cryofurnace
#  # Revision
#  $Revision: 2.17 $
#  # Sensors
#  # Syntax : channel,type,curve,serial,filter,numfilters,percentageband
#  # End with END_SENS
#  A,21,3,P6626,0,20,5
#  C,22,12,CAL,1,20,5
#  D,23,12,CAL,1,20,5
#  END_SENS
#  #
#  # Resistance of Heater
#  # Syntax : resistance
#  #
#  50
#  #
#  # Temperature Limits
#  # lower,upper
#  #
#  10,300
#  #
#  # Control Parameters
#  # Syntax : sensor,units
#  # units (1 = Kelvin, 2=Celsius, 3=Sensor)
#  C,1
#  #
#  # Zonetable
#  # Syntax : top,p,i,d,mout,range
#  # end with END_ZONE
#  100,1000,20,15,0,4
#  END_ZONE
#  #
#  # End with END.
#  #
#  END
#%PRE%
#%BR%
#%INTERNALS%
#Currently in this implementation GPIB is used to communicate with the
# instrument. However, all comms are done through two functions %B%_ls_send%B% and
# %B%_ls_read%B% and is is possible, therefore, to overload these to allow
# communication with a non-gpib interface, eg. a device server.%BR%
# %BR%
"""


global LS_VERSION LS_MODEL332
global TEMP_SP
global LS_TUNETEXT,LS_ONOFF,LS_UNITS
global LS_SENSOR_COUNTER, LS_SENSOR_CHANNEL, LS_SENSOR_VALUE
global LS_SENSOR_COUNTER_RESISTANCE, LS_SENSOR_CHANNEL_RESISTANCE
global LS_SENSOR_RESISTANCE
global LS_NUM_SENSORS, LS_NUM_SENSORS_RESISTANCE
global LS_NUM_SENSORS_POWER LS_COUNTER_POWER LS_CHANNEL_POWER LS_SENSOR_VALUE_POWER
global LS_LOOP
global LS_GPIB_ADDR,LS_SOCKET_ADDR,LS_COMM_MODE
global LS_CONFIG_FILENAME, LS_CONFIG_NAME, LS_CONFIG_REVISION
global LS_SETP_LIMITS
global LS_SILENT

LS_VERSION = "$Id: lakeshore340.mac,v 2.17 2017/01/31 15:05:19 domingue Exp $"

#%UU%
#%MDESC%
# Syntax : lsgpib_setup <GPIB unit> <GPIB number>.%BR%
# Set the global LS_ADDR which is used for all gpib access
def lsgpib_setup '{
  global LS_GPIB_ADDR
  if ($# != 2) {
    printf("Usage: lsgpib_setup <Spec GPIB unit range [0-3]> <Instrument GPIB number>")
  } else {
    gpib_unit = $1 ; gpib_addr = $2
    LS_GPIB_ADDR = sprintf("%1d:%1d",gpib_unit,gpib_addr)
    LS_COMM_MODE = "GPIB"
    LS_MODEL332= (index(_ls_get_ident(), "MODEL332")>0)
  }
}'

#%UU%
#%MDESC%
# Syntax : lssocket_setup <host> <port>.%BR%
# Set the global LS_ADDR which is used for all socket access
def lssocket_setup '{
  global LS_SOCKET_ADDR
  if ($# != 2) {
    printf("Usage: lssocket_setup <hostname> <port>")
  } else {
    LS_SOCKET_ADDR = sprintf("%s:%s","$1","$2")
    LS_COMM_MODE = "SOCKET"
  }
}'


"""
#%UU%
#%MDESC%
# Syntax : lsontemp%BR%
# Switch temperature logging on. Spec will read the temperature at each
# count and load temperature values into the pseudo counters
# defined by %B%lsspec_setup%B% the temperature setpoints are also
# set from the global variable %B%LS_SETP_LIMITS%B%
"""
def lsontemp '{
    global LS_SETP_LIMITS
    local ci counter

    T_LO_SP = LS_SETP_LIMITS[0]
    T_HI_SP = LS_SETP_LIMITS[1]

    for(ci=0 ; ci<LS_NUM_SENSORS ; ci++){
        counter = cnt_num(LS_SENSOR_COUNTER[ci])
        if(counter != -1){
            counter_par(counter, "disable", 0)
        }
    }

    cdef("measuretemp",    "_lsreadtemp()\n",                     "_LS")
    cdef("_settemp",       "_ls_setp(TEMP_SP); DEGC = TEMP_SP\n", "_LS")
    cdef("user_getcounts", "_ls_set_cnt\n",                       "_LS")
}'

"""
#%UU%
#%MDESC%
# Syntax : lsofftemp%BR%
# Switch temperature logging off. See %B%ontemp%B%
"""
def lsofftemp '{
    global LS_SENSOR_COUNTER
    global LS_NUM_SENSORS
    local ci counter

    cdef("","","_LS","delete")
    for(ci=0;ci<LS_NUM_SENSORS;ci++){
        counter = cnt_num(LS_SENSOR_COUNTER[ci])
        if(counter != -1){
            S[counter] = -1
            counter_par(counter, "disable", 1)
        }
    }
}'

"""
#%UU%
#%MDESC%
# Syntax : lsonreg%BR%
# Switch temperature regulation on for the loop defined by the
# global variable LS_LOOP
"""
def lsonreg '{
    local ans

    ans = _ls_set_control_state(LS_LOOP,1)
    print ans
    if(ans == 1){
        comment "Lakeshore temperature regulation switched ON (loop = %s)" LS_LOOP
    } else {
        comment "Error setting Lakeshore regulation ON"
    }
}'

"""
#%UU%
#%MDESC%
# Syntax : lsoffreg%BR%
# Switch temperature regulation off for the loop defined by the
# global variable LS_LOOP. See %B%onreg%B%
"""
def lsoffreg '{
    local ans

    ans = _ls_set_control_state(LS_LOOP,0)
    if(ans == 0){
        comment "Lakeshore temperature regulation switched OFF (loop = %s)" LS_LOOP
    } else {
        comment "Error setting Lakeshore regulation OFF"
    }
}'

"""
#%UU%
#%MDESC%
# Syntax : lsconfig [<filename>]%BR%
# Configure temperature controller from datafile. For datafile format see
# documentation and example file.%BR%
# This macro checks the global variable LS_CONFIG_NAME and if there
# is a match then the a reconfigure is %B%NOT%B% undertaken. This variable
# is loaded from the config files "name" field so care should be taken to
# ensure this is unique.%BR%
# This macro can therefore be called from the setup of spec. To force a
# config use the macro %B%lssendconfig%B% . If no parameter is passed the
# the current config is displayed from the global variables.%BR%
"""
def lsconfig '{
    global LS_CONFIG_FILENAME,LS_CONFIG_NAME,LS_LOOP
    local filename,rtn,flag

    flag = 0

    if($# == 1){
        filename = "$1"
        _ls_send_config(filename,LS_CONFIG_NAME,LS_CONFIG_REVISION,LS_LOOP)
        flag = 1
    }

    if($# == 0){
        if(LS_CONFIG_FILENAME == ""){
            printf("---- No Config has been previously loaded this spec session\n")
            flag = 1
        } else {
            printf("---- Config file : %s\n",filename)
            printf("---- Config for  : %s\n",LS_CONFIG_NAME)
            printf("---- Revision    : %s\n",LS_CONFIG_REVISION)
            flag = 1
        }

    }

    if(flag == 0){
        printf("Syntax : lsconfig [<filename>]\n")
        exit
    }
}'

"""
#%UU%
#%MDESC%
# Syntax : lssendconfig [<filename>]%BR%
# Configure temperature controller from datafile. For datafile format see
# documentation and example file.%BR%
# %B%WARNING%B% This config action will cause a reconfigure of the sensor
# inputs. This will disturb your temperature control and %B%WILL%B% switch
# off the control loop. You should run %B%lsconfig%B% if you just want to
# check config in the setup script of spec. Use this macro to force a
# reconfig. If no parameter is passed then a reconfig will commence
# from the pervious file.
"""
def lssendconfig '{
    global LS_LOOP
    local filename

    if($# == 0){
        _ls_send_config(LS_CONFIG_FILENAME,"","",LS_LOOP)
        flag = 1
    }

    if($# == 1){
        filename = "$1"
        _ls_send_config(filename,"","",LS_LOOP)
        flag = 1
    }

    if(flag == 0){
        printf("Syntax : lssendconfig <filename>\n")
        exit
    }
}'

#%IU%
#%MDESC%
# Syntax : _ls_send_config(filename,oldname,newname,loop)%BR%
# See %B%lssendconfig%B% and %B%lsconfig%B%
def _ls_send_config(filename,oldname,oldrevision,loop) '{
    local result

    printf("---- Loading LAKESHORE config from datafile\n")
    printf("---- File : %s\n",filename)

    result = _ls_load(filename,oldname,oldrevision,loop)

    if(result == 1){
        printf("\n---- There was an error during config PLEASE CHECK!\n")
        comment "Lakeshore Config with %s completed WITH ERRORS" filename
        exit
    }

    if(result == -1){
        printf("---- Lakeshore controller already configured this session\n")
        printf("---- Use < lssendconfig > to force.\n")
        return -1
    }

    if(result == 0){
        comment "Lakeshore config changed to %s" filename
        return 0
    }
}'

#%UU%
#%MDESC%
# Syntax : lsshow%BR%
# Display all main parameters and values for the temperature controller
def lsshow '{
    print date()
    print LS_VERSION
    lsident
    lspid
    lsheater
    lscontrol
    lsmode
    lscurve
    showtemp
}'

#%UU%
#%MDESC%
# Syntax : lsident%BR%
# Display the device indentification string of the lakeshore.
def lsident '{
  local ident
  ident = _ls_get_ident()
  printf("LakeShore identification %s\n",ident)
}'

"""
#%IU%
#%MDESC%
#Syntax : _ls_send(command)%BR%
#Internal function to send a command string to the lakeshore. This imp.
#uses gpib at an address defined my the global variable %B%LS_ADDR.%B%
#Returns %B%LSREADERROR%B% if the command could not be sent, otherwise
#%B%LSOK%B% is returned.
"""
def _ls_send(command) '{
    local numsent
    local reply
    global LS_GPIB_ADDR
    global LS_COMM_MODE

    if(LS_COMM_MODE == "GPIB"){
        numsent = gpib_put(LS_GPIB_ADDR,command)
        if(numsent==0)
            return "LSREADERROR"
        else
            return "LSOK"
    }

    if(LS_COMM_MODE == "SOCKET"){
        reply = _ls_read(command)
        if(reply != "LSREADERROR")
            return "LSOK"
        else
            return "LSREADERROR"
    }

}'

#%IU%
#%MDESC%
# Syntax : _ls_read(command)%BR%
# Internal function to send a command string to the lakeshore and get the
# reply.
def _ls_read(command) '{
    global LS_COMM_MODE
    global LS_GPIB_ADDR
    global LS_SOCKET_ADDR
    local ans;
    local test
           local numsent
    local tosend

    ans = "LSREADERROR"

    if(LS_COMM_MODE == "GPIB"){
               numsent = gpib_put(LS_GPIB_ADDR,command)
               if(numsent > 0){
                  ans = gpib_get(LS_GPIB_ADDR)
                 if (ans == "")
                ans = "LSREADERROR"
            } else {
                 p "_ls_read() : Error writing to GPIB"
                 ans = "LSREADERROR"
        }
    }

    if(LS_COMM_MODE == "SOCKET"){
        ans = sock_par(LS_SOCKET_ADDR,"connect")
        if(ans == 1) {
                tosend = sprintf("%s\n",command)
                ans = sock_put(LS_SOCKET_ADDR,tosend)
                ans = sock_get(LS_SOCKET_ADDR,0)
            sock_par(LS_SOCKET_ADDR,"close")
            ans = substr(ans,0,length(ans)-1)
                if(ans == "SERVER_TIMEOUT"){
                p "_ls_read() : Server Timeout"
                        ans = "LSREADERROR"
            }
            } else {
            p "_ls_read() : Cannot connect to server."
            ans = "LSREADERROR"
        }
    }

    return ans
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_get_ident()%BR%
# Internal function which gets the lakeshore identification string from
# the instrument and returns it.
"""
def _ls_get_ident() '{
    local ans
    ans = _ls_read("*IDN?")
    return ans
}'

"""
#%IU%
#%MDESC%
# Syntax : _lsreadtemp()%BR%
# Internal function which reads all temperature and sensor values defined by
# %B%ls_spec_setup%B% and stores them in the internal global variables.
# This macro is chained through the use of the
# %B%ontemp%B% command to the std macro %B%measuretemp%B%.
"""
def _lsreadtemp() '{
  global LS_SENSOR_CHANNEL
  global LS_SENSOR_VALUE
  global LS_SENSOR_RESISTANCE
  global LS_NUM_SENSORS
  global LS_NUM_SENSORS_RESISTANCE
  global LS_SENSOR_POWER
  global LS_LOOP

  local ci

  for(ci=0;ci<LS_NUM_SENSORS;ci++){
      LS_SENSOR_VALUE[ci] = _ls_readsensor_k(LS_SENSOR_CHANNEL[ci])
    if(LS_SENSOR_VALUE[ci] == "LSREADERROR"){
            LS_SENSOR_VALUE[ci] = -1;
        }
  }

  for(ci=0;ci<LS_NUM_SENSORS_RESISTANCE;ci++){
    LS_SENSOR_RESISTANCE[ci] = _ls_readsensor_o(LS_SENSOR_CHANNEL_RESISTANCE[ci])
    if(LS_SENSOR_RESISTANCE[ci] == "LSREADERROR"){
            LS_SENSOR_RESISTANCE[ci] = -1;
        }
  }
  
  for (ci=0 ; ci<LS_NUM_SENSORS_POWER ; ci++) {
    LS_SENSOR_POWER[ci] = _ls_read("HTR?")+0
  }
}'

"""
#%UU%
#%MDESC%
# Syntax : showtemp%BR%
# Read and display all sensors defined by the %B%ls_spec_setup%B% macro
# and the setpoint temperature this macro also shows the current
# setpoint ramprate if ramping is active
"""
def showtemp '{
  local ci,resistance,temperature,ramp,ramprate,isramping,control
  global LS_SENSOR_COUNTER
  global LS_SENSOR_CHANNEL
  global LS_NUM_SENSORS
  global LS_ONOFF
  global LS_UNITS

  printf("\n")
  for(ci=0;ci<LS_NUM_SENSORS;ci++){
        temperature = _ls_readsensor_k(LS_SENSOR_CHANNEL[ci])
    resistance = _ls_readsensor_o(LS_SENSOR_CHANNEL[ci])
    printf("%12s : Sensor(%s) = %7.3f K (%7.3f ohms)\n",LS_SENSOR_COUNTER[ci],LS_SENSOR_CHANNEL[ci],temperature,resistance)
  }

  ramp=_ls_read_ramp(LS_LOOP)
  ramprate=_ls_read_ramprate(LS_LOOP)
  setpoint=_ls_read_setpoint(LS_LOOP)
  isramping=_ls_ramp_state(LS_LOOP)
  control=_ls_read_control(LS_LOOP)

  if(ramp==1){
    if(isramping==1)
       printf("    Setpoint :           = %7.3f %s (ramp at %7.3f m^-1 ACTIVE)\n",setpoint,substr(LS_UNITS[control[1]],1,1),ramprate)
    else
       printf("    Setpoint :           = %7.3f %s (ramp at %7.3f m^-1)\n",setpoint,substr(LS_UNITS[control[1]],1,1),ramprate)
  } else {
    printf("    Setpoint :           = %7.3f %s\n",setpoint,LS_UNITS[control[1]])
  }
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_set_cnt()%BR%
# Read temperature and set the corresponding pseudo counters. This macro
# calls the %B%measuretemp%B% macro to load the current values into the
# global variables
"""
def _ls_set_cnt '{
  global LS_SENSOR_COUNTER
  global LS_SENSOR_VALUE
  global LS_NUM_SENSORS
  global LS_NUM_SENSORS_RESISTANCE
  local ci
  local counter

  measuretemp
  for(ci=0;ci<LS_NUM_SENSORS;ci++){
        counter = cnt_num(LS_SENSOR_COUNTER[ci])
    if(counter != -1){
        S[counter] = LS_SENSOR_VALUE[ci]
    }
  }

  for(ci=0;ci<LS_NUM_SENSORS_RESISTANCE;ci++){
        counter = cnt_num(LS_SENSOR_COUNTER_RESISTANCE[ci])
    if(counter != -1){
        S[counter] = LS_SENSOR_RESISTANCE[ci]
    }
  }

  for(ci=0;ci<LS_NUM_SENSORS_POWER;ci++){
    counter = cnt_num(LS_SENSOR_COUNTER_POWER[ci])
	if(counter != -1){
		S[counter] = LS_SENSOR_POWER[ci]
	}
  }

}'

"""
#%IU%
#%MDESC%
# Syntax _ls_setp()%BR%
# Change setpoint value. Function called by the std macro settemp when %B%ontemp%B% is run
"""
def _ls_setp(newval) '{
    local cmd
    _ls_read(sprintf("SETP %s, %g",LS_LOOP,newval))
    comment "New set point: %gK (loop= %s)" newval,LS_LOOP
}'



"""
#%UU%
#%MDESC%
# Syntax : lsramp [<rate>]%BR%
# Set the value of the setpoint ramp rate in (K/mn).
# If no parameter is passed the current setpoint ramp rate is displayed.
"""
def lsramp '{
    # Set ramprate
    local ramp,flag

    flag = 0
    if($# == 1){
        ramp = _ls_set_ramprate(LS_LOOP,$1)
        if(ramp == "LSREADERROR"){
            printf("Error setting ramprate.\n")
            exit
        }
        comment "Temperature ramping set to %gK.min^-1 (loop=%s)" ramp,LS_LOOP
    if (LS_MODEL332) {
      printf("WARNING !! Activate ramping using lsonramp !!\n")
    }
        flag = 1
    }

    if($# == 0){
        ramp = _ls_read_ramprate(LS_LOOP)
        if(ramp == "LSREADERROR"){
            printf("Error reading ramprate.\n")
            exit
        }
        printf("Current ramp rate is %gK.min^-1 on loop %s",ramp,LS_LOOP)
        flag = 1
    }

    if(flag == 0){
        printf("Syntax : lsramp [<rate>]\n")
        exit
    }

}'

"""
#%UU%
#%MDESC%
# Syntax : lsonramp%BR%
# Switch on temperature ramping. The rate must be set using the %B%lsramp%B%
# macro.
"""
def lsonramp '{
  local ans

  ans = _ls_set_ramp(LS_LOOP,1)
  if(ans == 1){
        ans = _ls_read_ramprate(LS_LOOP)
    comment "Temperature ramping enabled (%f K.min^-1)." ans
  } else {
        printf("Error : Temperature ramping was NOT enabled\n\n")
    exit
  }
}'

"""
#%UU%
#%MDESC%
# Syntax : lsofframp%BR%
# Switch off temperature ramping
"""
def lsofframp '{
  local ans

  ans = _ls_set_ramp(LS_LOOP,0)
  if(ans == 0){
    comment "Temperature ramping disabled."
  } else {
        printf("Error : Temperature ramping was NOT DISABLED\n\n")
    exit
  }
}'

"""
#
#%UU%
#%MDESC%
# Syntax : lsheater [<range>]%BR%
# Shows/allows to change the heater (0 to 5).
# If no parameter is given the current range is displayed
# heater 0 means heater off
"""
def lsheater '{
    local reply,heater,flag

    flag = 0

    if($# == 0){
        # Display
        reply = _ls_read_heater()
        if(reply=="LSREADERROR"){
            printf("Error reading lakeshore\n")
            exit
        }
        printf("Heater is on range %d\n",reply)
        flag = 1
    }

    if($# == 1){
        # Set
        reply = _ls_set_heater("$1")
        if(reply=="LSREADERROR"){
            printf("Error reading lakeshore\n")
            exit
        }
        comment "Lakeshore set to heater range %d" reply
        flag=1
    }

    if(flag==0){
        printf("Syntax : lsheater [<range>]\n")
        exit
    }
}'

"""
#%UU%
#%MDESC%
# Syntax : lspid [<p>] [<i>] [<d>]%BR%
# Macro to alter the PID values in the lakeshore. If no pid values are given
# then the current values are displayed.%BR%
"""
def lspid '{
    local reply,pid,flag

        flag = 0

    if($#==3){
        # Set PID parameters
        pid[0]=$1;pid[1]=$2;pid[2]=$3
        reply = _ls_set_pid(LS_LOOP,pid)
        if(reply[0] == "LSREADERROR"){
            printf("Error setting PID parameters\n")
            exit
        }

        comment "Lakeshore PID parameters set (P=%.1f,I=%.1f,D=%.1f)" reply[0],reply[1],reply[2]
                flag = 1
    }

    if($# == 0) {
        # display PIDs

        reply = _ls_read_pid(LS_LOOP)

        if(reply[0] == "LSREADERROR"){
            printf("Error Reading PID parameters from Lakeshore\n")
            exit
        } else {
            printf("PID Parameters\n\n")
            printf("     P = %f\n",reply[0])
            printf("     I = %f\n",reply[1])
            printf("     D = %f\n\n",reply[2])
        }
        flag = 1
    }

        if(flag == 0){
       printf("Syntax : lspid [<p>] [<i>] [<d>]\n\n")
       exit
    }
}'

"""
#%UU%
#%MDESC%
# Syntax : lsmode [<mode>]%BR%
# Shows/allows to change the temperature control mode.
# If no parameter is passed then the current control mode is displayed
# The available modes are:
# %DL%
# %DD% 1 Manual mode
# %DD% 2 Zone mode
# %DD% 3 Open Loop
# %DD% 4 Automatic PID
# %DD% 5 Automatic PI
# %DD% 6 Automatic P
# %XDL%
"""
def lsmode '{
   local ans,text,ci,flag;
   global LS_TUNETEXT

   flag = 0

   if($# == 1){
    ans = _ls_set_mode(LS_LOOP,$1)
    if(ans=="LSREADERROR"){
        printf("Error setting mode\n")
        exit
    }
    text = LS_TUNETEXT[ans]
    comment "Temperature control mode changed to %d (%s)" ans,text
        flag=1
   }

   if($# == 0){
    # Just display mode

    ans = _ls_read_mode(LS_LOOP)
    if(ans=="LSREADERROR"){
        printf("Error reading mode\n")
        exit
    }
    text = LS_TUNETEXT[ans]
    printf("\nTemperature control is set to %d (%s)\n\n",ans,text)
    flag=1
   }

   if(flag==0){
       printf("\nSyntax : lsmode [<mode>]\n\n")
       exit
   }
}'

"""
#%UU%
#%MDESC%
#Syntax : lsspec_setup <numsensors> [<spec counter> <lakeshore sensor> ...]%BR%
#Setup spec for the use of the lakeshore. This macro sets the internal global
# variables used by the whole macroset and configures the pseudo counters
# for measuring the temperature in KELVIN. See %B%lsspec_setup_resistance%B%
# to setup pseudo counters for measurement in sensor units.
"""
def lsspec_setup '{
    global LS_NUM_SENSORS
    global LS_NUM_SENSORS_RESISTANCE
    global LS_SENSOR_COUNTER
    global LS_SENSOR_CHANNEL
    global LS_SENSOR_VALUE
    global LS_TUNETEXT
    global LS_ONOFF;
    global LS_UNITS
    global LS_VERSION
    global LS_SETP_LIMITS
    local ci,npar,apar

    # First lets setup some nice text !

    LS_SETP_LIMITS[0] = 0
    LS_SETP_LIMITS[1] = 1000

        LS_TUNETEXT[0]="Not defined"
    LS_TUNETEXT[1]="Manual PID"
    LS_TUNETEXT[2]="Zone"
    LS_TUNETEXT[3]="Open loop"
    LS_TUNETEXT[4]="Auto Tune PID"
    LS_TUNETEXT[5]="Auto Tune PI"
        LS_TUNETEXT[6]="Auto Tune P"

    LS_ONOFF[0] = "OFF"
    LS_ONOFF[1] = "ON"

    LS_UNITS[0] = "Not Defined"
    LS_UNITS[1] = "Kelvin"
    LS_UNITS[2] = "Celsius"
    LS_UNITS[3] = "Sensor"

        # Set the default GPIB address ...

    #LS_ADDR = "0:7"
    LS_LOOP = 1;

    # By Default configure no counters

    LS_NUM_SENSORS=0
    LS_NUM_SENSORS_RESISTANCE=0

        # now lets setup the sensors

    npar = split("$*",apar," ")

    if (npar == 0) {
        # Print Syntax of command
        printf("Usage: lsspec_setup <numsensors> [<spec counter> <lakeshore sensor> ...]")
        exit
    }

    LS_NUM_SENSORS = $1

    if(npar != ((LS_NUM_SENSORS * 2) +1)) {
        printf("Incorect number of parameters for %d sensors\n")
        printf("Usage: lsspec_setup <numsensors> [<spec counter> <lakeshore sensor> ...]\n")
    }

    for(ci=0;ci<LS_NUM_SENSORS;ci++){
        if(cnt_num(apar[(ci * 2) + 1]) < 0){
            printf("%s is not a spec pseudocounter ... sorry it did not work out ...\n",apar[(ci * 2) + 1])
            exit
        }
        LS_SENSOR_COUNTER[ci] = apar[(ci * 2) + 1]
        LS_SENSOR_CHANNEL[ci] = apar[(ci * 2) + 2]
        LS_SENSOR_VALUE[ci] = -1
    }

    if (!LS_SILENT) {
        printf("---- Lakeshore 340 macroset : S.B. Wilkins 2003\n")
        printf("---- Version %s\n", LS_VERSION)
        printf("---- Lakeshore spec setup complete with %d counters configured\n", LS_NUM_SENSORS)
    }
}'

"""
#%UU%
#%MDESC%
# Syntax : lsspec_setup_resistance <numsensors>
# [<spec counter> <lakeshore sensor> ...]%BR%
# Setup spec for counting with sensor units (resistance / voltage etc.).
# This macro takes the same syntax as %B%lsspec_setup%B% but does not do any
# other actions than setup the pseudo counters.
# You %B%MUST%B% run %B%lsspec_setup%B% before running this macro.
"""
def lsspec_setup_resistance '{
    global LS_NUM_SENSORS_RESISTANCE
    global LS_COUNTER_RESISTANCE
    global LS_CHANNEL_RESITANCE
    global LS_SENSOR_VALUE_RESISTANCE
    local ci,npar,apar

    # now lets setup the sensors
    npar = split("$*",apar," ")

    if (npar == 0) {
        # Print Syntax of command
        printf("Syntax : lsspec_setup_resistance <numsensors> [<spec counter> <lakeshore sensor> ...]")
        exit
    }

    LS_NUM_SENSORS_RESISTANCE = $1

    if(npar != ((LS_NUM_SENSORS_RESISTANCE * 2) +1)) {
        printf("Incorect number of parameters for %d sensors\n")
        printf("Syntax : lsspec_setup_resistance <numsensors> [<spec counter> <lakeshore sensor> ...]\n")
    }

    for(ci=0;ci<LS_NUM_SENSORS_RESISTANCE;ci++){
        if(cnt_num(apar[(ci * 2) + 1]) < 0){
            printf("%s is not a spec pseudocounter ... sorry it did not work out ...\n",apar[(ci * 2) + 1])
            exit
        }
        LS_SENSOR_COUNTER_RESISTANCE[ci] = apar[(ci * 2) + 1]
        LS_SENSOR_CHANNEL_RESISTANCE[ci] = apar[(ci * 2) + 2]
        LS_SENSOR_VALUE_RESISTANCE[ci] = -1
    }
}'

"""
#%UU%
#%MDESC%
# Syntax : lsspec_setup_power <numloop> 
# [<spec counter> <lakeshore loop power> ...]%BR%
# Setup spec for counting with loop power
# This macro takes the same syntax as %B%lsspec_setup%B% but does not do any
# other actions than setup the pseudo counters. 
# You %B%MUST%B% run %B%lsspec_setup%B% before running this macro.
"""
def lsspec_setup_power '{
	global LS_NUM_SENSORS_POWER LS_SENSOR_COUNTER_POWER LS_SENSOR_CHANNEL_POWER LS_SENSOR_VALUE_POWER
	local ci,npar,apar

    # now lets setup the sensors
    npar = split("$*",apar," ")

	if (npar == 0) {
		# Print Syntax of command
		printf("Syntax : lsspec_setup_power <numloop> [<spec counter> <lakeshore loop> ...]")
		exit
	}

	LS_NUM_SENSORS_POWER = $1

	if(npar != ((LS_NUM_SENSORS_POWER * 2) +1)) {
		printf("Incorect number of parameters for %d loop\n")
		printf("Syntax : lsspec_setup_power <numloop> [<spec counter> <lakeshore loop> ...]\n")
	}

	for(ci=0;ci<LS_NUM_SENSORS_POWER;ci++){
		if(cnt_num(apar[(ci * 2) + 1]) < 0){
			printf("%s is not a spec pseudocounter ... sorry it did not work out ...\n",apar[(ci * 2) + 1])
			exit
		}
		LS_SENSOR_COUNTER_POWER[ci] = apar[(ci * 2) + 1]
		LS_SENSOR_CHANNEL_POWER[ci] = apar[(ci * 2) + 2]
		LS_SENSOR_VALUE_POWER[ci] = -1
	}
}'


"""
#%UU%
#%MDESC%
#Syntax : lscontrol [<sensor>] [<units>] [<on/off>]%BR%
# Change the sensor from which the lakeshore will control from, the units
# used for the setpoints and enable or disable the control loop.
# The loop to configure is taken from the global variable LS_LOOP.
# If no parameter is passed then the current control sensor is displayed.
# The options for <units> are given below.
# %DL%
# %DT%
# %DD%1 = Kelvin
# %DD%2 = Celcius
# %DD%3 = Sensor Units
"""
def lscontrol '{
    local ctrl,sensor,flag,onoff

    flag = 0;onoff = 0

    ctrl = _ls_read_control(LS_LOOP)

    sensor = ctrl[0]
    units = ctrl[1]
    onoff = ctrl[2]

    if($# == 3){
    # Send all commands
    if(("$3" == "on") || ("$3" == "off")){
        if("$3" == "on")
            onoff = 1
        else
            onoff = 0
        sensor = "$1"
        units = $2
        flag = 1
    } else {
        flag = 0
    }
    }

    if($# == 2){
        # Send all but onoff
        units = $2
    sensor = "$1"
        flag = 1
    }

    if($# == 1){
    # Set the control channel
    sensor = "$1"
        flag = 1
    }

   if(flag == 1){
    ctrl = _ls_set_control(LS_LOOP,sensor,units,onoff)
    comment "Temp Control on sensor %s in units %s %s (loop=%s)" ctrl[0],LS_UNITS[ctrl[1]],LS_ONOFF[ctrl[2]],LS_LOOP
    flag = 1
    }

    if($# == 0){
    ctrl = _ls_read_control(LS_LOOP)
    printf("Temp control on sensor %s in units %s %s (loop=%s)\n",ctrl[0],LS_UNITS[ctrl[1]],LS_ONOFF[ctrl[2]],LS_LOOP)
    flag=1
    }

    # So they have made an error
    if(flag==0){
        printf("\n Syntax : lscontrol [<sensor>] [<units>] [<on/off>]\n\n")
    exit
    }
}'

"""
#%UU%
#%MDESC%
# Syntax : lscurve [<sensor>] [<sensor type>] [<curve number>]%BR%
# Changes the number of the calibration curve for a given sensor.
# If only a sensor is passed then the calibration curve is displayed for that
# sensor. If no
# parameter is given then the calibration curve numbers and serial number
# is displayed for all sensors configured with %B%lsspec_setup%B%. The values
# for the sensor type are shown below.%BR%BR%
# %DL%
# %DT% Values for <sensor type> (Lakeshore 340)
# %DD% (0)  Special
# %DD% (1)  Silicon Diode
# %DD% (2)  GAlAs Diode
# %DD% (3)  PT100 (250ohm)
# %DD% (4)  PT100 (500ohm)
# %DD% (5)  PT1000
# %DD% (6)  Rhodium Iron
# %DD% (7)  Carbon-Glass
# %DD% (8)  Cernox
# %DD% (9)  RuOx
# %DD% (10) Germanium
# %DD% (11) Capacitor
# %DD% (12) Thermocouple
# %XDL%
"""
def lscurve '{
    global LS_NUM_SENSORS
    global LS_SENSOR_CHANNEL
    local cc,ans,sensor,flag,reply

    if($# == 0){
        # Display sensor(s).
        for(cc=0;cc<LS_NUM_SENSORS;cc++){
            ans = _ls_read_curve(LS_SENSOR_CHANNEL[cc])
            if(ans[0] == "LSREADERROR"){
                printf("Error reading curve for sensor %s\n",LS_SENSOR_CHANNEL[cc])
                exit
            }
            printf("Sensor %s : Curve %2s",LS_SENSOR_CHANNEL[cc],ans[3])
            printf(" Type : %18s Serial : %10s\n",ans[0],ans[1])
        }
        flag = 1
    }

    if($# == 1){
        ans = _ls_read_curve("$1")
        if(ans[0] == "LSREADERROR"){
            printf("Error reading curve for sensor %s\n",LS_SENSOR_CHANNEL[cc])
            exit
        }
        printf("Sensor %s : Curve %2s","$1",ans[3])
        printf(" Type : %18s Serial : %10s\n",ans[0],ans[1])
        flag = 1
    }

    if($# == 3){
        # Set Channel to curve number.

        _ls_set_curve("$1",$2,$3)
        ans = _ls_read_curve("$1")
        if(ans[0] == "LSREADERROR"){
            printf("Error Reading from Lakeshore\n")
            exit
        }
        sensor = "$1"

        comment "Sensor channel %s now using curve number %d (S/N:%s)" sensor,ans[3],ans[1]
    }
}'

"""
#%UU%
#%MDESC%
# Syntax : lsfilter [<sensor>] [<on/off>] [<n readings>] [<band>]%BR%
# Set the input filter for sensor channel <sensor>.
# Example : lsfilter A on 20 5%BR%
"""
def lsfilter '{
    local oldfilter,ci,flag
    local onoff,nread,band
    global LS_NUM_SENSORS
    global LS_SENSOR_CHANNEL
    global LS_ONOFF

    flag = 0

    if($# == 0){
        for(ci=0;ci<LS_NUM_SENSORS;ci++){
            oldfilter = _ls_read_infilter(LS_SENSOR_CHANNEL[ci])
            if(oldfilter[0] == "LSREADERROR"){
                printf("Error reading from Lakshore.\n")
                exit
            }
            printf("Sensor : %2s input filtering %3s (%d samples with %f band)\n",LS_SENSOR_CHANNEL[ci],LS_ONOFF[oldfilter[0]],oldfilter[1],oldfilter[2]);
        }
        flag = 1
    }

    if($# == 1){
        oldfilter = _ls_read_infilter("$1")
        if(oldfilter[0] == "LSREADERROR"){
            printf("Error reading from Lakshore.\n")
            exit
        }
        printf("Sensor : %2s input filtering %3s (%d samples with %f band)\n","$1",LS_ONOFF[oldfilter[0]],oldfilter[1],oldfilter[2]);
        flag = 1
    }

    if(flag == 0){
        oldfilter = _ls_read_infilter("$1")
        if(oldfilter[0] == "LSREADERROR"){
            printf("Error reading filter value from Lakeshore\n")
            exit
        }
    }

    if(($# > 1) && ($# < 5)){
        if(("$2" == "on") || ("$2" == "off")){
            if("$2" == "on")
                oldfilter[0] = 1
            if("$2" == "off")
                oldfilter[0] = 0
        }

        if($# > 2)
            oldfilter[1] = $3
        if($# > 3)
            oldfilter[2] = $4

        newfilter = _ls_set_infilter("$1",oldfilter[0],oldfilter[1],oldfilter[2])
        if(newfilter[0] == "LSREADERROR"){
            printf("Error setting filter parameters\n")
            exit
        }

        comment "Input sensor %s filter is %s with %d readings (band = %f)" newfilter[3],LS_ONOFF[newfilter[0]],newfilter[1],newfilter[2]
        flag = 1
    }

    if(flag == 0){
        #Syntax Error
        printf("Syntax : lsfilter [<sensor>] [<on/off>] [<nreadings>] [<band>]\n")
        exit
    }
}'

"""
#%IU%
#%MDESC%
#Syntax : _ls_set_curve(channel,type,curvenumber)%BR%
# This function sets both the sensor type and the calibration
# curve number. It returns LSOK if sucsessful or LSREADERROR
# if not. The curve number can be in the range 0 - 60. Curve 0 means no
# calibration curve. The sensor is also enabled after config.
"""
def _ls_set_curve(channel,type,curv_num)'{

    local rtn,ans

    ans = _ls_send(sprintf("INTYPE %s,%d",channel,type))
    if(ans != "LSOK"){
        printf("Error setting curve type\n")
        exit
    }
    while(_ls_isbusy()){
        sleep(0.2)
    }
    ans = _ls_send(sprintf("INCRV %s,%d",channel,curv_num))
    if(ans != "LSOK"){
        printf("Error setting curve type\n")
        exit
    }
    while(_ls_isbusy()){
        sleep(0.2)
    }
    ans = _ls_send(sprintf("INSET %s,1",channel))
    if(ans != "LSOK"){
        printf("Error while activating sensor\n")
        exit
    }
    return ans
}'

"""
#%IU%
#%MDESC%
# Syntax _ls_isbusy()%BR%
# Function to poll the busy status of the controller. Returns 0
# if the instrument is not busy and 1 otherwise.
"""
def _ls_isbusy() '{
    local ans

    ans = _ls_send("BUSY?")
    if(ans > 0){
        return 0
    } else {
        return 1
    }
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_read_curve(channel)%BR%
# Function to read the calibration curve parameters. Returns the parameters
# in an array with elements
# %DL%
# %DT% Returned Array
# %DD% 0 : Name
# %DD% 1 : Serial Number
# %DD% 2 : Format
# %DD% 3 : Calibration curve number.
# %XDL%
# The function returns LSREADERROR in the first element if there is an
# error reading from the controller.
"""
def _ls_read_curve(channel) '{
    local ans,rtn
    ans = _ls_read(sprintf("INCRV? %s",channel))
    if(ans!="LSREADERROR"){
        curv_num = ans
        ans = _ls_read(sprintf("CRVHDR? %s",curv_num))
        if(ans!="LSREADERROR"){
            split(ans,chead,",")
            sscanf(chead[0],"%s",rtn[0])
            sscanf(chead[1],"%s",rtn[1])
            sscanf(chead[2],"%s",rtn[2])
            rtn[3] = curv_num
        } else {
            rtn[0] = "LSREADERROR"
        }
    } else {
        rtn[0] = "LSREADERROR"
    }

    return rtn
}'

"""
#%UU%
#%MDESC%
# Syntax : lscontrast [<value>]%BR%
# Set display contrast. A value of zero switches off the backlight while
# if no parameters are passed then the current value is displayed.
"""
def lscontrast '{
    local contrast,flag,cval
    global LS_ONOFF

    flag = 0

    if($# == 0){
        contrast = _ls_read_contrast()
        if(contrast[0] != "LSREADERROR"){
            printf("Lakeshore display backlight is %s (contrast = %g)\n",LS_ONOFF[contrast[2]],contrast[1])
            flag = 1
        } else {
            printf("Error communicating with controller\n")
            exit
        }
    }

    if($# == 1){
        cval = $1
        contrast = _ls_set_contrast(cval)
        if(contrast[0] != "LSREADERROR"){
            comment "Lakeshore display backlight %s (contrast = %f)\n" LS_ONOFF[contrast[2]],contrast[1]
            flag = 1
        } else {
            printf("Error communicating with controller\n")
            exit
        }
    }

    if(flag == 0){
        printf("Syntax : lscontrast [<contrast>]\n")
        exit
    }
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_set_pid(loop,pid)%BR%
# Set pid parameters, returns the controller read pid's as an array.
"""
def _ls_set_pid(loop,pid) '{
    local ans,rtn

    rtn[0] = "LSREADERROR"

    ans = _ls_send(sprintf("PID %5.1f,%5.1f,%5.1f,%5.1f",loop,pid[0],pid[1],pid[2]))

    if(ans == "LSREADERROR"){
        return rtn
    }

    rtn = _ls_read_pid(loop)
    return rtn
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_read_pid(loop,pid)%BR%
# Read controller PID values, returns values as an array.
"""
def _ls_read_pid(loop,pid) '{
    local ans,newpid,rtn

    ans =_ls_read(sprintf("PID? %d", loop))
    if(ans!="LSREADERROR"){
        split(ans, newpid, ",")
        rtn[0]=newpid[0]
        rtn[1]=newpid[1]
        rtn[2]=newpid[2]

    }
    else {
        rtn[0] = "LSREADERROR"
    }
    return rtn
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_set_ramprate(loop,ramp)%BR%
# Sets controllers ramprate, returns controllers ramprate.
"""
def _ls_set_ramprate(loop,ramp)'{
    local ans,rtn,tmp
    global LS_RAMP

    rtn = "LSREADERROR"

    if (LS_MODEL332) {
        LS_RAMP= ramp
        rtn = LS_RAMP
    }
    else {
        ans = _ls_send(sprintf("RAMP %d,,%f",loop,ramp))
        if(ans=="LSREADERROR"){
            return rtn
        }

        LS_RAMP= ramp
        rtn = _ls_read_ramprate(loop)
    }

    return rtn
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_read_ramprate(loop)%BR%
# Reads and returns controllers ramprate.
"""
def _ls_read_ramprate(loop) '{
    local ans,tmp,rtn

    ans = _ls_read(sprintf("RAMP? %d",loop))
    if(ans=="LSREADERROR"){
        return "LSREADERROR"
    }
    split(ans, tmp, ",")
    rtn = tmp[1]
    return rtn
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_set_ramp(loop,state)%BR%
# Switches on or off temperature ramping (off = 0, on = 1)
"""
def _ls_set_ramp(loop,state) '{
    local ans,rtn
    global LS_RAMP

    if (LS_MODEL332) {
        ans = _ls_send(sprintf("RAMP %d,%d,%f",loop,state,LS_RAMP))
    } else {
        ans = _ls_send(sprintf("RAMP %d,%d",loop,state))
    }

    if(ans=="LSREADERROR"){
        return "LSREADERROR"
    }

    rtn = _ls_read_ramp(loop)
    return rtn
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_read_ramp(loop)%BR%
# Reads and returns controllers ramp setting (off = 0, on = 1)
"""
def _ls_read_ramp(loop) '{
    local ans,ramp,rtn

    ans = _ls_read(sprintf("RAMP? %d",loop))
    if(ans=="LSREADERROR"){
        return "LSREADERROR"
    }
    split(ans, ramp, ",")
    rtn = ramp[0]

    return rtn
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_ramp_state(loop)%BR%
# Reads and returns status of setpoint ramping (ramping = 1, not ramping = 0)
"""
def _ls_ramp_state(loop) '{
    local ans,ramp

    ans = _ls_read(sprintf("RAMPST? %d",loop))
    if(ans=="LSREADERROR")
        return "LSREADERROR"
    return ans
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_readsensor_k(sensor)%BR%
# Reads and returns sensor reading in kelvin.
# Returns -2 if there is an error condition on the sensor.
"""
def _ls_readsensor_k(sensor) '{
    local ans

    ans = _ls_sensorstatus(sensor)
    if(((ans & 16) == 16) || ((ans & 32) == 32)){
        ans = ans * -1
        return ans
    }

    ans = _ls_read(sprintf("KRDG? %s",sensor))
    return ans
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_readsensor_o(sensor)%BR%
# Reads and returns sensor reading in sensor units (ohms or voltage).
# returns -2 if there is an error with the sensor.
"""
def _ls_readsensor_o(sensor) '{
    local ans

    ans = _ls_sensorstatus(sensor)
    if(((ans & 64) == 64) || ((ans & 128) == 128)){
        ans = ans * -1
        return ans
    }
    ans = _ls_read(sprintf("SRDG? %s",sensor))
    return ans
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_set_control_state(loop,state)
# Switch on or off temperature control loop (1 = on, 0 = off).
"""
def _ls_set_control_state(loop,state) '{
    local ans,tmp,rtn
    ans = _ls_send(sprintf("CSET %d,,,%d",loop,state))
    if(ans == "LSREADERROR")
        return ans

    tmp = _ls_read_control(loop)
    if(tmp[0] == "LSREADERROR")
        return "LSREADERROR"
    else
        return tmp[2]
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_set_control(loop,controlchannel,units,onoff)%BR%
# Sets control loop parameters%BR%
# units (1 = Kelvin, 2 = Celsius, 3 = sensor units)%BR
# onoff (1 = on, 0 = off)
"""
def _ls_set_control(loop,ctrlcnl,units,onoff) '{
    local ans,rtn

    rtn[0] = "LSREADERROR"

    ans = _ls_send(sprintf("CSET %d,%s,%d,%d",loop,ctrlcnl,units,onoff))
    if(ans=="LSREADERROR")
        return rtn

    rtn = _ls_read_control(loop)
    return rtn
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_read_control(loop)%BR%
# Read and return control loop parameters as an array
"""
def _ls_read_control(loop) '{
    local ans,tmp,rtn

    ans = _ls_read(sprintf("CSET? %d",loop))
    if(ans=="LSREADERROR")
        return "LSREADERROR"
    split(ans,tmp,",")
    rtn[0] = tmp[0]
    rtn[1] = tmp[1]
    rtn[2] = tmp[2]
    return rtn
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_set_mode(loop,controlmode)%BR%
# Set and return controller control mode%BR%
# %DL% controlmode
# %DD% 1 = Manual mode
# %DD% 2 = Zone mode
# %DD% 3 = Open Loop
# %DD% 4 = Automatic PID
# %DD% 5 = Automatic PI
# %DD% 6 = Automatic P
# %XDL%
"""
def _ls_set_mode(loop,cmode) '{
    local rtn,ans

    if((cmode>0) && (cmode<7)){
        ans = _ls_send(sprintf("CMODE %d,%d",loop,cmode))
        if(ans=="LSREADERROR")
            return "LSREADERROR"
    }

    ans = _ls_read_mode(loop)
    return ans
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_read_mode(loop)%BR%
# Read and return current control mode.
"""
def _ls_read_mode(loop) '{
    local ans

    ans = _ls_read(sprintf("CMODE? %d",loop))
    if(ans=="LSREADERROR")
            return "LSREADERROR"
    return ans
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_read_contrast()%BR%
# Read and return display contrast.
"""
def _ls_read_contrast() '{
    local rtn,srtn,params
    rtn = _ls_read("DISPLAY?")
    if(rtn == "LSREADERROR"){
        srtn[0] = "LSREADERROR"
        return srtn
    }
    split(rtn,srtn,",")
    params[0] = srtn[0]
    params[2] = srtn[2]
     params[1] = srtn[1]
    return params
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_set_contrast(contrast)%BR%
# Set and return display contrast. A contrast of zero switches off the
# display backlight. Returns value of %B%_ls_read_constrast()%B%
"""
def _ls_set_contrast(contrast) '{
    local rtn,srtn

    srtn[0] = "LSREADERROR"

    if(contrast == 0){
        # Switch off backlight

        rtn = _ls_send("DISPLAY ,,0")
        if (rtn=="LSREADERROR")
            return srtn
    }

    if((contrast > 0) && (contrast <=100)){
        # Set constrast
        rtn = _ls_send(sprintf("DISPLAY ,%f,1",contrast))
        if (rtn=="LSREADERROR")
            return srtn
    }

    # Now read back params

    srtn = _ls_read_contrast()
    return srtn
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_set_heater(range)%BR%
# Set and return heater range (0 to 5, 0 = heater off).
"""
def _ls_set_heater(range) '{
    local rtn

    rtn = _ls_send(sprintf("RANGE %d",range))
    if(rtn=="LSREADERROR")
        return rtn
    rtn = _ls_read_heater()
    return rtn
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_read_heater%BR%
# Read and return heater range (0 to 5, 0 = heater off).
"""
def _ls_read_heater() '{
    local rtn
    rtn = _ls_read("RANGE?")
    return rtn
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_set_infilter(sensor,onoff,points,window)%BR%
# Set and return input filtering parameters.
"""
def _ls_set_infilter(sensor,onoff,points,window) '{
    local tmp,rtn,ans

    tmp = _ls_send(sprintf("FILTER %s,%d,%d,%f",sensor,onoff,points,window))
    if(tmp == "LSREADERROR"){
        rtn[0] = "LSREADERROR"
        return rtn
    }

    ans = _ls_read_infilter(sensor)

    rtn[0] = ans[0]
    rtn[1] = ans[1]
    rtn[2] = ans[2];
    rtn[3] = sensor

    return rtn
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_read_infilter(sensor)%BR%
# Read and return input filtering parameters.
"""
def _ls_read_infilter(sensor) '{
    local ans,rtn,tmp

    ans = _ls_read(sprintf("FILTER? %s",sensor))
    if(ans == "LSREADERROR"){
        rtn[0] = "LSREADERROR"
        return rtn
    }

    split(ans,tmp,",")

    rtn[0] = tmp[0]
    rtn[1] = tmp[1]
    rtn[2] = tmp[2]

    return rtn
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_set_setpoint(loop,sp)%BR%
# Set and read setpoint for given control loop.
"""
def _ls_set_zone(loop,zonenum,zoneparams) '{
    local rtn,command,tmp

    tmp[0] = "LSREADERROR"

    command = sprintf("ZONE %d,%d,%s",loop,zonenum,zoneparams)
    rtn = _ls_send(command)

    if(rtn == "LSREADERROR")
        return tmp
    tmp = _ls_read_zone(loop,zonenum)
    return tmp
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_read_setpoint(loop)%BR%
# Set and read setpoint for given control loop.
"""
def _ls_read_setpoint(loop) '{
    local rtn

    rtn = _ls_read(sprintf("SETP? %d",loop))
    return rtn
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_set_setpoint(loop,sp)%BR%
# Set and read setpoint for given control loop.
"""
def _ls_set_setpoint(loop,sp) '{
    local rtn,ans
    ans = _ls_send(sprintf("SETP %d,%f",loop,sp))
    if(ans == "LSREADERROR") # error corrected missing quote: HW 04/10/12
        return "LSREADERROR"
    rtn = _ls_read_setpoint(loop)
    return rtn
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_read_zone(loop,zonenumber)%BR%
# Read and return zone table entry for number zoneentry.
"""
def _ls_read_zone(loop,zonenum) '{
    local tmp,rtn,ans,res

    rtn[0] = "LSREADERROR"

    ans = _ls_read(sprintf("ZONE? %d,%d",loop,zonenum))
    #printf("Ans : %s\n",ans)
    if(ans == "LSREADERROR")
        return rtn

    split(ans,tmp,",")
    rtn[0] = zonenum
    rtn[1] = tmp[0]
    rtn[2] = tmp[1]
    rtn[3] = tmp[2]
    rtn[4] = tmp[3]
    rnt[5] = tmp[4]
    rtn[6] = tmp[5]

    return rtn
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_load(filename,oldsetupname,oldrevision,loop)%BR%
# Configure controller from datafile filename. If config is the same as in
# %B%oldsetupname%B% and %B%oldrevision%B% then NO config is done. To force
# a config pass these variables as blank strings. See %B%lsconfig%B% for
# datafile format.
"""
def _ls_load(filename,oldname,oldrevision,loop) '{
    local line,zoneparams,ci,tmp,flag,ulimit,llimit
    local csensor,config_name,config_version,cc

    global LS_SETP_LIMITS
    global LS_CONFIG_FILENAME
    global LS_CONFIG_NAME
    global LS_ONOFF
    global LS_VERSION

    # here we load a file and then set the zone table

    if(getline(filename,"open") == -1){
        printf("Cannot open filename %s ... exiting ...\n",filename)
        return 1
    }

    # First line should be a name for the configuration

    line = getline(filename)
    while(substr(line,1,1)=="#"){
        line = getline(filename)
    }
    config_name = substr(line,1,length(line)-1)
    line = getline(filename)
    while(substr(line,1,1)=="#"){
        line = getline(filename)
    }
    config_version = substr(line,1,length(line)-1)

    # Here we check the parameters passed
    if((oldname == config_name) && (oldrevision == config_version)){
        # We have the same config as has been loaded return with -1
        # close file as well
        getline(filename,"close")
        return -1;
    }

    printf("--- Config for : %s\n",config_name)
    printf("--- Revision   : %s\n",config_version)
    qcomment "_ls_load : Starting config for %s" config_name
    qcomment "_ls_load : Macroset version %s" LS_VERSION
    qcomment "_ls_load : Config revision %s" config_version
    LS_CONFIG_FILENAME = filename
    LS_CONFIG_NAME = config_name
    LS_CONFIG_REVISION = config_version

    line = getline(filename)

    ci = 0
    flag = 0

    printf("Configuring sensors ....\n")

    while(line != -1){
        if(substr(line,1,1) != "#"){
            if(substr(line,1,8) == "END_SENS")
                break
            # Configure the sensors
            split(substr(line,1,length(line)-1),tmp,",")

            _ls_set_curve(tmp[0],tmp[1],tmp[2])
            reply = _ls_read_curve(tmp[0])
            printf("--- Sensor Channel %s configured as curve %s (S/N : %s)\n",tmp[0],reply[3],reply[1])
            qcomment "_ls_load : Sensor %s, type %d using curve %s (S/N : %s)" tmp[0],tmp[1],reply[3],reply[1]
            if(reply[1] != tmp[3]){
                printf("***\n")
                printf("*** ERROR IN SENSOR S/N -- CALL LOCAL CONTACT\n")
                printf("*** Controller responded << %s >> configuration file says << %s >>\n",reply[1],tmp[3])
                printf("***\n")
                qcomment "_ls_load : MISSMACH Controller responds %s config file says %s" reply[1],tmp[3]
                flag = 1
            }
            reply = _ls_set_infilter(tmp[0],tmp[4],tmp[5],tmp[6])

            printf("--- Sensor Channel %s input filter %s (readings = %d, window = %f)\n",reply[3],LS_ONOFF[reply[0]],reply[1],reply[2])

            ci++
        }
        line = getline(filename);
    }

    printf("Finished configuring sensors .. setting params ...\n")

    ci = 1

    line = getline(filename)

    # This line is the heater resistance

    while(substr(line,1,1) == "#"){
        line = getline(filename)
    }
    sscanf(line,"%f",res)
    _ls_set_resistance(loop,res)
    printf("--- Resistance set to %f Ohms\n",res)
    qcomment "_ls_load : Heater resistance set (R = %f ohms)" res

    line = getline(filename) ;
    while(substr(line,1,1) == "#"){
        line = getline(filename)
    }
    split(substr(line,1,length(line)-1),setp,",")
    LS_SETP_LIMITS[0] = setp[0];LS_SETP_LIMITS[1] = setp[1]
    T_LO_SP = setp[0];T_HI_SP = setp[1]
    printf("--- Temperature limits set (%f > T > %f)\n",LS_SETP_LIMITS[0],LS_SETP_LIMITS[1])
    qcomment "_ls_load : Temp limits set (LL = %f UL = %f)\n" LS_SETP_LIMITS[0],LS_SETP_LIMITS[1]

    line = getline(filename) ;
    while(substr(line,1,1) == "#"){
        line = getline(filename)
    }
    split(line,control,",")
    reply = _ls_set_control(loop,control[0],control[1],0)
    printf("--- Control sensor set to %s with units %s control is %s\n",reply[0],LS_UNITS[reply[1]],LS_ONOFF[reply[2]])
    qcomment "_ls_load : Control sensor set to %s (units = %s,%s)\n" reply[0],LS_UNITS[reply[1]],LS_ONOFF[reply[2]]

    line = getline(filename)
    printf("Finished configuring settings ... loading zonetable ...\n")
    printf("--- Zone No Config String\n")
    while(line != -1){
        if(substr(line,1,1) != "#"){
            if(substr(line,1,8) == "END_ZONE"){
                break
            }
            _ls_set_zone(loop,ci,substr(line,1,length(line)-1))
            printf("---      %2d %s",ci,line)
            qcomment "_ls_load : Zone %d config %s" ci,substr(line,1,length(line)-1)
            ci++
        }
        line = getline(filename)
    }

    for(cc=ci;cc<=10;cc++){
        # Blank the other zone lines
        _ls_set_zone(loop,cc,"0,0,0,0,0")
        qcomment "_ls_load : Zone %d set to zero" cc
    }

    printf("--- zone entries %d to 10 are set to blank values\n",ci)

    printf("Finished configuring zonetable .. Have a Nice Day ...\n")

    getline(filename,"close")
    qcomment "_ls_load : Finished sending zonetable\n"
    qcomment "_ls_load : Finished"

    return flag
}'

"""
#%IU%
#%MDESC%
# Syntax : _ls_set_resistance(loop,resistance)%BR%
# Set the resistance value for the heater in the control loop passed
# to the function. If sucsessful then "LSOK" is returned else
# "LSREADERROR" is returned.
"""
def _ls_set_resistance(loop,resistance) '{
    local rtn

    rtn = _ls_send("CDISP %d,,%f,2",loop,resistance)
    return rtn

}'

"""
#%IU%
#%MDESC%
#Syntax : _ls_sensorstatus(sensor)%BR%
#Read status of sensor%BR%
#%DL%
#%DD% BIT     Parameter
#%DD% 0       Invalid Reading
#%DD% 1       Old Reading
#%DD% 4       Underrange
#%DD% 5       Overrange
#%DD% 6       Units Zero
#%DD% 7       Units Overrange
#%XDL%
#
"""
def _ls_sensorstatus(sensor) '{
    local ans

    ans = _ls_read(sprintf("RDGST? %s",sensor))
    return ans
}'

"""
#%IU%
#%MDESC%
#Syntax : _ls_istuning()%BR%
#Functions returns 1 if the controller is tuning the PID parameters ans
#0 if not.
"""
def _ls_istuning() '{
    local ans

    ans = _ls_read("TUNEST?")
    return ans
}'

"""
#%IU%
#%MDESC%
#Syntax : _ls_issettled()%BR%
#Function returns 1 if the controller is in settle condition, 0 otherwise.
"""
def _ls_issettled() '{
    local ans

    ans = _ls_send("*STB?")
    if (ans && 4)
        return 1
    else
        return 0
}'

#%IU%
#%MDESC%
#Syntax : _ls_isalarm()%BR%
#Returns 1 if the controller is in alarm condition, 0 otherwise.
def _ls_isalarm() '{
    local ans

    ans = _ls_send("*STB?")
    if (ans && 8)
        return 1
    else
        return 0
}'

"""
#%UU%
#%MDESC%
# Syntax : lshelp
# Display Functions and their syntax
"""
def lshelp '{
  global LS_VERSION
  print "Help for LAKESHORE Macros", LS_VERSION
  print "lsontemp / lsofftemp      Switch on/off temperature logging"
  print "lsonreg / lsoffreg        Switch on/off temperature regulation."
  print "te [setpoint]             Set the cotrollers setpoint."
  print "lsshow                    Show all parameters for the controller."
  print "lsramp [rate]             Set the setpoint ramp rate."
  print "lsonramp / lsofframp      Switch on/off setpoint ramping."
  print "lsheater [range]          Set heater range (0 = off 5 = max)."
  print "lsmode [mode]             Set the control mode (2 = zone, 4 = auto)"
  print "lscontrol [sensor]        Change the control sensor to [sensor]."
  print "lscontrast [contrast]     Set the controllers display contrast."
  print "lslistallcurves           Reads and displays all calibration curves."
  print "lswritecurve [crv] [file] Writes curve to instrument from file."
}'

"""
#%UU%
#%MDESC%
# Syntax : lslistallcurves%BR%
# List out all the curves used in the controller. There are 60 possible curves (1 - 60).
"""
def lslistallcurves '{
  local i, crv, curve[], curve_name[], curve_units[], curve_coeff[], fmt

    curve_units[1] = "mV/K"
    curve_units[2] = "V/K"
    curve_units[3] = "Ohm/K"
    curve_units[4] = "log(Ohm)/K"
    curve_units[5] = "log(Ohm)/log(K)"

    curve_coeff[1] = "negative"
    curve_coeff[2] = "positive"

  fmt = "%2s %-15s %-10s %-10s %-10s %-10s\n"

  global LS_GPIB_ADDR
  if ($# != 0) {
    printf("Usage: lslistallcurves")
  } else {
    crv = 0
    while (crv < 61) {
#      tty_cntl("cl") # cant scroll back if clear screen!
      printf(fmt, "#", "Name", "Serial #", "Format", "Limit", "Coefficient")

      for(i = 1; i < 22 && crv < 61; crv++, i++) {
          local ans
          ans = _ls_read(sprintf("CRVHDR? %d",crv))
          if(ans == "LSREADERROR"){
              eprint "Error reading curve header", crv
              exit
          }

        if (split(ans, curve, ",") != 5) {
              eprint "Funny answer from controller at curve", crv "."
              exit
          }

        printf(fmt, crv, curve[0], curve[1], curve_units[curve[2]], \
          curve[3], curve_coeff[curve[4]])
      }
      if ( crv < 61 && !yesno("Continue", 1)) break
    }
    printf("\nPlease choose a number to use to load a curve into with the lswritecurve macro\n")
  }
}'

"""
#%UU%
#%MDESC%
# Syntax : lswritecurve [filename] [curvenumber]%BR%
# Reads one sensor calibration curve from harddisk and writes it into the
# lakeshore 340 model. Only curves 21 to 60 can be written by the user.
# %BR%
#%B%EXAMPLE:%B%%BR%
#%PRE%
#Sensor Model:   CX-1030-CU-1.4L
#Serial Number:  X12379
#Data Format:    4      (Log Ohms/Kelvin)
#SetPoint Limit: 325.      (Kelvin)
#Temperature coefficient:  1 (Negative)
#Number of Breakpoints:   144
# .....
#%PRE%
"""
def lswritecurve '{
    local i, j, ii, dummy, crv, fname
    local curve[], textline, field[], ans

    if ($# == 0) {
    print "Use macro lslistallcurves to get a list of already stored curves!"
        crv   = getval("Number of curve to be written?",21)
        fname = getval("Filename of temperature curve?","X12379.340")
    } else if ($# == 2) {
        crv = $2
        fname = "$1"
    } else {
    print "Please give two or no args"
    exit
  }
    if ( (crv < 21) || (crv > 60)) {
        eprint "Curve number out of range."
        eprint "Only curves 21 to 60 may be written by the user."
        exit
    }
    if (!file_info(fname)) {
        eprint "File: ",fname,"does not exist!"
        exit
    }

  # this reads the existing entry
  {
    local ans
      curve_units[1] = "mV/K"
      curve_units[2] = "V/K"
      curve_units[3] = "Ohm/K"
      curve_units[4] = "log(Ohm)/K"
      curve_units[5] = "log(Ohm)/log(K)"

      curve_coeff[1] = "negative"
      curve_coeff[2] = "positive"

    fmt = "%2s %-15s %-10s %-10s %-10s %-10s\n"

      print "Readings from actual curve", crv, "in LakeShore 340 :"
      ans = _ls_read(sprintf("CRVHDR? %d",crv))
      if(ans == "LSREADERROR"){
          eprint "Error reading curve header", crv
          exit
      }

    if (split(ans, curve, ",") != 5) {
          eprint "Funny answer from controller for curve", crv "."
          exit
      }

    printf(fmt, "", curve[0], curve[1], curve_units[curve[2]], \
      curve[3], curve_coeff[curve[4]])
  }

  # scan in the informations from the head of the .340 file.
  {
    local stype, sernum, dfmt, sp_lim, coeff, npts
    dfmt = sp_lim = coeff = npts = -1
      open(fname)
      i = 0
    textline = getline(fname, 0)
      while(1) {
      if (split(textline, field, ":") == 1)  break # no : stop!
      # treat contents here, is that a new yacc :-)
      if (field[0] == "Sensor Model")             sscanf(field[1], "%s", stype)
      if (field[0] == "Serial Number")            sscanf(field[1], "%s", sernum)
      if (field[0] == "Data Format")              sscanf(field[1], "%d", dfmt)
      if (field[0] == "SetPoint Limit")           sscanf(field[1], "%f", sp_lim)
      if (field[0] == "Temperature coefficient")  sscanf(field[1], "%d", coeff)
      if (field[0] == "Number of Breakpoints")    sscanf(field[1], "%d", npts)
      textline = getline(fname)
    }

    # Some input checking on Rudolfs request
    if (stype == "") {
      eprint "Data file", fname, "does not have expected line for \"Sensor Model\"!"
      eprint "Aborted !"
      exit
    } else if (sernum == "") {
      eprint "Data file", fname, "does not have expected line for \"Serial Number\"!"
      eprint "Aborted !"
      exit
    } else if (dfmt == -1) {
      eprint "Data file", fname, "does not have expected line for \"Data Format\"!"
      eprint "Aborted !"
      exit
    } else if (sp_lim == -1) {
      eprint "Data file", fname, "does not have expected line for \"SetPoint Limit\"!"
      eprint "Aborted !"
      exit
    } else if (coeff == -1) {
      eprint "Data file", fname, "does not have expected line for \"Temperature coefficient\"!"
      eprint "Aborted !"
      exit
    }

    dummy = sprintf("CRVHDR %d,%s,%s,%d,%f,%d\r\n", crv, stype,\
      sernum, dfmt, sp_lim, coeff)
      ans = _ls_send(dummy)
      if(ans != "LSOK"){
          eprint "Error listing curve number ", crv "."
          exit
      }
  }
"""
  # Well now, to enable for Rudolf to add a header to a simple 2-column file, we have
  # to juggle with sscanf.
"""
  {
    local loop, ii, valunits, val_temp
    loop = 1 # index of point, valid entries 1 - 200
      while((textline = getline(fname)) != -1) {
      if (sscanf(textline, "%d %g %g", ii, valunits, val_temp) == 3) {
        if (ii == 0 && valunits == 0 && val_temp == 0)
          continue
      } else if (sscanf(textline, "%g %g", valunits, val_temp) == 2) {
        if (valunits == 0 && val_temp == 0)
          continue
      } else {
        continue # thats probably a text line. just forget
      }

        dummy = sprintf("CRVPT %d,%d,%6g,%6g\r\n", crv, loop, valunits, val_temp)
        ans = _ls_send(dummy)
        if(ans != "LSOK"){
            eprint "Error listing curve number ", crv "."
            exit
        }
      printf(".")
      loop ++
    }
    print
  }

    close(fname)

  print
    print "Curve", crv, "was written to the LakeShore model 340 temperature controller."; print

  # this reads the new entry
  {
    local ans
      curve_units[1] = "mV/K"
      curve_units[2] = "V/K"
      curve_units[3] = "Ohm/K"
      curve_units[4] = "log(Ohm)/K"
      curve_units[5] = "log(Ohm)/log(K)"

      curve_coeff[1] = "negative"
      curve_coeff[2] = "positive"

    fmt = "%2s %-15s %-10s %-10s %-10s %-10s\n"

      print "Readings from actual curve", crv, " in LakeShore 340 :"
      ans = _ls_read(sprintf("CRVHDR? %d",crv))
      if(ans == "LSREADERROR"){
          eprint "Error reading curve header", crv
          exit
      }

    if (split(ans, curve, ",") != 5) {
          eprint "Funny answer from controller for curve", crv "."
          exit
      }

    printf(fmt, "", curve[0], curve[1], curve_units[curve[2]], \
      curve[3], curve_coeff[curve[4]])
  }

    print "Warning: The curve was not saved to the flash memory of the LakeShore 340."

  if (yesno("Do you want to save it ", 1)) {
        ans = _ls_send("CRVSAV")
        if(ans != "LSOK"){
            eprint "Error saving curve number ", crv "."
            exit
        } else {
        eprint "Saved curve number ", crv "."
      }
  } else {
    print "Curve", crv, "is not saved yet!!!"; print
      print "To do so execute the command: _ls_send(\"CRVSAV\")"
      print "This will save all changes you made to curves since the controller was switched on."
      print "Otherwise all changes will be lost after it is switched off."
  }

    print "To do so execute the command: _ls_send(\"CRVSAV\")"
    print "This will save all changes you made to curves since the controller was switched on."
    print "Otherwise all changes will be lost after it is switched off."
  print

    print "To make sure the curve was written correctly check it on the front panel"
}'

"""
#%UU%
#%MDESC% activate loop 2
"""
def  lsloop2on '{
    local cmd, ret, fnId
    
    fnId="lsloop2on"

    cmd = "ANALOG 0,3"
    ret = _ls_send(cmd)
    if(ret == "LSREADERROR") {
        printf("%s: ERROR sending gpib cmd\n", fnId)
    
    } else {
    
        printf("switched loop 2 heater ON\n")
    }

}'

"""
#%UU%
#%MDESC% de-activate loop 2
"""
def lsloop2off '{
    local cmd, ret, fnId
    
    fnId="lsloop2off"

    cmd = "ANALOG 0,0"
    ret = _ls_send(cmd)
    if(ret == "LSREADERROR") {
        printf("%s: ERROR sending gpib cmd\n", fnId)
    
    } else {
    
        printf("switched loop 2 heater OFF\n")
    }

}'



"""
#%MACROS%
#%IMACROS%
#%DEPENDENCIES%
#STANDARD.MAC
#%AUTHOR%
#Stuart B. Wilkins, ID20%BR%
# Holger Witsch, BLISS (for curve listing & programming)%BR%
#%BR%
#$Date: 2017/01/31 15:05:19 $%BR%
#$Revision: 2.17 $%BR%
#$Id: lakeshore340.mac,v 2.17 2017/01/31 15:05:19 domingue Exp $#$State: Exp $
#%BUGS%
#Yes, I am sure there are bugs. Please report them!
#%TOC%
"""