Files
sics/site_ansto/instrument/config/environment/temperature/sct_watlow_st4.tcl
Ferdi Franceschini d7acb7c16c Load drivers which have been enabled in the SICS config ini files.
Lakeshore 336 drivers with known IP addresses have been added to the ini files with unique IDs.
All entries in the ini files now have unique IDs
The wombat ini now has radio buttons to select sample stage motor configurations.
2014-05-05 12:25:00 +10:00

806 lines
31 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::watlow_st {
# Temperature controllers must have at least the following nodes
# /tempcont/setpoint
# /tempcont/sensor/value
proc debug_log {args} {
set fd [open "/tmp/watlow_st.log" a]
puts $fd "[clock format [clock seconds] -format "%T"] $args"
close $fd
}
proc f_to_c { f_temp } {
return [expr ($f_temp - 32.0) * (5.0 / 9.0)]
}
proc c_to_f { c_temp } {
return [expr $c_temp * (9.0 / 5.0) + 32.0]
}
# issue a command to read a register and expect a value response
proc getValue {tc_root nextState cmd} {
set dev "[hval $tc_root/dev_id]"
sct send "$dev:3:$cmd"
return $nextState
}
# issue a command with a value in the target property of the variable
proc setValue {tc_root nextState cmd} {
set dev "[hval $tc_root/dev_id]"
set par [sct target]
sct send "$dev:16:$cmd $par"
debug_log "setValue $dev:16:$cmd $par"
return $nextState
}
proc rdValue {tc_root} {
set data [sct result]
switch -glob -- $data {
"ASCERR:*" {
sct geterror $data
}
default {
if { [hpropexists [sct] geterror] } {
hdelprop [sct] geterror
}
if {$data != [sct oldval]} {
sct oldval $data
sct update $data
sct utime readtime
}
}
}
return idle
}
# write a floating point value
proc setFloat {tc_root nextState cmd} {
set dev "[hval $tc_root/dev_id]"
set par [sct target]
sct send "$dev:1016:$cmd $par"
debug_log "setFloat $dev:1016:$cmd $par"
return $nextState
}
# request a floating point value
proc getFloat {tc_root nextState cmd} {
set dev "[hval $tc_root/dev_id]"
sct send "$dev:1003:$cmd"
return $nextState
}
# read a floating point value
proc rdFloat {tc_root} {
set data [sct result]
switch -glob -- $data {
"ASCERR:*" {
sct geterror $data
}
default {
if { [hpropexists [sct] geterror] } {
hdelprop [sct] geterror
}
if {$data != [sct oldval]} {
sct oldval $data
sct update $data
sct utime readtime
}
}
}
return idle
}
# write a floating point value as a temperature
proc setTemp {tc_root nextState cmd} {
set dev "[hval $tc_root/dev_id]"
set par [sct target]
set par [c_to_f $par]
sct send "$dev:1016:$cmd $par"
debug_log "setTemp $dev:1016:$cmd $par"
return $nextState
}
# request a floating point value as a temperature
proc getTemp {tc_root nextState cmd} {
set dev "[hval $tc_root/dev_id]"
sct send "$dev:1003:$cmd"
return $nextState
}
# read a floating point value as a temperature
proc rdTemp {tc_root} {
set data [sct result]
set data [f_to_c $data]
switch -glob -- $data {
"ASCERR:*" {
sct geterror $data
}
default {
if { [hpropexists [sct] geterror] } {
hdelprop [sct] geterror
}
if {$data != [sct oldval]} {
sct oldval $data
sct update $data
sct utime readtime
}
}
}
return idle
}
proc adjust_power {tc_root} {
set now_time [clock seconds]
set was_time [hval $tc_root/device_control/was_time]
set elapsed [expr $now_time - $was_time]
if {$elapsed < 1} {
return
}
set Heater_Kp 0.85
set Heater_Tp 600
set Heater_Td 30
if {[hval $tc_root/device_control/power] >= 0} {
set power [hval $tc_root/device_control/power]
} else {
hset $tc_root/device_control/power 20.0
set power [hval $tc_root/device_control/power]
debug_log "initialised $tc_root/device_control/power to $power"
}
set previous_error [hval $tc_root/device_control/previous_error]
set working_setpoint [hval $tc_root/device_control/target]
set heater_temp [hval $tc_root/samplesensor]
if {$Heater_Tp > 8.0*$Heater_Td} {
set Tc [expr {1.0 * $Heater_Tp}]
} else {
set Tc [expr {8.0 * $Heater_Td}]
}
# if aggressive divide Tc by ten
#set Tc [expr {$Tc / 10.0}]
#set Tc [expr {$Tc / 10.0}]
set Kc [expr {(1.0 / $Heater_Kp) * ((1.0 * $Heater_Tp)/($Tc + $Heater_Td))}]
set Kc [expr {1.0 * $Kc}]
set Ti [expr {1.0 * $Heater_Tp}]
set Kc [expr 1.00 * [hval $tc_root/device_control/Kc]]
set Ti [expr 1.00 * [hval $tc_root/device_control/Ti]]
set new_power $power
set current_error [expr {$working_setpoint - $heater_temp}]
set delta_power [expr {$Kc * ((1 + ((1.0 * $elapsed) / $Ti)) * $current_error - $previous_error)}]
debug_log {adjust_power: $delta_power = $Kc * ((1 + ((1.0 * $elapsed) / $Ti)) * $current_error - $previous_error)}
debug_log "adjust_power: $delta_power = $Kc * ((1 + ((1.0 * $elapsed) / $Ti)) * $current_error - $previous_error)"
debug_log "adjust_power: delta = $delta_power, elapsed = $elapsed, current_error = $current_error, previous_error = $previous_error"
set new_power [expr {$power + $delta_power}]
set min $working_setpoint
set max 400
if {$new_power < $min} {
set new_power $min
} elseif {$new_power > $max} {
set new_power $max
}
set test_value [expr {abs($new_power - $power)}]
set do_it ""
if {$test_value >= 50} {
set do_it "$test_value >= 50"
} elseif {$elapsed == 10 && $test_value >= 40} {
set do_it "$elapsed == 10 && $test_value >= 40"
} elseif {$elapsed == 20 && $test_value >= 30} {
set do_it "$elapsed == 20 && $test_value >= 30"
} elseif {$elapsed >= 30 && (abs($current_error) >= 20 || $test_value >= 2)} {
set do_it "$elapsed >= 30 && (abs($current_error) >= 20 || $test_value >= 2)"
} elseif {$elapsed >= 60 && (abs($current_error) >= 1 || $test_value >= 1)} {
set do_it "$elapsed >= 60 && (abs($current_error) >= 1 || $test_value >= 1)"
set new_power [expr {$power + $delta_power / 4.0}]
if {$new_power < $min} {
set new_power $min
} elseif {$new_power > $max} {
set new_power $max
}
}
if {$do_it != ""} {
debug_log "adjust_power: new_power = $new_power ($do_it)"
hset $tc_root/device_control/power $new_power
hset $tc_root/device_control/previous_error $current_error
hset $tc_root/device_control/was_time $now_time
hset $tc_root/Loop1/setpoint $new_power
hset $tc_root/Loop2/setpoint $new_power
hset $tc_root/Loop3/setpoint $new_power
hset $tc_root/Loop4/setpoint $new_power
}
}
proc getState {tc_root nextState cmd} {
set dev "[hval $tc_root/dev_id]"
sct send "$dev:3:$cmd"
return $nextState
}
##
# @brief Reads the current watlow state and error messages.
proc rdState {tc_root} {
set my_driving [SplitReply [hgetprop $tc_root/setpoint driving]]
debug_log "rdState $tc_root: driving=$my_driving"
set val [hval $tc_root/setpoint]
debug_log "rdState $tc_root: setpoint=$val"
if {![hpropexists $tc_root/setpoint target]} {
set tgt 20.0
hset $tc_root/setpoint $tgt
debug_log "rdState $tc_root: initialised target to: target=$tgt"
}
set tgt [SplitReply [hgetprop $tc_root/setpoint target]]
debug_log "rdState $tc_root: target=$tgt"
if {![hpropexists $tc_root/limit_hi target]} {
hset $tc_root/limit_hi 25.0
}
if {$my_driving > 0} {
set temp [hval $tc_root/samplesensor]
set tol [hval $tc_root/tolerance]
set lotemp [expr {$tgt - $tol}]
set hitemp [expr {$tgt + $tol}]
debug_log "rdState driving $tc_root until $temp in ($lotemp, $hitemp)"
if {$temp < $lotemp} {
} elseif {$temp > $hitemp} {
} else {
hset $tc_root/status "idle"
hsetprop $tc_root/setpoint driving 0
}
} else {
if {[hval $tc_root/status] != "idle"} {
hset $tc_root/status "idle"
}
}
set data [SplitReply [hgetprop $tc_root/setpoint driving]]
debug_log "rdState $tc_root: result=$data"
if {[string first "ASCERR:" $data] >=0} {
sct geterror $data
} elseif {$data != [sct oldval]} {
sct oldval $data
sct update $data
sct utime readtime
}
set cur [hval $tc_root/samplesensor]
debug_log "rdState: target = $tgt, current = $cur"
if {[hval $tc_root/device_control/Auto] != 0} {
adjust_power $tc_root
}
return idle
}
# Get the Sample Sensor
proc getSS {tc_root nextState cmd} {
set d1 [hval $tc_root/Loop1/sensor2]
set d2 [hval $tc_root/Loop2/sensor2]
set d3 [hval $tc_root/Loop3/sensor2]
set d4 [hval $tc_root/Loop4/sensor2]
set data [expr ($d1 + $d2 + $d3 + $d4) / 4.0]
# KLUDGE TODO remove
set data [expr 1.0 * $d1]
if {$data != [sct oldval]} {
sct oldval $data
sct update $data
sct utime readtime
}
if {![hpropexists $tc_root/setpoint target]} {
hsetprop $tc_root/setpoint target 20.0
debug_log "getSS initialised $tc_root/setpoint target to: target=$data"
hset $tc_root/device_control/target 20.0
debug_log "getSS initialised $tc_root/device_control/target to $data"
}
debug_log "getSS $tc_root $nextState $cmd [sct] = $data ($d1 $d2 $d3 $d4)"
for {set i 1} {$i <= 4} {incr i} {
debug_log "getSS Loop $i limit test: [hval $tc_root/Loop$i/limit_state] == 51 && [hval $tc_root/Loop$i/sensor2] < [hval $tc_root/Loop$i/limit_hi]"
if {[hval $tc_root/Loop$i/limit_state] == 51 && [hval $tc_root/Loop$i/sensor2] < ([hval $tc_root/Loop$i/limit_hi] - 2.0)} {
debug_log "getSS Loop $i limit reset)"
hset $tc_root/Loop$i/limit_clear 0
}
}
return idle
}
# Get the Heater Power
proc getHP {tc_root nextState cmd} {
set d1 [hval $tc_root/Loop1/power]
set d2 [hval $tc_root/Loop2/power]
set d3 [hval $tc_root/Loop3/power]
set d4 [hval $tc_root/Loop4/power]
set data [expr ($d1 + $d2 + $d3 + $d4) / 4.0]
if {$data != [sct oldval]} {
sct oldval $data
sct update $data
sct utime readtime
}
debug_log "getHP $tc_root $nextState $cmd [sct] = $data ($d1 $d2 $d3 $d4)"
return idle
}
# Get the Process Variable
proc getPV {tc_root nextState cmd} {
set d1 [hval $tc_root/Loop1/sensor]
set d2 [hval $tc_root/Loop2/sensor]
set d3 [hval $tc_root/Loop3/sensor]
set d4 [hval $tc_root/Loop4/sensor]
set data [expr ($d1 + $d2 + $d3 + $d4) / 4.0]
if {$data != [sct oldval]} {
sct oldval $data
sct update $data
sct utime readtime
}
if {[hval $tc_root/device_control/power] < 0} {
hset $tc_root/device_control/power $data
debug_log "getPV initialised $tc_root/device_control/power to $data"
}
debug_log "getPV $tc_root $nextState $cmd [sct] = $data ($d1 $d2 $d3 $d4)"
return idle
}
# Get the Set Point
proc getSP {tc_root nextState cmd} {
set d1 [hval $tc_root/Loop1/setpoint]
set d2 [hval $tc_root/Loop2/setpoint]
set d3 [hval $tc_root/Loop3/setpoint]
set d4 [hval $tc_root/Loop4/setpoint]
set data [expr {($d1 + $d2 + $d3 + $d4) / 4.0}]
if {$data != [sct oldval]} {
sct oldval $data
sct update $data
sct utime readtime
}
debug_log "getSP $tc_root $nextState $cmd [sct] = $data ($d1 $d2 $d3 $d4)"
return idle
}
# Set the Set Point
proc setSP {tc_root nextState cmd} {
debug_log "setSP $tc_root $nextState $cmd [sct]=[sct target] [hget [sct]]"
if {[hval $tc_root/device_control/Auto] == 0} {
hset $tc_root/Loop1/setpoint [sct target]
hset $tc_root/Loop2/setpoint [sct target]
hset $tc_root/Loop3/setpoint [sct target]
hset $tc_root/Loop4/setpoint [sct target]
}
hset $tc_root/device_control/target [sct target]
hset $tc_root/device_control/previous_error [expr [sct target] - [hval $tc_root/samplesensor]]
hset $tc_root/status "busy"
return idle
}
# Get the High Limit Point
proc getLimHi {tc_root nextState cmd} {
set d1 [hval $tc_root/Loop1/limit_hi]
set d2 [hval $tc_root/Loop2/limit_hi]
set d3 [hval $tc_root/Loop3/limit_hi]
set d4 [hval $tc_root/Loop4/limit_hi]
set data [expr {($d1 + $d2 + $d3 + $d4) / 4.0}]
if {$data != [sct oldval]} {
sct oldval $data
sct update $data
sct utime readtime
}
debug_log "getLimHi $tc_root $nextState $cmd [sct] = $data ($d1 $d2 $d3 $d4)"
return idle
}
# Set the High Limit Point
proc setLimHi {tc_root nextState cmd} {
debug_log "setLimHi $tc_root $nextState $cmd [sct]=[sct target] [hget [sct]]"
hset $tc_root/Loop1/limit_hi [sct target]
hset $tc_root/Loop2/limit_hi [sct target]
hset $tc_root/Loop3/limit_hi [sct target]
hset $tc_root/Loop4/limit_hi [sct target]
return idle
}
# Set the All Set Points
proc setAll {tc_root nextState cmd} {
debug_log "setAll $tc_root $nextState $cmd [sct]=[sct target] [hget [sct]]"
hset $tc_root/Loop1/setpoint [sct target]
hset $tc_root/Loop2/setpoint [sct target]
hset $tc_root/Loop3/setpoint [sct target]
hset $tc_root/Loop4/setpoint [sct target]
hset $tc_root/device_control/previous_error [expr [sct target] - [hval $tc_root/samplesensor]]
return idle
}
proc setPoint {tc_root nextState cmd} {
set dev "[hval $tc_root/dev_id]"
set par [sct target]
if {[sct writestatus] == "start"} {
# Called by drive adapter
hset $tc_root/status "busy"
hsetprop $tc_root/setpoint driving 1
}
set par [c_to_f $par]
sct send "$dev:1016:$cmd $par"
debug_log "setPoint $dev:1016:$cmd $par"
return $nextState
}
proc noResponse {} {
return idle
}
proc wrtValue {wcmd args} {
}
# check that a target is within allowable limits
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} {
sct driving 0
error "setpoint violates limits"
}
return OK
}
# Check that the sensor is reading within tolerance of the setpoint.
# Return 1 or 0 if it is or is not, respectively.
proc checktol {tc_root currtime timecheck} {
debug_log "checktol $tc_root $currtime $timecheck"
set temp [hval $tc_root/sensor/value]
set lotemp [hval $tc_root/subtemp_warnlimit]
set hitemp [hval $tc_root/overtemp_warnlimit]
if { $temp < $lotemp || $temp > $hitemp} {
hset $tc_root/emon/isintol 0
return 0
} else {
set timeout [hval $tc_root/tolerance/settletime]
if { ($currtime - $timecheck) > $timeout } {
hset $tc_root/emon/isintol 1
}
return 1
}
}
##
# @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 {
sct print "drivestatus: idle"
return idle
}
}
proc halt {tc_root} {
debug_log "halt $tc_root"
hset $tc_root/setpoint [hval $tc_root/sensor/value]
hsetprop $tc_root/setpoint driving 0
return idle
}
##
# @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 scriptcontext object (typically sct_xxx_yyy)
# @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 drivable if set to 1 it prepares the node to provide a drivable interface
# @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 klass Nexus class name (?)
# @return OK
proc createNode {scobj_hpath sct_controller cmdGroup varName readable writable\
drivable dataType permission rdCmd rdFunc wrCmd\
wrFunc allowedValues klass} {
set catch_status [ catch {
# set ns ::scobj::ls460
set ns "[namespace current]"
set nodeName "$scobj_hpath/$cmdGroup/$varName"
if {1 > [string length $cmdGroup]} {
set nodeName "$scobj_hpath/$varName"
}
debug_log "Creating node $nodeName"
hfactory $nodeName plain $permission $dataType
if {$readable > 0} {
set parts [split "$rdFunc" "."]
if { [llength $parts] == 2 } {
set func_name [lindex $parts 0]
set next_state [lindex $parts 1]
hsetprop $nodeName read ${ns}::$func_name $scobj_hpath $next_state $rdCmd
hsetprop $nodeName $next_state ${ns}::$next_state $scobj_hpath
} else {
if {$rdFunc == "getPV"} {
set func_name "$rdFunc"
} elseif {$rdFunc == "getSP"} {
set func_name "$rdFunc"
} elseif {$rdFunc == "getHP"} {
set func_name "$rdFunc"
} elseif {$rdFunc == "getSS"} {
set func_name "$rdFunc"
} elseif {$rdFunc == "getLimHi"} {
set func_name "$rdFunc"
} elseif {$rdFunc == "rdFloat"} {
set func_name "getFloat"
} elseif {$rdFunc == "rdTemp"} {
set func_name "getTemp"
} else {
set func_name "getValue"
}
hsetprop $nodeName read ${ns}::$func_name $scobj_hpath $rdFunc $rdCmd
hsetprop $nodeName $rdFunc ${ns}::$rdFunc $scobj_hpath
}
set poll_period 30
if { $readable >= 0 && $readable <= 9 } {
set poll_period [lindex [list 0 1 2 3 4 5 10 15 20 30] $readable]
}
debug_log "Registering node $nodeName for poll at $poll_period seconds"
$sct_controller poll $nodeName $poll_period
}
if {$writable == 1} {
set parts [split "$wrFunc" "."]
if { [llength $parts] == 2 } {
set func_name [lindex $parts 0]
set next_state [lindex $parts 1]
hsetprop $nodeName write ${ns}::$func_name $scobj_hpath $next_state $wrCmd
hsetprop $nodeName $next_state ${ns}::$next_state $scobj_hpath
} else {
hsetprop $nodeName write ${ns}::$wrFunc $scobj_hpath noResponse $wrCmd
hsetprop $nodeName noResponse ${ns}::noResponse
}
hsetprop $nodeName writestatus UNKNOWN
debug_log "Registering node $nodeName for write callback"
$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
hsetprop $nodeName driving 0
hsetprop $nodeName checklimits ${ns}::check $scobj_hpath
hsetprop $nodeName checkstatus ${ns}::drivestatus $scobj_hpath
hsetprop $nodeName halt ${ns}::halt $scobj_hpath
}
} message ]
if {$catch_status != 0} {
return -code error "in createNode $message"
}
return OK
}
proc mk_sct_watlow_st {sct_controller klass tempobj dev_id tol CID CTYPE} {
set catch_status [ catch {
set ns "[namespace current]"
MakeSICSObj $tempobj SCT_OBJECT
sicslist setatt $tempobj klass $klass
sicslist setatt $tempobj long_name $tempobj
set scobj_hpath /sics/$tempobj
set deviceCommand {\
{} all 0 1 0 float user {0} {} {0} {setAll} {}\
{} setpoint 1 1 1 float user {0} {getSP} {0} {setSP} {}\
sensor value 1 0 0 float internal {0} {getPV} {0} {} {}\
{} power 1 0 0 float internal {0} {getHP} {0} {} {}\
{} samplesensor 1 0 0 float internal {0} {getSS} {0} {} {}\
{} limit_hi 1 1 0 float user {0} {getLimHi} {0} {setLimHi} {}\
Loop1 setpoint 1 1 0 float user {2160} {rdTemp} {2160} {setTemp} {}\
Loop1 sensor 1 0 0 float internal {1940} {rdTemp} {1940} {} {}\
Loop1 sensor2 1 0 0 float internal {562} {rdTemp} {562} {} {}\
Loop1 limit_hi 1 1 0 float user {686} {rdTemp} {686} {setTemp} {}\
Loop1 limit_state 1 0 0 int internal {690} {rdValue} {690} {} {}\
Loop1 limit_clear 0 1 0 int user {680} {} {680} {setValue} {}\
Loop1 power 1 0 0 float internal {1900} {rdFloat} {1900} {} {}\
Loop2 setpoint 1 1 0 float user {5160} {rdTemp} {5160} {setTemp} {}\
Loop2 sensor 1 0 0 float internal {4940} {rdTemp} {4940} {} {}\
Loop2 sensor2 1 0 0 float internal {3562} {rdTemp} {3562} {} {}\
Loop2 limit_hi 1 1 0 float user {3686} {rdTemp} {3686} {setTemp} {}\
Loop2 limit_state 1 0 0 int internal {3690} {rdValue} {3690} {} {}\
Loop2 limit_clear 0 1 0 int user {3680} {} {3680} {setValue} {}\
Loop2 power 1 0 0 float internal {4900} {rdFloat} {4900} {} {}\
Loop3 setpoint 1 1 0 float user {8160} {rdTemp} {8160} {setTemp} {}\
Loop3 sensor 1 0 0 float internal {7940} {rdTemp} {7940} {} {}\
Loop3 sensor2 1 0 0 float internal {6562} {rdTemp} {6562} {} {}\
Loop3 limit_hi 1 1 0 float user {6686} {rdTemp} {6686} {setTemp} {}\
Loop3 limit_state 1 0 0 int internal {6690} {rdValue} {6690} {} {}\
Loop3 limit_clear 0 1 0 int user {6680} {} {6680} {setValue} {}\
Loop3 power 1 0 0 float internal {7900} {rdFloat} {7900} {} {}\
Loop4 setpoint 1 1 0 float user {11160} {rdTemp} {11160} {setTemp} {}\
Loop4 sensor 1 0 0 float internal {10940} {rdTemp} {10940} {} {}\
Loop4 sensor2 1 0 0 float internal {9562} {rdTemp} {9562} {} {}\
Loop4 limit_hi 1 1 0 float user {9686} {rdTemp} {9686} {setTemp} {}\
Loop4 limit_state 1 0 0 int internal {9690} {rdValue} {9690} {} {}\
Loop4 limit_clear 0 1 0 int user {9680} {} {9680} {setValue} {}\
Loop4 power 1 0 0 float internal {10900} {rdFloat} {10900} {} {}\
}
hfactory $scobj_hpath/sensor plain spy none
hfactory $scobj_hpath/Loop1 plain spy none
hfactory $scobj_hpath/Loop2 plain spy none
hfactory $scobj_hpath/Loop3 plain spy none
hfactory $scobj_hpath/Loop4 plain spy none
foreach {cmdGroup varName readable writable drivable dataType permission rdCmd rdFunc wrCmd wrFunc allowedValues} $deviceCommand {
createNode $scobj_hpath $sct_controller $cmdGroup $varName $readable $writable $drivable $dataType $permission $rdCmd $rdFunc $wrCmd $wrFunc $allowedValues $klass
}
hsetprop $scobj_hpath/sensor/value lowerlimit 0
hsetprop $scobj_hpath/sensor/value upperlimit 500
hsetprop $scobj_hpath/sensor/value units "C"
hsetprop $scobj_hpath/sensor/value permlink data_set ${CTYPE}${CID}S1
hsetprop $scobj_hpath/setpoint permlink data_set ${CTYPE}${CID}SP1
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/dev_id plain user int
hsetprop $scobj_hpath/dev_id values 0,1,2,3,4,5,6,7,8,9
hset $scobj_hpath/dev_id $dev_id
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 5.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/device_state plain spy text
hsetprop $scobj_hpath/device_state read ${ns}::getState $scobj_hpath rdState "2160"
hsetprop $scobj_hpath/device_state rdState ${ns}::rdState $scobj_hpath
hsetprop $scobj_hpath/device_state oldval UNKNOWN
hfactory $scobj_hpath/device_control plain spy none
hfactory $scobj_hpath/device_control/target plain user float
hset $scobj_hpath/device_control/target 20.0
hfactory $scobj_hpath/device_control/power plain user float
hset $scobj_hpath/device_control/power 0.0
hfactory $scobj_hpath/device_control/previous_error plain user float
hset $scobj_hpath/device_control/previous_error 0.0
hfactory $scobj_hpath/device_control/was_time plain internal int
hset $scobj_hpath/device_control/was_time [clock seconds]
hfactory $scobj_hpath/device_control/Kc plain user float
hset $scobj_hpath/device_control/Kc [expr 6.0]
hfactory $scobj_hpath/device_control/Ti plain user float
hset $scobj_hpath/device_control/Ti [expr 250.0]
hfactory $scobj_hpath/device_control/Auto plain user int
hset $scobj_hpath/device_control/Auto 1
hfactory $scobj_hpath/remote_ctrl plain spy text
hset $scobj_hpath/remote_ctrl UNKNOWN
hfactory $scobj_hpath/device_lasterror plain user text
hset $scobj_hpath/device_lasterror ""
hfactory $scobj_hpath/lowerlimit plain mugger float
hsetprop $scobj_hpath/lowerlimit units "C"
hset $scobj_hpath/lowerlimit 0
hfactory $scobj_hpath/upperlimit plain mugger float
hsetprop $scobj_hpath/upperlimit units "C"
hset $scobj_hpath/upperlimit 500
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 "pause"
if {[SplitReply [environment_simulation]]=="false"} {
$sct_controller poll $scobj_hpath/device_state 1 halt read
}
::scobj::hinitprops $tempobj
hsetprop $scobj_hpath klass NXenvironment
::scobj::set_required_props $scobj_hpath
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
hsetprop $scobj_hpath/setpoint data true
if {[SplitReply [environment_simulation]]=="false"} {
ansto_makesctdrive ${tempobj}_driveable $scobj_hpath/setpoint $scobj_hpath/sensor/value $sct_controller
}
} catch_message ]
if {$catch_status != 0} {
return -code error $catch_message
}
}
namespace export mk_sct_watlow_st
}
##
# @brief Create a Watlow ST temperature controller
#
# @param name, the name of the temperature controller (eg tc1)
# @param IP, the IP address of the device, this can be a hostname, (eg ca5-kowari)
# @param port, the IP protocol port number of the device (502 for modbus)
# @param _tol (optional), this is the initial tolerance setting
proc add_watlow_st {name IP port dev_id {_tol 5.0} {CID 1} {CTYPE T}} {
set fd [open "/tmp/watlow_st.log" a]
if {[SplitReply [environment_simulation]]=="false"} {
puts $fd "makesctcontroller sct_${name} modbus ${IP}:$port"
makesctcontroller sct_${name} modbus ${IP}:$port
}
puts $fd "mk_sct_watlow_st sct_${name} environment $name $dev_id $_tol"
mk_sct_watlow_st sct_${name} environment $name $dev_id $_tol $CID $CTYPE
puts $fd "makesctemon $name /sics/$name/emon/monmode /sics/$name/emon/isintol /sics/$name/emon/errhandler"
makesctemon $name /sics/$name/emon/monmode /sics/$name/emon/isintol /sics/$name/emon/errhandler
close $fd
}
puts stdout "file evaluation of sct_watlow_st4.tcl"
set fd [open "/tmp/watlow_st.log" w]
puts $fd "file evaluation of sct_watlow_st4.tcl"
close $fd
if {[ catch {
if { [ info exists ::config_dict ] } {
dict for {secname secinfo} $::config_dict {
if { [dict exists $secinfo "driver"] && ([dict get $secinfo "driver"] == "watlow_st") } {
if { [ dict get $::secinfo enabled ] } {
set name [dict get $::secinfo name]
set IP [dict get $::secinfo ip]
set PORT [dict get $::secinfo port]
set sensor [dict get $::secinfo sensor]
set tol [dict get $::secinfo tol]
set cid [dict get $::secinfo id]
set ctype [dict get $::secinfo type]
add_watlow_st $name $IP $PORT $devid $tol $cid $ctype
}
}
}
}
} message ]} {
puts "ERROR: $message"
}
namespace import ::scobj::watlow_st::*