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