411 lines
8.6 KiB
Tcl
411 lines
8.6 KiB
Tcl
namespace eval smc {
|
|
}
|
|
|
|
source drivers/magfield.tcl
|
|
|
|
proc stdConfig::smc {} {
|
|
|
|
# GPIB through Prologix controller
|
|
controller lsc timeout=5 writedelay=0.2
|
|
prop write smc::write
|
|
prop read smc::read
|
|
|
|
variable node
|
|
set node $node/tasks
|
|
prop start smc::start
|
|
|
|
pollperiod 2 2
|
|
|
|
variable name
|
|
magfield_obj SMC_MAGFIELD "smc::cmd /$name/smc"
|
|
|
|
kids "SMC magnet power supply" {
|
|
|
|
magfield_kids
|
|
|
|
node smc rd
|
|
prop read smc::read_gn
|
|
prop label persistent field
|
|
|
|
kids "SMC settings" {
|
|
|
|
node ramp_slow out
|
|
prop write smc::set_ramp_rate ramp_slow
|
|
default 0.04
|
|
prop help "ramp rate for coils Tesla/min."
|
|
|
|
node ramp_fast out
|
|
prop write smc::set_ramp_rate ramp_fast
|
|
default 100
|
|
prop help "ramp rate for leads Tesla/min."
|
|
|
|
# use MID as set_field
|
|
node set_field out
|
|
prop cmd L
|
|
prop get S
|
|
prop check smc::check_mid
|
|
|
|
node at_target upd -int
|
|
prop enum 1
|
|
|
|
node heater wr -int
|
|
prop write smc::set_ramp_rate heater
|
|
prop enum 1
|
|
prop cmd H
|
|
prop get J
|
|
prop "persistent switch heater"
|
|
|
|
node ramp_state out -int
|
|
prop check smc::chk_ramp_state
|
|
prop write stdSct::complete
|
|
prop enum hold,goto_zero,goto_set
|
|
|
|
node leads_set upd
|
|
prop help "calculated current in the leads, converted to Tesla"
|
|
|
|
node leads_meas upd
|
|
prop help {measured current in the leads, converted to Tesla}
|
|
|
|
node show_internals -int par 1
|
|
prop enum 1
|
|
prop newline 1
|
|
prop show_more 1
|
|
|
|
node ramp_amp_sec wr
|
|
prop cmd A
|
|
prop get O
|
|
|
|
node pause out -int
|
|
prop enum 1
|
|
prop cmd P
|
|
prop get K
|
|
|
|
node ramp_target wr -int
|
|
prop enum go2zero,go2mid,go2max
|
|
prop cmd R
|
|
prop get K
|
|
|
|
# MAX is always kept as least as high as set_field
|
|
node max wr
|
|
prop cmd U
|
|
prop get S
|
|
|
|
node units wr -int
|
|
prop enum amps,tesla
|
|
prop cmd T
|
|
prop get S
|
|
default 1
|
|
|
|
node calib out
|
|
prop cmd C
|
|
prop get O
|
|
|
|
node heater_voltage out
|
|
prop cmd W
|
|
prop get O
|
|
|
|
node volt_limit out
|
|
prop cmd Y
|
|
prop get S
|
|
|
|
node xtrip out -int
|
|
prop cmd X
|
|
prop get K
|
|
|
|
node volt upd
|
|
|
|
node error_code upd -int
|
|
|
|
node quench_field upd
|
|
|
|
node v_at_lim upd -int
|
|
}
|
|
}
|
|
}
|
|
|
|
proc smc::cmd {node args} {
|
|
set cmd [linsert $args 0 node_cmd $node]
|
|
if {[llength $args] < 2} {
|
|
return [eval $cmd]
|
|
}
|
|
lassign $args var val
|
|
set old [eval [list node_cmd $node $var]]
|
|
set scache [silent $old hgetpropval $node/$var cached_set]
|
|
if {[silent 0 hgetpropval $node/$var cache_state] == 2} {
|
|
set rcache [hgetpropval $node/$var cached_readback]
|
|
if {$rcache != $old || abs($scache - $rcache) > 0.1 * $scache} {
|
|
clientput "$node/$var: $old != $rcache || $scache far $rcache"
|
|
set scache $old
|
|
}
|
|
} else {
|
|
set scache $old
|
|
}
|
|
if {$val != $scache} {
|
|
# clientput "$node: set $var to $val"
|
|
hsetprop $node/$var cached_set $val
|
|
return [eval [list node_cmd $node $var $val]]
|
|
}
|
|
return $old
|
|
}
|
|
|
|
proc smc::start {} {
|
|
sct send "++addr"
|
|
return smc::start1
|
|
}
|
|
|
|
proc smc::start1 {} {
|
|
sct send "O\n++read"
|
|
sct cnt 0
|
|
return smc::start2
|
|
}
|
|
|
|
proc smc::start2 {} {
|
|
set id 0
|
|
regexp {A.{19}(C.*)} [sct result] -> id
|
|
if {$id eq "0"} {
|
|
sct cnt [expr [sct cnt] + 1]
|
|
if {[sct cnt] < 5} {
|
|
sct send "O\n++read"
|
|
return smc::start2
|
|
}
|
|
error "[sct] bad response from SMC: [sct result]"
|
|
}
|
|
sct send "T1\n++ver"
|
|
return "smc::start3 $id"
|
|
}
|
|
|
|
proc smc::start3 {id} {
|
|
clientput [sct result]
|
|
sct result $id
|
|
return [stdSct::completeStart]
|
|
}
|
|
|
|
proc smc::write {} {
|
|
update_field
|
|
sct send "[sct cmd][sct target]\n++auto"
|
|
sct update [sct target]
|
|
update_field
|
|
sct cache_state 1
|
|
return "smc::read 1"
|
|
}
|
|
|
|
proc smc::complete {} {
|
|
sct cache_state 1
|
|
clientput "complete [sct]"
|
|
return idle
|
|
}
|
|
|
|
proc smc::check_mid {} {
|
|
if {[sct target] > [hvali [sct parent]/max]} {
|
|
hset [sct parent]/max [sct target]
|
|
}
|
|
}
|
|
|
|
proc smc::read {{from_write 0}} {
|
|
sct send "[sct get]\n++auto"
|
|
sct from_write $from_write
|
|
return smc::update0
|
|
}
|
|
|
|
proc smc::update0 {} {
|
|
sct send "++read eoi"
|
|
return smc::update
|
|
}
|
|
|
|
proc smc::read_gn {} {
|
|
if {[hvali [sct]/units] == 0} {
|
|
sct get G
|
|
} else {
|
|
sct get N
|
|
}
|
|
return [smc::read]
|
|
}
|
|
|
|
proc smc::eat_rubbish {} {
|
|
sct send "++read"
|
|
return stdSct::complete
|
|
}
|
|
|
|
proc smc::update_field {} {
|
|
set op [sct objectPath]
|
|
magfield::simleads [hgetpropval $op script] pf ls
|
|
hupdate $op/smc/leads_set $ls
|
|
if {[hval $op/smc/heater]} {
|
|
hupdate $op/smc $ls
|
|
}
|
|
}
|
|
|
|
proc smc::updateit {node val} {
|
|
updateval $node $val
|
|
switch [silent 0 hgetpropval $node cache_state] {
|
|
1 {
|
|
set t [hgetpropval $node target]
|
|
if {$t != $val} {
|
|
clientput "$node set to $val (target [hgetpropval $node target])"
|
|
} else {
|
|
clientput "$node set to $val"
|
|
}
|
|
hsetprop $node cached_readback $val
|
|
hsetprop $node cache_state 2
|
|
return
|
|
}
|
|
2 {
|
|
if {[hgetpropval $node cached_readback] != $val} {
|
|
hsetprop $node cache_state 0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc smc::update {} {
|
|
set r [sct result]
|
|
set op [sct objectPath]/smc
|
|
if {[regexp {T(.)U(.{7})L(.{7})Y(.{4})} $r -> t u l y]} {
|
|
set tst S
|
|
updateit $op/units $t
|
|
updateit $op/max $u
|
|
updateit $op/set_field $l
|
|
updateit $op/volt_limit $y
|
|
} elseif {[regexp {(F|I)(.{8})H(.)} $r -> fi f h]} {
|
|
set tst J
|
|
set pf [hvali $op]
|
|
if {$h == 0} {
|
|
if {$pf != $f} {
|
|
clientput "persistent $f"
|
|
}
|
|
updateit $op $f
|
|
} elseif {[catch {hval $op}]} {
|
|
updateit $op $pf
|
|
}
|
|
updateit $op/heater $h
|
|
} elseif {[regexp {(F|I)(.{8})V(.{4})R(.)(A|V)} $r -> fi f v r av]} {
|
|
set tst (G|N)
|
|
updateit $op/leads_meas $f
|
|
updateit $op/volt $v
|
|
if {$av eq "A"} {
|
|
updateit $op/v_at_lim 0
|
|
} else {
|
|
updateit $op/v_at_lim 1
|
|
}
|
|
} elseif {[regexp {R(.)M(.)P(.)X(.)H(.)Z0.00E(..)Q(.{8})} $r -> r m p x h e q]} {
|
|
set tst K
|
|
updateit $op/ramp_target $r
|
|
updateit $op/pause $p
|
|
if {$p} {
|
|
updateit $op/ramp_state 0
|
|
} else {
|
|
updateit $op/at_target $m
|
|
incr r
|
|
if {$r > 2} {
|
|
set r 2
|
|
}
|
|
updateit $op/ramp_state $r
|
|
}
|
|
updateit $op/xtrip $x
|
|
updateit $op/error_code $e
|
|
updateit $op/quench_field $q
|
|
} elseif {[regexp {A(.{8})D.T(.)B0W(.{4})C(.{8})} $r -> a t w c]} {
|
|
set tst O
|
|
updateit $op/ramp_amp_sec $a
|
|
set af [format %.3g [expr $a * $c * 60]]
|
|
set rf [hvali $op/ramp_fast]
|
|
set rs [hvali $op/ramp_slow]
|
|
set h [hvali $op/heater]
|
|
set am [expr sqrt($rf * $rs)]
|
|
if {$af > $am && $rf > $rs && $h == 0} {
|
|
updateit $op/ramp_fast $af
|
|
}
|
|
if {$af < $am && $rf > $rs && $h == 1} {
|
|
updateit $op/ramp_slow $af
|
|
}
|
|
updateit $op/units $t
|
|
updateit $op/heater_voltage $w
|
|
updateit $op/calib $c
|
|
} else {
|
|
set tst [sct get]
|
|
clientlog "unknown response: [sct get] $r"
|
|
}
|
|
catch {update_field}
|
|
if {![regexp $tst [sct get]]} {
|
|
[sct controller] queue [sct] write smc::eat_rubbish
|
|
}
|
|
return idle
|
|
}
|
|
|
|
proc smc::ramp_lim {field} {
|
|
set oldf 0
|
|
set oldr 99999
|
|
set result 0
|
|
foreach {r f} [hval [sct objectPath]/profile] {
|
|
if {$r > $oldr} {
|
|
error "ERROR: in ramp profile, ramps must be decreasing"
|
|
}
|
|
if {$r == 0} {
|
|
error "ERROR: in ramp profile, ramps must be > 0"
|
|
}
|
|
set oldr $r
|
|
if {$f < $oldf} {
|
|
error "ERROR: in ramp profile, fields must be increasing"
|
|
}
|
|
set oldf $f
|
|
if {$result == 0 && $f >= $field} {
|
|
set result $r
|
|
}
|
|
}
|
|
if {$result == 0} {
|
|
error "ERROR: field too high"
|
|
}
|
|
return $result
|
|
}
|
|
|
|
proc smc::set_ramp_rate {target_name} {
|
|
foreach var {heater ramp_slow ramp_fast} {
|
|
if {$target_name eq $var} {
|
|
set $var [sct target]
|
|
sct update [sct target]
|
|
} else {
|
|
set $var [hval [sct parent]/$var]
|
|
}
|
|
}
|
|
if {$heater} {
|
|
set r $ramp_slow
|
|
} else {
|
|
set r $ramp_fast
|
|
}
|
|
set calib [hval [sct parent]/calib]
|
|
if {$calib == 0} {
|
|
set calib 1
|
|
}
|
|
set rr [expr $r / 60.0 / $calib]
|
|
set rr [format %.3g $rr]
|
|
hset [sct parent]/ramp_amp_sec $rr
|
|
if {$target_name eq "heater"} {
|
|
return smc::write
|
|
}
|
|
sct cache_state 1
|
|
return idle
|
|
}
|
|
|
|
proc smc::chk_ramp_state {} {
|
|
set pr [sct parent]
|
|
switch -- [sct target] {
|
|
0 {
|
|
clientput "set pause to 1"
|
|
clientput "hset $pr/pause 1"
|
|
clientput "pause set to 1"
|
|
hset $pr/pause 1
|
|
}
|
|
1 {
|
|
hset $pr/pause 0
|
|
hset $pr/ramp_target 0
|
|
}
|
|
2 {
|
|
hset $pr/pause 0
|
|
hset $pr/ramp_target 1
|
|
}
|
|
default {
|
|
error "illegal ramp_target: [sct target]"
|
|
}
|
|
}
|
|
}
|