Files
sea/tcl/drivers/smc.tcl
2022-08-22 14:59:00 +02:00

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]"
}
}
}