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.
394 lines
15 KiB
Tcl
394 lines
15 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::et2000 {
|
|
# Temperature controllers must have at least the following nodes
|
|
# /tempcont/setpoint
|
|
# /tempcont/sensor/value
|
|
proc debug_log {args} {
|
|
set fd [open "/tmp/et2000.log" a]
|
|
puts $fd $args
|
|
close $fd
|
|
}
|
|
|
|
proc getValue {tc_root nextState cmd} {
|
|
set dev "[hval $tc_root/dev_id]"
|
|
sct send "$dev:3:$cmd"
|
|
return $nextState
|
|
}
|
|
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 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
|
|
}
|
|
sct send "$dev:16:$cmd $par"
|
|
debug_log "setPoint $dev:16:$cmd $par"
|
|
return $nextState
|
|
}
|
|
|
|
proc rdValue {} {
|
|
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
|
|
}
|
|
|
|
proc getState {tc_root nextState cmd} {
|
|
set dev "[hval $tc_root/dev_id]"
|
|
sct send "$dev:3:$cmd"
|
|
return $nextState
|
|
}
|
|
|
|
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 Reads the current et2000 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 [SplitReply [hgetprop $tc_root/setpoint target]]
|
|
debug_log "rdState $tc_root: target=$tgt"
|
|
} else {
|
|
hsetprop $tc_root/setpoint target $val
|
|
set tgt [SplitReply [hgetprop $tc_root/setpoint target]]
|
|
debug_log "rdState $tc_root: initialised target to: target=$tgt"
|
|
}
|
|
set data [sct result]
|
|
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
|
|
}
|
|
if {$my_driving > 0} {
|
|
set temp [hval $tc_root/sensor/value]
|
|
set tol [hval $tc_root/tolerance]
|
|
set lotemp [expr {$tgt - $tol}]
|
|
set hitemp [expr {$tgt + $tol}]
|
|
debug_log "rdState driving $tc_root until $data in ($lotemp, $hitemp)"
|
|
if {$data < $lotemp} {
|
|
} elseif {$data > $hitemp} {
|
|
} else {
|
|
hset $tc_root/status "idle"
|
|
hsetprop $tc_root/setpoint driving 0
|
|
}
|
|
} else {
|
|
if {[SplitReply [hget $tc_root/status]] != "idle"} {
|
|
hset $tc_root/status "idle"
|
|
}
|
|
}
|
|
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} {
|
|
debug_log "halt $tc_root"
|
|
hset $tc_root/setpoint [hval $tc_root/sensor/value]
|
|
hsetprop $tc_root/setpoint driving 0
|
|
return idle
|
|
}
|
|
|
|
proc mk_sct_eurotherm_et2000 {sct_controller klass tempobj dev_id tol CID CTYPE} {
|
|
if {[ catch {
|
|
set ns ::scobj::et2000
|
|
|
|
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 $scobj_hpath rdValue "2"
|
|
hsetprop $scobj_hpath/setpoint write ${ns}::setPoint $scobj_hpath noResponse "2"
|
|
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
|
|
# 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
|
|
hsetprop $scobj_hpath/setpoint permlink data_set ${CTYPE}${CID}SP1
|
|
|
|
hfactory $scobj_hpath/overtemp_warnlimit plain user float
|
|
hsetprop $scobj_hpath/overtemp_warnlimit read ${ns}::getValue $scobj_hpath rdValue "14"
|
|
hsetprop $scobj_hpath/overtemp_warnlimit write ${ns}::setValue $scobj_hpath noResponse "14"
|
|
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 $scobj_hpath rdValue "13"
|
|
hsetprop $scobj_hpath/subtemp_warnlimit write ${ns}::setValue $scobj_hpath noResponse "13"
|
|
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 $scobj_hpath rdValue "1"
|
|
hsetprop $scobj_hpath/sensor/value rdValue ${ns}::rdValue
|
|
hsetprop $scobj_hpath/sensor/value oldval UNKNOWN
|
|
hsetprop $scobj_hpath/sensor/value units "C"
|
|
hsetprop $scobj_hpath/sensor/value permlink data_set ${CTYPE}${CID}S1
|
|
|
|
hfactory $scobj_hpath/setpoint_slew_rate plain user float
|
|
hsetprop $scobj_hpath/setpoint_slew_rate read ${ns}::getValue $scobj_hpath rdValue "35"
|
|
hsetprop $scobj_hpath/setpoint_slew_rate write ${ns}::setValue $scobj_hpath noResponse "35"
|
|
hsetprop $scobj_hpath/setpoint_slew_rate rdValue ${ns}::rdValue
|
|
hsetprop $scobj_hpath/setpoint_slew_rate noResponse ${ns}::noResponse
|
|
hsetprop $scobj_hpath/setpoint_slew_rate oldval UNKNOWN
|
|
|
|
hfactory $scobj_hpath/power_limit_low plain user float
|
|
hsetprop $scobj_hpath/power_limit_low read ${ns}::getValue $scobj_hpath rdValue "31"
|
|
hsetprop $scobj_hpath/power_limit_low write ${ns}::setValue $scobj_hpath noResponse "31"
|
|
hsetprop $scobj_hpath/power_limit_low rdValue ${ns}::rdValue
|
|
hsetprop $scobj_hpath/power_limit_low noResponse ${ns}::noResponse
|
|
hsetprop $scobj_hpath/power_limit_low oldval UNKNOWN
|
|
|
|
hfactory $scobj_hpath/power_limit_high plain user float
|
|
hsetprop $scobj_hpath/power_limit_high read ${ns}::getValue $scobj_hpath rdValue "30"
|
|
hsetprop $scobj_hpath/power_limit_high write ${ns}::setValue $scobj_hpath noResponse "30"
|
|
hsetprop $scobj_hpath/power_limit_high rdValue ${ns}::rdValue
|
|
hsetprop $scobj_hpath/power_limit_high noResponse ${ns}::noResponse
|
|
hsetprop $scobj_hpath/power_limit_high oldval UNKNOWN
|
|
|
|
hfactory $scobj_hpath/power_slew_rate plain user float
|
|
hsetprop $scobj_hpath/power_slew_rate read ${ns}::getValue $scobj_hpath rdValue "37"
|
|
hsetprop $scobj_hpath/power_slew_rate write ${ns}::setValue $scobj_hpath noResponse "37"
|
|
hsetprop $scobj_hpath/power_slew_rate rdValue ${ns}::rdValue
|
|
hsetprop $scobj_hpath/power_slew_rate noResponse ${ns}::noResponse
|
|
hsetprop $scobj_hpath/power_slew_rate oldval UNKNOWN
|
|
|
|
hfactory $scobj_hpath/heating_power_percent plain internal float
|
|
hsetprop $scobj_hpath/heating_power_percent read ${ns}::getValue $scobj_hpath rdValue "3"
|
|
hsetprop $scobj_hpath/heating_power_percent rdValue ${ns}::rdValue
|
|
hsetprop $scobj_hpath/heating_power_percent oldval UNKNOWN
|
|
|
|
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 5.0
|
|
hsetprop $scobj_hpath/tolerance/settletime units "s"
|
|
hset $scobj_hpath/tolerance $tol
|
|
|
|
hfactory $scobj_hpath/dev_id plain user int
|
|
hsetprop $scobj_hpath/dev_id values 1,2,3,4,5,6,7,8,9,10,11
|
|
hset $scobj_hpath/dev_id $dev_id
|
|
|
|
hfactory $scobj_hpath/status plain spy text
|
|
hset $scobj_hpath/status "idle"
|
|
hsetprop $scobj_hpath/status values busy,idle
|
|
|
|
hfactory $scobj_hpath/et2000_state plain spy text
|
|
hsetprop $scobj_hpath/et2000_state read ${ns}::getState $scobj_hpath rdState "1"
|
|
hsetprop $scobj_hpath/et2000_state rdState ${ns}::rdState $scobj_hpath
|
|
hsetprop $scobj_hpath/et2000_state oldval UNKNOWN
|
|
|
|
hfactory $scobj_hpath/remote_ctrl plain spy text
|
|
hset $scobj_hpath/remote_ctrl UNKNOWN
|
|
|
|
hfactory $scobj_hpath/et2000_lasterror plain user text
|
|
hset $scobj_hpath/et2000_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/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/setpoint_slew_rate
|
|
$sct_controller write $scobj_hpath/setpoint_slew_rate
|
|
$sct_controller poll $scobj_hpath/power_slew_rate
|
|
$sct_controller write $scobj_hpath/power_slew_rate
|
|
$sct_controller poll $scobj_hpath/power_limit_low
|
|
$sct_controller write $scobj_hpath/power_limit_low
|
|
$sct_controller poll $scobj_hpath/power_limit_high
|
|
$sct_controller write $scobj_hpath/power_limit_high
|
|
$sct_controller poll $scobj_hpath/sensor/value
|
|
$sct_controller poll $scobj_hpath/et2000_state 5 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
|
|
}
|
|
} message ]} {
|
|
return -code error $message
|
|
}
|
|
}
|
|
namespace export mk_sct_eurotherm_et2000
|
|
}
|
|
|
|
##
|
|
# @brief Create a Eurotherm et2000 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_et2000 {name IP port dev_id {_tol 5.0} {CID 1} {CTYPE T}} {
|
|
set fd [open "/tmp/et2000.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_eurotherm_et2000 sct_${name} environment $name $dev_id $_tol"
|
|
mk_sct_eurotherm_et2000 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_eurotherm_2000.tcl"
|
|
set fd [open "/tmp/et2000.log" w]
|
|
puts $fd "file evaluation of sct_eurotherm_2000.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"] == "et2000") } {
|
|
if { [ dict get $::secinfo enabled ] } {
|
|
set name [dict get $::secinfo name]
|
|
set IP [dict get $::secinfo ip]
|
|
set PORT [dict get $::secinfo port]
|
|
set devid [dict get $::secinfo devid]
|
|
set tol [dict get $::secinfo tol]
|
|
set cid [dict get $::secinfo id]
|
|
set ctype [dict get $::secinfo type]
|
|
add_et2000 $name $IP $PORT $devid $tol $cid $ctype
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} message ]} {
|
|
puts "ERROR: $message"
|
|
}
|
|
|
|
namespace import ::scobj::et2000::*
|
|
|
|
#add_et2000 et2000 137.157.201.213 502 1 5
|
|
#add_et2000 et2000 localhost 30502 1 5
|