Files
sics/site_ansto/instrument/config/environment/temperature/sct_julabo_lh45.tcl
Ferdi Franceschini 202bb2869a servlog.c
Fix month in logfile name and put date in all log file names.
sct_protek_common.tcl
Catch non-numeric readings from main multimeter display
Added support for a callbank function which is called after reportVal

sct_julabo_lh45.tcl
Clear the geterror property when getting a new reading.
Don't set the overtemp and subtemp warning limits because this can cause the julabo to alarm.
Do nothing if the setpoint hasn't been updated.
Set default settletime to 60s and the default error handler to "lazy".
Added start_temperature and end_temperature which are updated by callbacks on the histogram memory control.

sct_lakeshore_340.tcl
Set the type for the setpoint nodes to drivable
r3032 | ffr | 2010-12-02 14:03:44 +1100 (Thu, 02 Dec 2010) | 15 lines
2012-11-15 17:06:45 +11:00

396 lines
14 KiB
Tcl

# Define procs in ::scobj::xxx namespace
# MakeSICSObj $obj SCT_<class>
# The MakeSICSObj cmd adds a /sics/$obj node. NOTE the /sics node is not browsable.
namespace eval ::scobj::lh45 {
# Temperature controllers must have at least the following nodes
# /tempcont/setpoint
# /tempcont/sensor/value
proc getValue {nextState cmd} {
if [hpropexists [sct] geterror] {
hdelprop [sct] geterror
}
sct send $cmd
return $nextState
}
proc setValue {nextState cmd} {
set par [sct target]
sct send "$cmd $par"
return $nextState
}
proc setPoint {tc_root nextState cmd} {
if {[hval $tc_root/remote_ctrl] == "False"} {
return idle
}
set par [sct target]
# if {[hval $tc_root/apply_tolerance]} {
# set tol [hval $tc_root/tolerance]
# hset $tc_root/subtemp_warnlimit [expr {$par - $tol}]
# hset $tc_root/overtemp_warnlimit [expr {$par + $tol}]
# }
hset $tc_root/power 1
hset $tc_root/status "busy"
if {[sct writestatus] == "start"} {
# Called by drive adapter
hsetprop $tc_root/setpoint driving 1
}
sct send "$cmd $par"
sct updated 0
return $nextState
}
proc rdValue {} {
set data [sct result]
switch -glob -- $data {
"ASCERR:*" {
sct geterror $data
}
default {
if {$data != [sct oldval]} {
sct oldval $data
sct update $data
sct utime readtime
sct updated 1
}
}
}
return idle
}
##
# @brief Check if temperature controller is on or off
#
# Julabo LH45 Manual pg41
# If a time of 00:00 is set for a profile, the profile is continued with
# the next section only after the setpoint temperature (±0.2 °C) is
# reached.
# That's good enough for me.
#
# When the power is off no temp is outside of any range, therefore we
# report that the T.C. is in tolerance. This implies that counters
# can continue running if the T.C. is off, also lets you acquire data
# while allowing a sample to cool to ambient temperature.
proc rdPower {tc_root} {
set power [sct result]
sct utime readtime
switch -glob -- $power {
"ASCERR:*" {
sct geterror $power
}
default {
set oldval [sct oldval]
if {$oldval == "UNKNOWN"} { sct utime timecheck }
if {$power != $oldval} {
sct oldval $power
sct update $power
}
if {$power==1} {
set setpoint_updated [hgetpropval $tc_root/setpoint updated]
if {$setpoint_updated != 1} {
return idle
}
set currtime [sct readtime]
set timecheck [sct timecheck]
set temp [hval $tc_root/sensor/value]
set setpoint [hval $tc_root/setpoint]
set tol [hval $tc_root/tolerance]
if { abs($temp - $setpoint) > $tol } {
hset $tc_root/emon/isintol 0
set intol 0
sct utime timecheck
} else {
set timeout [hval $tc_root/tolerance/settletime]
if { [expr $currtime - $timecheck] > $timeout } {
hset $tc_root/emon/isintol 1
set intol 1
} else {
set intol 0
}
}
set setpt [hval $tc_root/setpoint]
set temp [hval $tc_root/sensor/value]
if { $intol } {
hsetprop $tc_root/setpoint driving 0
hset $tc_root/emon/monmode "monitor"
hset $tc_root/status "idle"
} else {
hset $tc_root/emon/monmode "drive"
hset $tc_root/status "busy"
}
} else {
hset $tc_root/emon/monmode "idle"
hset $tc_root/emon/isintol 1
hset $tc_root/status "idle"
}
}
}
return idle
}
proc getState {tc_root nextState cmd} {
sct send $cmd
return $nextState
}
proc checktol {tc_root currtime timecheck} {
set temp [hval $tc_root/sensor/value]
set setpoint [hval $tc_root/setpoint]
set tol [hval $tc_root/tolerance]
if { abs($temp - $setpoint) > $tol } {
hset $tc_root/emon/isintol 0
return 0
} else {
set timeout [hval $tc_root/tolerance/settletime]
if { [expr $currtime - $timecheck] > $timeout } {
hset $tc_root/emon/isintol 1
return 1
} else {
return 0
}
}
}
##
# @brief Reads the current lh45 state and error messages.
proc rdState {tc_root} {
set data [sct result]
if {[string first "ASCERR:" $data] >=0} {
sct geterror $data
} elseif {$data != [sct oldval]} {
sct oldval $data
sct update $data
sct utime readtime
switch -- [lindex $data 0] {
"00" {
hset $tc_root/remote_ctrl False
}
"01" {
hset $tc_root/remote_ctrl False
}
"02" {
hset $tc_root/remote_ctrl True
}
"03" {
hset $tc_root/remote_ctrl True
}
default {
hset $tc_root/remote_ctrl UNKNOWN
hset $tc_root/lh45_lasterror $data
}
}
}
return idle
}
proc noResponse {} {
return idle
}
proc wrtValue {wcmd args} {
}
proc check {tc_root} {
set setpoint [sct target]
set lolimit [hval $tc_root/lowerlimit]
set hilimit [hval $tc_root/upperlimit]
if {$setpoint < $lolimit || $setpoint > $hilimit} {
error "setpoint violates limits"
}
return OK
}
##
# @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 {[sct driving]} {
return busy
} else {
return idle
}
}
proc halt {tc_root} {
hset $tc_root/setpoint [hval $tc_root/sensor/value]
hsetprop $tc_root/setpoint driving 0
return idle
}
proc mk_sct_julabo_lh45 {sct_controller klass tempobj tol} {
if {[ catch {
set ns ::scobj::lh45
MakeSICSObj $tempobj SCT_OBJECT
sicslist setatt $tempobj klass $klass
sicslist setatt $tempobj long_name $tempobj
set scobj_hpath /sics/$tempobj
hfactory $scobj_hpath/setpoint plain user float
hsetprop $scobj_hpath/setpoint read ${ns}::getValue rdValue "in_sp_00"
hsetprop $scobj_hpath/setpoint write ${ns}::setPoint $scobj_hpath noResponse "out_sp_00"
hsetprop $scobj_hpath/setpoint check ${ns}::check $scobj_hpath
hsetprop $scobj_hpath/setpoint rdValue ${ns}::rdValue
hsetprop $scobj_hpath/setpoint noResponse ${ns}::noResponse
hsetprop $scobj_hpath/setpoint oldval UNKNOWN
hsetprop $scobj_hpath/setpoint driving 0
hsetprop $scobj_hpath/setpoint writestatus UNKNOWN
hsetprop $scobj_hpath/setpoint type drivable
hsetprop $scobj_hpath/setpoint updated 0
# Drive adapter interface
hsetprop $scobj_hpath/setpoint checklimits ${ns}::check $scobj_hpath
hsetprop $scobj_hpath/setpoint checkstatus ${ns}::drivestatus $scobj_hpath
hsetprop $scobj_hpath/setpoint halt ${ns}::halt $scobj_hpath
hfactory $scobj_hpath/overtemp_warnlimit plain user float
hsetprop $scobj_hpath/overtemp_warnlimit read ${ns}::getValue rdValue "in_sp_03"
# hsetprop $scobj_hpath/overtemp_warnlimit write ${ns}::setValue noResponse "out_sp_03"
hsetprop $scobj_hpath/overtemp_warnlimit rdValue ${ns}::rdValue
hsetprop $scobj_hpath/overtemp_warnlimit noResponse ${ns}::noResponse
hsetprop $scobj_hpath/overtemp_warnlimit oldval UNKNOWN
hfactory $scobj_hpath/subtemp_warnlimit plain user float
hsetprop $scobj_hpath/subtemp_warnlimit read ${ns}::getValue rdValue "in_sp_04"
# hsetprop $scobj_hpath/subtemp_warnlimit write ${ns}::setValue noResponse "out_sp_04"
hsetprop $scobj_hpath/subtemp_warnlimit rdValue ${ns}::rdValue
hsetprop $scobj_hpath/subtemp_warnlimit noResponse ${ns}::noResponse
hsetprop $scobj_hpath/subtemp_warnlimit oldval UNKNOWN
hfactory $scobj_hpath/sensor plain spy none
hfactory $scobj_hpath/sensor/value plain internal float
hsetprop $scobj_hpath/sensor/value read ${ns}::getValue rdValue "in_pv_02"
hsetprop $scobj_hpath/sensor/value rdValue ${ns}::rdValue
hsetprop $scobj_hpath/sensor/value oldval UNKNOWN
hsetprop $scobj_hpath/sensor/value units "C"
hfactory $scobj_hpath/sensor/start_temperature plain user float
hfactory $scobj_hpath/sensor/end_temperature plain user float
# proc ${ns}::OnFirstSave {} [subst -nocommands {
# hset $scobj_hpath/sensor/start_temperature [hval $scobj_hpath/sensor/value]
# hset $scobj_hpath/sensor/end_temperature [hval $scobj_hpath/sensor/value]
# }]
# proc ${ns}::OnLastSave {} [subst -nocommands {
# hset $scobj_hpath/sensor/end_temperature [hval $scobj_hpath/sensor/value]
# }]
# ::nexus::OnFirstSave ${ns}::OnFirstSave
# ::nexus::OnLastSave ${ns}::OnLastSave
hfactory $scobj_hpath/heating_power_percent plain internal float
hsetprop $scobj_hpath/heating_power_percent read ${ns}::getValue rdValue "in_pv_01"
hsetprop $scobj_hpath/heating_power_percent rdValue ${ns}::rdValue
hsetprop $scobj_hpath/heating_power_percent oldval UNKNOWN
hfactory $scobj_hpath/power plain user int
hsetprop $scobj_hpath/power read ${ns}::getValue rdValue "in_mode_05"
hsetprop $scobj_hpath/power write ${ns}::setValue noResponse "out_mode_05"
hsetprop $scobj_hpath/power rdValue ${ns}::rdPower $scobj_hpath
hsetprop $scobj_hpath/power noResponse ${ns}::noResponse
hsetprop $scobj_hpath/power oldval UNKNOWN
hsetprop $scobj_hpath/power values 0,1
hfactory $scobj_hpath/apply_tolerance plain user int
hsetprop $scobj_hpath/apply_tolerance values 0,1
hset $scobj_hpath/apply_tolerance 1
hfactory $scobj_hpath/tolerance plain user float
hsetprop $scobj_hpath/tolerance units "C"
hfactory $scobj_hpath/tolerance/settletime plain user float
hset $scobj_hpath/tolerance/settletime 60.0
hsetprop $scobj_hpath/tolerance/settletime units "s"
hset $scobj_hpath/tolerance $tol
hfactory $scobj_hpath/status plain spy text
hset $scobj_hpath/status "idle"
hsetprop $scobj_hpath/status values busy,idle
hfactory $scobj_hpath/lh45_state plain spy text
hsetprop $scobj_hpath/lh45_state read ${ns}::getState $scobj_hpath rdState "status"
hsetprop $scobj_hpath/lh45_state rdState ${ns}::rdState $scobj_hpath
hsetprop $scobj_hpath/lh45_state oldval UNKNOWN
hfactory $scobj_hpath/remote_ctrl plain spy text
hset $scobj_hpath/remote_ctrl UNKNOWN
hfactory $scobj_hpath/lh45_lasterror plain user text
hset $scobj_hpath/lh45_lasterror ""
hfactory $scobj_hpath/lowerlimit plain mugger float
hsetprop $scobj_hpath/lowerlimit units "C"
hset $scobj_hpath/lowerlimit -45
hfactory $scobj_hpath/upperlimit plain mugger float
hsetprop $scobj_hpath/upperlimit units "C"
hset $scobj_hpath/upperlimit 130
hfactory $scobj_hpath/emon plain spy none
hfactory $scobj_hpath/emon/monmode plain user text
hsetprop $scobj_hpath/emon/monmode values idle,drive,monitor,error
hset $scobj_hpath/emon/monmode "idle"
hfactory $scobj_hpath/emon/isintol plain user int
hset $scobj_hpath/emon/isintol 1
hfactory $scobj_hpath/emon/errhandler plain user text
hset $scobj_hpath/emon/errhandler "lazy"
if {[SplitReply [environment_simulation]]=="false"} {
$sct_controller poll $scobj_hpath/setpoint
$sct_controller write $scobj_hpath/setpoint
$sct_controller poll $scobj_hpath/subtemp_warnlimit
# $sct_controller write $scobj_hpath/subtemp_warnlimit
$sct_controller poll $scobj_hpath/overtemp_warnlimit
# $sct_controller write $scobj_hpath/overtemp_warnlimit
$sct_controller poll $scobj_hpath/heating_power_percent
$sct_controller poll $scobj_hpath/power
$sct_controller write $scobj_hpath/power
$sct_controller poll $scobj_hpath/sensor/value
$sct_controller poll $scobj_hpath/lh45_state 5 halt read
}
foreach {rootpath hpath klass priv} "
$scobj_hpath sensor NXsensor spy
$scobj_hpath sensor/value sensor user
" {
hsetprop $rootpath/$hpath klass $klass
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
hsetprop $scobj_hpath/sensor/value nxalias tc1_sensor_value
hsetprop $scobj_hpath/sensor/value mutable true
hsetprop $scobj_hpath/sensor/value sdsinfo ::nexus::scobj::sdsinfo
hsetprop $scobj_hpath privilege spy
::scobj::hinitprops $tempobj setpoint sensor/start_temperature sensor/end_temperature
hsetprop $scobj_hpath/sensor/start_temperature mutable true
hsetprop $scobj_hpath/sensor/end_temperature mutable true
if {[SplitReply [environment_simulation]]=="false"} {
ansto_makesctdrive ${tempobj}_driveable $scobj_hpath/setpoint $scobj_hpath/sensor/value $sct_controller
}
} message ]} {
return -code error $message
}
}
namespace export mk_sct_julabo_lh45
}
##
# @brief Create a Julabo lh45 temperature controller
#
# @param name, then name of the temperature controller (eg tc1)
# @param IP, the IP address of the device, this can be a hostname, (eg ca5-quokka)
# @param port, the IP protocol port number of the device
# @param _tol (optional), this is the initial tolerance setting
proc add_lh45 {name IP port {_tol 5.0}} {
if {[SplitReply [environment_simulation]]=="false"} {
makesctcontroller sct_lh45 std ${IP}:$port "\r"
}
mk_sct_julabo_lh45 sct_lh45 environment $name $_tol
makesctemon $name /sics/$name/emon/monmode /sics/$name/emon/isintol /sics/$name/emon/errhandler
}
namespace import ::scobj::lh45::*