From d185647cbbdeace39943e6fc09680ad7a93ce7a4 Mon Sep 17 00:00:00 2001 From: Ferdi Franceschini Date: Fri, 2 Jul 2010 14:03:08 +1000 Subject: [PATCH] Removed obsolete lakeshore configurations. r2973 | ffr | 2010-07-02 14:03:08 +1000 (Fri, 02 Jul 2010) | 2 lines --- .../temperature/lakeshore340_common.tcl | 44 - .../temperature/sct_lakeshore_3xx.tcl | 2102 ----------------- 2 files changed, 2146 deletions(-) delete mode 100644 site_ansto/instrument/config/environment/temperature/lakeshore340_common.tcl delete mode 100755 site_ansto/instrument/config/environment/temperature/sct_lakeshore_3xx.tcl diff --git a/site_ansto/instrument/config/environment/temperature/lakeshore340_common.tcl b/site_ansto/instrument/config/environment/temperature/lakeshore340_common.tcl deleted file mode 100644 index f4b81771..00000000 --- a/site_ansto/instrument/config/environment/temperature/lakeshore340_common.tcl +++ /dev/null @@ -1,44 +0,0 @@ -namespace eval ::environment::temperature { -# Default temperature controller parameters - array set tc_dfltPar { - tolerance 1 - settle 30 - range 5 - upperlimit 500 - lowerlimit 4 - } - - array set moxaPortMap {1 4001 2 4002 3 4003 4 4004} -} - -# @brief Make a simulated temperature controller object. -# -# @param temp_sobj, name for temperature controller object. -proc ::environment::temperature::mkls340sim {temp_sobj} { - if [catch { - EvFactory new $temp_sobj sim - sicslist setatt $temp_sobj numsensors 4 - sicslist setatt $temp_sobj controlsensor sensora - sicslist setatt $temp_sobj sensorlist sensora,sensorb,sensorc,sensord - sicslist setatt $temp_sobj heateron 1 - sicslist setatt $temp_sobj range 5 - sicslist setatt $temp_sobj units kelvin - sicslist setatt $temp_sobj klass @none - } message ] { - if {$::errorCode=="NONE"} {return $message} - return -code error $message - } -} - -# @brief Make a lakeshore340 temperature controller object. -# -# @param temp_sobj, name for temperature controller object -# @param IP, (optional) IP address for temperature controller. -# @param port, (optional) port number for temperature controller. -proc ::environment::temperature::mkls340 {temp_sobj IP port} { - Makeasyncqueue ${temp_sobj}_AsyncQ LS340 $IP $port - ${temp_sobj}_AsyncQ timeout 2000 - EvFactory new $temp_sobj ls340 ${temp_sobj}_AsyncQ 1 A ABCD - sicslist setatt $temp_sobj units kelvin - sicslist setatt $temp_sobj klass @none -} diff --git a/site_ansto/instrument/config/environment/temperature/sct_lakeshore_3xx.tcl b/site_ansto/instrument/config/environment/temperature/sct_lakeshore_3xx.tcl deleted file mode 100755 index c91608ed..00000000 --- a/site_ansto/instrument/config/environment/temperature/sct_lakeshore_3xx.tcl +++ /dev/null @@ -1,2102 +0,0 @@ -# Define procs in ::scobj::xxx namespace -# MakeSICSObj $obj SCT_ -# The MakeSICSObj cmd adds a /sics/$obj node. NOTE the /sics node is not browsable. - -## -# /*-------------------------------------------------------------------------- -# L A K E S H O R E 3 x x S E R I E S D R I V E R -# -# @file: This file contains the implementation of a driver for the -# Lakeshore 336 and 340 Temperature controller implemented as a scriptcontext -# object in TCL. -# -# @author: Arndt Meier, ANSTO, 2009-08-05 -# @brief: driver for Lakeshore 336 and 340 Temperature Controller (in TCL) -# @version: 20091127 for sics2_4 -# -# known bugs/limitations: beta stage, lacks testing of ramping, relays, setpoint driving, -# alarm_limit compliance, some commands issued at initialisation are not honored, -# device and alarm reset not working correctly (nodes with no values). -# Namespace conflict: If both a model 336 and 340 are run at the same time, then -# the model 340 tries to access nodes such as outMode3 that only exist in the -# model 336 which segfaults SICServer. The problem is likely due to both models -# using the same namespace, but I have not figured out yet how to give the -# namespace a dynamic name specific to the model. -# ----------------------------------------------------------------------------*/ - -# Notes -# Hdb nodes which report data readings should have a "get" script attached to the -# "read" property of the node. This ensures that we can update the reading on demand -# which is necessary for logging data. -# -# Hdb nodes which report parameters which don't change after the driver has -# connected/reconnected to the device should be initialised with a call to the queue -# subcommand of the sct controller, Eg. -# sct queue /sics/path progress read -# -# If there are a large number of settings which need to be reported, and the device -# lets you get the read these setting with a single transaction then you can create -# a status polling object which fetches the settings and updates a given list of hdb -# nodes. - - -# Default temperature controller parameters -namespace eval ::scobj::ls3xx { - # Some global variables that are useful as default initilisation values or for tracking - # Name of the scriptcontext object created from calling this driver - an instrument may use more than one - set ls3xx_sct_obj_name "UNKNOWN" - # What Lakeshore model are we dealing with? 336 or 340? - set ls3xx_LSmodel "UNKNOWN" - # Last query and write command sent to the device - for debugging and other tasks - set ls3xx_lastQueryCmd " " - set ls3xx_lastWriteCmd " " - # provide a global variable holding the path to the nodes - set ls3xx_path2nodes "/sample/tc1" - # terminator string for serial communication (empty for ls340, taken car of with the COMM command) - # obsolete - handled by sct object - set ls3xx_term "" - - # Variables that are identical to node names but are needed internally as well - # temperature difference between setpoint and actual temperature at which the - # heater changes from idle to driving - set ls3xx_driveTolerance1 2 - set ls3xx_driveTolerance2 2 - # Next 2 parameters are supported by LS model 340 only - # ctrl loop 1 settle parameter, threshold=allowable band around setpoint (0,..,100) - set ls340_settleThr 30 - # ctrl loop 1 settle parameter, settle time in seconds - set ls340_settleTime 30 - # default Heater Range (0,..,5) zero is off, hence the least dangerous - set ls3xx_range 0 - # upper and lower temperature limit in Kelvin - set ls3xx_upperlimit 500.0 - set ls3xx_lowerlimit 4.0 - # temperature units are Kelvin - set ls3xx_tempUnits "K" - # ls3xx status byte - set ls3xx_statusByte -1 - # enable extra logging - can produce huge stout****.log file in /usr/local/sics/log/ - set ls3xx_verbose 0 - # a list of available sensors (not all may be connected/active) - set this_sensorlist [list A B C D] - # a list of controler loops - set this_controlerlist [list 1 2] - # set device ID to unknown - set this_sDeviceID "Unknown_Device" - # set self-test result to unknown - set this_selfTestResult -1 - # status of input channels - unknown at startup - set ls3xx_inputStatusA "UNKNOWN" - set ls3xx_inputStatusB "UNKNOWN" - set ls3xx_inputStatusC "UNKNOWN" - set ls3xx_inputStatusD "UNKNOWN" - set ls3xx_inpSetupA "UNKNOWN" - set ls3xx_inpSetupB "UNKNOWN" - set ls3xx_inpSetupC "UNKNOWN" - set ls3xx_inpSetupD "UNKNOWN" - set ls3xx_input4CtrlLp1 "0" - set ls3xx_input4CtrlLp2 "0" - set ls3xx_input4CtrlLp3 "0" - set ls3xx_input4CtrlLp4 "0" - set ls3xx_sampleSensor "UNKNOWN" - set timeInSecsSince2000 0 - - set alarm_Limit_LoA $ls3xx_lowerlimit - set alarm_Limit_LoB $ls3xx_lowerlimit - set alarm_Limit_LoC $ls3xx_lowerlimit - set alarm_Limit_LoD $ls3xx_lowerlimit - set alarm_Limit_HiA $ls3xx_upperlimit - set alarm_Limit_HiB $ls3xx_upperlimit - set alarm_Limit_HiC $ls3xx_upperlimit - set alarm_Limit_HiD $ls3xx_upperlimit - set checkAlarmLimitsA 1 - set checkAlarmLimitsB 1 - set checkAlarmLimitsC 1 - set checkAlarmLimitsD 1 - - set tc_dfltURL ca5-[instname] - array set moxaPortMap {1 4001 2 4002 3 4003 4 4004} - -########### Initialisation ############################# - -## -# Initialise the ls3xx: -# Checks the device ID, resets the device, checks the self-test, sets the communication -# protocol, sets the default alarm levels, heater range, settle threshold and tolerance. -# @param sct_controller the controller object created for this driver -# @param tc_root string variable holding the path to the object's base node in sics -# @return 0, always -proc ls3xx_init {sct_controller tc_root} { - if {[ catch { - # Define a constant time offset for later logging of data with timStamp - # counting from 1st Jan 2000 00:00hrs - # clock command does not work in tcl8.5 ?! - set ::scobj::ls3xx::timeInSecsSince2000 [clock scan 20000101T000000A] -#set ::scobj::ls3xx::timeInSecsSince2000 1000 - # set the communication protocol: terminator , bps 9600 baud, 7 data bits + - # 1 stop bit + odd parity bit - if { $::scobj::ls3xx::ls3xx_LSmodel == 340 } { - # puts "setting serial communication parameters" - hset $tc_root/other/cfgProtocol_comm "COMM 1,5,1" - } - # Query the device ID - are we talking to a Lakeshore 340 or 336? -# puts "sending: $sct_controller queue $tc_root/other/deviceID_idn progress read" -# $sct_controller queue $tc_root/other/deviceID_idn progress read - # !! Not working properly yet - needs fixing - #sct send "*IDN?" - #sct data [$sct_controller result] - #puts "rdValDrct(): result is $data" - #set data [hget $tc_root/other/deviceID_idn] -# puts "set deviceID_idn (hval $tc_root/other/deviceID_idn)" - #set data [hval $tc_root/other/deviceID_idn] - #set ::scobj::ls3xx::this_sDeviceID data -# puts "sct_lakeshore3xx.tcl: connected to device $::scobj::ls3xx::this_sDeviceID" - # reset the device to have it in a defined state -# hset $tc_root/other/reset_rst {*RST} - # Queue the Read Device Status-byte command so we can access the result in the - # corresponding node later -# puts "sending: $sct_controller queue $tc_root/other/statusByte progress read" -# $sct_controller queue $tc_root/other/statusByte progress read - if { $::scobj::ls3xx::ls3xx_LSmodel == 340 } { - hset $tc_root/other/cfgProtocol_comm "COMM 1,5,1" - } - # Was the self-test successful? - $sct_controller queue $tc_root/other/selftest progress read - set ::scobj::ls3xx::this_selfTestResult [hval $tc_root/other/selftest] - if {$::scobj::ls3xx::this_selfTestResult == 0} { - puts "sct_lakeshore3xx.tcl: Lakeshore $::scobj::ls3xx::ls3xx_LSmodel self-test ok." - } else { - puts "sct_lakeshore3xx.tcl: The Lakeshore $::scobj::ls3xx::ls3xx_LSmodel failed its self-test." - } - # Set the default upper and lower temperature alarm limits in Kelvin - foreach iSensor $::scobj::ls3xx::this_sensorlist { - hsetprop $tc_root/input/alarm_Limits_$iSensor units "K" - hsetprop $tc_root/input/alarm_Limits_$iSensor units "K" - } - # Set the default heater range (1,..,5) - if { $::scobj::ls3xx::ls3xx_LSmodel == 340 } { -# hset $tc_root/heater/heaterRange $::scobj::ls3xx::ls3xx_range - } else { -# hset $tc_root/heater/heaterRange_1 $::scobj::ls3xx::ls3xx_range -# hset $tc_root/heater/heaterRange_2 $::scobj::ls3xx::ls3xx_range - } - # Set the default settle parameters - if { $::scobj::ls3xx::ls3xx_LSmodel == 340 } { - hset $tc_root/control/settleThr_Loop_1 $::scobj::ls3xx::ls340_settleThr - hset $tc_root/control/settleTime_Loop_1 $::scobj::ls3xx::ls340_settleTime - hsetprop $tc_root/control/settleTime_Loop_1 units "s" - puts "Make sure INTERFACE : SERIAL : TERMINATOR is set correctly" - } - # Set the default tolerances for the setpoint temperatures - hset $tc_root/control/tolerance1 $::scobj::ls3xx::ls3xx_driveTolerance1 - hset $tc_root/control/tolerance2 $::scobj::ls3xx::ls3xx_driveTolerance2 - } message ]} { - return -code error "in ls3xx_init: $message" - } -} - -############# Reading polled nodes ################################### - -## -# @brief Sends a query command to the device via a read node formalism -# @param tc_root The path to the root of the node -# @param nextState The next function to call after this one (typically 'rdValue' -# to read the response from the device) -# @param cmd The query command to be send to the device (written to the -# node data value) -# @param idx indicates which control loop or which input channel -# the command belongs to -# @return nextState The next function to call after this one (typically 'rdValue') -proc getValue {tc_root nextState cmd idx} { - if {[ catch { - if { 0 == [string compare -length 7 $cmd "InpSample"] } { - # we are reading from a pseudo-node where there is no direct representation - # in the device - # puts "getValue(InpSample)" - set ::scobj::ls3xx::ls3xx_lastQueryCmd $cmd - #sct send $cmd$::scobj::ls3xx::ls3xx_term - } elseif { 0 == [string compare -length 7 $cmd "CRVHDR?"] } { - # In the case of calCurveHdr we need an extra parameter with the command sent - set nodename $tc_root/input/inpCalCurve_$idx - set whichCurve [hval $nodename] - if {$whichCurve < 1 | $whichCurve > 58} { - # Quering 'CRVHDR? 0' is an invalid curve index. The right answer is 'noCurve' - # However, cannot do the following 2 lines because then the nextState rdFunc has no value it can get - # set nodename $tc_root/input/calCurveHdr_$idx - # hset $nodename "noCurve" - # workaround: set whichCurve to 59 which would normally be empty and fix things up in rdValue - set whichCurve 59 - } - set ::scobj::ls3xx::ls3xx_lastQueryCmd "$cmd$whichCurve" - sct send $cmd$whichCurve - } else { - set ::scobj::ls3xx::ls3xx_lastQueryCmd "$cmd" - sct send $cmd - } - } message ]} { - return -code error "in getValue: $message. Last query command: $::scobj::ls3xx::ls3xx_lastQueryCmd" - } - return $nextState -} - -## -# @brief Reads the value of a read-node typically following a query command sent to the device -# rdValue is the default nextState for getValue() and setValue() -# @param idx indicates which control loop or which input channel the command belongs to -# @return idle Always returns system state idle - command sequence completed. - proc rdValue {idx} { - if {[ catch { - set data [sct result] - # puts "rdValue(): result is $data" - # broadcast rdValue "rdValue(): result is $data" - - # Check if an invalid curveHeader was queried and set the result to 'noCurve' - if { 0 == [string compare -length 10 $::scobj::ls3xx::ls3xx_lastQueryCmd "CRVHDR? 59"] } { - set data "noCurve" - if {$idx > 0 && $idx <= 4} { - switch $idx { - 1 {set idx "A"} - 2 {set idx "B"} - 3 {set idx "C"} - 4 {set idx "D"} - } - } - if {$idx == "A" || $idx == "B" || $idx == "C" || $idx == "D"} { - set nodename $::scobj::ls3xx::ls3xx_path2nodes/input/calCurveHdr_$idx - hset $nodename "noCurve" - } - } - # Continue as normal - switch -glob -- $data { - "ASCERR:*" { - puts "ASCERR in rdValue: Last query command: $::scobj::ls3xx::ls3xx_lastQueryCmd" - sct geterror $data - } - default { - if {$data != [sct oldval]} { - sct oldval $data - sct update $data - sct utime readtime - - # We are done here - below are some special cases where we keep - # track of some global variables and stuff for the nodes in /sensor/ - - # Keep track of input Setup - tells us whether any channels are disabled - # Lakeshore Model 336 and 340 differ in that this information is requested via - # INTYPE? and INSET? commands, respectively, and with the LS336 not having - # the INSET? command - set mustUpdate 0 - if { 0 == [string compare -length 3 $::scobj::ls3xx::ls3xx_LSmodel "336"] - && 0 == [string compare -length 7 $::scobj::ls3xx::ls3xx_lastQueryCmd "INTYPE?"] } { - set mustUpdate 1 - } - if {0 == [string compare -length 6 $::scobj::ls3xx::ls3xx_lastQueryCmd "INSET?"] || $mustUpdate == 1 } { - switch $idx { - "A" {set ::scobj::ls3xx::ls3xx_inpSetupA $data} - "B" {set ::scobj::ls3xx::ls3xx_inpSetupB $data} - "C" {set ::scobj::ls3xx::ls3xx_inpSetupC $data} - "D" {set ::scobj::ls3xx::ls3xx_inpSetupD $data} - } - } - - # Keep track of the time at which data was observed ** NXsensor allows float values only, not text - if {0 == [string compare -length 9 $::scobj::ls3xx::ls3xx_lastQueryCmd "DATETIME?"] } { - # DATETIME «MM»,«DD»,«YYYY»,«HH»,«mm»,«SS»,«sss» Configure Date and Time. - regsub -all {,} $data {:} data - # data=08:31:2009:12:58:58:910 - set separator {:} - set amonth [::scobj::ls3xx::getValFromString $data 0 $separator] - set aday [::scobj::ls3xx::getValFromString $data 1 $separator] - set ayear [::scobj::ls3xx::getValFromString $data 2 $separator] - set ahour [::scobj::ls3xx::getValFromString $data 3 $separator] - set amin [::scobj::ls3xx::getValFromString $data 4 $separator] - set asec [::scobj::ls3xx::getValFromString $data 5 $separator] - # use this code block to report time in seconds since 1/1/2000 - set aA "A" - set aT "T" - set timeString $ayear$amonth$aday$aT$ahour$amin$asec$aA - set timeInSecs [clock scan $timeString] - set timeInSecs [expr {$timeInSecs - $::scobj::ls3xx::timeInSecsSince2000}] - hset $::scobj::ls3xx::ls3xx_path2nodes/sensor/timStamp $timeInSecs - if {1==0} { - # if we could write a string value to NXsensor, then this date-time format would be nicer... - set sColon ":" - set sSpace " " - set isoTimeString $ayear$amonth$aday$sSpace$ahour$sColon$amin$sColon$asec - hset $::scobj::ls3xx::ls3xx_path2nodes/sensor/timStamp $isoTimeString - } - } - } - } - } - } message ]} { - return -code error "in rdValue: $message. Last query command: $::scobj::ls3xx::ls3xx_lastQueryCmd" - } - return idle - } - -## -# @brief Reads the values of the alarm_Limit_* nodes. Needs extra code compared to proc 'rdValue' -# because multiple variables are represented by only one concatenated command in the device command list. -# It is preceeded by a call to getValue() and a replacement for rdValue. -# @param idx indicates which control loop or which input channel the command belongs to -# @return idle Always returns system state idle - command sequence completed. -proc rdAlarmVal {iSensor} { - if {[ catch { - set data [sct result] - switch -glob -- $data { - "ASCERR:*" { - puts "ASCERR in rdAlarmVal: Last query command: $::scobj::ls3xx::ls3xx_lastQueryCmd" - sct geterror $data - } - default { - if {$data != [sct oldval]} { - sct oldval $data - sct update $data - sct utime readtime - # ALARM? returns «off/on», «source», «high value», «low value», «latch enable», «relay» - # idx points to the position of the last coma in the string - # 1, 1, 500.00, 0.00, 0, 0 - #puts "rdAlarmVal: iSensor= $iSensor ;; data= $data " - set separator {,} - set onOff [::scobj::ls3xx::getValFromString $data 0 $separator] - if { $::scobj::ls3xx::ls3xx_LSmodel == 340 } { - #set source [::scobj::ls3xx::getValFromString $data 1 $separator] - set hiVal [::scobj::ls3xx::getValFromString $data 2 $separator] - set loVal [::scobj::ls3xx::getValFromString $data 3 $separator] - #set latch [::scobj::ls3xx::getValFromString $data 4 $separator] - #set relay [::scobj::ls3xx::getValFromString $data 5 $separator] - } else { - set hiVal [::scobj::ls3xx::getValFromString $data 1 $separator] - set loVal [::scobj::ls3xx::getValFromString $data 2 $separator] - #set deadbd [::scobj::ls3xx::getValFromString $data 3 $separator] - #set latch [::scobj::ls3xx::getValFromString $data 4 $separator] - #set audible [::scobj::ls3xx::getValFromString $data 5 $separator] - #set visible [::scobj::ls3xx::getValFromString $data 6 $separator] - } - #puts "alarm-data= $data ;; onOff= $onOff ;; source= $source ;; hiVal= $hiVal ;; loVal= $loVal ;; latch= $latch ;; relay= $relay" - - switch $iSensor { - "A" { - set ::scobj::ls3xx::checkAlarmLimitsA $onOff - if {$loVal >= 0} {set ::scobj::ls3xx::alarm_Limit_LoA $loVal} - if {$hiVal >= 0} {set ::scobj::ls3xx::alarm_Limit_HiA $hiVal} - } - "B" { - set ::scobj::ls3xx::checkAlarmLimitsB $onOff - if {$loVal >= 0} {set ::scobj::ls3xx::alarm_Limit_LoB $loVal} - if {$hiVal >= 0} {set ::scobj::ls3xx::alarm_Limit_HiB $hiVal} - } - "C" { - set ::scobj::ls3xx::checkAlarmLimitsC $onOff - if {$loVal >= 0} {set ::scobj::ls3xx::alarm_Limit_LoC $loVal} - if {$hiVal >= 0} {set ::scobj::ls3xx::alarm_Limit_HiC $hiVal} - } - "D" { - set ::scobj::ls3xx::checkAlarmLimitsD $onOff - if {$loVal >= 0} {set ::scobj::ls3xx::alarm_Limit_LoD $loVal} - if {$hiVal >= 0} {set ::scobj::ls3xx::alarm_Limit_HiD $hiVal} - } - } - } - } - } - } message ]} { - return -code error "in rdAlarmVal: $message. Last query command: $::scobj::ls3xx::ls3xx_lastQueryCmd" - } - return idle -} - - -## -# @brief rdCfgValue() does what rdValue() does but it replaces /sensor/ctrl_Loop_1 value -# with a more human readable version of the information from /control/config_Loop_1. This -# function is called for the CSET* and OUTMODE* commands. -# @param idx indicates which control channel the command acts upon -# @return idle Always returns system state idle - command sequence completed. - proc rdCfgValue {idx} { - if {[ catch { - set data [sct result] - switch -glob -- $data { - "ASCERR:*" { - puts "ASCERR in rdCfgValue: Last query command: $::scobj::ls3xx::ls3xx_lastQueryCmd" - sct geterror $data - } - default { - set oval [sct oldval] - if { $data != [sct oldval] } { - # puts "rdCfgValue: idx:$idx Last query command: $::scobj::ls3xx::ls3xx_lastQueryCmd" - sct oldval $data - sct update $data - sct utime readtime - # update the /sensor/ctrl_Loop_1 and /sensor/ctrl_Loop_2 manual nodes which show - # DISABLED if the control channel is disabled - set ctrl_Loop_Txt "enabled, Input " - set input "A" - set separator {,} - if { $::scobj::ls3xx::ls3xx_LSmodel == 340 } { - # LS340, device command CSET* - set input [::scobj::ls3xx::getValFromString $data 0 $separator] - set units [::scobj::ls3xx::getValFromString $data 1 $separator] - set onOff [::scobj::ls3xx::getValFromString $data 2 $separator] - #set powerup [::scobj::ls3xx::getValFromString $data 3 $separator] - if {$onOff == 0} { - set ctrl_Loop_Txt "DISABLED, Input " - } - set in ", in " - switch -glob -- $units { - "1*" {set units "Kelvin"} - "2*" {set units "Celsius"} - "3*" {set units "sensor units"} - default {set units "UNKNOWN units"} - } - set ctrl_Loop_Txt $ctrl_Loop_Txt$input$in$units - # puts "ls340 rdCfgValue() idx: $idx, data: $data, units: $units, ctrl_Loop_Txt: $ctrl_Loop_Txt" - } else { - # LS 336, device command outMode_* - set mode [::scobj::ls3xx::getValFromString $data 0 $separator] - set input [::scobj::ls3xx::getValFromString $data 1 $separator] - # set powerup [::scobj::ls3xx::getValFromString $data 2 $separator] - if {$mode == 0} { - set ctrl_Loop_Txt " DISABLED, Input " - } - set myInp $input - switch -glob -- $myInp { - "0*" {set input "None"} - "1*" {set input "A"} - "2*" {set input "B"} - "3*" {set input "C"} - "4*" {set input "D"} - default {set input "UNKNOWN"} - } - append ctrl_Loop_Txt $input - set myMode $mode - switch -glob -- $myMode { - "0*" {set mode ", control off"} - "1*" {set mode ", PID closed loop"} - "2*" {set mode ", zone control"} - "3*" {set mode ", open loop"} - "4*" {set mode ", monitor out"} - "5*" {set mode ", warmup supply"} - default {set mode ", UNKNOWN control"} - } - append ctrl_Loop_Txt $mode - # puts "rdCfgValue() idx: $idx, data: $data, output: $idx, ctrl_Loop_Txt: $ctrl_Loop_Txt" - # puts "rdCfgValue setting ls3xx_input4CtrlLp idx:$idx, input:$input, myInp:$myInp" - } - set nodename $::scobj::ls3xx::ls3xx_path2nodes/sensor/ctrl_Loop_$idx - hset $nodename $ctrl_Loop_Txt - # Keep track of which inputs are used for the control loops - # puts "rdCfgValue() idx: $idx, data: $data, input:$input, ctrl_Loop_Txt: $ctrl_Loop_Txt" - switch $idx { - "1" {set ::scobj::ls3xx::ls3xx_input4CtrlLp1 $input} - "2" {set ::scobj::ls3xx::ls3xx_input4CtrlLp2 $input} - "3" {set ::scobj::ls3xx::ls3xx_input4CtrlLp3 $input} - "4" {set ::scobj::ls3xx::ls3xx_input4CtrlLp4 $input} - } - # puts "rdCfgValue ls3xx_input4CtrlLp:$::scobj::ls3xx::ls3xx_input4CtrlLp2 idx:$idx, input:$input, myInp:$myInp" - } - } - } - } message ]} { - return -code error "in rdCfgValue: $message. Last query command: $::scobj::ls3xx::ls3xx_lastQueryCmd" - } - return idle - } - - - -## -# @brief Reads the values of the RDGST* nodes. Needs extra code compared to proc 'rdValue' -# because it interprets the bit coded results and updates affected node values accordingly -# It is preceeded by a call to getValue() and is a replacement for rdValue(). -# @param iSensor indicates which input channel the command belongs to -# @return idle Always returns system state idle - command sequence completed. -proc rdBitValue {iSensor} { - if {[ catch { - set data [sct result] - switch -glob -- $data { - "ASCERR:*" { - puts "ASCERR in rdBitValue: Last query command: $::scobj::ls3xx::ls3xx_lastQueryCmd" - sct geterror $data - } - default { - if {$data != [sct oldval]} { - sct oldval $data - sct update $data - sct utime readtime - # RDGST? A/B/C/D Read input status returns an integer with the following meaning - # Bit Weighting StatusIndicator - # 0 1 invalid reading - # 1 2 old reading (not an error, ignored in ls336) - # 4 16 temp underrange - # 5 32 temp overrange - # 6 64 sensor units zero - # 7 128 sensor units overrange - set sValue "" - # Remove any leading zeros from string 'data' which ought to represent an integer, - # ("001" => "1", "096" => "96") else the string may be misinterpreted as an octal number. - if {0 == [string compare -length 1 $data "0"] } { - set data [string range $data 1 5] - } - if {0 == [string compare -length 1 $data "0"] } { - set data [string range $data 1 5] - } - set i $data - # puts "rdBitValue(): iSensor:$iSensor, data:$data" - set bitValue [expr {$i & 1}] - if {$bitValue == 1} {set sValue "Invalid reading, "} - #set i [expr $i >> 1] - # set bitValue [expr $i & 1] - # if {$bitValue == 1} {set sValue "old reading"} - set i [expr {$i >> 4}] - set bitValue [expr {$i & 1}] - if {$bitValue == 1} { set sValue [append sValue "temp underrange, "] } - set i [expr {$i >> 1}] - set bitValue [expr {$i & 1}] - if {$bitValue == 1} { set sValue [append sValue "temp overrange, "] } - set i [expr {$i >> 1}] - set bitValue [expr {$i & 1}] - if {$bitValue == 1} { set sValue [append sValue "sensor units zero, "] } - set i [expr {$i >> 1}] - set bitValue [expr {$i & 1}] - if {$bitValue == 1} { set sValue [append sValue "sensor units overrange, "] } - if { [string length $sValue] < 4 } { - set sValue "ok" - } - #puts "rdBitValue(): iSensor:$iSensor, data:$data, sValue:$sValue " - switch $iSensor { - "A" {set ::scobj::ls3xx::ls3xx_inputStatusA $sValue} - "B" {set ::scobj::ls3xx::ls3xx_inputStatusB $sValue} - "C" {set ::scobj::ls3xx::ls3xx_inputStatusC $sValue} - "D" {set ::scobj::ls3xx::ls3xx_inputStatusD $sValue} - } - } - } - } - } message ]} { - return -code error "in rdBitValue: $message. Last query command: $::scobj::ls3xx::ls3xx_lastQueryCmd" - } - return idle -} - - -## -# @brief rdInpValue() does what rdValue() does but it replaces the input's Kelvin Reading -# with the message from RDGST? if the input is invalid. -# @param idx indicates which input channel the command acts upon -# @return idle Always returns system state idle - command sequence completed. - proc rdInpValue {idx} { - if {[ catch { - set data [sct result] - switch -glob -- $data { - "ASCERR:*" { - puts "ASCERR in rdInpValue: Last query command: $::scobj::ls3xx::ls3xx_lastQueryCmd" - sct geterror $data - } - default { - if {$idx == "A"} { - # update only once per poll cycle needed - # Read the sics node sampleSensor to - # determine which input represents the sample temperature - set nodename $::scobj::ls3xx::ls3xx_path2nodes/sensor/sampleSensor - set ::scobj::ls3xx::ls3xx_sampleSensor [hval $nodename] - } - if { $data != [sct oldval] } { - sct oldval $data - sct update $data - sct utime readtime - # update the /sensor/ctrlLp1_value, /sensor/ctrlLp2_value, and /sensor/Tsample manual nodes which show - # zero or DISABLED if the input channel is disabled - - set inputStatus $::scobj::ls3xx::ls3xx_inputStatusA - set inpEnabled $::scobj::ls3xx::ls3xx_inpSetupA - switch $idx { - "B" {set inpEnabled $::scobj::ls3xx::ls3xx_inpSetupB} - "C" {set inpEnabled $::scobj::ls3xx::ls3xx_inpSetupC} - "D" {set inpEnabled $::scobj::ls3xx::ls3xx_inpSetupD} - } - if {0 == [string compare -length 1 $inpEnabled "0"] } { - # puts "Inp$idx is DISABLED" - set inputStatus "DISABLED" - } else { - # RDGST? if RDGST is NOT zero -- or else the Kelvin reading for that input. - switch $idx { - "A" {set inputStatus $::scobj::ls3xx::ls3xx_inputStatusA} - "B" {set inputStatus $::scobj::ls3xx::ls3xx_inputStatusB} - "C" {set inputStatus $::scobj::ls3xx::ls3xx_inputStatusC} - "D" {set inputStatus $::scobj::ls3xx::ls3xx_inputStatusD} - } - } - # RDGST? is 'ok' or 'UNKNOWN' -> it is okay to show the Kelvin reading we have - set value $data - if { [string length $inputStatus] >= 8 } { - # The status of the input channel meets an error condition - show the error message instead - # puts "rdInpValue() idx: $idx, data: $data, invalid: $inputStatus" - set value -1.0 - } - if {$idx == $::scobj::ls3xx::ls3xx_sampleSensor} { - hset $::scobj::ls3xx::ls3xx_path2nodes/sensor/Tsample $value - } - # Switch command did not work reliably below, hence a less elegant but - # functional if-elseif-else contruct is implemented instead - if {$idx == $::scobj::ls3xx::ls3xx_input4CtrlLp1} { - hset $::scobj::ls3xx::ls3xx_path2nodes/sensor/ctrlLp1_value $value - } elseif {$idx == $::scobj::ls3xx::ls3xx_input4CtrlLp2} { - hset $::scobj::ls3xx::ls3xx_path2nodes/sensor/ctrlLp2_value $value - } elseif {$idx == $::scobj::ls3xx::ls3xx_input4CtrlLp3} { - hset $::scobj::ls3xx::ls3xx_path2nodes/sensor/ctrlLp3_value $value - } elseif {$idx == $::scobj::ls3xx::ls3xx_input4CtrlLp4} { - hset $::scobj::ls3xx::ls3xx_path2nodes/sensor/ctrlLp4_value $value - } - } - } - } - } message ]} { - return -code error "in rdInpValue: $message. Last query command: $::scobj::ls3xx::ls3xx_lastQueryCmd" - } - return idle - } - - - -## -# @brief Does what rdValue() does plus it checks if the temperature is in tolerance. -# inTolerance is the default nextState after getValue() for read node other/deviceID_idn. -# If the LS3xx is switched off, temperature is reported to be in tolerance so that -# slow return to ambient temperature can be carried out (see comments in Julabo driver -# for reasoning). -# @param CtrlLoopIdx indicates which control loop the command acts upon -# @return idle Always returns system state idle - command sequence completed. -proc inTolerance {CtrlLoopIdx} { - if {[ catch { - set tc_root $::scobj::ls3xx::ls3xx_path2nodes - set data [sct result] - set oldvalue [sct oldval] - # puts "inTolerance(): data=$data oldvalue=$oldvalue idx:$CtrlLoopIdx" - switch -glob -- $data { - "ASCERR:*" { - puts "ASCERR in inTolerance: Last query command: $::scobj::ls3xx::ls3xx_lastQueryCmd" - sct geterror $data - } - default { - if {$data != $oldvalue} { - # timecheck is an internal node that is set to the current time at the - # start of measurement and it is reset to current time every time the tolerance - # test for a control loop decides that it is outside tolerance. With the - # ls366 we need 2 such variables, one for each control loop. - if {$oldvalue == "UNKNOWN"} { - sct utime timecheck - sct utime timecheck2 - sct utime currtime - } - sct oldval $data - sct update $data - sct utime readtime - } - } - } - sct utime currtime - # puts "inTolerance $::scobj::ls3xx::ls3xx_sct_obj_name CtrlLoopIdx:$CtrlLoopIdx data:$data" - # now update the manual nodes reporting whether the actual temperature - # is within tolerance of the corresponding setpoint - for {set CtrlLoopIdx 1} {$CtrlLoopIdx < 3} {incr CtrlLoopIdx 1} { - set cmpIdString [string compare -length 13 $data "LSCI,MODEL340"] - if {$cmpIdString != 0 } { - set cmpIdString [string compare -length 13 $data "LSCI,MODEL336"] - } - if {$cmpIdString == 0 } { - # set nodename $tc_root/control/config_Loop_$CtrlLoopIdx - # set iSensor [hval $nodename] - # set iSensor [string range $iSensor 0 0] - set iSensor [getCorrespondingInputSensor $CtrlLoopIdx] - # puts "inTolerance 2 $::scobj::ls3xx::ls3xx_sct_obj_name CtrlLoopIdx:$CtrlLoopIdx data:$data, iSensor:$iSensor" - #puts {set intol [checktol $tc_root [sct readtime] [sct timecheck] $CtrlLoopIdx $iSensor]} - if {[string length $iSensor] == 1} { - if {$CtrlLoopIdx == 1} { - set intol [checktol $tc_root [sct currtime] [sct timecheck] $CtrlLoopIdx $iSensor] - } else { - set intol [checktol $tc_root [sct currtime] [sct timecheck2] $CtrlLoopIdx $iSensor] - } - set nodename $tc_root/sensor/setpoint$CtrlLoopIdx - set setpt [hval $nodename] - set nodename $tc_root/sensor/sensorValue$iSensor - set temp [hval $nodename] - # puts "inTolerance(): comparing sensor/setpoint$CtrlLoopIdx=$setpt with actual sensorValue$iSensor=$temp" - set diff [expr {abs($setpt - $temp)}] - # $::scobj::ls3xx::ls3xx_driveTolerance = 0.2 Kelvin - set tol $::scobj::ls3xx::ls3xx_driveTolerance1 - if {$CtrlLoopIdx == 2} { - set tol $::scobj::ls3xx::ls3xx_driveTolerance2 - } - # puts "inTolerance(): diff=$diff tol=$tol" - # if $diff > $tol - if {$intol==0} { - set nodename $tc_root/emon/monMode_Lp$CtrlLoopIdx - hset $nodename "drive" - if {$CtrlLoopIdx == 1} { - hset $tc_root/status "busy" - if {$::scobj::ls3xx::ls3xx_verbose==1} {puts "hset $nodename drive; hset $tc_root/status busy"} - } else { - hset $tc_root/status_Ctrl_Lp2 "busy" - if {$::scobj::ls3xx::ls3xx_verbose==1} {puts "hset $nodename drive; hset $tc_root/status_Ctrl_Lp2 busy"} - } - } else { - set nodename $tc_root/sensor/setpoint$CtrlLoopIdx - hsetprop $nodename driving 0 - set nodename $tc_root/emon/monMode_Lp$CtrlLoopIdx - hset $nodename "monitor" - if {$CtrlLoopIdx == 1} { - hset $tc_root/status "idle" - if {$::scobj::ls3xx::ls3xx_verbose==1} {puts "hset $nodename idle; hset $tc_root/status monitor"} - } else { - hset $tc_root/status_Ctrl_Lp2 "idle" - if {$::scobj::ls3xx::ls3xx_verbose==1} {puts "hset $nodename idle; hset $tc_root/status_Ctrl_Lp2 monitor"} - } - } - } - } else { - # puts "inTolerance(): uuppss - should not go here" - hset $tc_root/emon/monMode_Lp1 "idle" - hset $tc_root/emon/monMode_Lp2 "idle" - hset $tc_root/emon/isInTolerance_Lp1 "inTolerance" - hset $tc_root/emon/isInTolerance_Lp2 "inTolerance" - hset $tc_root/status "idle" - hset $tc_root/status_Ctrl_Lp2 "idle" - } - } - # puts "inTolerance 4 $::scobj::ls3xx::ls3xx_sct_obj_name CtrlLoopIdx:$CtrlLoopIdx data:$data" - } message ]} { - return -code error "in inTolerance: $message. Last query command: $::scobj::ls3xx::ls3xx_lastQueryCmd" - } - # puts "Leaving inTolerance idx:$CtrlLoopIdx" - return idle -} - - -## -# @brief rdCalValue()) does what rdValue() does plus it resets the value /input/calCurveHdr_$idx forcing that node to refresh -# @param idx indicates which control loop or which input channel the command belongs to -# @return idle Always returns system state idle - command sequence completed. -proc rdCrvValue {idx} { - if {[ catch { - set data [sct result] - switch -glob -- $data { - "ASCERR:*" { - puts "ASCERR in rdCrvValue: Last query command: $::scobj::ls3xx::ls3xx_lastQueryCmd" - sct geterror $data - } - default { - if {$data != [sct oldval]} { - sct oldval $data - sct update $data - sct utime readtime - # The calibration curve has changed. - # Set the curve header name to unknown, thus forcing the respective node to refresh - set tc_root $::scobj::ls3xx::ls3xx_path2nodes - set nodename $tc_root/input/calCurveHdr_$idx - hset $nodename "request refresh" - #puts "hset $nodename request refresh" - } - } - } - } message ]} { - return -code error "in rdCrvValue: $message. Last query command: $::scobj::ls3xx::ls3xx_lastQueryCmd" - } - return idle -} - - -################## Writing to nodes ########################################### - -## -# @brief Writes a new value to a node and sends the corresponding command to the device. -# @param tc_root string variable holding the path to the object's base node in sics -# @param nextState the next function to call after this one -# @param cmd the command to be send to the device (written to the node data value) -# @param idx indicates which control loop or which input channel the command belongs to -# @return nextState Is typically noResponse as the device does not acknowledge the write request -proc setValue {tc_root nextState cmd {idx ""}} { - # tc_root and idx are not being used - however, don't remove so we can use the - # same calling mask as for setPoint() or other $wrFunc - if {[ catch { - # Some commands have no argument and no matching read command, like reset_rst or alarmResetAll. - # Provide a default value for parameter 'idx' and initialize 'par' to an empty string because [sct target] - # is not an allowed operation in this case. - set par "" - if {$idx != ""} { - set par [sct target] - } - set ::scobj::ls3xx::ls3xx_lastWriteCmd "$cmd$par" - # Talking to a pseudo-node (no equivalent command in the device communication) - sct send "$cmd$par" - } message ]} { - return -code error "in setValue: $message. While sending command: $::scobj::ls3xx::ls3xx_lastWriteCmd" - } - return $nextState -} - - -## -# @brief Writes a new value to a node but does NOT send the corresponding command to the device. -# @param tc_root string variable holding the path to the object's base node in sics -# @param nextState the next function to call after this one -# @param cmd the command to be send to the device (written to the node data value) -# @param idx indicates which control loop or which input channel the command belongs to -# @return nextState Is typically noResponse as the device does not acknowledge the write request -proc setPseudoValue {tc_root nextState cmd {idx ""}} { - # tc_root and idx are not being used - however, don't remove so we can use the - # same calling mask as for setPoint() or other $wrFunc - if {[ catch { - # Some commands have no argument and no matching read command, like reset_rst or alarmResetAll. - # Provide a default value for parameter 'idx' and initialize 'par' to an empty string because [sct target] - # is not an allowed operation in this case. - set par "" - if {$idx != ""} { - set par [sct target] - } - set ::scobj::ls3xx::ls3xx_lastWriteCmd "$cmd$par" - # Talking to a pseudo-node (no equivalent command in the device communication) - # puts "setPseudoValue($tc_root $nextState $cmd $idx)" - #sct send "$cmd$par" - } message ]} { - return -code error "in setPseudoValue: $message. While processing command: $::scobj::ls3xx::ls3xx_lastWriteCmd" - } - return $nextState -} - - -## -# @brief Is an empty function just so we can define a next state function after a write operation. -# @return idle Returns the default system state indicating that the device is ready for the next command -proc noResponse {} { - return idle -} - - -## -# @brief Sets the desired temperature for the selected control loop: -# @param tc_root string variable holding the path to the object's base node in sics -# @param nextState next state of the device, typically that is 'noResponse' -# @param cmd string variable containing the device command to change the setpoint -# @param whichCtrlLoop specifies whether the setpoint is for control loop 1 or 2 -# @return nextState -proc setPoint {tc_root nextState cmd whichCtrlLoop} { - if {[ catch { - #puts "executing setPoint ($tc_root $nextState $cmd $whichCtrlLoop)" - #broadcast setPoint "executing setPoint ($tc_root $nextState $cmd $whichCtrlLoop)" - set ns ::scobj::lh45 - set par [sct target] - - # determine the corresponding input sensor - # set whichSensor [getCorrespondingInputSensor $whichCtrlLoop] - #hset $tc_root/status "busy" - set wrStatus [sct writestatus] - if {$wrStatus == "start"} { - # Called by drive adapter - # puts "setPoint(): driving set to 1" - set nodename $tc_root/sensor/setpoint$whichCtrlLoop - hsetprop $nodename driving 1 - } - #puts "setPoint(wrStatus=$wrStatus): sct send $cmd$par" - sct send "$cmd$par" - } message ]} { - return -code error "in setPoint: $message. Last write command: $::scobj::ls3xx::ls3xx_lastWriteCmd" - } - return $nextState -} - - -## -# @brief Writes a command directly to the device - device reset and alarm reset commands. -# @param tc_root string variable holding the path to the object's base node in sics -# @param nextState the next function to call after this one -# @param cmd the command to be send to the device (written to the node data value) -# @param idx indicates which control loop or which input channel the command belongs to -# @return nextState Is typically noResponse as the device does not acknowledge the write request -# NOT WORKING CORRECTLY YET -proc sendCmd {tc_root nextState cmd {idx ""}} { - # tc_root and idx are not being used - however, don't remove so we can use the - # same calling mask as for setPoint() or other $wrFunc - if {[ catch { - # Some commands have no argument and no matching read command, like reset_rst or alarmResetAll. - # Provide a default value for parameter 'idx' and initialize 'par' to an empty string because [sct target] - # is not an allowed operation in this case. - set par "" - if {$idx != ""} { - set par [sct target] - } - set ::scobj::ls3xx::ls3xx_lastWriteCmd "$cmd$par" - #sct send "$cmd$par" - if { 0 == [string compare -length 4 $cmd "*RST"]} { - sct_controller queue $tc_root/other/selftest progress read - } elseif { 0 == [string compare -length 6 $cmd "ALMRST"]} { - sct_controller queue $tc_root/input/alarmResetAll progress read - } - } message ]} { - return -code error "in setValue: $message. While sending command: $::scobj::ls3xx::ls3xx_lastWriteCmd" - } - return $nextState -} - - - -############# functions used with drivable ########################################## - -## -# @brief Implement the checkstatus command for the drivable interface -# -# NOTE: The drive adapter initially sets the writestatus to "start" and will -# only call this when writestatus!="start" - proc drivestatus {tc_root} { - if {[ catch { - if {[sct driving]} { - set retval busy - } else { - set retval idle - } - } message ]} { - return -code error "in drivestatus: $message. Last write command: $::scobj::ls3xx::ls3xx_lastWriteCmd" - } - return $retval - } - -## -# @brief Stops driving at current temperature. -# Sets the setpoint to the current temperature of the corresponding input -# @param tc_root string variable holding the path to the object's base node in sics -# @param whichCtrlLoop specifies whether the setpoint is for control loop 1 or 2 -# @return idle Indicates that the device is ready for the next command - proc halt {tc_root whichCtrlLoop} { - # stop driving at current temperature - # determine the corresponding input sensor -# ffr 2009-11-12 TODO what happens if whichSensor is none or UNKOWN, or if whichCtrlLoop > 2, we stay busy forever. - set whichSensor [getCorrespondingInputSensor $whichCtrlLoop] - if {[string length $whichSensor] == 1} { - set sensorValue $tc_root/sensor/sensorValue$whichSensor - if {$whichCtrlLoop <= 2} { - set nodename $tc_root/sensor/setpoint$whichCtrlLoop - hset $nodename [hval $sensorValue] - hsetprop $nodename driving 0 - } - } - return idle - } - -############# Auxiliary functions ########################################## - -## -# @brief Extracts elements from a coma (or other symbol) separated list of values provided in a string -# @param s The string holding a list of values separated by comas -# @param element Index of the element to extract (starts from zero) -# @param separator String holding the separator used in $s, e.g. a coma -# @return returnval String holding the extracted element. String is empty if operation failed. - proc getValFromString {s element separator} { - #puts "getValFromString $s $element $separator" - set startIdx 0 - set endIdx 0 - set eIdx $element - set idx 0 - while {$eIdx > 0} { - set idx [string first $separator $s $startIdx] - if {$idx > 0} { - if { " " == [string range $s $idx $idx]} { - incr idx 1 - } - set startIdx $idx - if {$startIdx > 0} { - incr startIdx 1 - } - } - incr eIdx -1 - } - # startIdx points to the first non-blank character of the value we are interested in - set returnval "" - if {$startIdx < 0} { - return $returnval - } - set endIdx [string first $separator $s $startIdx] - incr endIdx -1 - #puts "startIdx=$startIdx endIdx=$endIdx" - # endIdx points to one character before the next separator or is -1 if it is the - # last element in the string $s - if {$endIdx >= 0} { - set returnval [string range $s $startIdx $endIdx] - } else { - set returnval [string range $s $startIdx 555] - } - #puts "getValFromString $s, $element, $separator,\n returns: $returnval" - return $returnval - } - -## -# @brief determines which input sensor corresponds to this control loop or output -# @param CtrlLoopIdx the control loop (valid values 1,2) or output (1,2,3,4) -# @return iSensor returns A,B,C or D or None or Unknown -proc getCorrespondingInputSensor {CtrlLoopIdx} { - if { $::scobj::ls3xx::ls3xx_LSmodel == 340 } { - if {$CtrlLoopIdx < 1 || $CtrlLoopIdx > 2} { - set iSensor "UNKOWN" - return $iSensor - } - set nodename $::scobj::ls3xx::ls3xx_path2nodes/control/config_Loop_$CtrlLoopIdx - set iSensor [hval $nodename] - set iSensor [string range $iSensor 0 0] - } else { - # LS 336, device command outMode_* - if {$CtrlLoopIdx < 1 || $CtrlLoopIdx > 4} { - set iSensor "UNKOWN" - return $iSensor - } - set nodename $::scobj::ls3xx::ls3xx_path2nodes/control/outMode_$CtrlLoopIdx - set data [hval $nodename] - set input [::scobj::ls3xx::getValFromString $data 1 ","] - switch -glob -- $input { - "0*" {set iSensor "None"} - "1*" {set iSensor "A"} - "2*" {set iSensor "B"} - "3*" {set iSensor "C"} - "4*" {set iSensor "D"} - default {set iSensor "UNKNOWN"} - } - } - return $iSensor -} - - - -## -# @brief Checktol() checks whether the current temperature is within tolerance of the Setpoint. -# @param tc_root string variable holding the path to the object's base node in sics -# @param currtime current time -# @param timecheck time since last check(?) -# @param iLoop index of the control loop we are acting upon (is 1 or 2) -# @param iSensor indicates the corresponding input sensor (A,B,C or D) -# @return retVal returns 1 if in tolerance, 0 else. -proc checktol {tc_root currtime timecheck iLoop iSensor} { - if {[ catch { - set retVal 0 - set sensorValue $tc_root/sensor/sensorValue$iSensor - set temp [hval $sensorValue] - set isetp $tc_root/sensor/setpoint$iLoop - set setpt [hval $isetp] - set tol [hval $tc_root/control/tolerance1] - if {$iLoop == 2 } { - set tol [hval $tc_root/control/tolerance2] - } - set lotemp [expr {$setpt - $tol}] - set hitemp [expr {$setpt + $tol}] - if {$::scobj::ls3xx::ls3xx_verbose==1} { - puts "checktol(): setpt $isetp=$setpt lotemp=$lotemp, current $sensorValue=$temp, hitemp=$hitemp, tol=$tol, iLoop=$iLoop, timecheck=$timecheck, currtime=$currtime" - } - if { $temp < $lotemp || $temp > $hitemp} { - hset $tc_root/emon/isInTolerance_Lp$iLoop "outsideTolerance" - if {$::scobj::ls3xx::ls3xx_verbose==1} {puts "hset $tc_root/emon/isInTolerance_Lp$iLoop outsideTolerance"} - if {$iLoop==1} { sct utime timecheck } - if {$iLoop==2} { sct utime timecheck2 } - set retVal 0 - } else { - set timeout $::scobj::ls3xx::ls340_settleTime - if { $::scobj::ls3xx::ls3xx_LSmodel == 340 } { - set timeout [hval $tc_root/control/settleTime_Loop_1] - } - set elapsedTime [expr {$currtime - $timecheck}] - #puts "if (elapsedTime=$elapsedTime > timeout=$timeout) we are inTolerance" - if {$elapsedTime > $timeout} { - hset $tc_root/emon/isInTolerance_Lp$iLoop "inTolerance" - if {$::scobj::ls3xx::ls3xx_verbose==1} { - puts "hset $tc_root/emon/isInTolerance_Lp$iLoop inTolerance (elapsedTime=$elapsedTime greater than settleTime=$timeout)" - } - set retVal 1 - } else { - # Temperature has not been within tolerance for enough time - (overshoots, oscillations,..) - hset $tc_root/emon/isInTolerance_Lp$iLoop "outsideTolerance" - if {$::scobj::ls3xx::ls3xx_verbose==1} { - puts "hset $tc_root/emon/isInTolerance_Lp$iLoop outsideTolerance (elapsedTime=$elapsedTime less than settleTime=$timeout)" - } - set retVal 0 - } - } - } message ]} { - return -code error "in checktol: $message. Last query command: $::scobj::ls3xx::ls3xx_lastQueryCmd" - } - return $retVal -} - - -## -# @brief check() checks whether the the newly chosen Setpoint is inside the alarm levels -# @param tc_root string variable holding the path to the object's base node in sics -# @param whichCtrlLoop index of the control loop we are operating on (is 1 or 2) -# @return 'OK' if the new setpoint is within the alarm levels; else an error is reported -proc check {tc_root whichCtrlLoop} { - if {[ catch { - set setpoint [sct target] - #puts "check(): setpoint= $setpoint" - # determine the corresponding input sensor - set whichSensor [getCorrespondingInputSensor $whichCtrlLoop] - # puts "check(): whichCtrlLoop=$whichCtrlLoop whichSensor= $whichSensor" - set lolimit $::scobj::ls3xx::alarm_Limit_LoA - set hilimit $::scobj::ls3xx::alarm_Limit_HiA - set bCheckLimits $::scobj::ls3xx::checkAlarmLimitsA - switch $whichSensor { - "A" { - set lolimit $::scobj::ls3xx::alarm_Limit_LoA - set hilimit $::scobj::ls3xx::alarm_Limit_HiA - set bCheckLimits $::scobj::ls3xx::checkAlarmLimitsA - } - "B" { - set lolimit $::scobj::ls3xx::alarm_Limit_LoB - set hilimit $::scobj::ls3xx::alarm_Limit_HiB - set bCheckLimits $::scobj::ls3xx::checkAlarmLimitsB - } - "C" { - set lolimit $::scobj::ls3xx::alarm_Limit_LoC - set hilimit $::scobj::ls3xx::alarm_Limit_HiC - set bCheckLimits $::scobj::ls3xx::checkAlarmLimitsC - } - "D" { - set lolimit $::scobj::ls3xx::alarm_Limit_LoD - set hilimit $::scobj::ls3xx::alarm_Limit_HiD - set bCheckLimits $::scobj::ls3xx::checkAlarmLimitsD - } - default { - error "sct_ls3xx.tcl check(): Can't set setpoint. No valid input sensor specified for this output control loop." - } - } - # puts "check(): doCheck:$bCheckLimits lolimit=$lolimit setpoint=$setpoint hilimit=$hilimit" - if {$bCheckLimits == 1} { - if {$setpoint < $lolimit || $setpoint > $hilimit} { - error "sct_ls3xx.tcl: setpoint $tc_root/sensor/sensorValue$whichSensor violates set alarm limits" - } - } - } message ]} { - return -code error "in check(): $message. Last write command: $::scobj::ls3xx::ls3xx_lastWriteCmd" - } - return OK -} - - -## -# Provides online help for the driver commands available and the meaning of their -# options and parameters. Note that the help text is limited to -# - 500 bytes in total length. -# - 128 characters per line (if not, may get truncated on the display) -# - The following 5 special characters must be escape-coded for xml-compliance: -# Character Name Entity Reference Numeric Reference -# & Ampersand & &#38; -# < Left angle bracket < &#60; -# > Right angle bracket > > -# " Straight quotation mark " ' -# ' Apostrophe ' " -# Note that the xml file will be parsed more than once, meaning that escaping -# special characters may be insufficient and it may be necessary to avoid all -# xml special characters to avoid problems further downstream. It appears also -# that at present gumtree is truncating the help text when it comes across an -# equal sign '=' within the string. Multiple lines are not a problem. -# A later version of Gumtree may show this text as a tooltip - meanwhile it is -# available in the Properties tab of each node. The help text provided is taken -# from the user manual for the Lakeshore 336 and 340 but is shortened in some -# cases due to the restriction to max 500 characters. -proc helpNotes4user {scobj_hpath cmdGroup varName} { - if {[ catch { - set nodeName "$scobj_hpath/$cmdGroup/$varName" - # We presume that SICServer is running on Linux but Gumtree on Windows. - # Hence multi-line help texts should use CRLF instead of only LF - # Note that gumxml.tcl processes the node properties including this help text - # and may do strange things to it... - #set CR 0x0D - #set LF 0x0A - set CR "\r" - set LF "\n" - set CRLF $CR$LF - if {1 > [string length $cmdGroup]} { - set nodeName "$scobj_hpath/$varName" - } - set helptext "No help available" - #puts "helpNotes4user $scobj_hpath/$cmdGroup varName" - switch -glob $varName { - "sensorValue*" { - set h1 {KRDG? «input» Query Kelvin Reading for an Input} - set h2 {Returned: «kelvin value«. Format: nnn.nnn.} - set h3 {Remarks: Returns the kelvin reading for an input. «input» specifies which input to query.} - set helptext $h1$CRLF$h2$CRLF$h3 - } - "ctrlLp*" { - set h1 {KRDG? «input» Query Kelvin Reading for the sensor corresponding to this control loop} - set h2 {Returned: «kelvin value«. Format: nnn.nnn.} - set h3 {Remarks: Returns the kelvin reading for an input. «input» specifies which input to query.} - set helptext $h1$CRLF$h2$CRLF$h3 - } - "Tsample*" { - set helptext {Sample temperature: returns the kelvin reading for the sample input as defined by sampleSensor.} - } - "sampleSensor*" { - set helptext {Specifies the input channel that reads the temperature at the sample location.} - } - "setpoint*" { - set h1 {SETP «loop», «value» Configure Control Loop Setpoint.} - if { $::scobj::ls3xx::ls3xx_LSmodel == 336 } { - set h1 {SETP «output», «value» Set the Setpoint for the selected output's control loop.} - } - set h2 {«value» The value for the setpoint (in whatever units the setpoint is using).} - set h3 {Example: SETP 1, 122.5. Control Loop 1 setpoint is now 122.5 (based on its units).} - set helptext $h1$CRLF$h2$CRLF$h3 - } - "device_busy*" { - set h1 {BUSY? Query Instrument Busy Status. Returned: «instrument busy status». Format: n.} - set h2 {Indicates that the instrument is busy performing a lengthy operation like generating a SoftCal curve, writing to the Flash chip, etc.} - set h3 {Commands that use the Instrument Busy Status say so in their description.} - set helptext $h1$CRLF$h2$CRLF$h3 - } - "cfgProtocol_comm*" { - set h1 {COMM [«terminator»], [«bps»], [«parity»] Configure Serial Interface Parameters.} - set h2 {«terminator» Specifies the terminator: 1: «CR»«LF», 2: «LF»«CR», 3: «CR», 4: «LF»} - set h3 {«bps» Specifies the bits per second (bps) rate. Valid entries: 1: 300, 2: 1200, 3: 2400, 4: 4800, 5: 9600, 6: 19200} - set h4 {«parity» Valid entries: 1: 7 data bits, 1 stop bit, odd parity; 2: 7 data bits, 1 stop bit, even parity;} - set h5 {3: 8 data bits, 1 stop bit, no parity.} - #Example: COMM 1, 6, 3[term]. After receiving the current terminator, the instrument responds at - #19,200 bps using 8 data bits, 1 stop bit, no parity, and «CR»«LF» as a terminator. - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5 - } - "deviceID_idn*" { - set h1 {*IDN? Query Identification. Returned: «manufacturer», «model number», «serial number», «firmware date»} - set h2 {Format: LSCI,MODEL340,aaaaaa,nnnnnn. Remarks: Identifies the instrument model and software level.} - set helptext $h1$CRLF$h2 - } - "relayStatus*" { - set h1 {RELAYST? «high/low» Queries specified Relay Status} - set h2 {Returned: «status». Format: n} - set h3 {Returns specified relay status,: 0 : off, 1 : on} - set helptext $h1$CRLF$h2$CRLF$h3 - } - "relayCtrlParmHi*" { - set h1 {RELAY «high/low», [«mode»], [«off/on»] } - set h2 {Configure Relay Control Parameters for the HIGH relay.} - set h3 {«mode» Specifies relay settings mode. Valid entries: 0 : off, 1 : alarms, 2 : manual.} - set h4 {«off/on» off:0, on:1 Specifies the manual relay settings if «mode» : 2.} - set h5 {Example: RELAY 1, 2, 1. Manually turns on the high relay} - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5 - if { $::scobj::ls3xx::ls3xx_LSmodel == 336 } { - set h1 {RELAY «high/low», «mode», «input alarm», «alarm type» } - set h3 {«mode» Specifies relay settings mode. Valid entries: 0:off, 1:on, 2:alarms.} - set h4 {«input alarm» Specifies which input alarm activates the relay when it is in alarm mode (A-D).} - set h5 {«alarm type» Specifies the alarm type that activates the relay. 0:Low alarm, 1:High alarm, 2:Both alarms} - set h6 {Example: RELAY 1,2,B,0. Relay 1 (Hi) activates when input B low alarm activates.} - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5$CRLF$h6 - } - } - "relayCtrlParmLo*" { - set h1 {RELAY «high/low», [«mode»], [«off/on»] } - set h2 {Configure Relay Control Parameters for the LOW relay} - set h3 {«mode» Specifies relay settings mode. Valid entries: 0 : off, 1 : alarms, 2 : manual.} - set h4 {«off/on» off:0, on:1 Specifies the manual relay settings if «mode» : 2.} - set h5 {Example: RELAY 1, 2, 1. Manually turns on the high relay} - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5 - if { $::scobj::ls3xx::ls3xx_LSmodel == 336 } { - set h1 {RELAY «high/low», «mode», «input alarm», «alarm type» } - set h3 {«mode» Specifies relay settings mode. Valid entries: 0:off, 1:on, 2:alarms.} - set h4 {«input alarm» Specifies which input alarm activates the relay when it is in alarm mode (A-D).} - set h5 {«alarm type» Specifies the alarm type that activates the relay. 0:Low alarm, 1:High alarm, 2:Both alarms} - set h6 {Example: RELAY 2,2,B,0. Relay 2 (Lo) activates when input B low alarm activates.} - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5$CRLF$h6 - } - } - "reset_rst*" { - set h1 {*RST Reset Instrument. Returned: Nothing.} - set h2 {Sets controller parameters to power_up settings.} - set helptext $h1$CRLF$h2 - } - "selftest*" { - set h1 {*TST? Query Self Test. Returned: 0 or 1. Format: n.} - set h2 {The Lakeshore 336 and 340 perform a selftest at power_up. 0 : no errors found, 1 : errors found.} - set helptext $h1$CRLF$h2 - } - "statusByte*" { - set h1 {*STB? Query Status Byte. The integer returned represents the sum of the bit weighting of the status flag bits that} - set h2 {are set in the Status Byte Register. Acts like a serial poll, but does not reset the register to all zeros.} - set h3 {Bit Bit Weighting Event Name} - set h4 {0 1 New A and B} - set h5 {1 2 New Option} - set h6 {2 4 Settle} - set h7 {3 8 Alarm} - set h8 {4 16 Error} - set h9 {5 32 ESB Event summary bit} - set hA {6 64 SRQ Service request bit} - set hB {7 128 Ramp Done} - if { $::scobj::ls3xx::ls3xx_LSmodel == 336 } { - set h4 {0 1 not used} - set h5 {1 2 not used} - set h6 {2 4 not used} - set h7 {3 8 not used} - set h8 {4 16 MAV Message available bit} - set h9 {5 32 ESB Event summary bit} - set hA {6 64 RQS Request service bit} - set hB {7 128 OSB Operation summary bit} - } - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5$CRLF$h6$CRLF$h7$CRLF$h8$CRLF$h9$CRLF$hA$CRLF$hB - } - "alarm_Limits_*" { - set h1 {ALARM «input», [«off/on»], [«source»], [«high value»], [«low value»], [«latch enable»], [«relay»]} - set h2 {Configures the alarm parameters for an input} - set h3 {«off/on» check the alarm for this input} - set h4 {«source» units for high/low values 1:Kelvin, 2:Celsius, 3:Sensor units, 4:Linear data} - set h5 {«high value» Limit to activate the high alarm} - set h6 {«low value» Limit to activate low alarm} - set h7 {«latch enable» enable latched alarm} - set h8 {«relay enable» 0:off, 1:on} - set h9 { } - #«relay enable» Specifies how the activated alarm affects relays. NOTE: Does not - #guarantee the alarm activates the relays. See the RELAY command. - #Example: ALARM A, 0. Turns off alarm checking for Input A. - #ALARM B, 1, 1, 270.0, ,1. Turns on alarm checking for input B, activates high alarm if - #kelvin reading is over 270, and latches the alarm when kelvin reading falls below 270 - if { $::scobj::ls3xx::ls3xx_LSmodel == 336 } { - set h1 {ALARM «input», [«off/on»], [«high value»], [«low value»], [«deadband»], [«latch enable»], [«audible»], [«visible»]} - set h2 {Configures alarm parameters for an input} - set h3 {«off/on» check the alarm for this input} - set h4 {«high value» Limit to activate the high alarm} - set h5 {«low value» Limit to activate low alarm} - set h6 {«deadband» sets the value the source must change} - set h7 {«latch enable» enable latched alarm} - set h8 {«audible» alarm 0:off,1:on} - set h9 {«visible» alarm 0:off,1:on} - } - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5$CRLF$h6$CRLF$h7$CRLF$h8$CRLF$h9 - } - "alarm_Limit_Lo*" { - set h1 {ALARM_Lo «input»,«low value»} - set h2 {«low value» Sets the value the source is checked against to activate low alarm.} - set helptext $h1$CRLF$h2 - } - "alarm_Limit_Hi*" { - set h1 {ALARM_Hi «input»,«high value»} - set h2 {«high value» Sets the value the source is checked against to activate the high alarm.} - set helptext $h1$CRLF$h2 - } - "alarmStatus*" { - set h1 {ALARMST? «input» Query Input Alarm Status.} - set h2 {Returned: «high status», «low status». Format: n,n.} - set h3 {Remarks: Returns the alarm status of an input. «input» specifies which input to query.} - set helptext $h1$CRLF$h2$CRLF$h3 - } - "calCurveHdr*" { - set h1 {CRVHDR «curve», [«name»], [«SN»], [«format»], [«limit value»], [«coefficient»]} - set h2 {Configures the user curve header} - set h3 {«curve» Specifies which curve to configure (21 - 59)} - set h4 {«name» Curve name (max 15 chars).} - set h5 {«SN» Curve serial number (max 10 chars)} - set h6 {«format» Curve data format (1:mV/K, 2:V/K, 3:Ω/K, 4:log Ω/K, 5:log Ω/log K)} - set h7 {«limit value» Curve temperature limit in kelvin.} - set h8 {«coefficient» Curves temperature coefficient (1:negative,2:positive)} - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5$CRLF$h6$CRLF$h7$CRLF$h8 - } - "inpSetup*" { - set h1 {INSET «input», «enable», «compensation»} - set h2 {Configure hardware input setup parameters} - set h3 {«input» Specifies which input to configure (A,B,C,D)} - set h4 {«enable» Specifies whether the input is allowed to be read.} - set h5 {«compensation» For NTC resistors and special sensors only. 0: off, 1: on, 2: pause} - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5 - } - "inpCalCurve*" { - set h1 {INCRV «input», «curve number»} - set h2 {Specifies the curve an input uses for temperature conversion.} - set h3 {«input» Specifies which input to configure (A,B,C,D)} - set h4 {«curve number» Specifies which curve the input uses. If specified curve parameters do not match the input,} - set h5 {the curve number defaults to 0. 0: none, 1 to 20: standard curves, 21 to 59: user curves} - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5 - } - "alarmResetAll*" { - set helptext {ALMRST Clear Alarm Status for All Inputs} - } - "sensorType*" { - set h1 {INTYPE «input», [«type»], [«units»], [«coeff»], [«excitation»], [«range»]} - set h2 {Configure Input Type Parameters} - set h3 {«type» 0:Special,1:SiDiode,2:GaAlAsDiode,3:Platinum100 (250Ω),4:as 3 (500Ω),5:Platinum1000,6:RhodiumIron,7:CarbonGlass,} - set h4 {8:Cernox,9:RuOx,10:Ge,11:Capacitor,12:Thermocpl} - set h5 {«units» Sensor units 1:Volts,2:ohms} - set h6 {«coefficient» input coeff. 1:neg,2:pos} - set h7 {«excitation» 0:Off,1:30nA,2:100nA,3:300nA,..} - set h8 {«range» 1:1mV,2:2.5mV,..} - # Lakeshore 340 model only - # <excitation> 0:Off,1:30nA,2:100nA,3:300nA,4:1µA,5:3µA,6:10µA,7:30µA,8:100µA,9:300µA,10:1mA,11:10mV,12:1mV - # <range> 1:1 mV,2:2.5 mV,3:5 mV,4:10 mV,5:25 mV,6:50 mV,7:100 mV,8:250 mV,9:500 mV,10:1 V,11:2.5V,12:5 V,13:7.5 V - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5$CRLF$h6$CRLF$h7$CRLF$h8 - } - "inputType*" { - set h1 {INTYPE «input», [«type»], [«autorange»], [«range»], [«compensation»], [«units»]} - set h2 {Configure Input Type Parameters} - set h3 {«type» 0:Disabled,1:Diode,2:PlatinumRTD,3:NTC RTD,4:Thermocouple} - set h4 {«autorange» 0:off,1:on} - set h5 {«range» specifies range if autorange is off} - set h6 {«compensation» 0:off,1:on. Reversal for thermal EMF compensation if input} - set h7 { is resistive, room comp. if input is thermocpl. Always 0 if input is diode} - set h8 {«units» Sensor and setpoint units 1:Kelvin,2:Celsius,3:Sensor} - # Lakeshore 336 model only - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5$CRLF$h6$CRLF$h7$CRLF$h8 - } - "minMaxInpFunc*" { - set h1 {MNMX? «input» Query Minimum and Maximum Input Function Parameters} - set h2 {Returned: «on/pause», «source». Format: n,n} - set h3 {«on/pause» Turns on or Pauses the max/min function. Valid entries: 1 : on, 2 : paused.} - set h4 {«source» Specifies input data to process through max/min. Valid entries: 1 : Kelvin,} - set h5 {2 : Celsius, 3 : sensor units, 4 : linear data} - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5 - } - "sensorStatus*" { - set h1 {RDGST? «input» Query Input Status. Returned: «reading bit weighting»} - set h2 {The integer returned represents the sum of the bit weighting of the input status flag bits} - set h3 {Bit Weighting StatusIndicator} - set h4 {0 1 invalid reading} - set h5 {1 2 old reading} - set h6 {4 16 temp underrange} - set h7 {5 32 temp overrange} - set h8 {6 64 units zero} - set h9 {7 128 units overrange} - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5$CRLF$h6$CRLF$h7$CRLF$h8$CRLF$h9 - } - "ctrl_Limit*" { - set h1 {CLIMIT «loop», [«SP limit value»],[«pos slope value»],[«neg slope value»],[«max current»],[«max range»]} - set h2 {Control Loop Limit Parameters} - set h3 {«SP limit value» limit at which the loop turns off output} - set h4 {«positive slope value» max pos change in output} - set h5 {«negative slope value» max neg change in output} - set h6 {«max current» Max current for loop 1 heater output (1:0.25A,2:0.5A,3:1.0A,4:2.0A,5:User)} - set h7 {«max range» Max loop 1 heater range (0 to 5)} - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5$CRLF$h6$CRLF$h7 - } - "ctrl_Mode*" { - set h1 {CMODE «loop», «mode» Configure Control Loop Mode} - set h2 {«mode» Specifies the control mode. Valid entries: 1: Manual PID,2: Zone,3: Open Loop,4: AutoTune PID, 5: AutoTune PI, 6: AutoTune P} - set h3 {Example: CMODE 1, 4. Control Loop 1 uses PID AutoTuning.} - set helptext $h1$CRLF$h2$CRLF$h3 - } - "outMode_*" { - set h1 {OUTMODE «output», «mode» «input» «powerup enable» Output Mode Command} - set h2 {«mode» Specifies the control mode. Valid entries: 0:off, 1:Closed loop PID,2:Zone,3:Open Loop,4:Monitor out, 5:Warmup Supply} - set h3 {«input» which input to use for control. 0:none, 1:A, 2:B, 3:C, 4:D} - set h4 {«powerup enable» 0:output shuts off 1:output remains on after power cycle} - set h5 {Remarks: Modes 1 and 2 are only valid for heater outputs, and modes 4 and 5 are only valid for Monitor Out} - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5 - } - "config_Loop*" { - set h1 {CSET «loop», [«input»], [«units»], [«off/on»], [«powerup enable»] Configure Control Loop Parameters} - set h2 {«input» which input to control from. (A,B,..)} - set h3 {«units» Setpoint units. 1: Kelvin, 2: Celsius, 3: sensor units} - set h4 {«off/on» Control loop is on:1 or off:0} - set h5 {«powerup enable» Control loop is on or off after power_up} - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5 - } - "ctrl_Loop*" { - set h1 {Shows the Control Loop Parameters.} - set h2 {Use the /control/config_Loop_x entry to change settings} - if { $::scobj::ls3xx::ls3xx_LSmodel == 336 } { - set h1 {Shows the Output Control Parameters.} - set h2 {Use the /control/outMode_x entry to change settings} - } - set helptext $h1$CRLF$h2 - } - "pid_Loop*" { - set h1 {PID «loop», [«P value»], [«I value»], [«D value»] Configure Control Loop PID Values} - if { $::scobj::ls3xx::ls3xx_LSmodel == 336 } { - set h1 {PID «output», [«P value»], [«I value»], [«D value»] Configure Control Loop PID Values} - } - set h2 {«P value» The value for P (proportional)} - set h3 {«I value» The value for I (integral)} - set h4 {«D value» The value for D (derivative)} - set h5 {Example: PID 1, 10, 50. Control Loop 1 P is 10 and I is 50.} - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5 - } - "ramp_Loop*" { - set h1 {RAMP «loop», [«off/on»], [«rate value»] Configure Ramp Parameters for specified Control Loop} - if { $::scobj::ls3xx::ls3xx_LSmodel == 336 } { - set h1 {RAMP «output», [«off/on»], [«rate value»] Configure Ramp Parameters for specified output} - } - set h2 {«off/on» Specifies whether ramping is off or on} - set h3 {«rate value» Specifies how many kelvin per minute to ramp the setpoint (0.1 - 100)} - set h4 {Example: RAMP 1, 1, 10.5. When Control Loop 1 setpoint is changed, ramp the current setpoint to the target setpoint at 10.5 K/minute.} - if { $::scobj::ls3xx::ls3xx_LSmodel == 336 } { - set h4 {Example: RAMP 1, 1, 10.5. When the setpoint for output 1 is changed, ramp the current setpoint to the target setpoint at 10.5 K/minute.} - } - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4 - } - "rampStatus_Loop*" { - set h1 {RAMPST? «loop» Query Ramp Status for specified Control Loop.} - if { $::scobj::ls3xx::ls3xx_LSmodel == 336 } { - set h1 {RAMPST? «output» Query Ramp Status for specified output.} - } - set h2 {Returned: «ramp status». Format: n} - set h3 {Remarks: Returns 0 if setpoint is not ramping, and 1 if it is ramping. «loop» specifies loop to query.} - set helptext $h1$CRLF$h2$CRLF$h3 - } - "settle*" { - set h1 {SETTLE [«threshold»], [«time»] Sets Loop_1 Settle Parameters} - set h2 {«threshold» Specifies the allowable band around the setpoint. Valid entries: 0.0 to 100.00} - set h3 {«time» Specifies time in seconds the reading must stay within the band. Valid entries: 0 to 86400} - set h4 {Example: SETTLE 10.0, 10. The Control Loop 1 input readings must be within ±10 K of the setpoint for 10 seconds before the Within Control Limit flag is set.} - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4 - } - "heaterOutp*" { - set h1 {HTR? Query Heater Output.} - set h2 {Returned: «heater value». Format: nnn.n.} - set h3 {Remarks: Returns the heater output in percent.} - set helptext $h1$CRLF$h2$CRLF$h3 - if { $::scobj::ls3xx::ls3xx_LSmodel == 336 } { - set h1 {HTR? «output» Query Heater Output.} - set h2 {«output» is 1 or 2; use command AOUT for output 3 and 4.} - set h3 {Returned: «heater value». Format: nnn.n.} - set h4 {Remarks: Returns the heater output in percent.} - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4 - } - } - "manualOut_*" { - set h1 {MOUT «loop», «value» Manual Output Command.} - set h2 {«loop» specifies the control loop to configure: 1-4.} - if { $::scobj::ls3xx::ls3xx_LSmodel == 336 } { - set h1 {MOUT «output», «value» Manual Output Command.} - set h2 {«output» specifies output to configure: 1-4.} - } - set h3 {«value» Specifies value for manual output in percent (non-integer allowed).} - set h4 {Remarks: Requires closed-loop-PID, Zone, or Open-Loop mode.} - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4 - } - "heaterStatus*" { - set h1 {HTRST? Query Heater Status. Returned: «error code». Format: nn.} - if { $::scobj::ls3xx::ls3xx_LSmodel == 336 } { - set h1 {HTRST? «output» Query Heater Status. Returned: «error code». Format: nn.} - } - set h2 {Remarks: Returns the heater error code (User Manual Paragraph 11.8).} - set h3 {A value of zero means that the system is happy.} - set helptext $h1$CRLF$h2$CRLF$h3 - } - "heaterRange*" { - if { $::scobj::ls3xx::ls3xx_LSmodel == 340 } { - set h1 {RANGE «range» Configure Heater Range} - set h2 {«range» specifies the heater range (0 to 5)} - set h3 {0 : heater switched off} - set h4 {1 : 5 mW} - set h5 {2 : 50 mW} - set h6 {3 : 500 mW} - set h7 {4 : 5 W} - set h8 {5 : 50 W} - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5$CRLF$h6$CRLF$h7$CRLF$h8 - } else { - set h1 {RANGE «output» «range» Configure Heater Range} - set h2 {«output» specifies which output (1,2,3,4)} - set h3 {«range» specifies the heater range (0 to 3)} - set h4 {0 : heater switched off} - set h5 {1 : low} - set h6 {2 : medium} - set h7 {3 : high} - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5$CRLF$h6$CRLF$h7 - } - } - "isInTolerance_Lp*" { - set h1 {A flag that indicates whether the actual temperature is within tolerance} - set h2 {of the setpoint temperature for that control loop.} - set helptext $h1$CRLF$h2 - } - "apply_tolerance*" { - set h1 {A flag that indicates whether the control loop should actively try} - set h2 {to keep the temperature within the set tolerance of the setpoint.} - set helptext $h1$CRLF$h2 - } - "tolerance*" { - set h1 {Tolerance specifies the temperature tolerance in Kelvin applicable to the setpoint.} - set helptext $h1 - } - "monMode_Lp*" { - set h1 {A flag that indicates whether heaters or other active components are attempting to} - set h2 {drive the temperature towards the setpoint or whether they are currently inactive} - set h3 {with the device just monitoring while the temperature is in tolerance with the setpoint.} - set helptext $h1$CRLF$h2$CRLF$h3 - } - "errhandler*" { - set h1 {Specifies the default action in case of a serious error.} - set h2 {The default action is always 'pause'.} - set helptext $h1$CRLF$h2 - } - "dateTime*" { - set h1 {DATETIME «MM»,«DD»,«YYYY»,«HH»,«mm»,«SS»,«sss» Configure Date and Time.} - set h2 {«MM» Month} - set h3 {«DD» Day of month} - set h4 {«YYYY» Year} - set h5 {«HH» Hours (0..23)} - set h6 {«mm» Minutes} - set h7 {«SS» Seconds} - set h8 {«sss» milliseconds} - set helptext $h1$CRLF$h2$CRLF$h3$CRLF$h4$CRLF$h5$CRLF$h6$CRLF$h7$CRLF$h8 - } - "timStamp*" { - set h1 {Time stamp. Seconds since 1st January 2000.} - set h2 {See node /other/dateTime for editing and formatted date/time display.} - set helptext $h1$CRLF$h2 - } - "status*" { - set helptext {Device status. Is 'idle' while in tolerance or 'busy' while driving or resetting} - } - default { - set helptext {Sorry mate. No help available.} - puts "No help info available for node $varName" - } - } - #set sLen [string bytelength $helptext] - #puts "helptext ($sLen bytes) $helptext" - hsetprop $nodeName help $helptext - } message ]} { - return -code error "in helpNotes4user: $message" - } -} - -## -# @brief createNode() creates a node for the given nodename with the properties and virtual -# function names provided -# @param scobj_hpath string variable holding the path to the object's base node in sics (/sample/tc1) -# @param sct_controller name of the ls3xx scriptcontext object (typically sct_ls3xx_tc1 or tc2) -# @param cmdGroup subdirectory (below /sample/tc*/) in which the node is to be created -# @param varName name of the actual node typically representing one device command -# @param readable set to 1 if the node represents a query command, 0 if it is not -# @param writable set to 1 if the node represents a request for a change in settings sent to the device -# @param pollEnabled set to 1 if the node property pollable is to be enabled (node gets read every 5 secs) -# @param drivable if set to 1 it prepares the node to provide a drivable interface -# @param idx indicates which control loop or which input channel the command corresponds to -# @param ls340 set to 1 if this command is supported by device model-340 -# @param ls336 set to 1 if this command is supported by device model-336 -# @param dataType data type of the node, must be one of none, int, float, text -# @param permission defines what user group may read/write to this node (is one of spy, user, manager) -# @param rdCmd actual device query command to be sent to the device -# @param rdFunc nextState Function to be called after the getValue function, typically rdValue() -# @param wrCmd actual device write command to be sent to the device -# @param wrFunc Function to be called to send the wrCmd to the device, typically setValue() -# @param allowedValues allowed values for the node data - does not permit other -# @param klasse Nexus class name (?) -# @return OK -proc createNode {scobj_hpath sct_controller cmdGroup varName readable writable - pollEnabled drivable idx ls340 ls336 dataType permission rdCmd rdFunc wrCmd - wrFunc allowedValues klasse lsModel} { - #puts "createing node for: $scobj_hpath $cmdGroup $varName $readable $writable $pollEnabled $drivable $idx $dataType $permission $rdCmd $rdFunc $wrCmd $wrFunc" - #puts "createNode, lsModel = $lsModel, ls340=$ls340, ls336=$ls336, varName=$varName " - if {$lsModel == 340 && $ls340 == 0} { - # puts "Command node $cmdGroup/$varName not supported by Lakeshore $lsModel" - return OK - } - # Nothing to do - if {$lsModel == 336 && $ls336 == 0} { - # puts "Info: Command node $cmdGroup/$varName not supported by Lakeshore $lsModel" - return OK - } - # It is a command that is supported by the device - if {[ catch { - set ns ::scobj::ls3xx - set nodeName "$scobj_hpath/$cmdGroup/$varName" - if {1 > [string length $cmdGroup]} { - set nodeName "$scobj_hpath/$varName" - } - hfactory $nodeName plain $permission $dataType - if {$readable == 1} { - hsetprop $nodeName read ${ns}::getValue $scobj_hpath $rdFunc $rdCmd $idx - } - if {$pollEnabled == 1} { - # puts "enabling polling for $nodeName" - $sct_controller poll $nodeName - } - hsetprop $nodeName $rdFunc ${ns}::$rdFunc $idx - if {$writable == 1} { - hsetprop $nodeName write ${ns}::$wrFunc $scobj_hpath noResponse $wrCmd $idx - hsetprop $nodeName writestatus UNKNOWN - hsetprop $nodeName noResponse ${ns}::noResponse - if {$pollEnabled == 1} { - $sct_controller write $nodeName - } - } - switch -exact $dataType { - "none" { } - "int" { hsetprop $nodeName oldval -1 } - "float" { hsetprop $nodeName oldval -1.0 } - default { hsetprop $nodeName oldval UNKNOWN } - } - if {1 < [string length $allowedValues]} { - hsetprop $nodeName values $allowedValues - } - # Drive adapter interface - if {$drivable == 1} { - hsetprop $nodeName check ${ns}::check $scobj_hpath 1 - hsetprop $nodeName driving 0 - hsetprop $nodeName checklimits ${ns}::check $scobj_hpath $idx - hsetprop $nodeName checkstatus ${ns}::drivestatus $scobj_hpath - hsetprop $nodeName halt ${ns}::halt $scobj_hpath $idx - } - } message ]} { - return -code error "in createNode $message" - } - helpNotes4user $scobj_hpath $cmdGroup $varName - return OK -} - - - ## - # @brief mk_sct_lakeshore_3xx() creates a scriptcontext object for a Lakeshore 336 or 340 temperature controller - # @param sct_controller name of the ls3xx scriptcontext object (typically sct_ls3xx_tc1 or tc2) - # @param klasse Nexus class name (?), typically 'environment' - # @param tempobj short name for the temperature controller scriptcontext object (typ. tc1 or tc2) - # @param tol temperature tolerance in Kelvin (typ. 1) - # @return nothing (well, the sct object) - proc mk_sct_lakeshore_3xx {sct_controller klasse tempobj LSmodel tol1 tol2 verbose} { - if {[ catch { - set ::scobj::ls3xx::ls3xx_driveTolerance1 $tol1 - set ::scobj::ls3xx::ls3xx_driveTolerance2 $tol2 - set ::scobj::ls3xx::ls3xx_LSmodel $LSmodel - set ::scobj::ls3xx::ls3xx_verbose $verbose - set ns ::scobj::ls3xx - set ::scobj::ls3xx::ls3xx_sct_obj_name $tempobj - - # terminator string for serial communication (empty for ls340, taken care of with the COMM command) - #set CR "\r" - #set LF "\n" - #Wombat uses only CR not CRLF - #set ::scobj::ls3xx::ls3xx_term "" ! obsolete - - MakeSICSObj $tempobj SCT_OBJECT - sicslist setatt $tempobj klass $klasse - sicslist setatt $tempobj long_name $tempobj - # Create a base node for all the state machines of this sics object - set scobj_hpath /sics/$tempobj - set ::scobj::ls3xx::ls3xx_path2nodes $scobj_hpath - - # Create state machines for the following device commands (non-polled entries are place-holders - # for manually maintained nodes, like the selector for the input that provides the sample temperature - # 'sampleSensor', the sample tempreature reading 'Tsample', the input that provides for the controlLoop - # 'value', and the control loop parameters in human-readable form 'ctrl_Loop_x') - # Note that drivable nodes require the index of the control loop in their call to halt() - # Nodes appear in gumtree in the order in which they are created here. - # - # Initialise the model-dependent list of supported device commands - # RdWrPlDrIdx - # cmdGroup subdirectory (below /sample/tc*/) in which the node is to be created - # varName name of the actual node typically representing one device command - # readable set to 1 if the node represents a query command, 0 if it is not - # writable set to 1 if the node represents a request for a change in settings sent to the device - # pollEnabled set to 1 if the node property pollable is to be enabled (node gets read every 5 secs) - # drivable if set to 1 it prepares the node to provide a drivable interface - # idx indicates which control loop or which input channel the command corresponds to - # ls340 command supported by Lakeshore model 340 - # ls336 command supported by Lakeshore model 336 - # dataType data type of the node, must be one of none, int, float, text - # permission defines what user group may read/write to this node (is one of spy, user, manager) - # rdCmd actual device query command to be sent to the device - # rdFunc nextState Function to be called after the getValue function, typically rdValue() - # wrCmd actual device write command to be sent to the device - # wrFunc Function to be called to send the wrCmd to the device, typically setValue() - # allowedValues allowed values for the node data - does not permit other - set deviceCommandToplevel { - sensor sampleSensor 0 1 0 0 1 1 1 text user {CSET? 1} {rdValue} {InpSample } {setPseudoValue} {A,B,C,D} - sensor Tsample 1 0 0 0 1 1 1 float spy {KRDG? A} {rdValue} {} {setValue} {} - sensor ctrl_Loop_1 1 0 0 0 1 1 1 text user {CSET? 1} {rdValue} {} {setValue} {} - sensor ctrlLp1_value 1 0 0 0 1 1 1 float spy {KRDG? A} {rdValue} {} {setValue} {} - sensor setpoint1 1 1 1 1 1 1 1 float user {SETP? 1} {rdValue} {SETP 1,} {setPoint} {} - sensor ctrl_Loop_2 1 0 0 0 2 1 1 text user {CSET? 2} {rdValue} {} {setValue} {} - sensor ctrlLp2_value 1 0 0 0 2 1 1 float spy {KRDG? B} {rdValue} {} {setValue} {} - sensor setpoint2 1 1 1 1 2 1 1 float user {SETP? 2} {rdValue} {SETP 2,} {setPoint} {} - sensor ctrl_Loop_3 1 0 0 0 3 0 1 text user {CSET? 3} {rdValue} {} {setValue} {} - sensor ctrlLp3_value 1 0 0 0 3 0 1 float spy {KRDG? C} {rdValue} {} {setValue} {} - sensor setpoint3 1 1 1 1 3 0 1 float user {SETP? 3} {rdValue} {SETP 3,} {setPoint} {} - sensor ctrl_Loop_4 1 0 0 0 4 0 1 text user {CSET? 4} {rdValue} {} {setValue} {} - sensor ctrlLp4_value 1 0 0 0 4 0 1 float spy {KRDG? D} {rdValue} {} {setValue} {} - sensor setpoint4 1 1 1 1 4 0 1 float user {SETP? 4} {rdValue} {SETP 4,} {setPoint} {} - sensor sensorValueA 1 0 1 0 A 1 1 float spy {KRDG? A} {rdInpValue} {} {setValue} {} - sensor sensorValueB 1 0 1 0 B 1 1 float spy {KRDG? B} {rdInpValue} {} {setValue} {} - sensor sensorValueC 1 0 1 0 C 1 1 float spy {KRDG? C} {rdInpValue} {} {setValue} {} - sensor sensorValueD 1 0 1 0 D 1 1 float spy {KRDG? D} {rdInpValue} {} {setValue} {} - sensor timStamp 1 0 0 0 0 1 0 int user {DATETIME?} {rdValue} {} {setValue} {} - } - set deviceCommand { - input alarm_Limits_A 1 1 1 0 A 1 1 text spy {ALARM? A} {rdAlarmVal} {ALARM A,} {setValue} {} - input alarm_Limits_B 1 1 1 0 B 1 1 text spy {ALARM? B} {rdAlarmVal} {ALARM B,} {setValue} {} - input alarm_Limits_C 1 1 1 0 C 1 1 text spy {ALARM? C} {rdAlarmVal} {ALARM C,} {setValue} {} - input alarm_Limits_D 1 1 1 0 D 1 1 text spy {ALARM? D} {rdAlarmVal} {ALARM D,} {setValue} {} - input alarmStatusA 1 0 1 0 A 1 1 text spy {ALARMST? A} {rdValue} {} {setValue} {} - input alarmStatusB 1 0 1 0 B 1 1 text spy {ALARMST? B} {rdValue} {} {setValue} {} - input alarmStatusC 1 0 1 0 C 1 1 text spy {ALARMST? C} {rdValue} {} {setValue} {} - input alarmStatusD 1 0 1 0 D 1 1 text spy {ALARMST? D} {rdValue} {} {setValue} {} - input inpSetup_A 1 1 1 0 A 1 0 text user {INSET? A} {rdValue} {INSET A,} {setValue} {} - input inpSetup_B 1 1 1 0 B 1 0 text user {INSET? B} {rdValue} {INSET B,} {setValue} {} - input inpSetup_C 1 1 1 0 C 1 0 text user {INSET? C} {rdValue} {INSET C,} {setValue} {} - input inpSetup_D 1 1 1 0 D 1 0 text user {INSET? D} {rdValue} {INSET D,} {setValue} {} - input inpCalCurve_A 1 1 1 0 A 1 1 int user {INCRV? A} {rdCrvValue} {INCRV A,} {setValue} {} - input calCurveHdr_A 1 0 1 0 A 1 1 text user {CRVHDR? } {rdValue} {} {setValue} {} - input inpCalCurve_B 1 1 1 0 B 1 1 int user {INCRV? B} {rdCrvValue} {INCRV B,} {setValue} {} - input calCurveHdr_B 1 0 1 0 B 1 1 text user {CRVHDR? } {rdValue} {} {setValue} {} - input inpCalCurve_C 1 1 1 0 C 1 1 int user {INCRV? C} {rdCrvValue} {INCRV C,} {setValue} {} - input calCurveHdr_C 1 0 1 0 C 1 1 text user {CRVHDR? } {rdValue} {} {setValue} {} - input inpCalCurve_D 1 1 1 0 D 1 1 int user {INCRV? D} {rdCrvValue} {INCRV D,} {setValue} {} - input calCurveHdr_D 1 0 1 0 D 1 1 text user {CRVHDR? } {rdValue} {} {setValue} {} - input sensorTypeA 1 1 1 0 A 1 0 text user {INTYPE? A} {rdValue} {INTYPE A,} {setValue} {} - input sensorTypeB 1 1 1 0 B 1 0 text user {INTYPE? B} {rdValue} {INTYPE B,} {setValue} {} - input sensorTypeC 1 1 1 0 C 1 0 text user {INTYPE? C} {rdValue} {INTYPE C,} {setValue} {} - input sensorTypeD 1 1 1 0 D 1 0 text user {INTYPE? D} {rdValue} {INTYPE D,} {setValue} {} - input inputTypeA 1 1 1 0 A 0 1 text user {INTYPE? A} {rdValue} {INTYPE A,} {setValue} {} - input inputTypeB 1 1 1 0 B 0 1 text user {INTYPE? B} {rdValue} {INTYPE B,} {setValue} {} - input inputTypeC 1 1 1 0 C 0 1 text user {INTYPE? C} {rdValue} {INTYPE C,} {setValue} {} - input inputTypeD 1 1 1 0 D 0 1 text user {INTYPE? D} {rdValue} {INTYPE D,} {setValue} {} - input minMaxInpFuncA 1 0 1 0 A 1 0 int user {MNMX? A} {rdValue} {} {setValue} {} - input minMaxInpFuncB 1 0 1 0 B 1 0 int user {MNMX? B} {rdValue} {} {setValue} {} - input minMaxInpFuncC 1 0 1 0 C 1 0 int user {MNMX? C} {rdValue} {} {setValue} {} - input minMaxInpFuncD 1 0 1 0 D 1 0 int user {MNMX? D} {rdValue} {} {setValue} {} - input sensorStatusA 1 0 1 0 A 1 1 int spy {RDGST? A} {rdBitValue} {} {setValue} {} - input sensorStatusB 1 0 1 0 B 1 1 int spy {RDGST? B} {rdBitValue} {} {setValue} {} - input sensorStatusC 1 0 1 0 C 1 1 int spy {RDGST? C} {rdBitValue} {} {setValue} {} - input sensorStatusD 1 0 1 0 D 1 1 int spy {RDGST? D} {rdBitValue} {} {setValue} {} - control config_Loop_1 1 1 1 0 1 1 0 text user {CSET? 1} {rdCfgValue} {CSET 1,} {setValue} {} - control config_Loop_2 1 1 1 0 2 1 0 text user {CSET? 2} {rdCfgValue} {CSET 2,} {setValue} {} - control ctrl_Limit_1 1 1 1 0 1 1 0 text user {CLIMIT? 1} {rdValue} {CLIMIT 1,} {setValue} {} - control ctrl_Limit_2 1 1 1 0 2 1 0 text user {CLIMIT? 2} {rdValue} {CLIMIT 2,} {setValue} {} - control ctrl_Mode_1 1 1 1 0 1 1 0 int user {CMODE? 1} {rdValue} {CMODE 1,} {setValue} {} - control ctrl_Mode_2 1 1 1 0 2 1 0 int user {CMODE? 2} {rdValue} {CMODE 2,} {setValue} {} - control outMode_1 1 1 1 0 1 0 1 text user {OUTMODE? 1} {rdCfgValue} {OUTMODE 1,} {setValue} {} - control outMode_2 1 1 1 0 2 0 1 text user {OUTMODE? 2} {rdCfgValue} {OUTMODE 2,} {setValue} {} - control outMode_3 1 1 1 0 3 0 1 text user {OUTMODE? 3} {rdCfgValue} {OUTMODE 3,} {setValue} {} - control outMode_4 1 1 1 0 4 0 1 text user {OUTMODE? 4} {rdCfgValue} {OUTMODE 4,} {setValue} {} - control manualOut_1 1 1 1 0 1 1 1 text user {MOUT? 1} {rdValue} {MOUT 1,} {setValue} {} - control manualOut_2 1 1 1 0 2 1 1 text user {MOUT? 2} {rdValue} {MOUT 2,} {setValue} {} - control manualOut_3 1 1 1 0 3 0 1 text user {MOUT? 3} {rdValue} {MOUT 3,} {setValue} {} - control manualOut_4 1 1 1 0 4 0 1 text user {MOUT? 4} {rdValue} {MOUT 4,} {setValue} {} - control pid_Loop_1 1 1 1 0 1 1 1 text user {PID? 1} {rdValue} {PID 1,} {setValue} {} - control pid_Loop_2 1 1 1 0 2 1 1 text user {PID? 2} {rdValue} {PID 2,} {setValue} {} - control ramp_Loop_1 1 1 1 0 1 1 1 text user {RAMP? 1} {rdValue} {RAMP 1,} {setValue} {} - control ramp_Loop_2 1 1 1 0 2 1 1 text user {RAMP? 2} {rdValue} {RAMP 2,} {setValue} {} - control rampStatus_Loop_1 1 0 1 0 1 1 1 int spy {RAMPST? 1} {rdValue} {} {setValue} {} - control rampStatus_Loop_2 1 0 1 0 2 1 1 int spy {RAMPST? 2} {rdValue} {} {setValue} {} - control settleThr_Loop_1 1 1 1 0 1 1 0 float user {SETTLE?} {rdValue} {SETTLE } {setValue} {} - control settleTime_Loop_1 1 1 1 0 1 1 0 int user {SETTLE?} {rdValue} {SETTLE ,} {setValue} {} - heater heaterOutpPercent 1 1 1 0 0 1 0 float user {HTR?} {rdValue} {} {setValue} {} - heater heaterOutput_1 1 1 1 0 1 0 1 float user {HTR? 1} {rdValue} {} {setValue} {} - heater heaterOutput_2 1 1 1 0 2 0 1 float user {HTR? 2} {rdValue} {} {setValue} {} - heater heaterStatus 1 0 1 0 0 1 0 int spy {HTRST?} {rdValue} {} {setValue} {} - heater heaterStatus_1 1 0 1 0 1 0 1 int spy {HTRST? 1} {rdValue} {} {setValue} {} - heater heaterStatus_2 1 0 1 0 2 0 1 int spy {HTRST? 2} {rdValue} {} {setValue} {} - heater heaterRange 1 1 1 0 0 1 0 int user {RANGE?} {rdValue} {RANGE } {setValue} {0,1,2,3,4,5} - heater heaterRange_1 1 1 1 0 0 0 1 int user {RANGE? 1} {rdValue} {RANGE 1,} {setValue} {0,1,2,3} - heater heaterRange_2 1 1 1 0 0 0 1 int user {RANGE? 2} {rdValue} {RANGE 2,} {setValue} {0,1,2,3} - heater heaterRange_3 1 1 1 0 0 0 1 int user {RANGE? 3} {rdValue} {RANGE 3,} {setValue} {0,1} - heater heaterRange_4 1 1 1 0 0 0 1 int user {RANGE? 4} {rdValue} {RANGE 4,} {setValue} {0,1} - other dateTime 1 1 1 0 0 1 0 text user {DATETIME?} {rdValue} {DATETIME } {setValue} {} - other device_busy 1 0 1 0 0 1 0 int spy {BUSY?} {rdValue} {} {setValue} {} - other cfgProtocol_comm 1 1 0 0 0 1 0 text user {COMM?} {rdValue} {COMM } {setValue} {} - other deviceID_idn 1 0 1 0 0 1 1 text spy {*IDN?} {inTolerance} {} {setValue} {} - other selftest 1 0 0 0 0 1 1 int user {*TST?} {rdValue} {} {setValue} {} - other relayStatusHi 1 0 1 0 1 1 1 int spy {RELAYST? 1} {rdValue} {} {setValue} {} - other relayStatusLo 1 0 1 0 2 1 1 int spy {RELAYST? 2} {rdValue} {} {setValue} {} - other relayCtrlParmHi 1 1 1 0 0 1 1 int spy {RELAY? 1} {rdValue} {RELAY 1,} {setValue} {} - other relayCtrlParmLo 1 1 1 0 0 1 1 int spy {RELAY? 2} {rdValue} {RELAY 2,} {setValue} {} - other statusByte 1 0 1 0 0 1 1 int spy {*STB?} {rdValue} {} {setValue} {} - } - # The following 2 commands take no parameter - this makes them difficult to implement in a hipadaba structure - # because they would be nodes without values... - # input alarmResetAll 0 1 0 0 0 1 1 text user {} {rdValue} {ALMRST} {setValue} {} - # other reset_rst 0 1 0 0 0 1 1 text user {} {rdValue} {*RST} {setValue} {} - - hfactory $scobj_hpath/status plain spy text - hsetprop $scobj_hpath/status values busy,idle - hset $scobj_hpath/status "idle" - hfactory $scobj_hpath/status_Ctrl_Lp2 plain spy text - hsetprop $scobj_hpath/status_Ctrl_Lp2 values busy,idle - hset $scobj_hpath/status_Ctrl_Lp2 "idle" - helpNotes4user $scobj_hpath "" "status" - - hfactory $scobj_hpath/sensor plain spy none - # Flags ls340 and ls336 indicate whether this command is support by Lakeshore model ls340 and ls336, respectively - foreach {cmdGroup varName readable writable pollEnabled drivable idx ls340 ls336 dataType permission rdCmd rdFunc wrCmd wrFunc allowedValues} $deviceCommandToplevel { - createNode $scobj_hpath $sct_controller $cmdGroup $varName $readable $writable $pollEnabled $drivable $idx $ls340 $ls336 $dataType $permission $rdCmd $rdFunc $wrCmd $wrFunc $allowedValues $klasse $LSmodel - } - - # create a base node for each commandGroup element - these are all polled - hfactory $scobj_hpath/emon plain spy none - hfactory $scobj_hpath/control plain spy none - hfactory $scobj_hpath/heater plain spy none - hfactory $scobj_hpath/input plain spy none - hfactory $scobj_hpath/other plain spy none - - foreach {cmdGroup varName readable writable pollEnabled drivable idx ls340 ls336 dataType permission rdCmd rdFunc wrCmd wrFunc allowedValues} $deviceCommand { - createNode $scobj_hpath $sct_controller $cmdGroup $varName $readable $writable $pollEnabled $drivable $idx $ls340 $ls336 $dataType $permission $rdCmd $rdFunc $wrCmd $wrFunc $allowedValues $klasse $LSmodel - # helpNotes4user $scobj_hpath $cmdGroup $varName - } - - hsetprop $scobj_hpath/input/alarm_Limits_A units $::scobj::ls3xx::ls3xx_tempUnits - hsetprop $scobj_hpath/input/alarm_Limits_B units $::scobj::ls3xx::ls3xx_tempUnits - hsetprop $scobj_hpath/input/alarm_Limits_C units $::scobj::ls3xx::ls3xx_tempUnits - hsetprop $scobj_hpath/input/alarm_Limits_D units $::scobj::ls3xx::ls3xx_tempUnits - - # Create state machines for the following required nodes that do not correspond - # to device commands. So far we only provide one tolerance for both control loops. - hfactory $scobj_hpath/control/apply_tolerance plain user int - hsetprop $scobj_hpath/control/apply_tolerance values 0,1 - hset $scobj_hpath/control/apply_tolerance 1 - helpNotes4user $scobj_hpath "control" "apply_tolerance" - - hfactory $scobj_hpath/control/tolerance1 plain user float - hsetprop $scobj_hpath/control/tolerance1 units $::scobj::ls3xx::ls3xx_tempUnits - # hsetprop $scobj_hpath/control/tolerance units "K" - hset $scobj_hpath/control/tolerance1 $tol1 - helpNotes4user $scobj_hpath "control" "tolerance1" - - hfactory $scobj_hpath/control/tolerance2 plain user float - hsetprop $scobj_hpath/control/tolerance2 units $::scobj::ls3xx::ls3xx_tempUnits - hset $scobj_hpath/control/tolerance2 $tol2 - helpNotes4user $scobj_hpath "control" "tolerance2" - - # hfactory $scobj_hpath/lowerlimit plain mugger float - # hsetprop $scobj_hpath/lowerlimit units $::scobj::ls3xx::ls3xx_tempUnits - # hset $scobj_hpath/lowerlimit $::scobj::ls3xx::ls3xx_lowerlimit - # hfactory $scobj_hpath/upperlimit plain mugger float - # hsetprop $scobj_hpath/upperlimit units $::scobj::ls3xx::ls3xx_tempUnits - # hset $scobj_hpath/upperlimit $::scobj::ls3xx::ls3xx_upperlimit - - # environment monitoring flags: shows if setpoints of loop 1 and 2 are in tolerance - hfactory $scobj_hpath/emon/monMode_Lp1 plain user text - hsetprop $scobj_hpath/emon/monMode_Lp1 values idle,drive,monitor,error - hset $scobj_hpath/emon/monMode_Lp1 "idle" - helpNotes4user $scobj_hpath "emon" "monMode_Lp1" - hfactory $scobj_hpath/emon/monMode_Lp2 plain user text - hsetprop $scobj_hpath/emon/monMode_Lp2 values idle,drive,monitor,error - hset $scobj_hpath/emon/monMode_Lp2 "idle" - helpNotes4user $scobj_hpath "emon" "monMode_Lp2" - hfactory $scobj_hpath/emon/errhandler plain user text - hset $scobj_hpath/emon/errhandler "lazy" - helpNotes4user $scobj_hpath "emon" "errhandler" - - hfactory $scobj_hpath/emon/isInTolerance_Lp1 plain spy text - hsetprop $scobj_hpath/emon/isInTolerance_Lp1 values idle,drive,monitor,error - hset $scobj_hpath/emon/isInTolerance_Lp1 "inTolerance" - helpNotes4user $scobj_hpath "emon" "isInTolerance_Lp1" - hfactory $scobj_hpath/emon/isInTolerance_Lp2 plain spy text - hsetprop $scobj_hpath/emon/isInTolerance_Lp2 values idle,drive,monitor,error - hset $scobj_hpath/emon/isInTolerance_Lp2 "inTolerance" - helpNotes4user $scobj_hpath "emon" "isInTolerance_Lp2" - - # Temperature controllers must have at least the following nodes (for data logging?) - # /tempcont/setpoint - # /tempcont/sensor/ctrlLp1_value - - ::scobj::hinitprops $tempobj - hsetprop $scobj_hpath klass NXenvironment - ::scobj::set_required_props $scobj_hpath - # These are loggable parameters that need additional nexus properties - # Note: node names longer than 8 characters cause eror messages - avoid - set nxProperties " - $scobj_hpath sensor NXsensor spy - $scobj_hpath sensor/Tsample sensor user - $scobj_hpath sensor/ctrlLp1_value sensor user - $scobj_hpath sensor/ctrlLp2_value sensor user - $scobj_hpath sensor/timStamp sensor user - $scobj_hpath sensor/sensorValueA sensor user - $scobj_hpath sensor/sensorValueB sensor user - $scobj_hpath sensor/sensorValueC sensor user - $scobj_hpath sensor/sensorValueD sensor user - " - set aliasProperties " - $scobj_hpath Tsample sensor _sensor_Tsample - $scobj_hpath ctrlLp1_value sensor _sensor_ctrlLp1_value - $scobj_hpath ctrlLp2_value sensor _sensor_ctrlLp2_value - $scobj_hpath timStamp sensor _sensor_timStamp - $scobj_hpath sensorValueA sensor _sensor_sensorValueA - $scobj_hpath sensorValueB sensor _sensor_sensorValueB - $scobj_hpath sensorValueC sensor _sensor_sensorValueC - $scobj_hpath sensorValueD sensor _sensor_sensorValueD - " - # from nexus.dic file - # tc1_sensor_Tsample = /entry1,NXentry/sample,NXsample/tc1,NXenvironment/sensor,NXsensor/SDS Tsample -type NX_FLOAT32 -rank 1 -dim {-1} - # tc1_sensor_value = /entry1,NXentry/sample,NXsample/tc1,NXenvironment/sensor,NXsensor/SDS ctrlLp1_value -type NX_FLOAT32 -rank 1 -dim {-1} - if { $::scobj::ls3xx::ls3xx_LSmodel == 336 } { - # $scobj_hpath sensor/sampleSensor sensor user - set nxProperties " - $scobj_hpath sensor NXsensor spy - $scobj_hpath sensor/Tsample sensor user - $scobj_hpath sensor/ctrlLp1_value sensor user - $scobj_hpath sensor/ctrlLp2_value sensor user - $scobj_hpath sensor/sensorValueA sensor user - $scobj_hpath sensor/sensorValueB sensor user - $scobj_hpath sensor/sensorValueC sensor user - $scobj_hpath sensor/sensorValueD sensor user - " - # $scobj_hpath sampleSensor _sensor_sampleSensor - set aliasProperties " - $scobj_hpath Tsample sensor _sensor_Tsample - $scobj_hpath ctrlLp1_value sensor _sensor_ctrlLp1_value - $scobj_hpath ctrlLp2_value sensor _sensor_ctrlLp2_value - $scobj_hpath sensorValueA sensor _sensor_sensorValueA - $scobj_hpath sensorValueB sensor _sensor_sensorValueB - $scobj_hpath sensorValueC sensor _sensor_sensorValueC - $scobj_hpath sensorValueD sensor _sensor_sensorValueD - " - } - foreach {rootpath hpath klasse priv} $nxProperties { - hsetprop $rootpath/$hpath klass $klasse - hsetprop $rootpath/$hpath privilege $priv - hsetprop $rootpath/$hpath control true - hsetprop $rootpath/$hpath data true - hsetprop $rootpath/$hpath nxsave true - } - hsetprop $scobj_hpath type part - hsetprop $scobj_hpath/sensor type part - foreach {rootpath node groupy myalias} $aliasProperties { - hsetprop $scobj_hpath/$groupy/$node nxalias $tempobj$myalias - hsetprop $scobj_hpath/$groupy/$node mutable true - hsetprop $scobj_hpath/$groupy/$node sdsinfo ::nexus::scobj::sdsinfo - } - - hsetprop $scobj_hpath privilege spy - # call hinitprops from script_context_util.tcl which initialises the hdb properties required - # for generating the GumTree interface and saving data for script context objects (hdf file) - # @param scobj, name of script context object (path to a node) - # @param par, optional parameter (name of the node variable) - ::scobj::hinitprops $tempobj/sensor setpoint1 - ::scobj::hinitprops $tempobj/sensor setpoint2 - - # Problem: Does not write non-numbers to the hdf file unless told differently - but how? - # How can I make it write the NAME (or any character/string variable) to the hdf file? - # ::scobj::hinitprops $tempobj/sensor sampleSensor - - ansto_makesctdrive ${tempobj}_driveable $scobj_hpath/sensor/setpoint1 $scobj_hpath/sensor/ctrlLp1_value $sct_controller - ansto_makesctdrive ${tempobj}_driveable2 $scobj_hpath/sensor/setpoint2 $scobj_hpath/sensor/ctrlLp2_value $sct_controller - - # initialise the device - ls3xx_init $sct_controller $scobj_hpath - puts "Lakeshore $::scobj::ls3xx::ls3xx_LSmodel temperature controller ready at /sample/$tempobj (Driver 2010-03-05)" - } message ]} { - return -code error "in mk_sct_lakeshore_3xx $message" - } - } - # endproc mk_sct_lakeshore_3xx sct_controller klasse tempobj tol ls3xx_LSmodel - - namespace export mk_sct_lakeshore_3xx -} -# end of namespace mk_sct_lakeshore_3xx - -## -# @brief add_ls3xx() adds a scriptcontext object for a Lakeshore 336 o 340 temperature controller -# and makes it available to SICServer -# @param name short name for the temperature controller scriptcontext object (typ. tc1 or tc2) -# @param IP IP address of the device (e.g. IP of moxabox that hooks up to the Lakeshore 3xx) -# @param port port number on the moxabox (typ. 4001, 4002, 4003, or 4004) -# @param tol temperature tolerance in Kelvin (typ. 1) -# @return nothing (well, the sct object) -proc add_ls3xx {name IP port terminator {_ls3xx_LSmodel 340} {_tol1 1.0} {_tol2 1.0} {_verbose 0} } { - # ffr 2009-11-09, Don't create a temperature controller for the script validator, this causes the - # lakeshore to lock up. - # NOTE: I put this outside the catch block because "return" raises an exception - if {[SplitReply [environment_simulation]]} { - return - } - if {[ catch { - puts "\nadd_ls3xx: makesctcontroller $name std ${IP}:$port for Lakeshore model $_ls3xx_LSmodel" - makesctcontroller sct_ls3xx_$name std ${IP}:$port $terminator - mk_sct_lakeshore_3xx sct_ls3xx_$name environment $name $_ls3xx_LSmodel $_tol1 $_tol2 $_verbose - makesctemon $name /sics/$name/emon/monMode_Lp1 /sics/$name/emon/isInTolerance_Lp1 /sics/$name/emon/errhandler - # set m2 "_2" - # makesctemon $name$m2 /sics/$name/emon/monMode_Lp2 /sics/$name/emon/isInTolerance_Lp2 /sics/$name/emon/errhandler - } message ]} { - return -code error "in add_ls3xx: $message" - } -} - -namespace import ::scobj::ls3xx::*