esrf

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


#%TITLE% LAKESHORE.MAC
#%NAME%
#   Temperature control macros for the LakeShore model 336 (ID12)
#%CATEGORY% Temperature
#%DESCRIPTION%
# This macroset contains macros to control and read the temperature from the
# Lakeshore 336 controller. The macroset has two 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.
# Macros, present in lakeshore340.mac, provided to enable auto configuration
# from a datafile for standard parameters which are specific to the type of 
# cryostat in use, are not present here beacause ID12 do not need them and
# this functionnality is slightly different in the model 336 than in the
# model 340 and need to be entirely redone %BR%
#%BR%
#Getting Started%BR%
#%BR%
# To start logging the temperature from within Spec the command %B%ls336_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%ls336_offtemp%B% will stop the logging of the temperature.
# The cpmmand %B%ls336_setup%B% should be called at a first stage as it defined global parameters
# for the lakeshore 336
# The command %B%ls336_spec_setup%B% should be run (usually from the setup macro 
# of spec) for temperature counters to pair the lakeshore sensor to a spec counter mnemonics.
# Please note that %B%ls336_spec_setup%B% also sets various global parameters so should
# be run at startup.%BR%
#%BR%
# To show all relevant parameters for the controller the command %B%ls336_show%B% can
# can be used, while %B%ls336_showtemp%B% displays all configured sensor temperature. 
# Setpoint ramping is enabled through the command
# %B%ls336_onramp%B% and disabled with %B%ls336_offramp%B%. The rate of ramping can be changed
# through the command %B%ls336_ramp%B%.%BR% 
# %BR%
#%INTERNALS%
#Currently in this implementation GPIB is used to communicate with the
# instrument. However, all comms are done through two functions %B%_ls336_send%B% and
# %B%_ls336_read%B% and is is possible, therefore, to overload these to allow 
# communication with a non-gpib interface, eg. a device server.%BR%
# %BR%

##################################################################################################
# Yes, I am sure there are bugs. Please report them!
##################################################################################################
# 2014-06-14 - Anthony Mauro
#    lls336range did not display the right setting values. It is fixed. 
# 2014-06-24 - Anthony Mauro
#    sommetimes ls336setpoint do not displayed the last set value but the one before
#    Solution: Add *OPC at the end of the command for _ls336_send.  
# 2016/04/05 - rh
#   included the nr of heaters in the setup
#   fixed the loop (from 1 in the equipment and from 0 in the macro)
#   included the preferred unit to correct the temp print
#   included the celsius reading
##################################################################################################


global TEMP_SP
global LS_TUNETEXT,LS_UNITS
global LS_LOOP
global LS_CONFIG_FILENAME, LS_CONFIG_NAME, LS_CONFIG_REVISION
global LS_SETP_LIMITS

##################################################################################################
##################################################################################################
##########                                                                              ##########
##########                          Setup Lakeshore 336 macros                          ##########
##########                                                                              ##########
##################################################################################################
##################################################################################################
#%UU%
#%MDESC%
# Syntax : ls336_setup.%BR%
# Set the global variables for Lakeshore336
def ls336_setup '{
    global LS336_PAR[]
    global LS336_SENSOR[]


    if ($# != 1) {
        printf("Usage: ls336_setup <nr of heathers>")
    } else {
        LS336_PAR["heater"]["nb"] = $1 
        LS336_PAR["version"]      = "$Id: lakeshore336.mac,v 1.4 2016/04/05 14:22:52 homsrego Exp $"
    }
}'

##################################################################################################
##################################################################################################
#%UU%
#%MDESC%
# Syntax : ls336_gpib_setup <GPIB unit> <GPIB number>.%BR%
# Set the global variables used for all gpib access: LS336_PAR["comm_mode"] and LS336_PAR["addr"]
def ls336_gpib_setup '{ 
    local gpib_unit gpib_addr
     
    if ($# != 2) {
        printf("Usage: ls336_gpib_setup <Spec GPIB unit range [0-3]> <Instrument GPIB number>")
    } else {
        gpib_unit = $1 ; gpib_addr = $2
        LS336_PAR["addr"] = sprintf("%1d:%1d",gpib_unit,gpib_addr)
        LS336_PAR["comm_mode"] = "GPIB"
    }
}'

##################################################################################################
##################################################################################################
#%UU%
#%MDESC%
# Syntax : ls336_socket_setup <host> <port>.%BR%
# Set the global variables used for all socket access: LS336_PAR["comm_mode"] and LS336_PAR["addr"]
def ls336_socket_setup '{
    if ($# != 2) {
        printf("Usage: ls336_socket_setup <hostname> <port>")
    } else {
        LS336_PAR["addr"] = sprintf("%s:%s","$1","$2")
        LS336_PAR["comm_mode"] = "SOCKET"
    }
}'


##################################################################################################
##################################################################################################
#%UU%
#%MDESC%
#Syntax : ls336_spec_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.

def ls336_spec_setup '{
	global LS_TUNETEXT
	global LS_ONOFF	
	global LS_UNITS
	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"

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

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

	LS336_PAR["cnt_nb"] = $1

	if(npar != ((LS336_PAR["cnt_nb"] * 2) +1)) {
		printf("Incorrect number of parameters for %d sensors\n", $1)
		printf("Usage: ls336_spec_setup <numsensors> [<spec counter> <lakeshore sensor> ...]\n")
        exit
	}

	for(ci=0;ci<LS336_PAR["cnt_nb"];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
		}
        LS336_SENSOR[ci]["counter"] = apar[(ci * 2) + 1]
		LS336_SENSOR[ci]["channel"] = apar[(ci * 2) + 2]
		LS336_SENSOR[ci]["value"]   = -1
	}

    	if (!LS_SILENT) {
		printf("---- Lakeshore 336 macroset : G. Berruyer 2013\n")
		printf("---- Version %s\n",LS336_PAR["version"])
		printf("---- Lakeshore spec setup complete with %d counters configured\n", LS336_PAR["cnt_nb"])
        }
}'

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


##################################################################################################
##################################################################################################
#%IU%
#%MDESC%
# Syntax : _ls336_get_ident()%BR%
# Internal function which gets the lakeshore identification string from
# the instrument and returns it.

def _ls336_get_ident() '{
	local ans
    
	ans = _ls336_read("*IDN?")
	return ans
}'

##################################################################################################
##################################################################################################
##########                                                                              ##########
##########                      Input/Output command to lakeshore                      ##########
##########                                                                              ##########
##################################################################################################
##################################################################################################

#%IU%
#%MDESC%
#Syntax : _ls336_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 _ls336_send(command) '{
	local numsent
	local reply
    local opc

    opc=" *OPC"
    command = command opc

	if(LS336_PAR["comm_mode"] == "GPIB"){
		numsent = gpib_put(LS336_PAR["addr"],command)
		if(numsent == 0) {
			return "LSREADERROR"
        } else {
			return "LSOK"
        }
	}

	if(LS336_PAR["comm_mode"] == "SOCKET"){
		reply = _ls336_read(command)
		if(reply != "LSREADERROR") {
			return "LSOK"
        } else {
			return "LSREADERROR"
        }
	}
}'
	
##################################################################################################
##################################################################################################
#%IU%
#%MDESC%
# Syntax : _ls336_read(command)%BR%
# Internal function to send a command string to the lakeshore and get the 
# reply.
def _ls336_read(command) '{
	local ans numsent tosend

	ans = "LSREADERROR"

	if (LS336_PAR["comm_mode"] == "GPIB") {		
        numsent = gpib_put(LS336_PAR["addr"], command)
        if (numsent > 0) {
            ans = gpib_get(LS336_PAR["addr"])
            if (ans == "") {	
				ans = "LSREADERROR"
            }
        } else {
            p "_ls336_read() : Error writing to GPIB"
            ans = "LSREADERROR"
        }
    }    

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

	return ans
}'


##################################################################################################
##################################################################################################
##########                                                                              ##########
##########                              Allow SPEC reading                              ##########
##########                                                                              ##########
##################################################################################################
##################################################################################################


#%UU%
#%MDESC%
# Syntax : ls336on%BR%
# Switch temperature logging on. Spec will read the temperature at each
# count and load sensor 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 ls336on '{
	global LS_SETP_LIMITS

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

	cdef("user_getcounts","_ls336_set_cnt\n","_LS336")
}'


##################################################################################################
##################################################################################################
#%UU%
#%MDESC%
# Syntax : ls336off%BR%
# Switch temperature logging off. See %B%ontemp%B%

def ls336off '{
  local ci

  cdef("","","_LS336","delete")
  for(ci=0;ci<LS336_PAR["cnt_nb"];ci++){
        counter = cnt_num(LS336_SENSOR[ci]["counter"])
        if(counter != -1){
            S[cnt_num(LS336_SENSOR[ci]["counter"])] = -1
        }
  }
}'

##################################################################################################
##################################################################################################
##########                                                                              ##########
##########                         Lakeshore parameters display                         ##########
##########                                                                              ##########
##################################################################################################
##################################################################################################

#%UU%
#%MDESC%
# Syntax : ls336show%BR%
# Display all main parameters and values for the temperature controller
def ls336show '{
    print date()
    print LS336_PAR["version"]
    ls336_ident
#    ls336_pid
    ls336pid
#    ls336_heater
    ls336_showtemp
}'


##################################################################################################
##################################################################################################
#%UU%
#%MDESC%
# Syntax : ls336_showtemp%BR%
# Read and display all sensors defined by the %B%ls336_spec_setup%B% macro
# and the setpoint temperature this macro also shows the current 
# setpoint ramprate if ramping is active

def ls336_showtemp '{
    local ci temperatureC temperature ramprate isramping setpoint loop ch unit

    printf("\n")
    for (ci=0 ; ci<LS336_PAR["cnt_nb"] ; ci++){
        temperature = _ls336_readsensor_k(LS336_SENSOR[ci]["channel"])
        temperatureC = _ls336_readsensor_c(LS336_SENSOR[ci]["channel"])
        printf("%12s : Sensor(%s) = %7.3f K (%7.3f C)\n",LS336_SENSOR[ci]["counter"], \
                                               LS336_SENSOR_[ci]["channel"], temperature, temperatureC)
    }

    printf("\n")
    for (ci=0 ; ci<LS336_PAR["heater"]["nb"] ; ci++) {
        loop = ci +1
        ramprate  =_ls336_read_ramprate(ci)
        setpoint  =_ls336_read_setpoint(loop)
        isramping =_ls336_ramp_state(ci)


	unit = _ls336_read_preferred_unit_loop(loop)
        if(isramping==1) {
            printf("Setpoint for heater %d = %7.3f %s (ramp at %7.3f m^-1 ACTIVE)\n", loop, setpoint,\
                                                unit, ramprate)
        } else {
            printf("Setpoint for heater %d = %7.3f %s (ramp at %7.3f m^-1)\n",loop, setpoint,unit, ramprate)
        }
    }
}'






##################################################################################################
##################################################################################################
##########                                                                              ##########
##########                                Sensor Reading                                ##########
##########                                                                              ##########
##################################################################################################
##################################################################################################


#%IU%
#%MDESC%
# Syntax : _ls336_set_cnt()%BR%
# Read temperature and set the corresponding pseudo counters. 

def _ls336_set_cnt '{
    local ci lscnt
    local counter

    _ls336_readtemp()
    
    for (ci=0 ; ci<LS336_PAR["cnt_nb"] ; ci++){
        lscnt = cnt_num(LS336_SENSOR[ci]["counter"])
        if(lscnt != -1){
            S[lscnt] = LS336_SENSOR[ci]["value"]
        }
    }
}'


##################################################################################################
##################################################################################################
#%IU%
#%MDESC%
# Syntax : _ls336_readtemp()%BR%
# Internal function which reads all temperature and sensor values defined by 
# %B%ls336_spec_setup%B% and stores them in the internal global variables. 

def _ls336_readtemp() '{
    local ci
	
    for(ci=0 ; ci<LS336_PAR["cnt_nb"] ; ci++){
        LS336_SENSOR[ci]["value"] = _ls336_readsensor_k(LS336_SENSOR[ci]["channel"])
        if (LS336_SENSOR[ci]["value"] == "LSREADERROR"){
            LS336_SENSOR[ci]["value"] = -1
        }
    }
}'


##################################################################################################
##################################################################################################
#%IU%
#%MDESC%
# Syntax : _ls336_readsensor_k(sensor)%BR%
# Reads and returns sensor reading in kelvin.
# Returns -2 if there is an error condition on the sensor.

def _ls336_readsensor_k(sensor) '{
	local ans

	ans = _ls336_read(sprintf("KRDG? %s",sensor))

	return ans
}'

def _ls336_readsensor_c(sensor) '{
	local ans

	ans = _ls336_read(sprintf("CRDG? %s",sensor))

	return ans
}'

##################################################################################################
##################################################################################################
#%IU%
#%MDESC%
# Syntax : _ls336_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 _ls336_readsensor_o(sensor) '{
	local ans

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


##################################################################################################
##################################################################################################
#%IU%
#%MDESC%
#Syntax : _ls336_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 _ls336_sensorstatus(sensor) '{
	local ans

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

##################################################################################################
##################################################################################################
##########                                                                              ##########
##########      LA                            Set Point                                 ##########
##########                                                                              ##########
##################################################################################################
##################################################################################################


#%IU%
#%MDESC%
# Syntax ls336setpoint [<heater 1-4> <newval>] [<heater 1-4> <newval> .... ] %BR%
# Change setpoint value. 

def ls336setpoint '{
    local nbout nrtok tabval[] msg setpoint iout _loop idx unit

    
    if (($# != 0) && ($# % 2 != 0)) {
        p "Usage: ls336setpoint [<heater number (from 1)> <newval>] [[heater number (from 1)] ...]"
        exit
    }
    
    if ($# == 0) {
        # Display all heater setpoint
        # iout (loop) is from 1!!!!
        for (_loop=1 ; _loop<=LS336_PAR["heater"]["nb"] ; _loop++) {
            setpoint = _ls336_read_setpoint(_loop)
            unit =  _ls336_read_preferred_unit_loop(_loop)
            printf("Heater %d setpoint: %g %s\n", _loop, setpoint, unit)
        }
    } else {
        nrtok = split("$*", tabval)
        nbout = nrtok / 2
    
        for (idx=0 ; idx<nbout ; idx++) {
            if ((tabval[2*idx] < 1) || (tabval[2*idx] > 4)) {
                printf("Wrong heater index (%d), should be between 1 and 4, skip...\n", tabval[2*idx])
            } else {
		_loop = tabval[2*idx]
                setpoint = _ls336_set_setpoint(_loop, tabval[2*idx+1])
                unit =  _ls336_read_preferred_unit_loop(_loop)
                if (setpoint == "LSREADERROR"){
                    printf("Error reading setpoint for heater %d\n", _loop)
                } else {
                    printf("Setpoint set to %g %s on heater %d", setpoint,unit, _loop)
                }
            }
        }
    }
}'


##################################################################################################
##################################################################################################
#%IU%
#%MDESC%
# Syntax : _ls336_read_setpoint(loop)%BR%
# Set and read setpoint for given control loop.

def _ls336_read_setpoint(loop) '{
	local rtn
	
        # the loop is from 1!!!!!!!!!
	rtn = _ls336_read(sprintf("SETP? %d",loop))
	return rtn
}'


##################################################################################################
##################################################################################################
def _ls336_read_preferred_unit_loop(_loop) '{
	return _ls336_read_preferred_unit(sprintf("%c", 0x40 + loop))

}'


def _ls336_read_preferred_unit(_sensor) '{

	local rtn nrTok tok[] unit
	
        # the loop is from 1!!!!!!!!!
	rtn = _ls336_read(sprintf("INTYPE? %s",_sensor))

	nrTok = split(rtn, tok, ",")
	if(nrTok != 5) {
		print "FATAL ERROR"
		print nrTok
		print rtn	
	}

	unit = LS_UNITS[ tok[4] ]

	return unit


}'

##################################################################################################
##################################################################################################
#%IU%
#%MDESC%
# Syntax : _ls336_set_setpoint(loop,sp)%BR%
# Set and read setpoint for given control loop.

def _ls336_set_setpoint(loop,sp) '{
	local rtn,ans
	ans = _ls336_send(sprintf("SETP %d,%f",loop,sp))
	if(ans == "LSREADERROR") # error corrected missing quote: HW 04/10/12
		return "LSREADERROR"
	
    #sleep(0.1)  # added and commented. Solved with *OPC in _ls336_send. AM
    rtn = _ls336_read_setpoint(loop)
	return rtn
}'



##################################################################################################
##################################################################################################
##########                                                                              ##########
##########                                  Ramp Rate                                   ##########
##########                                                                              ##########
##################################################################################################
##################################################################################################


#%UU%
#%MDESC%
# Syntax : ls336ramprate [<heater 1-4> <rate 0.1-10>] [<heater 1-4> <rate 0.1-10>] ...%BR%
# Set the value of the setpoint ramp rate in (K/mn) for heater <heater>. 
# If no parameter is passed all heater setpoint ramp rate are displayed.

def ls336ramprate '{
    local iout ramp str nbout tabval[]

    if (($# != 0) && ($#/2 != int($#/2))) {
        p "Usage:  ls336ramprate [<heater 1-4> <rate 0.1-10>] [<heater 1-4> <rate 0.1-10>] ..."
        exit
    }
    
	if ($# == 0){
		# Display all
        for (iout=1; iout<=LS336_PAR["heater"]["nb"] ; iout++) {
		    ramp = _ls336_read_ramprate(iout)
            if(ramp == "LSREADERROR"){
                printf("Error reading ramp rate for heater %d.\n", iout)
            } else {
                printf("Ramp rate is %gK.min^-1 on heater %d",ramp,iout)
            }
        }
	} else {
        nbout = split("$*", tabval)
        nbout = nbout / 2

        for (iout=0 ; iout<nbout ; iout++) {
            if ((tabval[2*iout] < 1) || (tabval[2*iout] > 4)) {
                printf("Wrong heater index (%d), should be between 1 and 4, skip...\n", tabval[2*iout])
            } else {
                if ((tabval[2*iout+1] < 0.1) || (tabval[2*iout] > 10)) {
                    printf("Wrong Ramprate (%g) for heater (%d), should be between 0.1 and 10, skip...\n", \
                                tabval[2*iout+1], tabval[2*iout])
                } else {
                    ramp = _ls336_set_ramprate(tabval[2*iout], tabval[2*iout+1])
                    if(ramp == "LSREADERROR"){
                        printf("Error reading ramp rate for heater %d\n", tabval[2*iout])
                    } else {
                        comment "Ramp rate set to %gK.min^-1 on heater %d" ramp,tabval[2*iout]
                    }
                }
            }
        }
    }           	
}'
	

##################################################################################################
##################################################################################################
#%IU%
#%MDESC%
# Syntax : _ls336_set_ramprate(heater, ramprate)%BR%
# Sets controllers ramprate, returns controllers ramprate.

def _ls336_set_ramprate(heater, ramprate)'{
	local ans rtn

	ans = _ls336_send(sprintf("RAMP %d,0,%f", heater, ramprate))
	if (ans == "LSREADERROR")
		return "LSREADERROR"

	rtn = _ls336_read_ramprate(lsoutput)
	return rtn
}'


##################################################################################################
##################################################################################################
#%IU%
#%MDESC%
# Syntax : _ls336_read_ramprate(lsoutput)%BR%
# Reads and returns controllers ramprate.

def _ls336_read_ramprate(heater) '{
	local ans tmp[] rtn

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

##################################################################################################
##################################################################################################
##########                                                                              ##########
##########                            Start/Stop Ramping                                ##########
##########                                                                              ##########
##################################################################################################
##################################################################################################


#%UU%
#%MDESC%
# Syntax : ls336onramp <heater> [<heater> heater> ...]%BR%
# Switch on temperature ramping. The rate must be set using the %B%ls336_ramprate%B%
# macro.

def ls336onramp '{
    local ans heater nbout tabval[] iout

    if ($# == 0) {
        p "Usage: ls336onramp <heater> [<heater> heater> ...]"
        exit
    }

    nbout = split("$*", tabval)

    for (iout=0 ; iout<nbout ; iout++) {
        if ((tabval[iout] < 1) || (tabval[iout] > 4)) {
            printf("Wrong heater index (%d), should be between 1 and 4, skip...\n", tabval[iout])
        } else {
            ans = _ls336_set_ramp(tabval[iout], 1)
            if (ans == "LSREADERROR"){
                printf("Error starting ramp for heater %d\n", tabval[iout])
            } else {
                ans = _ls336_read_ramprate(tabval[iout])
                comment "Temperature ramping enabled (%f K.min^-1) for heater %d" ans,tabval[iout]
            }
        }
    }    
}'


##################################################################################################
##################################################################################################
#%UU%
#%MDESC%
# Syntax : ls336offramp <heater> [<heater> heater> ...]%BR%
# Switch off temperature ramping

def ls336offramp '{
    local ans heater nbout tabval[] iout

    if ($# == 0) {
        p "Usage: ls336offramp <heater> [<heater> heater> ...]"
        exit
    }

    nbout = split("$*", tabval)

    for (iout=0 ; iout<nbout ; iout++) {
        if ((tabval[iout] < 1) || (tabval[iout] > 4)) {
            printf("Wrong heater index (%d), should be between 1 and 4, skip...\n", tabval[iout])
        } else {
            ans = _ls336_set_ramp(tabval[iout], 0)
            if (ans == "LSREADERROR"){
                printf("Error stoping ramp for heater %d\n", tabval[iout])
            } else {
                comment "Temperature ramping stopped for heater %d" ans,tabval[iout]
            }
        }
    }    
}'


##################################################################################################
##################################################################################################
#%IU%
#%MDESC%
# Syntax : _ls336_set_ramp(heater,state)%BR%
# Switches on or off temperature ramping (off = 0, on = 1)

def _ls336_set_ramp(heater, state) '{
	local ans rtn ramprate
	
    ramprate = _ls336_read_ramprate(heater)
	ans = _ls336_send(sprintf("RAMP %d,%d,%f",heater, state, ramprate))
	if(ans=="LSREADERROR")
		return "LSREADERROR"

	rtn = _ls336_read_ramp(heater)
	return rtn
}'
	

##################################################################################################
##################################################################################################
#%IU%
#%MDESC%
# Syntax : _ls336_read_ramp(heater)%BR%
# Reads and returns controllers ramp setting (off = 0, on = 1)

def _ls336_read_ramp(heater) '{
	local ans ramp[] rtn

	ans = _ls336_read(sprintf("RAMPST? %d",heater))
	if(ans=="LSREADERROR")
		return "LSREADERROR"
	split(ans,ramp,",")
	rtn = ramp[0]

	return rtn
}'


##################################################################################################
##################################################################################################
#%IU%
#%MDESC%
# Syntax : _ls336_ramp_state(heater)%BR%
# Reads and returns status of setpoint ramping (ramping = 1, not ramping = 0)

def _ls336_ramp_state(heater) '{
	local ans ramp

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

##################################################################################################
##################################################################################################
##########                                                                              ##########
##########                                Heater type                                   ##########
##########                                                                              ##########
##################################################################################################
##################################################################################################


#
#%UU%
#%MDESC%
# Syntax : ls336range [<heater 1-4> <range 0-3>] [<heater 1-4> <range 0-3>] ...%BR%
# Shows/allows to change the range 0=off 1=low 2=medium 3=high. 
# If no parameter is given the current range is displayed
# range 0 means heater off

def ls336range '{
    local nbout tabval[] msg range iout

    
    if (($# != 0) && ($#/2 != int($#/2))) {
        p "Usage: ls336range [<heater 1-4> <range 0-3>] [<heater 1-4> <range 0-3>] ..."
        exit
    }
    
    if ($# == 0) {
        # Display all heater type
        for (iout=1 ; iout<=LS336_PAR["heater"]["nb"] ; iout++) {
            range = _ls336_read_range(iout)
            printf("Heater %d set on range %d\n", iout, range)
        }
    } else {
        nbout = split("$*", tabval)
        nbout = nbout / 2
    
        for (iout=0 ; iout<nbout ; iout++) {
            if ((tabval[2*iout] < 1) || (tabval[2*iout] > 4)) {
                printf("Wrong heater index (%d), should be between 1 and 4, skip...\n", tabval[2*iout])
            } else {
                if ((tabval[2*iout+1] < 0) || (tabval[2*iout] > 3)) {
                    printf("Wrong range (%d) for heater (%d), should be between 0 and 3, skip...\n", \
                                tabval[2*iout+1], tabval[2*iout])
                } else {
                    range = _ls336_set_range(tabval[2*iout], tabval[2*iout+1])
                    if (range == "LSREADERROR"){
                        printf("Error reading range for heater %d\n", tabval[2*iout])
                    } else {
                        comment "Range set to %d for heater %d" range,tabval[2*iout]
                    }
                }
            }
        }
    }
}'


##################################################################################################
##################################################################################################
#%IU%
#%MDESC%
# Syntax : _ls336_set_range(heater, range)%BR%
# Set and return heater range (0 to 3, 0 = heater off).

def _ls336_set_range(heater, range) '{
	local rtn

	rtn = _ls336_send(sprintf("RANGE %d,%d",heater, range))
	if (rtn == "LSREADERROR")
		return "LSREADERROR"
    
	rtn = _ls336_read_range(heater)
	return rtn
}'


##################################################################################################
##################################################################################################
#%IU%
#%MDESC%
# Syntax : _ls336_read_range%BR%
# Read and return heater range (0 to 3, 0 = heater off).

def _ls336_read_range(heater) '{
	local rtn 
    
	rtn = _ls336_read(sprintf("RANGE? %d", heater))
	return rtn
}'

##################################################################################################
##################################################################################################
##########                                                                              ##########
##########                                    PID                                       ##########
##########                                                                              ##########
##################################################################################################
##################################################################################################


#%UU%
#%MDESC%
# Syntax : ls336pid [<heater> <p> <i> <d>] [<heater> <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 ls336pid '{
    local nbout tabval[] msg reply iout auxtab[]

    
    if (($# != 0) && ($#/4 != int($#/4))) {
        p "Usage: ls336pid [<heater> <p> <i> <d>] [<heater> <p> <i> <d>] ..."
        exit
    }

	if ($# == 0) {
		# display PIDs
        for (iout=1 ; iout<=LS336_PAR["heater"]["nb"] ; iout++) {
		    reply = _ls336_read_pid(iout)
		    if (reply[0] == "LSREADERROR"){
			    printf("Error Reading PID parameters for heater %d\n", iout)
            } else {
                printf("Heater %d: P=%g I=%g D=%g\n", iout, reply[0], reply[1], reply[2])
            }
        }
    } else {
        nbout = split("$*", tabval)
        nbout = nbout / 4
    
        for (iout=0 ; iout<nbout ; iout++) {
            if ((tabval[2*iout] < 1) || (tabval[2*iout] > 4)) {
                printf("Wrong heater index (%d), should be between 1 and 4, skip...\n", tabval[2*iout])
            } else {
                auxtab[0] = tabval[2*iout+1]
                auxtab[1] = tabval[2*iout+2]
                auxtab[2] = tabval[2*iout+3]
                reply = _ls336_set_pid(tabval[2*iout], auxtab)
                if (reply == "LSREADERROR"){
                    printf("Error setting PID\'s for heater %d\n", tabval[2*iout])
                } else {
                    comment "Set heater %d PID: P=%g I=%g D=%g" tabval[2*iout],reply[0],reply[1],reply[2]
                }
            }
        }
    }
}'


##################################################################################################
##################################################################################################
#%IU%
#%MDESC%
# Syntax : _ls336_set_pid(heater, pid)%BR%
# Set pid parameters, returns the controller read pid's as an array.

def _ls336_set_pid(heater,pid) '{
	local ans rtn
		
	ans = _ls336_send(sprintf("PID %d,%5.1f,%5.1f,%5.1f", heater, pid[0], pid[1], pid[2]))
	
	if(ans == "LSREADERROR")
		return "LSREADERROR"

	rtn = _ls336_read_pid(heater)
	return rtn
}'


##################################################################################################
##################################################################################################
#%IU%
#%MDESC%
# Syntax : _ls336_read_pid(heater, pid)%BR%
# Read controller PID values, returns values as an array.

def _ls336_read_pid(heater, pid) '{
	local ans newpid[]
	
	ans =_ls336_read(sprintf("PID? %d",heater))
    
	if ( ans == "LSREADERROR")
        return "LSREADERROR"
    
    split(ans,newpid,",")

	return newpid
}'


##################################################################################################
##################################################################################################
#%MACROS%
#%IMACROS%
#%DEPENDENCIES%
#%AUTHOR%
#G. Berruyer, BCU%BR%
#%BR%
#$Date: 2016/04/05 14:22:52 $%BR%
#$Revision: 1.4 $%BR%
#$State: Exp $
#%BUGS%
#Yes, I am sure there are bugs. Please report them!
#2014-06-14: lls336range did not display the right setting values. It is fixed. Anthony Mauro.
#2014-06-24: sommetimes ls336setpoint do not displayed the last set value but the one before
#Solution: Add *OPC at the end of the command for _ls336_send. Anthony Mauro. 
#%TOC%