esrf

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

#%TITLE% TEMPERATURE.MAC
#$Revision: 1.46 $
#%NAME% Macros for general temperature control.
#%DESCRIPTION%
# Those macros provide users with a common interface between SPEC and different type of temperature controllers. %BR%The temperature setpoint is driven as a (pseudo) motor, and other controller specific parameters can be set as (pseudo) counters.  
#%OVERVIEW%
# Every standard %B%ct%B% / %B%mv%B% / and %B%scan%B% commands apply, plus the following ones defined by this set of macros :%BR%%BR%
#%DL% 
#%DT% tcon / tcoff: %DD%enabling / disabling temperature controller devices one by one. 
#%DT% rt: %DD%reports about all set up temperature controllers.
#%DT% tcramp: %DD%initiates a ramp into the controller. 
#%DT% tclim: %DD%set temperature hardware limits.
#%DT% temperature_control: %DD%Setup command. see SETUP below.
#%DT% user_tc_io_1:%DD%User input for an action to be inserted just before addressing the hardware. 
#%DT% user_tc_io_2:%DD%User input for an action to be inserted just after the device command is sent. 
#%DT% user_tc_io_3:%DD% User input for an action to be inserted just after the device response is read. 
#%XDL%
#%SETUP%
#%DL%
#%DT% temperature_control (name,type,interface,address,sleept,channel,setuppars):
#%DD% It is the setup function for temperature controllers, that will associate each temperature setpoint to a motor. Basically, this function is called from setup file (one call per setpoint), and commented / uncommented along the user needs. After this command is executed for the first time, the device is by default enabled, unless it is unresponsive.  
#%DL% Input parameters description:
#%DT% name: %DD%generic name for one temperature controller device, also used as motor mnemonic, to be put into SPEC config, controller NONE (pseudo motor), for controlling the setpoint. T_<name> can be set as a pseudo counter mnemonic to report the controlled temperature value in a counter as well. 
#%DT% type: %DD%Supported controller types are "%B%ILL%B%","%B%OX%B%","%B%HCC%B%", "%B%F700%B%", "%B%F26%B%", "%B%OXISO%B%","%B%ST15%B%", "%B%ST9700%B%", "%B%EURO%B%","%B%EURO900%B%","%B%LTC20%B%", "%B%LS200%B%", "%B%LS300%B%" and "%B%SIM%B%". (more details later in the document (%{%<A HREF="#Specific"><B>"Devices Specific Issues"</B></A>%}%)).
#%DT% interface: %DD%Supported I/O interfaces are "%B%GPIB%B%", "%B%RS232%B%" and "%B%RS232_1by1%B%"; the last one stands for sending command characters one by one from SPEC, that considerably slows down the communication when it goes through the ethernet. It has proved to be sometimes necessary with the Oxford Instrument devices.  
#%DT% address:%DD% the GPIB address or the Serial Line number relatively to SPEC config.
# %DT%sleept: %DD%slows down the communication flow. (in second# %DT%channel and setuppars%DD% are specific for each type of controller. They are described later; (%{%<A HREF="#Specific"><B>"Device Specific Issues"</B></A>%}%).
#%XDL%
#%DT%Temperature limits: %DD%The setpoint software limits are taken out from the config corresponding motor limits. Hardware limits can be also set up in some controllers; use the command " %B%tclim%B%". 
#%DT%Temperature polling:%DD%"DC_settle_time" and "DC_dead_band" config motors parameters are respectively used as temperature stabilization time in seconds and temperature bandwidth around setpoint in degrees. Default values are 0, what makes the move macros returns immediately after a change in setpoint. If they are set, the macro returns when the temperature has remain within the specified bandwidth at least the specified settling time. 
#If only the "DC_settle_time" is set, the macros simply waits the specified amount of seconds, and if only the "DC_dead_band" is set, the macro waits for the temperature entering this bandwidth.
#%DT% %{%<A NAME="Specific"><B>Devices Specific Issues:</B></A>%}%%DD%
#%DL%
#%DT%"ILL": ILL Sample Environment Controller:%DD%
#Device specific temperature_control () parameters are not needed:
#%UL%
#%LI% channel  :0
#%LI% setuppars:0. In fact this can be the OS9 prompt text, used internally for communication purposes only, but SPEC sets its own default if 0.
#%XUL%
# ATTENTION: If several controller of that type are in use, they MUST all be configured with the same OS9 prompt.
#%DT% "OX": Oxford ITC 503:%DD%
#Device specific temperature_control () parameters:
#%UL%
#%LI% channel  : 1, 2 or 3, as sensor number that will be used for feedback.
#%LI% setuppars: maximum output voltage value in Volts.
#%XUL%
# Three %B%additional pseudo-counters%B% can be defined, following the naming convention T1<name> T2<name> and T3<name>, where <name> is the name given to temperature_control (). They corresponds to the 3 sensors temperatures handled by the Oxford ITC.%BR%
#%B%_ox_checkres%B%: is a macro that can eventually be hooked to %B%user_tc_io_3%B% macro to perform Oxford ITC specific communication handcheck.%BR%
#%B%oxstatus%B%: is a macro that displays Oxford controllers specific parameters.%BR%
# ATTENTION: changing the setpoint will not work if the controller is running a sweep.
#%DT% "OXISO": Oxford ITC 503 IsoBus:%DD%
# Refer to "OX" part. Only the low level communication protocol changes, what is transparent to users.
#%DT% "HCC": Hubber CC41 Chiller Controller:%DD%
#%UL%%LI% channel:0
#%LI% setuppars:"intern" or "extern", referring to the temperature reference used for feedback. default is "intern".
#%XUL%
# ATTENTION: If several controller of that type are in use, they MUST all be configured the same, either intern or extern.
#%DT% "F700": ASL Bridge:%DD%
#%UL%%LI% channel:0
#%LI% setuppars: double space separated list of 5 numbers, meaning:
#%UL%
#%LI%1st number is the Initial/Nominal Setpoint value in degrees.
#%LI%2nd number is the Gain, value 0, 1 or 2.(0=x1;1=x10 and 2=x100)
#%LI%3rd number is the Current, value 0, 2 to 5.(0=0.1mA;2=0.5mA;3=1mA;4=2mA and 5=5mA)
#%LI%4th number is the Bandwidth, value 0, 1 or 2.(0=1Hz;1=10Hz and 2=0.1Hz)
#%LI%5th number is a flag to say clear/reset (1) or not (0).
#%XUL%
#%XUL%
# ATTENTION: This type of controller does not provide a reliable way of reading back the temperature. The A[] array then holds the setpoint value rather than the current temperature.%BR%
# ATTENTION: For the time being, only one controller of that type can be setup in a same SPEC application. 
#%DT% "F26": ASL Bridge:%DD%
#%UL%%LI% channel:0
#%LI% setuppars: double space separated list of 2 numbers, meaning:
#%UL%
#%LI%1st number is the Current, value 0 to 3.(0=0.1mA;1=0.3mA;2=1mA;3=3mA)
#%LI%2nd number is the Sensitivity, value 0,1,2 as low, med, high
#%XUL%
#%XUL%
# ATTENTION: For the time being, only one controller of that type can be setup in a same SPEC application. 
#%DT% "EURO": EuroTherm 2000 series (also being tested for EURO900):%DD%
#%UL%%LI% setuppars:"group:address" i.e "0:1". Many Eurotherm devices can be connected to the same serial line. Check the address in the device (usually 1).
#%LI% Serial line must be configured as [1 start, 7 data, even parity, 1 stop]. For instance, in a solaris machine, if you want to use it from the workstation serial line just config the serial line as /dev/ttya raw evenp.  
#%LI% example: SPEC>temperature_control ("euro1","EURO","RS232",0,0,0,"0:1") 
#%LI% example: SPEC>temperature_control ("euro1","EURO900","RS232",0,0,0,"0:1") 
#%XUL%

#%DT% "LTC20": Conductus LTC-20%DD%
#%UL%%LI% setuppars:"group:address" i.e "0:1". 
#%LI% example: SPEC>temperature_control ("ltc","LTC20","GPIB",0,0,0,"0:1") 
#%XUL%

#%DT% "LS200 & LS300": LakeShore 200 and 300 Series%DD%
#%UL%%LI% setuppars:"group:address" i.e "0:1". 
#%LI% The controllers have been tested with type 218, 331, 340.
#%LI% example: SPEC>temperature_control ("ex7","LS200","GPIB","0:5",0,1,"K", 1)
#%LI% Possible channels are 1 to 8. The "K" is the unit to do the readings in: K Kelvin, C Celsius, S Sensor units.
#%LI% example: SPEC>temperature_control ("ex8","LS300","GPIB","0:12",0,"B","K:1")
#%LI% Possible channels A or B. The "K" is the unit to do the readings in: K Kelvin, C Celsius, S Sensor units. 
#%LI% Last value is the number of loop (":" separated from unit letter for LS300); the 300 series usually has two contrik loop outputs, which are used for the temperature setpoints.
#%LI% Series 200 is read only.
#%LI% On request of a user the usage of the heater of the series 300 is left to the user. The macros are LS300_heater_off and LS300_heater_setrange.
#%XUL%

#%DT% "SIM": Simulation of temperature control. %DD%Only one at a time.
#%BR%
#%XDL%
#Others devices can be added easily. see "%B%%{% <A HREF="#INTERNALS">INTERNALS  </A>%}%%B%".
#%XDL%
#%END%

#temperature_control ("ex1","ILL","RS232")
#temperature_control ("ex2","SIM")
#temperature_control ("ex3","OX","RS232_1by1",0,0.1,1,10)
#temperature_control ("ex4","HCC","RS232")
#temperature_control ("ex5","F700","GPIB",3,0,0,"25  1  0  1  0")
#temperature_control ("ex5","F26","GPIB",11,0.5,0,"2  2")
#temperature_control ("ex5","EURO900","RS232",0,0,2,"0:1") # channel 2
#temperature_control ("ex5","EURO","RS232",0,0,0,"0:1")
#                                                 group:euroaddress
#temperature_control ("ex6","LTC20","GPIB","2:14",0,1,"")
#                                                   ^=channel 1 or 2
#                                           ^=gpib address
#                                    ^=gpib interface
#temperature_control ("ex7","LS200","GPIB","0:5",0,1,"K")
#                                                     ^=K for Kelvin, C for Celsius, S for what ?
#                                                  ^=channel 1 to 8
#                                           ^=gpib interface and address
#temperature_control ("ex8","LS300","GPIB","0:12",0,"B","K:1")
#                                                         ^ # of control loop output
#                                                       ^=K for Kelvin, C for Celsius, S for what ?
#                                                       ":" seperated!
#                                                   ^=channel A or B
#                                          ^=gpib interface and address

#%HISTORY%
#$Log: temperature.mac,v $
#Revision 1.46  2016/01/05 16:16:21  guilloud
#fix wrong ^? char.
#
#Revision 1.45  2015/10/22 15:38:53  ohlsson
#Modified test on mode in _tc_io (bug fix)
#
#Revision 1.44  2013/12/05 10:02:33  ahoms
#* Fixed failing TCxxx array whatis check before delete in remove (unsetup)
#
#Revision 1.43  2012/07/19 14:59:22  guilloud
#+tests to avoid error messages on temperatureunsetup
#
#Revision 1.42  2012/05/29 08:02:51  lagier
#modif 1.41 on st15 controller (forgot last time...)
#
#Revision 1.41  2012/05/24 09:07:11  lagier
#bug fix for some controllers that did not fill TC_SP array at setpoint,
#what prevented from revision 1.38 changes to work.
#
#Revision 1.40  2012/05/24 08:30:44  domingue
#modify serialflush
#
#Revision 1.39  2012/05/03 08:23:37  domingue
#ls200, ls300: do not wait for a response in setup phase (temperature_control)
#
#Revision 1.38  2012/04/03 08:12:39  lagier
#bug fix in motorsrun
#getpangles always returns setpoint if no polling parameters configured
#
#Revision 1.37  2011/10/26 13:27:04  beteva
#added check for TC_ON in _tc_checkall, _tc_moveall and _tc_getpangles (GB)
#
#Revision 1.36  2011/06/30 13:48:57  witsch
#sorted out, when europrog (and needed macros) are loaded.
#
#Basically, eurotherm2400.mac has the same macro. So we had to work
#out a way of overloading europrog from eurotherm2400, but not from
#temperature.mac.
#
#This has been accomplished by looking, which file the macro comes from
#and then in temperature.mac it is loaded only, if it has not been loaded
#from eurotherm2400 previously.
#
#The macros europrog (and needed macros) are defined with a rdef from a
#function, which is executed under the conditions described above.
#
#Revision 1.35  2011/02/16 15:04:31  witsch
#To treat the conflict between europrog from temperature.mac or
#eurotherm2400.mac all macros concerned with europrog were moved to the
#end of the file.
#If europrog is already defined from eurotherm2400.mac an error message
#will appear and the loading will be blocked.
#
#Revision 1.34  2011/02/03 10:14:45  lagier
#added some documention for LS300 configuration.
#
#Revision 1.33  2010/12/02 15:33:42  lagier
#BUG FIX in _tc_st9700
#
#Revision 1.32  2010/10/25 11:33:34  homsrego
#* LS300_heater_setrange & LS300_heater_off - included serial comm
#
#Revision 1.31  2008/06/20 12:09:12  lagier
#keep compatible with st15 series
#
#Revision 1.30  2008/06/17 13:05:24  lagier
#new controller : Scientific Instrument S9700
#
#Revision 1.29  2007/11/13 15:15:36  claustre
#europrog_read, missing a \n
#
#Revision 1.28  2007/10/04 14:44:56  guijarro
#added USER_WAITINGMOVE to the condition in _tc_motorsrun
#
#Revision 1.27  2007/05/11 06:58:33  claustre
#fixed some bugs in the europrog macros. Now we can use
#europrog to program ramps and complex sequences of ramps
#
#Revision 1.26  2007/03/08 14:35:43  lagier
#modify st15 cryostat control so that pseudo motor holds setpoint value rather than current temperature. added curremt temperature reading as T1 counter.
#
#Revision 1.25  2007/02/02 17:18:31  rey
#Bug that causes waiting for the dc_settle_time on a pseudo
#at any macro calling waitmove. For example ct
#
#Revision 1.24  2007/01/25 13:18:28  witsch
#missing termination character for SETP in the Conductus part.
#
#Revision 1.23  2006/03/09 15:39:58  lagier
#bug fix in _tc_motorsrun
#
#Revision 1.22  2006/03/07 10:24:33  lagier
#F26 ASL controller: modified to operate like the F700: motor pos holds setpoint and not real temperature.
#
#Revision 1.21  2006/02/28 11:53:12  witsch
#variable T0 was defined as global in temperature.mac. However,
#someone else hadthe great idea to use the same name for something else.
#Rename T0 to _t_t0_, is that unique enough.
#
#Revision 1.20  2005/01/30 16:11:45  fernande
#bug fixed in europrog (macro to program the Eurotherm (2000))
#new macro added : europrogreset . Manual reset of the running program
#
#Revision 1.19  2004/11/19 08:27:16  berruyer
#for LS200-300 action=sp inverted test for heater use and add terminator (\r\n) for the command
#
#Revision 1.18  2004/10/26 13:22:25  fernande
#New features were added to europrog . Skip segment
#and others.
#
#Revision 1.17  2004/10/20 21:39:35  fernande
#europrog. Some cosmetics were done and some bugs fixed...
#
#Revision 1.16  2004/10/01 16:23:27  fernande
#europrog macro added to program the eurotherm. Type europrog for usage
#local macros needed were added as well. Now one can manage programs
#from spec. Examples
#europrog write -> writes a program
#europrog run -> starts the program
#europrog reset ->resets the program
#europrog status -> shows the status of the program running
#
#Revision 1.15  2004/03/09 08:49:27  claustre
#local declaration of variable channel was missing.
#
#Revision 1.14  2003/12/15 15:09:04  fernande
#redone
#
#Revision 1.13  2003/12/15 15:03:20  fernande
#EURO900 added to tc_hardware (forgotten)
#
#Revision 1.12  2003/04/14 11:20:41  lagier
#put flag 0x02 in cdefs, rather than '2'
#
#Revision 1.11  2003/03/04 16:03:35  lagier
#bug fixes in Oxford ITC503 control.
#
#Revision 1.10  2003/02/25 13:49:53  witsch
#changes for more freedom in name choice for counters.
#Actually this change allows one to have only a counter defined, rather than
#a motor and an associated counter. It is a possible source of trouble
#if a read only temperature controller is defined as pseudo motor. Thus
#allow the same name to become a counter, or only allow the name with
#the known "T_" prefix to be a counter. No motor required any more. All
#depends on what motor and/or counter is defined in the config.
#
#Revision 1.8  2003/02/10 12:22:03  witsch
#add control loop channel parameter to last element in temperature_control
#for _tc_ls200 function.
#
#Revision 1.7  2003/01/24 13:53:01  lagier
#bug fix
#
#Revision 1.6  2003/01/21 09:25:32  lagier
#Added control of alpha-sigma-lambda f26 bridges.
#
#Revision 1.5  2002/12/02 14:20:06  lagier
#temperature_control():
#test if instrum_connected is a string valued symbol.
#an empty string or a string beginning with a space is <0.
#_tc_hardware():
#remove argument "name" from calls to _tc_st15(), _tc_f700(), _tc_ox(), _tc_oxiso(), _tc_sim(), _tc_hcc() and _tc_ill().
#_tc_st15():
#print info message
#_tc_f700():
#bug fix readin initial setpoint. par[0]+0
#
#Revision 1.4  2002/12/02 13:12:43  fernande
#new support for eurotherm 900 (still a problem with 2nd setpoint)
#
#Revision 1.4  2002/10/14 16:18:50  fernande
#name in _tc_euro fucntion\n
#
#Revision 1.3  2002/04/11 16:25:46  fernande
#Eurotherm 2000 series. Bug in setpoint fixed
#
#Revision 1.2  2002/04/11 15:33:49  witsch
#Added controllers Conductus LTC20, Lakeshore 200 and 300 series.
#Found bugs in temperature_controller, where the channel was not correctly
#forwarded into the get_pangles etc macros. Corrected.
#
#Most important, for the implementation of the LakeShore 200 & 200 series,
#the introduction of the name being used in _tc_hardware, _tc_io and all _tc_*
#macros was necessary.
#
#Temperature_control now correctly recognized if an instrument is really
#connected or not.
#
#The LakeShore 200 and 300 series and the Conductus LTC20 have been
#implemented and successfully tested.
#
#
# This has been tested with EURO 900 on ID19 (27 11 2002)
#     There was a problem setting the setpoint 2 (command S2)
#     For the setpoint 1 worked ok (SL), and also for the temp. reading (PV)
#     
#     Note that this behaves different than the EURO200 (channel+SL)
#     or (SL if it has only one loop)
#     I still have to test this multiple channels features with the EURO2000
#     
#     Hope I didn't break anything.
#                                       DFC (27/11/2002)
#     DFC (15/12/2003) . Modified _tc_hardware to have EURO900 (missing)
# 
#
#
#%UU% (name,type,interface,address,sleept,channel,setuppars)
#%MDESC% Setup macro. already explained into %{%<A HREF="#SETUP">SETUP paragraph</A>%}% above.

def temperature_control (name,type,interface,address,sleept,channel,setuppars)'{

  global TC []
  global TC_ON []
  global TC_SP []
  global TC_OLD []
  global TC_NOTREAD []
  global TC_HL []
  global TC_LL []

  local support_list instrum_connected associated_counter

  support_list    = "%ILL%SIM%OX%OXISO%HCC%F700%F26%ST15%ST9700%EURO%EURO900%LTC20%LS200%LS300%"

  if (0==index (support_list,sprintf("%%%s%%",type))) {

    print "cannot install "name" temperature control system;"
    print "hardware \""type"\" not supported yet."
    temperature_remove(name)
		return(-1)
  } else {
    
    setup_tail ("temperature",name)

    list_add   (TC,name)
    list_setpar(TC,name,"type",type)
    list_setpar(TC,name,"intf",interface)
    list_setpar(TC,name,"add",address)
    list_setpar(TC,name,"slp",sleept)
    list_setpar(TC,name,"ch",channel)
    
    associated_counter = sprintf("T_%s", name)
    if (motor_num(name) == -1) # Hmm, no such motor ? check counter
      if (cnt_num(name) != -1) # yep! its a counter
        associated_counter = name

    cdef ("user_getcounts",\
        sprintf ("S[%s]=_tc_hardware(\"rt\",\"%s\",0,\"%s\",\"%s\",\"%s\",\"%s\",\"%s\")\n", \
					associated_counter,name,type,interface,address,sleept,channel),associated_counter,0x02)
    cdef ("prompt_mac" ,\
        sprintf ("TC_NOTREAD [\"%s\"]=0;",name),name,1)
    cdef ("user_motorsrun" ,\
        sprintf ("_tc_motorsrun %s %s %s %s %s %s\n",\
            name,type,interface,address,sleept,channel),name,1)
    cdef ("user_pollmove",\
        sprintf ("_tc_getpangles %s %s %s %s %s %s \$0\n",\
                   name,type,interface,address,sleept,channel),name,1) 
    cdef ("user_getpangles",\
        sprintf ("_tc_getpangles %s %s %s %s %s %s \$0\n",\
                    name,type,interface,address,sleept,channel),name,1)
    cdef ("user_checkall", sprintf ("_tc_checkall %s\n",name,channel),name,1)
    cdef ("user_moveall",  \
        sprintf ("_tc_moveall %s %s %s %s %s %s\n",\
                           name,type,interface,address,sleept,channel),name,1)
    cdef ("user_finished1" ,sprintf ("TC_OLD[%s]=A[%s]\n",name,name),name,1)

    if (!(name in TC_ON)) {
      TC_ON[name]  =  1
    } else if (TC_ON[name]==0) {
      _tcoff(name)
    }

    print "\""name "\" temperature control installed." 

    setuppars = setuppars "  " name
    instrum_connected = _tc_hardware ("setup",name,setuppars,type,interface,address,sleept,channel)

    if ((instrum_connected<0) && (0==whatis("instrum_connected")&0x00200000)) {
      print name " temperature controller not responding."
      print name " disabled. (tcon "name"/ tcoff "name")."
      TC_ON[name]=0
      _tcoff (name)
			return(-1)
    } 

#else if (instrum_connected || whatis(intrum_connected)&0x00200000)
#      print instrum_connected
#p "whatis(intrum_connected)", whatis(intrum_connected)

#    if (motor_num(name)<0)
#      print "WARNING:\""name "\" pseudo motor not configured."

#    if (cnt_num(associated_counter)<0)
#      print "WARNING:\"T_"name "\" pseudo counter not configured."

		return(0)
  }
}'


def temperatureunsetup '{
  temperature_remove("$1")
}'


#%UU% (name)
#%MDESC%
#    Has the same effect as commenting out the
# temperature_control() line in setup, i.e. remove all the control
# software associated with "name".
def temperature_remove(name) '{

   if (whatis("TC")!=0) {
        if (list_remove(TC, name)>0){
            print name " temperature control un-installed."
        }
    }

   cdef ("","",name,"delete")
   cdef ("","",sprintf("T_%s",name),"delete")
   cdef ("","",sprintf("T1%s",name),"delete")
   cdef ("","",sprintf("T2%s",name),"delete")
   cdef ("","",sprintf("T3%s",name),"delete")

   if (whatis("TC_SP")!=0){
        delete TC_SP[name]
    }

    if (whatis("TC_ON")!=0){
        delete TC_ON[name]
    }

    if (whatis("TC_NOTREAD")!=0){
        delete TC_NOTREAD[name]
    }

    if (whatis("TC_LL")!=0){
        delete TC_LL[name]
    }

    if (whatis("TC_HL")!=0){
        delete TC_HL[name]
    }

    if (whatis("TC_OLD")!=0){
        delete TC_OLD[name]
    }
}'


#%UU% <name>
#%MDESC% Turns On the specified device.

def tcon '{
  
  if (!("$1" in TC_ON)) {
    print "$1 invalid name."
  } else {

    _tcon("$1")

    print "$1 was "TC_ON["$1"]?"On":"Off" ", now is On"
    TC_ON["$1"]=1
  }
}'


#%IU% (name)
#%MDESC% Enabling sub-function.

def _tcon (name) '{
    cdef ("","",name,"enable")
    cdef ("","",sprintf("T_%s",name),"enable")
}'


#%UU% <name>
#%MDESC%Turns Off the specified device.

def tcoff '{

  if (!("$1" in TC_ON)) {
    print "$1 invalid name."
  } else {

    _tcoff("$1")
    print "$1 was "TC_ON["$1"]?"On":"Off" ", now is Off"
    TC_ON["$1"]=0
  }
}'

#%IU% (name)
#%MDESC% Disabling sub-function.

def _tcoff (name) '{

    cdef ("","",name,"disable")
    cdef ("user_checkall","",name,"enable")
#    cdef ("blmenubody","",name,"enable")
    cdef ("","",sprintf("T_%s",name),"disable")
}'





if (!(whatis("user_tc_io_1")&2)) rdef user_tc_io_1 '#$*'
if (!(whatis("user_tc_io_2")&2)) rdef user_tc_io_2 '#$*'
if (!(whatis("user_tc_io_3")&2)) rdef user_tc_io_3 '#$*'


#%IU% (interface,address,sleept,cmdstr,mode) 
#%MDESC% Low level communication. mode=0 means do not read anything back, otherwise it should hold the terminator character/string.

def _tc_io (interface,address,sleept,cmdstr,mode) '{

  global TC_RES
  local  _send _read
  
  _send = (cmdstr!="")
  _read = ((!_send)||(length(mode)>0))

  user_tc_io_1

  if (_send) {

    if ("RS232"==interface) 
      TC_RES=ser_put(address,cmdstr)

    if ("GPIB"==interface)
      TC_RES=gpib_put(address,cmdstr)

    if ("RS232_1by1"==interface) {
      local _c _nc _l
      _l=length(cmdstr)
      for (TC_RES=0,_nc=1;_nc<=_l;_nc++) {
        _c=substr (cmdstr,_nc,1)
        TC_RES+=ser_put(address,_c);	#sleep(0)
      }
    }
 
    user_tc_io_2

    if (length(cmdstr)!=TC_RES)
      return -1

    sleep (sleept)
  }

  if (_read) {
    if ("RS232"==interface || "RS232_1by1"==interface) {    
      #if (mode>=0) TC_RES=ser_get(address,mode)
      if (mode != 0) TC_RES=ser_get(address,mode)
      else         TC_RES=ser_get(address)
    }
    if ("GPIB"==interface) {
      #if (mode>=0) TC_RES=gpib_get(address,mode)
      if (mode != 0) TC_RES=gpib_get(address,mode)
      else         TC_RES=gpib_get(address)
    }
  }

  user_tc_io_3

  return TC_RES
}'



#%IU% (action,value,type,interface,address,sleept,channel) 
#%MDESC% Hardware interface. Convert generic action into hardware language.

def _tc_hardware (action,name,value,type,interface,address,sleept,channel) '{
#DBG
#print "_tc_hardware:",action,value,type,interface,address,sleept,channel

  if (type=="ST9700") 
    return _tc_st9700 (action,value,interface,address,sleept,channel)  ;
    
  if (type=="ST15") 
    return _tc_st15 (action,value,interface,address,sleept,channel)  ;
    
  if (type=="F700") 
    return _tc_f700 (action,value,interface,address,sleept,channel)  ;

  if (type=="F26") 
    return _tc_f26 (action,value,interface,address,sleept,channel)  ;

  if (type=="OX") 
    return _tc_ox (action,value,interface,address,sleept,channel) ;

  if (type=="OXISO") 
    return _tc_oxiso (action,value,interface,address,sleept,channel) ;

  if (type=="SIM") 
    return _tc_sim (action,value);

  if (type=="HCC") 
    return  _tc_hcc (action,value,interface,address,sleept,channel) ;

  if (type=="ILL") 
    return _tc_ill (action,value,interface,address,sleept,channel) ;

  if (type=="EURO"  ||  type == "EURO900")
    return _tc_euro (action,name,value,interface,address,sleept,channel) 

  if (type=="LTC20") 
    return _tc_ltc20 (action,name,value,interface,address,sleept,channel) 

  if (type=="LS200") 
    return _tc_ls200 (action,name,value,interface,address,sleept,channel) 

  if (type=="LS300") 
    return _tc_ls300 (action,name,value,interface,address,sleept,channel) 
}'

#%UU%
#%MDESC% Not ready yet.
def tcramp '{
  local type value name

  if  ((type=_tc_check_dev("$1"))<0)
    exit

  if (_tc_check_lim("$1",$2,$3)<0)
    exit

  name  = motor_mne($1)
  value = "$2  $3"
  _tc_hardware ("ramp", name, value, type)
}'

#%IU% (name,min,max) 
#%MDESC% Limit check for "tcramp".
def _tc_check_lim (name,min,max) '{
  local cmin cmax num
  if ((num=motor_num(name))>=0) {
    cmin = get_lim(num,-1)
    cmax = get_lim(num,1)
    if (min<cmin || max>cmax) {
      print "Out of Limits ",cmin,cmax
      return -1
    }
  } else if (min<TC_LL[name] || max>TC_HL[name]) {
      print "Out of Limits ",TC_LL[name],TC_HL[name]
      return -2
  }
  return 0
}'

#%UU% <name> <min> <max>
#%MDESC% Set Hardware Temperature Limits. Software Limits are set independently as motor limits in config. %BR%Those hardware limits are checked by tcramp command that can be used out of the scope of temperature pseudo motors, because in that last case, no software limits are defined. 

def tclim '{
  local value type vals name
 
  if ($#!=3) {
    print "usage: $0 mnemonic min max"
    exit
  }

  if ((type=_tc_check_dev("$1"))<0)
      exit

  global TC_HL []
  global TC_LL []

  value = _tc_hardware ("lim","$1","$2  $3",type)
  
  split (value,vals)
  TC_LL["$1"]=vals[0]
  TC_HL["$1"]=vals[1]
}'



#%IU% <motor_mne>
#%MDESC% user_checkall hook. Checks if temperature control device in question is enabled, otherwise exit.
def _tc_checkall '{

  if (TC_ON["$1"]) {
    if (TC_OLD[$1]!=A[$1]) {

      stim = motor_par($1, "dc_settle_time")

      if  (_tc_check_dev("$1")<0)
        exit

      #
      # initialize time for user_motorsrun if dc_settle_time not zero
      #
      USER_WAITINGMOVE=1	
      if (stim>0) {
         cdef("cleanup_once","_t_t0=0\n","_t_t0")
      }


    } else {
      TC_NOTREAD["$1"]=1
    }
  }
}'


#%IU% <motor_mne> <device_type> <interface> <address> [sleep_time]
#%MDESC% user_moveall hook. Changes the setpoint to the value requested by a move action. 
def _tc_moveall  '{
  global TC_SP []
  local type address interface sleept channel 

  if (TC_ON["$1"]) {
    if (TC_OLD[$1]!=A[$1]) {
      name      = "$1"
      type      = "$2" 
      address   = "$4"
      interface = "$3"
      sleept    = $5
      channel   = "$6"

      TC_SP["$1"]=_tc_hardware("sp","$1",A[$1],type,interface,address,sleept,channel)
    }
  }
#DBG
#print "$0:old",TC_OLD[$1],"A",A[$1],"Setpoint",TC_SP["$1"]
}'


#%IU% <motor_mne> <device_type> <interface> <address> [sleep_time]
#%MDESC% user_getpangles hook. Read and load into array A the current temperature value. (or the setpoint for F700 types controllers.)
def _tc_getpangles '{

  global TC_OLD []
  local tmot band stim 

  if (TC_ON["$1"]) {
    if (!TC_NOTREAD["$1"]) {

      tmot=motor_num("$1")
      band=motor_par(tmot,"dc_dead_band")
      stim=motor_par(tmot,"dc_settle_time")

      if (band>0||stim>0) {
        A[$1]=_tc_hardware ("rt","$1",0,"$2","$3","$4","$5","$6","$7")
      } else {
        A[$1]=TC_SP["$1"]
      }
    }
    if (!USER_WAITINGMOVE) 
      TC_OLD[$1]=A[$1]
  }
}'


def _oldtc_getpangles '
#DBG
#print "_tc_getpangles", "$*"
  global TC_OLD []
  if (TC_ON["$1"]) {
    if (!TC_NOTREAD["$1"])
      A[$1]=_tc_hardware ("rt","$1",0,"$2","$3","$4","$5","$6","$7")
    if (!USER_WAITINGMOVE) 
      TC_OLD[$1]=A[$1]
  }

#DBG
#print "$0,$6:old",TC_OLD[$1],"A",A[$1],"Setpoint",TC_SP["$1"]
'


#%IU% <motor_mne> <device_type> <interface> <address> <sleep_time>
#%MDESC% user_motorsrun hook. Returns 1 to say temperature setpoint reached in accordance with the config "DC_dead_band" and "DC_settle_time" parameters.

def _tc_motorsrun '{

#DBG

  if (USER_WAITINGMOVE) {
    global _t_t0
    local tmot band stim tp it ad sl

    tmot=motor_num("$1")
    tp="$2"
    it=$3
    ad="$4"
    sl=$5

    band=motor_par(tmot,"dc_dead_band")
    stim=motor_par(tmot,"dc_settle_time")

#print "$0:old",TC_OLD[$1],"A",A[$1],"Setpoint",TC_SP["$1"],"wait",USER_WAITINGMOVE,band,stim,_t_t0?time()-_t_t0:0

    if (band>0) {
      _tc_getpangles $* $0
 
      if (band>=fabs(TC_SP["$1"]-A[$1])) {
        if (stim) {
	  if (0==_t_t0) {
            _t_t0=time()
	  }

#print "within band ",A[$1],time()-_t_t0,"Sec "

          if ((time()-_t_t0) < stim) {
            return 1
          } else {
            _t_t0=0
	    return 0
	  }

        } else {
#print "band ",band,"reached"
	  return 0
        }
      } else {
        _t_t0=0
#print "outside band ",band
        return 1  
      }
    } else if (stim>0) {
      if (0==_t_t0)_t_t0=time()
#print "stabilized ",A[$1],time()-_t_t0,"Sec "
      if ((time()-_t_t0) < stim)
          return 1
      else _t_t0=0
    } 
  }    
}'

#%UU%
#%MDESC% Reports on all set up temperature controllers.
def rt '{
  local val i n name type address interface sleept channel

  n=list_n(TC)

  print "Temperature Values:"
  print "Device     Measure    Setpoint   Limits"
  print 

  user_getpangles

  for (i=1;i<=n;i++) {
    name      =list_item(TC,i)

    if (!TC_ON[name]) 
      printf ("%-10s Disabled.\n",name) 
    else {
      type      =list_getpar(TC,i,"type")
      interface =list_getpar(TC,i,"intf")
      address   =list_getpar(TC,i,"add")
      sleept    =list_getpar(TC,i,"slp")
      channel   =list_getpar(TC,i,"ch")
#DBG
#print "rt",0,type,interface,address,sleept,channel
      val=_tc_hardware ("rt",name,0,type,interface,address,sleept,channel)
      printf ("%-10s %-10s %-10s " , name,val,TC_SP[name])
      if ((num=motor_num(name))>=0) 
         printf ("%-10s %-10s\n" , get_lim(num,-1),get_lim(num,1))
      else 
         printf( "motor Not in config (%s %s)\n",TC_LL[name],TC_HL[name])
    }
  }
  print 
}'


#%IU% (name)
#%MDESC% Returns the type of the controller if it has been correctly set up and if it is enabled, or -1 if not setup, or -2 if disabled.

def _tc_check_dev (name) '{

  local type

  if (name == 0) {
    print "No name given."
    exit
  }

  type = list_getpar(TC,name,"type")
 
  if (type<0) {
    print name,"invalid name or setup."
    return type  
  }

  if (TC_ON[name]==0) {
    print name,"is disabled (\"tcon "name"\" needed first)."
    return -2
  }

  return type
}'


#############################################################################


 #####  #######    #    #######
#     #    #      ##    #
#          #     # #    #
 #####     #       #    ######
      #    #       #          #
#     #    #       #    #     #
 #####     #     #####   #####

#%IU% (action,value)
#%MDESC%  Scientific Instruments ST15 cryostat command interface.

def _tc_st15 (action,value,interface,address,sleept,channel) '{
 
  global ST15_SETPOINT

  local cmd par n mode ret
  n=split(value,par,"  ")

  cmd = mode = ""

  if ("sp"==action) {
    ST15_SETPOINT=value
    cmd = sprintf("S%4.1f",value)
  }
  if ("rt"==action) {
    return ST15_SETPOINT
  }

  if ("lim"==action);

  if ("ramp"==action);

  if ("setup"==action) {

    #par[0]#proportionnal
    #par[1]#integrative
    #par[2]#derivative
    cmd=sprintf("P%d\rI%d\rD%d",par[0],par[1],par[2])

    cdef ("user_getcounts",sprintf("S[T1%s]=substr(_tc_io(\"%s\",\"%s\",%g,\"T\\r\",\"\\r\"),2,5)+0\n",par[n-1],interface,address,sleept),sprintf("T1%s",par[n-1]),0x02)
    cdef ("user_getcounts",sprintf("S[T2%s]=substr(_tc_io(\"%s\",\"%s\",%g,\"t\\r\",\"\\r\"),2,5)+0\n",par[n-1],interface,address,sleept),sprintf("T2%s",par[n-1]),0x02)

    
  }
    
  if (cmd!="") 
    cmd = cmd "\r" 

  ret = _tc_io (interface,address,sleept,cmd,mode)

  if (action=="rt") {
    global ST15_RET 
    ST15_RET=ret
    ret=substr(ST15_RET,2,5)
  }

  if (action == "setup" && ret >0) {
    ret = "  Scientific Instrument ST15 cryostat."
    print ret
  }
  if (action == "sp") {
	ret=value
  }

  return ret
}'



#############################################################################

 #####  #######     #####  #######   ###     ###
#     #    #       #     # #    #   #   #   #   #
#          #       #     #     #   #     # #     #
 #####     #        ######    #    #     # #     #
      #    #             #   #     #     # #     #
#     #    #       #     #   #      #   #   #   #
 #####     #        #####    #       ###     ###


#%IU% (action,value)
#%MDESC%  Scientific Instruments ST9700 cryostat command interface.

def _tc_st9700 (action,value,interface,address,sleept,channel) '{
 
  global ST9700_SETPOINT

  local cmd par n mode ret
  n=split(value,par,"  ")

  cmd = mode = ""

  if ("sp"==action) {
    ST9700_SETPOINT=value
    cmd = sprintf("SET %7.3f",value)
  }
  if ("rt"==action) {
    cmd = sprintf("SET?")
    mode = "\r"
  }

  if ("lim"==action);

  if ("ramp"==action);

  if ("setup"==action) {

    #par[0]#proportionnal
    #par[1]#integrative
    #par[2]#derivative

    cmd=sprintf("PID 1,%d,%d,%d",par[0],par[1],par[2])

    cdef ("user_getcounts",sprintf("sscanf(_tc_io(\"%s\",\"%s\",%g,\"TA?\\r\",\"\\r\"),\"%%s%%f\",junk,S[T1%s])\n",interface,address,sleept,par[n-1]),sprintf("T1%s",par[n-1]),0x02)

    cdef ("user_getcounts",sprintf("sscanf(_tc_io(\"%s\",\"%s\",%g,\"TB?\\r\",\"\\r\"),\"%%s%%f\",junk,S[T2%s])\n",interface,address,sleept,par[n-1]),sprintf("T2%s",par[n-1]),0x02)

#    cdef ("user_getcounts",sprintf("sscanf(_tc_io(\"%s\",\"%s\",%g,\"TALL?\\r\",\"\\r\"),\"%%s%%f,%%f\",junk,S[T1%s],S[T2%s])\n",interface,address,sleept,par[n-1],par[n-1]),sprintf("T2%s",par[n-1]),0x02)
    
  }
    
  if (cmd!="") 
    cmd = cmd "\r" 

  ret = _tc_io (interface,address,sleept,cmd,mode)

  if (action=="rt") {
    local junk
    sscanf(ret,"%s%f",junk,ret)
    print "rt:",ret
  }

  if (action == "setup" && ret >0) {
    ret = "  Scientific Instrument ST9700 cryostat."
    print ret
  }

  if (action=="sp") {
    ret = value
  }
  return ret
}'



########################################################################



 #    #   ####    ####
 #    #  #    #  #    #
 ######  #       #
 #    #  #       #
 #    #  #    #  #    #
 #    #   ####    ####



#%IU% (action,value)
#%MDESC% HUBBER CHILLER CONTROLLER CC41 Command Interface.

def _tc_hcc (action,value,interface,address,sleept,channel)  '{

  global HCC 
  local cmd par n ret mode
  
  mode=-1

  n   = split(value,par,"  ")
  cmd = ""

  if ("setup"==action) {
  
    mode="\n"
    HCC=par[0]

    cmd="remote"
    if (HCC=="extern") 
      cmd = cmd "\r\n extern!"
    else 
      cmd = cmd "\r\n intern!" 

    cmd = cmd "\r\n STATUS0"

    print "  Huber CC41 Chiller Controller."
  }

  if ("sp"==action)
    cmd = sprintf("set %4.1f", value)

  if ("rt"==action) {
    mode="\n"
    cmd = HCC=="extern"?"extern?":"intern?"    
  }

  if ("lim"==action)
    cmd = sprintf ("lo_limit %4.1g \r\n hi_limit %4.1g",par[0],par[1])

  if ("ramp"==action);

  if (cmd!="") 
    cmd = cmd "\r\n" 

  ret=_tc_io(interface,address,sleept,cmd,mode)  
  
  if (action=="sp") {
    ret = value
  }
  return ((mode>=0)?ret:par[0])

}'

###########################################################################



  ####   #    #
 #    #   #  #
 #    #    ##
 #    #    ##
 #    #   #  #
  ####   #    #



#%UU% <name>
#%MDESC% Oxford ITC types controllers status report.
def oxstatus '{

  local text i ioa ios ioi ret type
  local zz ahg remlock swp sensor apid chk

  type=_tc_check_dev("$1")

  if (type!="OX"&&type!="OXISO") {
    print "$1 not an Oxford Instrument Temperature Controller. Sorry..."
    exit
  }
  if (type<0)
    exit

  ioi=list_getpar (TC,"$1","intf")
  ioa=list_getpar (TC,"$1","add")
  ios=list_getpar (TC,"$1","slp")

  text[0] ="SETPOINT      " ; 
  text[1] ="SENSOR 1 TEMP." ;
  text[2] ="SENSOR 2 TEMP." ; 
  text[3] ="SENSOR 3 TEMP." ;
  text[4] ="TEMP. ERROR   " ; 
  text[5] ="HEATER O/P %  " ;
  text[6] ="HEATER O/P V. " ; 
  text[7] ="GAS FLOW O/P  " ; 
  text[8] ="PROPORT. BAND " ; 
  text[9] ="INTEGRAL TIME " ; 
  text[10]="DERIV. TIME   " ;

  print;printf("$1 Oxford ITC:\n\n")

  for (i=0;i<=10;i++) {
    ret = _tc_io (ioi, ioa, ios, sprintf("R%d\r",i),"\r")
    sscanf( substr (ret,2),"%g",val)
    if (i==6) val/=10
    printf("%s : %g\n",text[i],val)
  }

  ret = _tc_io (ioi, ioa, ios, "X\r","\r")

  if (12==(chk=sscanf(ret,"%1s%d%1s%d%1s%d%1s%d%1s%d%1s%d",zz,zz,zz,                                ahg,zz,remlock,zz,swp,zz,sensor,zz,apid))) {

    print 
    printf ("HEATER %s, GAS %s\n",(ahg-(ahg<2?0:2))?"AUTO":"MANUAL",                                                   (ahg<2?0:2)?"AUTO":"MANUAL")
    printf ("%s & %s\n",(remlock-(remlock<2?0:2))?"REMOTE":"LOCAL",                                              (remlock<2?0:2)?"UNLOCKED":"LOCKED")

    if (swp) {
      zz=swp/2+0
      if (zz==int(zz)) printf("SWEEP: HOLDING AT STEP %d\n",zz)
      else                 printf("SWEEP: SWEEPING TO STEP %d\n",(swp+1)/2)
    } else                 printf("SWEEPING NOT RUNNING\n")  

    printf ("HEATER SENSOR in use : %d\n",sensor)
    printf("%s\n",apid==1?"AUTO-PID ON":"AUTO-PID DISABLED")

  } else print "              Error while reading controller status"
}'

#%IU% (action,value,interface,address,sleept,channel)
#%MDESC% OXFORD INSTRUMENTS ITC503 Command Interface.

def _tc_ox (action,value,interface,address,sleept,channel) '{

  local ret par n macstr format
  n =split (value,par," ")
#  print action, value, par, n

  ret = value

  if ("sp"==action){
    ret = _tc_io (interface,address,sleept,sprintf ("T%g\r",value),"\r")
    ret = value
  }

  if ("rt"==action) {
    ret = _tc_io (interface,address,sleept,sprintf ("R%d\r",channel),"\r")
    ret = _ox_decoderesp(ret)
  }

  if ("lim"==action)
    print "Warning:No Hardware Limits Set"

  if ("ramp"==action);

  if ("setup"==action) {
    if (_tc_io (interface,address,sleept,"\$C3\r")<0) return -1
    if (_tc_io (interface,address,sleept,"\$L1\r")<0) return -1
    if (_tc_io (interface,address,sleept,"\$A0\r")<0) return -1
    if (_tc_io (interface,address,sleept,sprintf("\$M%d\r",10*par[0]))<0) 
      return -1
    if (_tc_io (interface,address,sleept,sprintf("\$H%d\r",channel+0))<0) 
      return -1
    if (_tc_io (interface,address,sleept,"\$A3\r")<0) return -1

    ret = _tc_io (interface,address,sleept,"V\r","\r")
    print "  "ret
    print "  sensor "channel" used for feed back."

    format="S[T%d%s]=_ox_decoderesp(_tc_io(\"%s\",\"%s\",%g,\"R%d\\r\",\"\\r\"))\n"
    macstr=sprintf(format, 1, par[n-1],interface,address,sleept, 1)
    cdef ("user_getcounts",macstr, sprintf("T1%s",par[n-1]),0x02)
    macstr=sprintf(format, 2, par[n-1],interface,address,sleept, 2)
    cdef ("user_getcounts",macstr, sprintf("T2%s",par[n-1]),0x02)
    macstr=sprintf(format, 3, par[n-1],interface,address,sleept, 3)
    cdef ("user_getcounts",macstr, sprintf("T3%s",par[n-1]),0x02)

  }

  return ret
}'


def _ox_decoderesp(resp) '{

  local value

  sscanf (substr(resp,2),"%g", value)
  return value
}'

#%IU%  
#%MDESC% eventually to be hooked to user_tc_io_3. Oxford ITC specific communication checking.

def _ox_checkres  '{

# interface,address,sleept,cmdstr,mode: assigned into _tc_io macro.

  local checkres checkcom

  checkres = substr(TC_RES,1,1)
  checkcom = substr(cmdstr,1,1)

  if (checkres=="?") { 
        
    printf("OXFORD ITC %s %d: Command not acknoledged : \n", interface,address)
    printf("           Sent : <%s>\n",cmdstr)
    printf("           Got  : <%s>\n",TC_RES) 
    return -1
  } 

  if (checkres != "?" && checkres != checkcom) {

    printf("OXFORD ITC %s %d: Error while reading response to %s\n",\
                                               interface,address,cmdstr)

    if ("RS232"==interface) 
      serialflush (address)
    else if ("GPIB"==interface)
      gpibflush (address,18)

    return -1
  }
}'

###########################################################################



  ####   #    #     #     ####    ####
 #    #   #  #      #    #       #    #
 #    #    ##       #     ####   #    #
 #    #    ##       #         #  #    #
 #    #   #  #      #    #    #  #    #
  ####   #    #     #     ####    ####



#%IU% (action,value,interface,address,sleept,channel)
#%MDESC% OXFORD INSTRUMENTS ITC503 Command Interface Using IsoBus protocol.

def _tc_oxiso (action,value,interface,address,sleept,channel) '{

  local ret iso par add

  split(value,par,"  ")
  split(address,add,":")

  iso = "@" add[1]
  ret = value

  if ("sp"==action){
    ret = _tc_io (interface,add[0],sleept,sprintf ("%sT%g\r",iso,value),"\r")
    ret = value
  }

  if ("rt"==action) {
    ret = _tc_io (interface,add[0],sleept,sprintf ("%sR%d\r",iso,channel),"\r")
    sscanf (substr(ret,2),"%g",ret)
  }

  if ("lim"==action)
    print "Warning:No Hardware Limits Set"

  if ("ramp"==action);


  if ("setup"==action) {

    if (_tc_io (interface,add[0],sleept,sprintf("%s\$C3\r",iso),-1)<0) 
      return -1
    if (_tc_io (interface,add[0],sleept,sprintf("%s\$L1\r",iso),-1)<0)
      return -1
    if (_tc_io (interface,add[0],sleept,sprintf("%s\$A0\r",iso),-1)<0)
      return -1
    if (_tc_io (interface,add[0],sleept,sprintf("%s\$M%d\r",iso,10*par[0]))<0) 
      return -1
    if (_tc_io (interface,add[0],sleept,sprintf("%s\$H%d\r",iso,channel+0)<0)
      return -1

    ret = _tc_io (interface,add[0],sleept,sprintf("%sV\r",iso),"\r")
    print "  "ret
    print "  sensor "channel" used for feed back."

# pseudo not available in this case.
#    cdef ("user_getcounts",sprintf("S[cnt_num(sprintf(\"T1%%s\",add[0]))]=_tc_io(%s,%s,%g,\"R1\\r\",\"\\r\")\n",interface,add[0],sleept),sprintf("T1%s",add[0]),2)
#    cdef ("user_getcounts",sprintf("S[cnt_num(sprintf(\"T2%%s\",add[0]))]=_tc_io(%s,%s,%g,\"R2\\r\",\"\\r\")\n",interface,add[0],sleept),sprintf("T2%s",add[0]),2)
#    cdef ("user_getcounts",sprintf("S[cnt_num(sprintf(\"T3%%s\",add[0]))]=_tc_io(%s,%s,%g,\"R3\\r\",\"\\r\")\n",interface,add[0],sleept),sprintf("T3%s",add[0]),2)
  }

  return ret
}'
###############################################################################
###############################################################################
#                E U R O T H E R M   2 0 0 0
#%IU% (string)
#%MDESC% EuroTherm 2000 series checksum calculation.
def _euro_calc_bcc(_mystring) '{

  local _bcc _ii
  #calculates bcc ( without STX )
  _bcc = 0
  for ( _ii=2 ; _ii <= length(_mystring) ; _ii++ ) {
                _bcc = _bcc ^ asc( substr(_mystring,_ii,1) )
  }
  return _bcc
}'
def _euro_calc_bcc_stx(_mystring) '{
  local _bcc i

  _bcc = 0
  for ( i=1 ; i <= length(_mystring) ; i++ )
    _bcc = _bcc ^ asc( substr(_mystring,i,1) )

  _bcc = _bcc ^ _ETX

  return(_bcc)
}'

def _euro_read(address,channel, str) '{
  local mycom ret _bcc _d1

  if (channel == 0){ 
	channel = ""
  }

  mycom = sprintf("%c%s%s%s%c", _EOT, _EUROADDRESS, channel, str, _ENQ)
  ser_put(address, mycom)

  ret = ser_get(address, sprintf("%c", _ETX))

  _bcc = ser_get(address,1)

  if (asc(_bcc) != _euro_calc_bcc(ret)) {
    printf("%s : Communication error with Eurotherm; wrong bcc %s<>%s\n" \
                        , str, asc(_bcc), _euro_calc_bcc(ret))
    ret = 0.0
  } else {
    _d1=substr(ret,index(ret,str)+length(str))
    sscanf (_d1,"%g",ret);
    if (ret=="") {
      printf("Communication error with Eurotherm ...timeout!\n")
                  ret=0.0
          }
  }

  return(ret)
}'

def _euro_write(address, type, channel, value) '{
  local _mycom _bcc _str

  if (type == "EURO900") {
	if (channel == 2) {
  		_str = sprintf("S2%g", value)
	}else {
  		_str = sprintf("SL%g", value)
        }
  	_mycom = sprintf("%c%s%c%s%c", _EOT, _EUROADDRESS, _STX, _str, _ETX)

  } else {
  	if (channel == 0) {
		channel = ""
  	}
  	_str = sprintf("SL%g", value)
  	_mycom = sprintf("%c%s%c%s%s%c", _EOT, _EUROADDRESS, _STX,channel, _str, _ETX)
  }

  _bcc = _euro_calc_bcc_stx(_str)

  ser_put(address, _mycom)

  ser_put(address, sprintf("%c",_bcc))

  _bcc = ser_get(address, 1)

  return(1)
}'

#%IU% (address,channel)
#%MDESC% return true if EuroTherm 2000 support more than one prg
def _euro_multiprg(address, channel) '{
  local _mycom _bcc _str _ret
  if (channel == 0){ 
	channel = ""
  }

  _mycom = sprintf("%c%s%s%s%c", _EOT, _EUROADDRESS, channel, "PN", _ENQ)
  ser_put(address, _mycom)
  #flush the line
  _str = ser_get(address)
  
  # now ask for the  error state on comm, if 1 is returned 
  # the mnemonic "PN" is not recognized, so it means this eurotherm 2000
  # does not support more than 1 prg.
  p _ret = _euro_read(address,channel,"EE")+0
  if (_ret == 0) return 1
  else return 0
}'

#%IU% (action,value,interface,address,sleept,channel)
#%MDESC% EuroTherm 2000 series command Interface.

def _tc_euro (action,name,value,interface,address,sleept,channel) '{

  global _EUROADDRESS
  global _STX _ETX _EOT _ENQ _ACK _NAK
  local ret _bidon _gr _ad _command _eurocommand
  local par[]

  _STX=02 ; _ETX=03 ; _EOT=04 ; _ENQ=05 ; _ACK=06 ; _NAK=15 ;

  ret = value

  type = _tc_check_dev(name)

  if ("sp"==action){
    _euro_write(address, type, channel, value)
  }

 if ("rt"==action) {
    ret = _euro_read(address,channel, "PV")
  }

  if ("lim"==action)
    print "Warning:No Hardware Limits Set"

  if ("ramp"==action);

  if ("setup"==action) {
    split (value,_bidon,"  ") # bidon[0] = pars , bidon[1]= name
    split (_bidon[0],par,":") # par[0]= group_id , par[1] = euroaddress
    #p "Group: " par[0]  "      Euroaddres: " par[1]
    # par shoud be a number XY where X is the group and Y the address
    _EUROADDRESS=sprintf("%s%s%s%s",par[0],par[0],par[1],par[1])
    return 1 # no of eurotherms
  }

  return ret
}'

###############################################################################


  ####      #    #    #  #    #  #         ##     #####     #     ####   #    #
 #          #    ##  ##  #    #  #        #  #      #       #    #    #  ##   #
  ####      #    # ## #  #    #  #       #    #     #       #    #    #  # #  #
      #     #    #    #  #    #  #       ######     #       #    #    #  #  # #
 #    #     #    #    #  #    #  #       #    #     #       #    #    #  #   ##
  ####      #    #    #   ####   ######  #    #     #       #     ####   #    #




#%IU% (action,value)
#%MDESC% SIMULATION of a temperature control command interface.

def _tc_sim (action,value) '{
  
  global ST_SP0 ST_SP ST_SPT0 ST_TC
  local par

  split(value,par,"  ")

  if ("sp"==action) {
    ST_SP0=ST_SP
    ST_SP=value
    ST_SPT0=time()
  }

  if ("rt"==action) {
    _tc = ST_TC?ST_TC:5
    _t=time()-ST_SPT0
    _e=ST_SP-ST_SP0
    value= (ST_SP-_e*exp(-_t/_tc))
  }

  if ("setup"==action) {
    ST_TC = par[0]
    print "Simulation of Temperature Control"
    value = 0
  }

  if ("lim"==action)
    print "Warning:No Hardware Limits Set"


  return value
}'


#############################################################################



    #    #       #
    #    #       #
    #    #       #
    #    #       #
    #    #       #
    #    ######  ######



#%IU% (action,value)
#%MDESC%  ILL SAMPLE ENVIRONMENT CONTROLLER Command interface.

def _tc_ill (action,value,interface,address,sleept,channel) '{

  global ILL_PROMPT
  local cmd par n 
  n=split(value,par,"  ")

  cmd = ""

  if ("sp"==action)
    cmd = sprintf("sp %g", value)

  if ("rt"==action)
    cmd = "rt -v" 

  if ("lim"==action)
    cmd = sprintf ("lim sph=%g spl=%g",par[0],par[1])

  if ("ramp"==action);

  if ("setup"==action) {
    if (par[0]>0) 
      ILL_PROMPT=sprintf("%s",par[0])
    else 
      ILL_PROMPT="ILLSEC:/dd> "

    cmd = sprintf("tmode noecho;initio -;-p=\"%s\"",ILL_PROMPT)
    print "  ILL Sample Environment Controller." 

  }
    
  global ILL_RET []

#  if (cnt_num("T_%s")<0) ret=_tc_io ();split(ret,ILL_RET);S[]=ILL_RET[2]

#  cdef ("user_getcounts",sprintf("if (cnt_num(\"T_%s\")<0) {local ret;ret=_tc_io(\"%s\",\"%s\",%g,\"rt -v \\r\",\"\\n\");split (ret,ILL_RET)}; S[T1%s]=ILL_RET[2]\n",par[n-1],interface,address,sleept,par[n-1]),sprintf("T1%s",par[n-1]),0x22)

  if (cmd!="") 
    cmd = cmd "\r" 

  ret = _tc_io (interface,address,sleept,cmd,ILL_PROMPT) 
  split (ret,ILL_RET)
  ret=ILL_RET[1]

  if (action=="sp") {
    ret = value
  }
  return ret
}'

#############################################################################


####### #######   ###     ###
#       #    #   #   #   #   #
#           #   #     # #     #
#####      #    #     # #     #
#         #     #     # #     #
#         #      #   #   #   #
#         #       ###     ###


#%IU% (action,value)
#%MDESC%  Automatic Systems Laboratories F700 command interface.

def _tc_f700 (action,value,interface,address,sleept,channel) '{

  global F700_SETPOINT
  local cmd par n

  n   = split(value,par,"  ")
  cmd = ""

  if ("sp"==action) {
    local ratio
    ratio=_f700_ratio(value)
#    if (_tc_io (interface,address,sleept,sprintf("P%8.6f\r\n",ratio),-1) <0)
#      return -1
    _tc_io (interface,address,sleept,sprintf("P%8.6f\r\n",ratio))
    F700_SETPOINT=value
    return F700_SETPOINT;
  }

  if ("rt"==action)
    return F700_SETPOINT;

  if ("lim"==action);

  if ("ramp"==action);

  if ("setup"==action) {
   
    local ret

    #par[0]#temperature
    #par[1]#gain
    #par[2]#current
    #par[3]#bandwidth
    #par[4]#clear flag

    print "  Automatic Systems Laboratories F700 Bridge."

#    if (par[4]==1) {
#      if (_tc_io (interface,address,sleept,"K\r\n",-1) <0)
#        return -1
#    }
#    if (_tc_io (interface,address,sleept,sprintf("G%d\r\n",par[1]),-1) <0)
#      return -1
#    if (_tc_io (interface,address,sleept,sprintf("C0%d\r\n",par[2]),-1) <0)
#      return -1
#    if (_tc_io (interface,address,sleept,sprintf("B%d\r\n",par[3]),-1) <0)
#      return -1
#    if (_tc_io (interface,address,sleept,"E0\r\n",-1) <0)
#      return -1

    if (par[4]==1) 
      _tc_io (interface,address,sleept,"K\r\n") 
    _tc_io (interface,address,sleept,sprintf("G%d\r\n",par[1]))
    _tc_io (interface,address,sleept,sprintf("C0%d\r\n",par[2])) 
    _tc_io (interface,address,sleept,sprintf("B%d\r\n",par[3])) 
    _tc_io (interface,address,sleept,"E0\r\n")

    if (par[0]!=0) {
      local ratio
      F700_SETPOINT=par[0]+0
      ratio=_f700_ratio(par[0])
      cmd = sprintf("P%8.6f\r\n", ratio)
      return _tc_io (interface,address,sleept,cmd)
    }
  }
  
  return 0
}'


#%IU% (temperature)
#%MDESC% Converts temperature value into a ratio to feed the F700 controller.
def _f700_ratio (val) '{


  local _a_ _b_ _c_ ratio

  _a_=1.000012 ;  _b_=4.070399e-3 ;  _c_=-2.836229e-6

  ratio = _a_ + _b_*val + _c_*val*val

  return ratio

# _a_=1.000005 ;  _b_=4.00e-3 ;  _c_=6.52e-7
#  ratio = 1.000012 + (4.070399e-3*val) - (2.836229e-6*val*val) 

}'


#############################################################################

#######  #####   #####
#       #     # #     #
#             # #
#####    #####  ######
#       #       #     #
#       #       #     #
#       #######  #####


#%IU% (action,value)
#%MDESC%  Alpha-Sigma-Lambda F26 temperature bridge control.

def _tc_f26 (action,value,interface,address,sleept,channel) '{

  local cmd par n mode
  n=split(value,par,"  ")

  cmd = ""

  if ("sp"==action) {
    global F26_SETPOINT
    F26_SETPOINT=value
    cmd = sprintf("p%f",value)
    mode = ""
    sleept = 2

#### This stupid controller sends us the old temp value if we do not wait
#### for at least 2 seconds. !!!!!!!! So take a nap

  }

  if ("rt"==action) {
     return F26_SETPOINT

#    cmd = "d"
#    mode="/r/n"
  }
#  if ("lim"==action);

#  if ("ramp"==action);

  if ("setup"==action) {

    #par[0]#current 0,1,2,3 as 0.1,0.3,1,3
    #par[1]#sensitivity 0,1,2 as low, med, high

#    cmd=sprintf("P%d\rI%d\rD%d",par[0],par[1],par[2])
 
    _tc_io (interface,address,sleept,sprintf("s%d\r",par[1]))
    _tc_io (interface,address,sleept,sprintf("i%d\r",par[0]))
    _tc_io (interface,address,sleept,"u2\r") #degrees celcius
    _tc_io (interface,address,sleept,"m2\r") #deviation mode

    print "  Alpha-Sigma-Lambda F26 Bridge."
  
    return 0
  }
    
  if (cmd!="") 
    cmd = cmd "\r" 

  ret = _tc_io (interface,address,sleept,cmd,mode)

  if (action=="rt") {
#    local reta
#    global F26_RET 
#    F26_RET=ret
#    ret=substr(F26_RET,2,8)
#    ret+=F26_SETPOINT
# OR
#   split (ret,reta)
#   F26_RET=reta[0]
#   May be the deviation to the reference !

  }
  if (action=="sp") {
    ret = value
  }

  return ret
}'




###############################################################################
###############################################################################
#                C O N D U C T U S   L T C - 2 0

						#       #######  #####           #####    ###
						#          #    #     #         #     #  #   #
						#          #    #                     # #     #
						#          #    #        #####   #####  #     #
						#          #    #               #       #     #
						#          #    #     #         #        #   #
						#######    #     #####          #######   ###


#%IU% (action,value,interface,address,sleept,channel)
#%MDESC% Conductus LTC-20 command interface.

def _tc_ltc20 (action,name,value,interface,address,sleept,channel) '{
  local cmd par n mode read_value
  mode=-1

  n   = split(value,par,"  ")
  cmd = ""

  if ("setup"==action) {
		# set controller to control mode
    if (_tc_io (interface,address,sleept,"SCONT;","") < 0) return -1
    if (_tc_io (interface,address,sleept,"SLLOCK1;","") < 0) return -1
		# force to Kelvin
    if (_tc_io (interface,address,sleept,sprintf("SUNIT%d,K;\r\n",channel),"") < 0) return -1
		# just read something to be sure communication is established.
    if (_tc_io (interface,address,sleept,sprintf("QUNIT?%d;\r\n",channel),"x") < 0) return -1

    print "  Conductus LTC-20 - Cryogenic Temperature Controller. Channel",\
			channel, "."
		return(0)
  }

  if ("sp"==action) {
    cmd = sprintf("SETP%d,%4.1f%c;", channel, value, LTC20_unit)
		mode = 0 # dont read anything back!
	}

  if ("rt"==action) {
		# issues 11 chars with unit character attached.
    read_value = _tc_io (interface,address,sleept,sprintf("QSAMP?%d;", channel),-1)
		if(substr(read_value, "K")) {
			read_value = substr(read_value, "", 10);
			read_value = read_value * 1.0
		}
		return(read_value)
	}

  if ("lim"==action);
  if ("ramp"==action);

	ret= _tc_io (interface,address,sleept,cmd,mode)

  if (action=="sp") {
    ret = value
  }

  return ret


}'

###############################################################################
###############################################################################
#                L a k e S h o r e 2 0 0 

							#        #####   #####    ###     ###
							#       #     # #     #  #   #   #   #
							#       #             # #     # #     #
							#        #####   #####  #     # #     #
							#             # #       #     # #     #
							#       #     # #        #   #   #   #
							#######  #####  #######   ###     ###


#%IU% (action,value,interface,address,sleept,channel)
#%MDESC% LakeShore 200 series command interface.

def _tc_ls200(action, name, value, interface, address, sleept, channel) '{
#DBG
#print "\n_tc_ls200",action,name,value,interface,address,sleept,channel
  local cmd par n mode read_value unit cname type loop looptxt res
  mode=""
  n   = split(value,par,"  ")
  cmd = ""

  if ("setup"==action) {
		local x
		n = split(par[0],x,":")
		unit  = x[0]
		if ( n > 1 ) {
			loop  = x[1]
			looptxt = sprintf("and heater control loop %d", loop)
      list_setpar(TC, name,"loop",loop)
		} else {
      looptxt = "no heater control loop"
      list_removepar(TC, name,"loop")
    }
		# set controller to control mode
    if (_tc_io (interface,address,sleept,"MODE1\r\n","")<0) return -1 # remote withour local locking

    list_setpar(TC, name,"unit",unit)
    print "  LakeShore Series", type == "LS200" ? "200" : "300", \
			"\nTemperature Controller. Channel",\
			channel, "with reading unit", unit, looptxt "."
  }

  type = list_getpar(TC, name,"type")
  unit = list_getpar(TC, name,"unit")

	if (type != "LS200")
  	if ("sp"==action) {
      if ((loop = list_getpar(TC, name, "loop")) != -1) {
    	  cmd  = sprintf("SETP%s,%4.1f\r\n", loop, value)
			  mode = "" # dont read anything back!
      }
		}

  if ("rt"==action) {
		# issues 11 chars with unit character attached.
  	cmd = sprintf("%sRDG?%s\r\n", unit, channel)
		read_value = _tc_io (interface,address,sleept,cmd,-1) * 1.0
		return(read_value)
	}

  if ("lim"==action);
  if ("ramp"==action) {
    local par, ramprate
    n   = split(value,par,"  ")
    if (par[1] != 0) {
      print "Usage: tcramp motor_mne ramp_rate"
      exit
    }
    if ((loop = list_getpar(TC, name, "loop")) == -1) {
      print "tcramp: no heater control loop attributed to this channel!"
      exit
    }
    channel   = list_getpar(TC, name, "ch")
    interface = list_getpar(TC, name, "intf")
    address   = list_getpar(TC,name,"add")
    sleept    = list_getpar(TC,name,"slp")
    ramprate = par[0] * 1.0
    print "All movements for motor", name, "will cause the LakeShore (channel", channel ")" 
    print "on control loop", loop, "to ramp by", ramprate, "K/minute."
		mode = "" # dont read anything back!
    if (ramprate == 0) { # ramp off
    	cmd  = sprintf("RAMP%d,0,0.0", loop)
    } else { # ramp on with ramprate
    	cmd  = sprintf("RAMP%d,1,%f", loop, ramprate)
    }
  }

  #do not wait for a response in setup phase ...
  if ("setup"==action) {return}

  res= _tc_io (interface,address,sleept,cmd,mode)

  if ("sp"==action) {
     return value
  } else {
     return res
  }
}'

###############################################################################
###############################################################################
#                L a k e S h o r e 3 0 0 

							#        #####   #####    ###     ###
							#       #     # #     #  #   #   #   #
							#       #             # #     # #     #
							#        #####   #####  #     # #     #
							#             #       # #     # #     #
							#       #     # #     #  #   #   #   #
							#######  #####   #####    ###     ###

#%IU% (action,value,interface,address,sleept,channel)
#%MDESC% LakeShore 300 series command interface.

def _tc_ls300 '_tc_ls200'
# use the same stuff as for LakeShore200 although the 200 series 
# does not allow the set point command, but it wont hurt neither.

#%IU% motor_mnemonic
#%MDESC% LakeShore 300 series command interface.
def LS300_heater_off '{
	if ( $# != 1) {
		print "Only argument should be the motor mnemonic!"
		return
	}
	if(motor_num("$1") == -1) {
		print "No such motor!"
		return
	}

    local address interface cmdstr
    address   = list_getpar(TC,"$1","add")
    interface = list_getpar(TC,"$1","intf")
    cmdstr = "RANGE 0\r\n"

    if ("RS232"==interface) 
        ser_put(address,cmdstr)

    if ("GPIB"==interface)
        gpib_put(address, cmdstr);


}'

#%IU% motor_mnemonic
#%MDESC% LakeShore 300 series command interface.
def LS300_heater_setrange '{
	if ( $# != 2) {
		print "First argument should be the motor mnemonic!"
		print "Second argument should be the range value to be sent."
		print "For the LakeShore 300 series that would be :"
		print "   0 = off"
		print "   1 = Low     ( 0.5 W)"
		print "   2 = Medium  ( 5 W)"
		print "   3 = High    (50 W)"
		return
	}
	if(motor_num("$1") == -1) {
		print "No such motor!"
		return
	}


    local address interface cmdstr
    address   = list_getpar(TC,"$1","add")
    interface = list_getpar(TC,"$1","intf")
    cmdstr = sprintf("RANGE %s\r\n", "$2")

    if ("RS232"==interface) 
        ser_put(address,cmdstr)

    if ("GPIB"==interface)
        gpib_put(address, cmdstr);

}'

#%UU% (num)
#%MDESC% Flushes out data from serial line.
def serialflush (num) '{
  #remove that (spec display timeout errors)
  #print ser_get(num,"")
  ser_par(num,"flush",2)
}'

#%UU% (address)
#%MDESC% clean up gpib communication.
def gpibflush (address,st) '{
  while (gpib_poll(address)&st) 
    print gpib_get(address)
}'

###############################################################################
###############################################################################
#                Eurotherm 2400 series programming


        ####### #     # ######  ####### ######  ######  #######  #####
        #       #     # #     # #     # #     # #     # #     # #     #
        #       #     # #     # #     # #     # #     # #     # #
        #####   #     # ######  #     # ######  ######  #     # #  ####
        #       #     # #   #   #     # #       #   #   #     # #     #
        #       #     # #    #  #     # #       #    #  #     # #     #
        #######  #####  #     # ####### #       #     # #######  #####


#%IU%
#%MDESC% 
# a function to define macros, if needed by temperature.mac, while eurotherm2400
# isn`t loaded.
def __define__europrog() '{
#
#  DFC : 1/Oct/2004
#
# This is a macro set to write and read programs in the Eurotherm.
# it has been beta-tested on ID19 with a Eurotherm 2408 
# 
#
# /dev/ttyS1 is giving timeouts ... but
# /dev/ttyx3 (moxa ethernet hub) works fine ???... a suivre
# 
MAX_SEGMENTS = 16

#%IU% (serial_line_number ,string_to_send )
#%MDESC% this is a special macro for europrog 
# sends an arbitrary string to euro2000
rdef _my_euro_write(address, _str) \'{
  local _mycom _bcc
   
  _mycom = sprintf("%c%s%c%s%c", _EOT, _EUROADDRESS, _STX, _str,  _ETX)
  _bcc = _euro_calc_bcc_stx(_str)

  ser_put(address, _mycom)

  ser_put(address, sprintf("%c",_bcc))

  _bcc = ser_get(address, 1)
  
      	   # giving timeouts and testing ... l idee de HG
	   # /dev/ttyS1 is giving timeouts ... but
	   # /dev/ttyx3 (moxa ethernet hub) works fine ???... a suivre
           # 

  sleep(.1)

  return(1)
}
\'

#%IU% (serial_line_number ,string_to_send )
#%MDESC% this is a special macro for europrog 
# sends an arbitrary string to euro2000 and returns 
# the result
rdef _euro_com(address, _str, val) \'{
	local _cmd

	_cmd = sprintf("%s%g",_str, val)
	_my_euro_write(address,  _cmd); 
	return _euro_read(address, channel, _str)

}
\'

#%IU% (serial_line_number ,eurochannel )
#%MDESC% this is a special macro for europrog 
#  writes a EURO2000 series program 

rdef _europrog_write(address) \'{
	global SEGMENT[] PROGRAM_NUMBER
	local ii _cmd _ret
	local _units[]  _ssym _ramp_units _dwell_units

	_units[0]="secs" ; _units[1]="mins" ; _units[2]="hour" ; 
	_ssym[1]="1";  _ssym[2]="2";  _ssym[3]="3";  _ssym[4]="4";  
	_ssym[5]="5";  _ssym[6]="6";  _ssym[7]="7";  _ssym[8]="8"; 
	_ssym[9]="9";  _ssym[10]=":"; _ssym[11]=";"; _ssym[12]="<"; 
	_ssym[13]="="; _ssym[14]=">"; _ssym[15]="?"; _ssym[16]="@";

	PROGRAM_NUMBER = getval("Set pars for program number", PROGRAM_NUMBER)
	
	# Reading old program	
	_europrog_read(address, PROGRAM_NUMBER)
	printf("------------------------------------------")
	printf("------------------------------------------\n")
	printf("------------------------------------------")
	printf("------------------------------------------\n")

	_cmd = sprintf("EP%d",PROGRAM_NUMBER)
	_my_euro_write(address,  _cmd);  p _euro_read(address, channel,"EP")

	#holdback type: low
	SEGMENT[0][0] = getval("Holdback type (0:None, 1:Low, 2:High, 3:Band)",\
								SEGMENT[0][0])  
	_cmd = sprintf("\$0%d",SEGMENT[0][0])
	_my_euro_write(address, _cmd); #p _euro_read(address, channel,"\$0")

	SEGMENT[0][1] = getval("Holdback value", SEGMENT[0][1])  
	_cmd = sprintf("s0%d",SEGMENT[0][1])
	_my_euro_write(address, _cmd); #p _euro_read(address, channel,"s0")

	SEGMENT[0][2] = _ramp_units = \
		getval("Ramp units (0:secs, 1:mins, 2:hours)", SEGMENT[0][2])  
	_cmd = sprintf("d0%d",SEGMENT[0][2])
	_my_euro_write(address, _cmd); #p _euro_read(address, channel,"d0")

	SEGMENT[0][3] = _dwell_units = \
		getval("Dwell units (0:sec, 1:min, 2:hrs)", SEGMENT[0][3])  
	_cmd = sprintf("p0%d",SEGMENT[0][3])
	_my_euro_write(address, _cmd); #p _euro_read(address, channel,"p0")

	#SEGMENT[0][4] = getval("Cycles", SEGMENT[0][4])  
	SEGMENT[0][4] = getval("Cycles", 1)  
	_cmd = sprintf("o0%d",SEGMENT[0][4])
	_my_euro_write(address, _cmd); #p _euro_read(address, channel,"o0")

	# segments
	for (ii = 1 ; ii <= MAX_SEGMENTS ; ii++ ) { 
		printf("------------------------------------------")
		printf("------------------------------------------\n")
		p "\tSegment #" ii
		p
		_ret = getval(\
"\tType 0:End, 1:Ramp(rate) 2:Ramp(time) 3:Dwell 4:Step 5:Call program",\
							SEGMENT[ii][0])  
		if (_ret > 5 || _ret <0 ) {
			p "Type has to be between 0 and 5"
		} else {
			_cmd = sprintf("\$%s",_ssym[ii])
			_euro_com(address, _cmd, _ret)
			SEGMENT[ii][0] = _ret
			if (_ret == 0 ) {
				SEGMENT[ii][1] = getval(\
"\tEnd action (0:Indefinite_Dwell, 1:Reset, 2:SetOutput)", SEGMENT[ii][1])  
				_cmd = sprintf("p%s",_ssym[ii])
				_euro_com(address, _cmd, SEGMENT[ii][1])
				p 
				p "End type... this is the last segment !!!"
				exit
			}
			if (_ret == 1 ) {
				SEGMENT[ii][1] = getval("\tRamp target", \
								SEGMENT[ii][1])
				_cmd = sprintf("s%s",_ssym[ii])
				_euro_com(address, _cmd, SEGMENT[ii][1])

				SEGMENT[ii][2] = getval(sprintf(\
"\tRamp rate deg/%4s",_units[_ramp_units]), SEGMENT[ii][2])  
				_cmd = sprintf("d%s",_ssym[ii])
				_euro_com(address, _cmd, SEGMENT[ii][2])
			}
			if (_ret == 2 ) {
				SEGMENT[ii][1] = getval("\tRamp target", \
								SEGMENT[ii][1])
				_cmd = sprintf("s%s",_ssym[ii])
				_euro_com(address, _cmd, SEGMENT[ii][1])

				SEGMENT[ii][2] = getval(sprintf(\
"\tRamp duration (%4s)",_units[_ramp_units]), SEGMENT[ii][2])  
				_cmd = sprintf("d%s",_ssym[ii])
				_euro_com(address, _cmd, SEGMENT[ii][2])
			}
			if (_ret == 3 ) {
				SEGMENT[ii][1] = getval(sprintf(\
"\tDwell duration (%4s)",_units[_dwell_units]), SEGMENT[ii][1])  
				_cmd = sprintf("d%s",_ssym[ii])
				_euro_com(address, _cmd, SEGMENT[ii][1])
			}
			if (_ret == 4 ) {
				SEGMENT[ii][1] = getval("\tTarget", \
								SEGMENT[ii][1])
				_cmd = sprintf("s%s",_ssym[ii])
				_euro_com(address, _cmd, SEGMENT[ii][1])
			}
			if (_ret == 5 ) {
 _cmd = sprintf("\tCall program (program number has to be >%d ",_euro_read(address,channel,"EP"))
				_euro_read(address,channel,"EP")
				SEGMENT[ii][1] = getval("Jump to prog", SEGMENT[ii][1])
				_cmd = sprintf("p%s",_ssym[ii])
				_euro_com(address, _cmd, SEGMENT[ii][1])
			}
		}
	}
}
\'


#%IU% (serial_line_number ,euro_program_number )
#%MDESC% this is a special macro for europrog 
#  reads a EURO2000 series program 
rdef _europrog_read(address, program_number) \'{
	global SEGMENT
	local ii _cmd _ret _mytype
	local _units[]  _ssym _ramp_units _dwell_units

	_units[0]="sec" ; _units[1]="min" ; _units[2]="hour" ; 
	_ssym[1]="1"; _ssym[2]="2"; _ssym[3]="3"; _ssym[4]="4"; _ssym[5]="5";
	_ssym[6]="6"; _ssym[7]="7"; _ssym[8]="8"; _ssym[9]="9"; _ssym[10]=":";
	_ssym[11]=";";_ssym[12]="<";_ssym[13]="=";_ssym[14]=">";_ssym[15]="?";
	_ssym[16]="@";
	p "Reading values from Eurotherm"
	if (program_number >=0) {
		_ret = program_number
	} else {
		_ret = getval("Program number",_euro_read(address,channel,"EP"))
	}
        
	if (_ret != PROGRAM_NUMBER) {
		p 
		p " Default program number in SPEC  is     : " PROGRAM_NUMBER
		p " Default program number in EUROTHERM is : " _ret
		PROGRAM_NUMBER = getval("Choose the default working program", _ret)
		_cmd = sprintf("EP%d",PROGRAM_NUMBER)
		_my_euro_write(address,  _cmd)
		p _euro_read(address, channel,"EP")
	}
	printf("------------------------------------------")
	printf("------------------------------------------\n")
	p" Reading parameters from program number "_euro_com(address,"EP",_ret)

	SEGMENT[0][0] = _euro_read(address, channel,"\$0")
	p " Holdback type (0=None, 1=low, 2=high, 3=Band) : " SEGMENT[0][0]

	SEGMENT[0][1] =  _euro_read(address, channel,"s0")
	p " Holdback value                                : " SEGMENT[0][1]

	_ramp_units =  _euro_read(address, channel,"d0")
	p " Ramp units  (0=secs, 1=mins, 2=hours)         : " _ramp_units
	SEGMENT[0][2] = _ramp_units

	_dwell_units =  _euro_read(address, channel,"p0")
	p " Dwell units (0=secs 1=mins 2 hours)           : " _dwell_units
	SEGMENT[0][3] = _dwell_units

	SEGMENT[0][4] = _euro_read(address, channel,"o0")
	p " Number of cycles                              : " SEGMENT[0][4]

	# segments
	for (ii = 1 ; ii <= MAX_SEGMENTS ; ii++ ) { 
		p
		printf("------------------------------------------")
		printf("------------------------------------------\n")
		p "   Segment #" ii
		printf(\
"\tType (0:End, 1:Ramp(rate), 2:Ramp(time), 3:Dwell, 4:Step, 5:CallProgram) : \n")
		_cmd = sprintf("\$%s",_ssym[ii])
		_mytype =  _euro_read(address, channel,_cmd)
		SEGMENT[ii][0] = _mytype
		if (_mytype == 0 ) {
			_cmd = sprintf("p%s",_ssym[ii])
			SEGMENT[ii][1] =  _euro_read(address, channel,_cmd)
			print \
"\tEnd action (0:Indefinite_Dwell, 1:Reset, 2:SetOutput)     :  " SEGMENT[ii][1]
			break
		}
		if (_mytype == 1 ) {
			_cmd = sprintf("s%s",_ssym[ii])
			SEGMENT[ii][1] =  _euro_read(address, channel,_cmd)
			print\
"\tRamp target                                              :  " SEGMENT[ii][1]
			_cmd = sprintf("d%s",_ssym[ii])
			SEGMENT[ii][2] =  _euro_read(address, channel,_cmd)
			printf("\tRamp rate   deg/%3s                                      : %g",_units[_ramp_units],SEGMENT[ii][2])
		}
		if (_mytype == 2 ) {
			_cmd = sprintf("s%s",_ssym[ii])
			SEGMENT[ii][1] =  _euro_read(address, channel,_cmd)
			print \
"\tRamp target                                              :  " SEGMENT[ii][1]
			_cmd = sprintf("d%s",_ssym[ii])
			SEGMENT[ii][2] =  _euro_read(address, channel,_cmd)
			printf(\
"\tRamp duration  (%3s)                                     : %g",\
					_units[_dwell_units],SEGMENT[ii][2])
		}
		if (_mytype == 3 ) {
			_cmd = sprintf("d%s",_ssym[ii])
			SEGMENT[ii][1] =  _euro_read(address, channel,_cmd)
			printf(\
"\tDwell duration  (%3s)                                   : %g",\
					_units[_dwell_units],SEGMENT[ii][1])
		}
		if (_mytype == 4 ) {
			_cmd = sprintf("s%s",_ssym[ii])
			SEGMENT[ii][1] =  _euro_read(address, channel,_cmd)
			print \
"\tTarget                                                   :  " SEGMENT[ii][1]
		}
		if (_mytype == 5 ) {
			_cmd = sprintf("p%s",_ssym[ii])
			SEGMENT[ii][1] =  _euro_read(address, channel,_cmd)
			print \
"\tJump to program                                          :  " SEGMENT[ii][1]
		}
	}
	printf("------------------------------------------")
	printf("------------------------------------------\n")
}
\'

#%IU% (serial_line_number ,value )
#%MDESC% this is a special macro for europrog 
#  Sends a program control command to the euro2000
rdef _europrog_cmd(address, _val) \'{
	local _cmd _ret _states
	_states[1]= "RESET"   ; _states[2] ="RUN"       ; _states[4]="HOLD"; 
	_states[8]= "HOLDBACK"; _states[16]="COMPLETED"
	
	_ret =  _euro_read(address, channel,"PC")
	printf("\rProgram state is ")
	
	# _ret is not power of 2
	if ((_ret-1) & _ret) 
		print "UNKNOWN=" _ret
	else			
		print _states[_ret]
	
	#returns the state
#	if (_val == -1)  {
#		return _ret
#	}
	if ((_val-1) & _val) {
		# _val is not power of 2
		_europrog_status(address, _ret)
	} else {
#	        TOO MANY QUESTIONS... Commented out for the moment
#		if (yesno(sprintf("Do you want to %s the program",\
#							_states[_val]), 1)) {
#			_cmd = sprintf("PN%d",PROGRAM_NUMBER)
#			_my_euro_write(address, _cmd);
#			_ret =  _euro_read(address, channel,"PN")
#			p "Working program : " _ret 
#			if (PROGRAM_NUMBER != _ret && _val==2 ) { 
#				p "\tCAUTION!!!. Couldnt change the active prg#"
#				p "\tMake sure the previous prgram is RESET"
#				p "\tDo I resume/restart program  #" _ret
#				if (yesno("?",0) ==0)
#					exit
#			}
#			_cmd = sprintf("PC%d",_val)
# 			_my_euro_write(address, _cmd); 
#			p _euro_read(address, channel,"PC")
#			print "Sending " _states[_val] " to program " _ret
#		}else {
#			p "Nothing done"
#			exit
#		}
		_cmd = sprintf("PC%d",_val)
 		_my_euro_write(address, _cmd); 
		print "Sending " _states[_val] " to program "
 
	}
	_ret =  _euro_read(address, channel,"PC")
	return _ret
}
\'


#%IU% (serial_line_number ,value )
#%MDESC% this is a special macro for europrog 
#  Reads the status of the program of the  euro2000 
	
rdef _europrog_status(address, _state) \'{
	local _tags _cmd _ii _vao _mytype
 	_tags[0][1] = \
		"\t1.-Programmer active                :  " ; _tags[1][1]="PN"
 	_tags[0][2] = \
		"\t2.-Programmer setpoint              :  " ; _tags[1][2]="PS" 
 	_tags[0][3] = \
		"\t3.-Program cycles remaining         :  " ; _tags[1][3]="CL" 
 	_tags[0][4] = \
		"\t4.-Current segment number           :  " ; _tags[1][4]="SN" 
 	_tags[0][5] = \
		"\t5.-Current segment type             :  " ; _tags[1][5]="CS"
 	_tags[0][6] = \
		"\t6.-Segment time remaining (secs)    :  " ; _tags[1][6]="TS"
 	_tags[0][7] = \
		"\t7.-Segment time remaining (mins)    :  " ; _tags[1][7]="PM"
 	_tags[0][8] = \
		"\t8.-Target setpoint (current segment):  " ; _tags[1][8]="CT"
 	_tags[0][9] = \
		"\tProgram time remaining "                 ; _tags[1][9]="TP" 

	if (_state == 1 || _state == 16) {
# L.Claustre 30/11/2006
# 		p "\tProgrammer active                :  " \
#					 _euro_read(address, channel,"PN")
#		p "Cant read the status when reset or completed"
	} else {
		_mytype = 0
# L.Claustre 30/11/2006
#		for (_ii=1;_ii<10 ; _ii++) {        
		for (_ii=2;_ii<10 ; _ii++) {
			if (_ii == 6) {
                                # it is the 6 because _val corresponds
				# to the previous iteration :-)
                                # segment type ... check for dwell
                                _mytype = _val
                        }
			
			#if not a dwell does not do anythning
			if (_ii == 8  && _mytype == 3) { 
				print
			} else {
			 	_val =_euro_read(address, channel,_tags[1][_ii])
				print _tags[0][_ii] _val
			}
			if (_ii == 8  )
				p "\t9.-Skip Segment                      " 
		}
		_cmd = getval("Change ", 0)
		if (_cmd && (_cmd < 9)) {
			_val = getval(_tags[0][_cmd], -1) 
			_cmd = sprintf("%s%d",_tags[1][_cmd], _val)
			if (_europrog_cmd(address, 4)  != 4 ) {# hold
				p " Not hold, may be completed ... exit"
				exit;
			} else {
				_my_euro_write(address, _cmd); 
				_europrog_cmd(address, 2) # run ... (again)
			}
			p _euro_read(address, channel,"PC")
		} else if (_cmd == 9 ){
			if (_europrog_cmd(address, 4)  != 4 ) {# hold
				p " Not hold, may be completed ... exit"
				exit;
			} else {
				#remaining time 1sec
				_my_euro_write(address, "TS1"); 
				_europrog_cmd(address, 2) # run ... (again)
			}
		} else {
			if (_cmd)
				p "Cant change that ... sorry ... "
		}		
	}
}
\'


#%UU% < run | reset | hold | holdback | complete | status | read | write > <program_number>
#%MDESC% macro to manage programs in the eurotherm 2000 series. It has been
# tested on ID19 with a EUROTHERM 2408i . I do not think it works with EURO900
#   
rdef europrog \'{
	global SEGMENT[] PROGRAM_NUMBER MANSETPOINT
	global MY_TC
	local channel address _cmd _ret ident
	# change this if you have several temperature controllers
	if (MY_TC==0)
		MY_TC = 1
	if (list_getpar(TC,MY_TC,"type") !="EURO") {
		print "This is not a eurotherm 2000. If you have several "
		print "temperature controllers try to set MY_TC to the one "
		print "which is of type EURO "
		print "i.e. type MY_TC=1... "
		exit
	}
	# macros _euro_read and _my_euro_write may not work outside this macro 
	# (channel and address are locals
        #
	channel = list_getpar(TC,MY_TC,"ch")
	address   =list_getpar(TC,MY_TC,"add")
    
         
        sscanf(_euro_read(address, channel,"II"),"%4*s%d%*s",ident)
        if(ident <2000) {
          p "This is not an eurotherm 2000 "
          p "Check you connect the right controller "
          exit
        }

        # Fix here the max. number of segments according the controller limit
        _ret = _euro_read(address, channel,"ns")+0
        MAX_SEGMENTS = _ret        
	if ($2) {
		PROGRAM_NUMBER = $2
		p 
		p "Setting default program number to " $2
	}
	if (PROGRAM_NUMBER == "" )
		PROGRAM_NUMBER=1
	p "Default program number is " PROGRAM_NUMBER
	p

	if ("$1" == "run" ) {
		p
		p "You are about to run the program "
		p "make sure that the power supply water flow ... etc..."
		p "are ON and working ... "
		p 
		p "Default program number in SPEC is " PROGRAM_NUMBER
		p
		# Guess it is close
		MANSETPOINT= _euro_read(address, channel,"SL")
# L.Claustre 30/11/2006
# It seems the 2408CP can only have 1 prg defined at a time, so the 
# PN command is undefined !!
#		_cmd = sprintf("PN%d",PROGRAM_NUMBER)
#		_my_euro_write(address, _cmd);
#		_ret =  _euro_read(address, channel,"PN")
                _ret = PROGRAM_NUMBER
		p "Working program : " _ret 
		if (PROGRAM_NUMBER != _ret ) { 
			p "\tCAUTION!!!. Couldnt change the active prg#"
			p "\tMake sure the previous prgram is RESET"
			printf( "\tDo I resume/restart program  #%d ", _ret)
			if (yesno("?",0) ==0)
				exit
		}
		_europrog_cmd(address, 2)
	} else if ("$1"== "reset" ) {
		printf("Doing this you will GO TO THE MANUAL SETPOINT : %.1f\n",\
							MANSETPOINT)
		p "To modify the current program type: \"europrog status \" "
		if (yesno("Reset anyway",0)==0)
			exit
		MANSETPOINT = getval("Manual setpoint after reset",MANSETPOINT)
		_europrog_cmd(address, 1)
		_cmd = sprintf("SL%.1f",MANSETPOINT)
		_my_euro_write(address,  _cmd)
                # Set OP to off too, otherwise the powersupply remains.
                _my_euro_write(address,  "OP0")
	} else if ("$1"== "hold" ) {
		_europrog_cmd(address, 4)
	} else if ("$1"== "holdback" ) {
		_europrog_cmd(address, 8)
	} else if ("$1"== "complete" ) {
		_europrog_cmd(address, 16)
	} else if ("$1"== "read" ) {
		if ($2)
			_europrog_read(address,$2)
		else
			_europrog_read(address,-1)
	} else if ("$1"== "write" ) {
		_europrog_write(address) 
	} else if ("$1"== "status" ) {
		_europrog_cmd(address, -1) # jumps to the default (status)
	} else {
		printf("Usage: europrog < run | reset | hold | holdback | ")
		printf("complete | status | read | write > <program_number>\n")
	}
}
\'

#%UU% < manual_setpoint>
#%MDESC% Forces a reset of running program (if any) and sends a new setpoint
# to the eurotherm. Asked by ID01 to have a macro that one can call with
# no need of user interaction (calling "europrog status" first, and then reset)
# Usefull to concatenate many programs from a spec macro.
#
rdef europrogreset \'{
	local _cmd _address _setpoint

	if ($# != 1 ) {
		print "Usage: $0 <manual_setpoint>"
		exit
	}
	if ($1 < 10 ) {
		_setpoint = 10
		p "Warning: Setting setpoint to 10. Can not go below 10"
		# really dont know why 
	}else{
		_setpoint = $1
	}
	_address   =list_getpar(TC,MY_TC,"add")
	_europrog_cmd(_address, 1)
	_cmd = sprintf("SL%d",_setpoint)
	_my_euro_write(_address,  _cmd)
}
\'

}'


if (whatis("europrog") & 2) { #macro present
    ### introduce some code for the unfortunate choice to have a second europrog
    ### in eurotherm2400.mac on top of temperature.mac. Mea culpa,  Holger
    global grepeuroprog
    local fname, str
    pname   = "/tmp/" SPEC rand()
    str     = "/bin/rm -f " pname
    unix(str)
    on(pname)
    offt
    prdef europrog
    close(pname)
    ont
    str     = "head -2 " pname
    unix(str, grepeuroprog)
    if (!index(grepeuroprog, "eurotherm2400.mac")) {
        __define__europrog()
    }
    unglobal grepeuroprog tty_cntlred tty_cntlnotred
    undef __define__europrog
} else { # europrog is not present, load them
    __define__europrog()
    undef __define__europrog
}
        



#%MACROS%
#%IMACROS%
#%DEPENDENCIES%
# stlocal.mac  and pseudo.mac have to be read in.
#%ATTENTION%
#%DL%%DT% Oxford Instrument: %DD% Changing the setpoint will not be possible if a sweep is running.
#%DT% Hubber CC:%DD% If several controller of that type are in use, they MUST all be configured the same, either intern or extern, concerning the temperature sensor in use for regulation.
#%DT% ILL:%DD% If several controller of that type are in use, they MUST all be configured with the same OS9 prompt.
#%DT% F700:%DD%The A[] array holds the setpoint value rather than the current temperature value which cannot be provided by the controller. For the time being, only one controller of that type can be setup in a same SPEC application. 
#%DT% F26:%DD%For the time being, only one controller of that type can be setup in a same SPEC application. 
#%XDL%
# Available soon: tcramp and tcpid, respectively to program a ramp and to setup PID parameters.
#%INTERNALS%
# The entry points to add support for a new type of controller are temperature_control() function, _tc_hardware() function and a new _tc_ill() (or _tc_ox(), or _tc_hcc() ...) like command interface control function. 
#%DL%
#%DT%temperature_control ():%DD% add new "type" key into local "supported_list" variable, delimited by percent character.
#%DT%_tc_hardware():%DD% add the call to the new command interface function, in the same way as for the already existing ones.
#%DT%_tc_newinterface():%DD% convert each typical and common action into specific instrument language protocol. 
#%XDL%
#%AUTHOR% BLISS - ESRF . %{% <A HREF="mailto:lagier@esrf.fr"> Marie-Claire Lagier</A>%}%, May 2001 V.+1. Feel free to report any bug, comment or any other request.
#$Revision: 1.46 $, $Date: 2016/01/05 16:16:21 $
#%TOC%