403 lines
10 KiB
Tcl
403 lines
10 KiB
Tcl
namespace eval ipsmag {
|
|
}
|
|
|
|
source drivers/magfield.tcl
|
|
|
|
proc stdConfig::ipsmag {{n_of_slaves 3}} {
|
|
|
|
controller std timeout=5
|
|
prop write ipsmag::write
|
|
prop read ipsmag::read
|
|
prop update ipsmag::update
|
|
prop startcmd *IDN?
|
|
|
|
variable node
|
|
set node $node/tasks
|
|
prop complete ipsmag::completeStart
|
|
|
|
variable name
|
|
magfield_obj IPS_MAGFIELD "ipsmag::cmd /$name/ips"
|
|
#magfield_obj IPS_MAGFIELD "node_cmd /$name/ips"
|
|
|
|
kids "magnetic field control" {
|
|
|
|
# 1: bipolar
|
|
magfield_kids 1
|
|
|
|
node ips rd
|
|
prop adr DEV:GRPZ:PSU:SIG:PFLD
|
|
prop label persistent field
|
|
|
|
kids "IPS settings" {
|
|
|
|
node ramp_slow wr
|
|
prop adr DEV:GRPZ:PSU:SIG:RFST
|
|
default 0.1
|
|
prop help "ramp rate for coils Tesla/min."
|
|
|
|
node ramp_fast upd
|
|
default 100
|
|
prop help "ramp rate for leads Tesla/min."
|
|
|
|
node set_field wr
|
|
prop adr DEV:GRPZ:PSU:SIG:FSET
|
|
prop write ipsmag::write_set
|
|
|
|
node heater wr
|
|
prop enum 1
|
|
prop adr DEV:GRPZ:PSU:SIG:SWHT
|
|
prop cvt "ON=1 OFF=0"
|
|
prop label "persistent switch heater"
|
|
prop update ipsmag::update_heater
|
|
|
|
node ramp_state wr -int
|
|
prop enum hold=0,to_zero=1,to_set=2,clamp=3
|
|
prop adr DEV:GRPZ:PSU:ACTN
|
|
prop cvt "RTOZ=1 RTOS=2 CLMP=3 HOLD=0"
|
|
prop read ipsmag::read_ramp_state
|
|
|
|
node leads_set rd 1
|
|
prop adr DEV:GRPZ:PSU:SIG:FLD
|
|
prop help "calculated current in the leads, converted to Tesla"
|
|
|
|
node show_internals -int par 1
|
|
prop enum 1
|
|
prop newline 1
|
|
prop show_more 1
|
|
|
|
node leads_meas rd
|
|
prop adr DEV:GRPZ:PSU:SIG:CURR
|
|
prop help {measured current in the leads, converted to Tesla}
|
|
prop update ipsmag::update_leads $n_of_slaves
|
|
|
|
for {set i 1} {$i <= $n_of_slaves} {incr i} {
|
|
node slave$i upd
|
|
}
|
|
|
|
node volt rd
|
|
prop adr DEV:GRPZ:PSU:SIG:VOLT
|
|
|
|
node symode -text upd
|
|
default "correct"
|
|
|
|
node engineering_password wr -text
|
|
default ""
|
|
prop adr SYS:USER:ENG
|
|
prop write ipsmag::write_eng
|
|
prop read ipsmag::read_eng
|
|
prop update ipsmag::update_eng
|
|
|
|
node atob wr
|
|
prop help {Amp/Tesla}
|
|
prop adr DEV:GRPZ:PSU:ATOB
|
|
prop write ipsmag::write_config
|
|
prop update ipsmag::update_config
|
|
prop check ipsmag::check_config
|
|
|
|
node inductance wr
|
|
prop help {henries}
|
|
prop adr DEV:GRPZ:PSU:IND
|
|
prop write ipsmag::write_config
|
|
prop update ipsmag::update_config
|
|
prop check ipsmag::check_config
|
|
|
|
node switch_heater_current wr
|
|
prop help {switch heater current [mA]}
|
|
prop adr DEV:GRPZ:PSU:SHTC
|
|
prop write ipsmag::write_config
|
|
prop update ipsmag::update_config
|
|
prop check ipsmag::check_config
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
proc ipsmag::completeStart {{try 3}} {
|
|
if {![string match "IDN:OXFORD INSTRUMENTS:MERCURY*" [sct result]]} {
|
|
if {$try > 0} {
|
|
sct send "*IDN?"
|
|
incr try -1
|
|
clientput "[sct sicsdev]: bad IDN: [sct result]"
|
|
clientput "[sct sicsdev]: try again"
|
|
return "ipsmag::completeStart $try"
|
|
}
|
|
clientput "[sct sicsdev]: bad IDN: [sct result]"
|
|
return unpoll
|
|
}
|
|
return [stdSct::completeStart]
|
|
}
|
|
|
|
proc ipsmag::cmd {node args} {
|
|
set cmd [linsert $args 0 node_cmd $node]
|
|
if {[llength $args] < 2} {
|
|
return [eval $cmd]
|
|
}
|
|
lassign $args var val
|
|
if {[silent 0 hgetpropval $node/$var redo]} {
|
|
hsetprop $node/$var redo 0
|
|
set old -1
|
|
} else {
|
|
set old [eval [list node_cmd $node $var]]
|
|
}
|
|
set tar [silent $old hgetpropval $node/$var target]
|
|
if {$val != $old || $val != $tar} {
|
|
#clientlog "CMD $node $args ($old -> $val)"
|
|
return [eval [list node_cmd $node $var $val]]
|
|
}
|
|
# clientlog "KEEP $node $args"
|
|
return $old
|
|
}
|
|
|
|
proc ipsmag::write {} {
|
|
set val [sct target]
|
|
set cvt [silent "" sct cvt]
|
|
if {$cvt ne ""} {
|
|
set done 0
|
|
foreach item $cvt {
|
|
lassign [split $item =] key value
|
|
if {$value eq $val} {
|
|
set val $key
|
|
set done 1
|
|
break
|
|
}
|
|
}
|
|
if {!$done} {
|
|
set val $key
|
|
}
|
|
}
|
|
sct send "SET:[sct adr]:$val"
|
|
return "ipsmag::read 1"
|
|
}
|
|
|
|
proc ipsmag::write_set {} {
|
|
if {abs([silent 99999 hval [sct]] - [sct target]) > 1e-6} {
|
|
if {[hval [sct parent]/ramp_state] == 2} {
|
|
# we are in ramp_state "to_set" and the target changed while running
|
|
# to a setpoint. We have to switch the ramp_state to hold. This will
|
|
# remind the IPS that the setpoint has changed really!
|
|
# ramp_state will be switched to "to_set" again by the magfield script
|
|
sct send SET:DEV:GRPZ:PSU:ACTN:HOLD
|
|
clientput "setpoint changed: stop and restart ramp"
|
|
return ipsmag::write
|
|
}
|
|
}
|
|
return [ipsmag::write]
|
|
}
|
|
|
|
proc ipsmag::write_eng {} {
|
|
if {[sct target] eq ""} {
|
|
sct send SET:SYS:USER:NORM
|
|
} else {
|
|
sct send "SET:SYS:USER:ENG:[sct target]"
|
|
sct changed_password [DoubleTime]
|
|
}
|
|
return ipsmag::confirm_eng
|
|
}
|
|
|
|
proc ipsmag::confirm_eng {} {
|
|
if {[string match {*:DENIED} [sct result]]} {
|
|
sct print "ERROR: invalid password"
|
|
return idle
|
|
}
|
|
sct send READ:SYS:USER
|
|
return ipsmag::update_eng
|
|
}
|
|
|
|
proc ipsmag::read_eng {} {
|
|
if {[silent 0 sct changed_password] ne "0"} {
|
|
if {[DoubleTime] > [sct changed_password] + 60} {
|
|
sct changed_password 0
|
|
sct send SET:SYS:USER:NORM
|
|
return ipsmag::confirm_eng
|
|
}
|
|
}
|
|
sct send READ:SYS:USER
|
|
return ipsmag::update_eng
|
|
}
|
|
|
|
proc ipsmag::update_eng {} {
|
|
if {[ipsmag::cvt] eq "ENG"} {
|
|
sct update "***"
|
|
} else {
|
|
sct update ""
|
|
}
|
|
return idle
|
|
}
|
|
|
|
proc ipsmag::read {{from_write 0}} {
|
|
# TODO: split this into ipsmag::confirm and ipsmag::read
|
|
if {$from_write} {
|
|
if {![string match {*:VALID} [sct result]]} {
|
|
# show invalid messsage only when target value is different than actual
|
|
set tar [sct target]
|
|
set val [silent $tar hval [sct]]
|
|
if {abs($val - $tar) > abs($val + $tar) / 20000.} {
|
|
hdelprop [sct] requested
|
|
error "[sct]: [sct result]"
|
|
}
|
|
}
|
|
sct update [sct target] ;# do we need this? should be done in update script ...
|
|
}
|
|
sct send "READ:[sct adr]"
|
|
return update
|
|
}
|
|
|
|
proc ipsmag::cvt {} {
|
|
set val [lindex [split [sct result] :] end]
|
|
set cvt [silent "" sct cvt]
|
|
if {$cvt ne ""} {
|
|
set done 0
|
|
foreach item $cvt {
|
|
lassign [split $item =] key value
|
|
if {$key eq $val} {
|
|
set val $value
|
|
set done 1
|
|
break
|
|
}
|
|
}
|
|
if {!$done} {
|
|
clientput "[sct] can not parse '[sct result]', use '$value' instead"
|
|
set val $value
|
|
}
|
|
} else {
|
|
scan $val %f val
|
|
}
|
|
return $val
|
|
}
|
|
|
|
proc ipsmag::update {} {
|
|
sct update [ipsmag::cvt]
|
|
return idle
|
|
}
|
|
|
|
proc ipsmag::update_heater {} {
|
|
sct update [ipsmag::cvt]
|
|
if {[hval [sct]]} {
|
|
hsetprop [sct parent] adr DEV:GRPZ:PSU:SIG:FLD
|
|
} else {
|
|
hsetprop [sct parent] adr DEV:GRPZ:PSU:SIG:PFLD
|
|
}
|
|
return idle
|
|
}
|
|
|
|
proc ipsmag::update_leads {{n_of_slaves 3}} {
|
|
set current [ipsmag::cvt]
|
|
catch {
|
|
sct update [format %.6f [expr $current / [hval [sct parent]/atob]]]
|
|
} msg
|
|
if {$n_of_slaves} {
|
|
set currents [string trim [silent "" sct currents]]
|
|
if {$currents ne ""} {
|
|
# check currents
|
|
set tol [expr abs($current - [sct last_current]) * 1.2 + 0.06]
|
|
set mincur [format %.2f [expr ($current - $tol) / $n_of_slaves]]
|
|
set maxcur [format %.2f [expr ($current + $tol) / $n_of_slaves]]
|
|
set bad 0
|
|
foreach cur $currents {
|
|
if {$cur < $mincur || $cur > $maxcur} {
|
|
set bad 1
|
|
}
|
|
}
|
|
set status [hval [sct objectPath]/status]
|
|
if {$bad} {
|
|
set msg "slave currents ($currents) are not within $mincur .. $maxcur"
|
|
hupdate [sct objectPath]/status $msg
|
|
if {$status eq ""} {
|
|
clientlog "WARNING: $msg"
|
|
}
|
|
} elseif {[string match {slave currents *} $status]} {
|
|
hupdate [sct objectPath]/status ""
|
|
}
|
|
}
|
|
sct last_current $current
|
|
sct currents ""
|
|
sct send READ:DEV:PSU.M${n_of_slaves}:PSU:SIG:CURR
|
|
return "ipsmag::slave_currents $n_of_slaves"
|
|
}
|
|
return idle
|
|
}
|
|
|
|
proc ipsmag::slave_currents {index} {
|
|
set value [format %.2f [ipsmag::cvt]]
|
|
sct currents "$value [sct currents]"
|
|
updateval [sct parent]/slave$index $value
|
|
incr index -1
|
|
if {$index > 0} {
|
|
sct send READ:DEV:PSU.M${index}:PSU:SIG:CURR
|
|
return "ipsmag::slave_currents $index"
|
|
}
|
|
return idle
|
|
}
|
|
|
|
proc ipsmag::write_config {} {
|
|
if {[hvali [sct parent]/engineering_password] eq ""} {
|
|
sct update [sct target]
|
|
sct send READ:[sct adr]
|
|
return ipsmag::confirm_config
|
|
}
|
|
return [ipsmag::write]
|
|
}
|
|
|
|
proc ipsmag::confirm_config {} {
|
|
set val [ipsmag::cvt]
|
|
if {[hvali [sct parent]/engineering_password] eq ""} {
|
|
# check only
|
|
if {$val != [format %.7g [silent $val sct target]]} {
|
|
hdelprop [sct] requested
|
|
error "can not change [sct] with empty engineering_password"
|
|
}
|
|
}
|
|
sct update $val
|
|
return idle
|
|
}
|
|
|
|
proc ipsmag::update_config {} {
|
|
set val [ipsmag::cvt]
|
|
if {[hvali [sct parent]/engineering_password] eq ""} {
|
|
# check only
|
|
set msghead "make sure cables are connected for"
|
|
if {$val != [format %.7g [silent $val sct target]]} {
|
|
set txt "$msghead [hval [sct parent]/symode] mode, enter eng. pwd. and select [result device name] again"
|
|
if {[hvali [sct objectPath]/status] ne $txt} {
|
|
hupdate [sct objectPath]/status $txt
|
|
clientput "ERROR: $txt"
|
|
}
|
|
hsetprop [sct] geterror "$val does not match configured value [sct target]"
|
|
return idle
|
|
} else {
|
|
if {[string match "$msghead*" [hvali [sct objectPath]/status]]} {
|
|
hupdate [sct objectPath]/status ""
|
|
catch {hdelprop [sct] geterror}
|
|
}
|
|
}
|
|
}
|
|
sct update $val
|
|
return idle
|
|
}
|
|
|
|
proc ipsmag::check_config {} {
|
|
set val [silent [sct target] hval [sct]]
|
|
if {[hvali [sct parent]/engineering_password] eq ""} {
|
|
# check only
|
|
if {$val != [format %.7g [silent $val sct target]]} {
|
|
error "can not change [sct] with empty engineering_password"
|
|
}
|
|
}
|
|
}
|
|
|
|
proc ipsmag::read_ramp_state {{from_write 0}} {
|
|
if {$from_write} {
|
|
if {[string match {*:DENIED} [sct result]]} {
|
|
if {[hval [sct]] == 3} {
|
|
error "[sct]: power supply is clamped - please check reason"
|
|
}
|
|
error "[sct]: access not allowed: IPS in local mode?"
|
|
}
|
|
sct update [sct target] ;# do we need this? should be done in update
|
|
}
|
|
sct send "READ:[sct adr]"
|
|
return update
|
|
}
|
|
|
|
|