namespace eval sim921 { } # for curve reading if {![namespace exists lsc]} { source drivers/lsc.tcl } proc sim921::sendto {chan cmd} { sct send "_\nconn $chan,\"_\n\"\n$cmd" } proc stdConfig::sim921 {args} { variable node controller std lineseparator=| pollperiod 1 1 obj SIM921 -none upd kids "AC resistance bridge SIM921" { foreach {chan nam} $args { node $nam rd prop read "sim921::poll $chan" prop badcnt 0 prop rngcnt 0 prop snschk 0 prop modcnt 0 prop lastok 0 prop last_range_change 0 prop cnvcnt 0 kids "$nam" { node r upd node auto -int par 1 prop enum 1 node excitation -int out prop write "sim921::wrexci $chan" prop width 2 node range -int out prop write "sim921::wrrange $chan" prop width 2 node rangemin -int par 3 prop width 2 node rangemax -int par 8 prop width 2 node filter out prop write "sim921::wrtcon $chan" node status -text upd prop width 32 node current upd node voltage upd node mode -int out prop label "excit.mode" prop enum "passive,current,voltage,power" prop write "sim921::wrmode $chan" node rraw upd node sensorcheck -int par 0 prop enum 1 prop label "sensor check" node curve out -text prop chan $chan prop model 0 prop width 32 prop check lsc::read_curve prop write sim921::set_curve hfactory $node/points plain mugger floatvarar 1 node reset out -int prop enum push prop newline 1 prop label reset prop write "sim921::reset $chan" } } } } proc sim921::rohm {range} { if {$range < 0} { set range 0 } elseif {$range > 9} { set range 9 } return [lindex {20mOhm 200mOhm 2Ohm 20Ohm 200Ohm 2kOhm 20kOhm 200kOhm 2MOhm 20Mohm} $range] } proc sim921::rexci {exci} { if {$exci < -1} { set exci -1 } elseif {$exci > 8} { set exci 9 } incr exci return [lindex {0 3uV 10uV 30uV 100uV 300uV 1mV 3mV 10mV 30mV} $exci] } proc sim921::poll {chan} { sendto $chan "tval?;rval?;rang?;exci?;ovcr?;iexc?;vexc?;tcon?;agai?;mode?{10}" return sim921::upd } proc sim921::setstatus {msg} { # if {$msg ne "[hvali [sct]/status]"} { # if {$msg eq ""} { # clientput ok # } # clientput $msg # } hupdate [sct]/status $msg } proc sim921::upd {} { if {[scan [sct result] "%f|%f|%d|%d|%d|%f|%f|%d|%d|%d" t r rng exci status iex vex tcon agai mode] != 10} { error "bad result: [sct result]" } set now [DoubleTime] set rref [expr pow(10, $rng-2)] if {$exci % 2 == 1} { set exref [expr pow(10, ($exci - 11) / 2)] } else { set exref [expr 3 * pow(10, ($exci - 12) / 2)] } set oldrng $rng set bad 0 set msg "" updateval [sct]/current $iex updateval [sct]/voltage $vex updateval [sct]/mode $mode if {$agai == 1} { hupdate [sct]/status "adjust gain" return idle } if {1 & $status} { set msg "overload $status" set bad 2 } elseif {2 & $status} { set msg "preamp-overload $status" set bad 2 } elseif {4 & $status} { set msg "current-overload $status" set bad 2 } elseif {$mode == 2 && (24 & $status)} { # set msg "adjusting excit." # set bad 1 } elseif {$mode == 2 && abs(log10(abs($vex) / $exref)) > 0.08} { # 20 % error of excit, not detected by bridge # set msg "adjusting excit" set bad 1 } elseif {32 & $status} { # this is an R underflow, but we normally have a negative T coefficient set msg "T-overflow" } elseif {64 & $status} { set msg "T-underflow" } if {$mode == 0} { set rraw [expr $exref * 18.2 / $iex - 22 * $rref] } else { set rraw 0 } updateval [sct]/rraw $rraw set badcnt [sct badcnt] set rngcnt [sct rngcnt] set cnvcnt [sct cnvcnt] set rmin [hvali [sct]/rangemin] set rmax [hvali [sct]/rangemax] set vref [expr $iex * $rref] set auto [hvali [sct]/auto] set sensorcheck [hvali [sct]/sensorcheck] if {$mode == 0 && $bad == 0} { set snschk [sct snschk] if {$rmax < 8} { set rlim [expr 20 * pow(10, $rmax -2)] } else { set rlim 2.0e7 } if {$rraw > 20 * $rref || $rraw > $rlim} { # no sensor ? set bad 1 set msg "no sensor" setstatus $msg if {$snschk < -3} { set rm [expr $rmax - 1] if {$rng != $rm && $rraw < $rlim} { set rm [expr $rmax - 1] hset [sct]/range $rm clientput "[sct] max range $rm (passive)" sct snschk 3 } else { # error message immediately updateerror [sct]/r $msg 1 updateerror [sct] $msg 1 } return idle } incr snschk -1 } elseif {$auto} { setstatus "sensor check" if {$snschk > 10} { set cnt 0 while {$r > $rref * 5 && $cnt < 3} { incr rng incr cnt set rref [expr 10 * $rref] } while {$r < $rref * 0.2 && $cnt < 3} { incr rng -1 incr cnt set rref [expr 0.1 * $rref] } if {$rng > $rmax} { set rng $rmax } elseif {$rng < $rmin} { set rng $rmin } if {$rng != $oldrng} { clientput "[sct] new range $rng voltage excit." } else { clientput "[sct] range $rng voltage excit." } hset [sct]/range $rng hset [sct]/mode 2 sct snschk 0 return idle } else { incr snschk } } sct snschk $snschk } set cnvlim 4 if {$bad <= 1} { if {$cnvcnt < $cnvlim || ($cnvcnt <= $cnvlim && $bad == 0)} { incr cnvcnt sct cnvcnt $cnvcnt } } if {$cnvcnt > $cnvlim} { updateval [sct]/r $r if {[string match T-* $msg]} { updateerror [sct] $msg 1 } else { sct update $t } sct lastok $now } elseif {$msg eq ""} { set msg "stabilize $cnvcnt" } setstatus $msg if {$now > [sct lastok] + 60} { updateerror [sct]/r $msg 1 updateerror [sct] $msg 1 } if {$mode == 2} { if {$sensorcheck} { set modcnt [sct modcnt] if {$bad > 0} { if {$modcnt > 20} { sct modcnt 0 sct rngcnt 0 clientput "[sct] passive excit." hset [sct]/mode 0 return idle } incr modcnt } elseif {$modcnt > 15} { incr modcnt -1 } sct modcnt $modcnt } if {abs($vex) > $vref * 5} { incr rngcnt } elseif {abs($vex) < $vref * 0.2} { incr rngcnt -1 } } if {$bad > 1} { set rngcnt 0 if {$badcnt > 5} { set bad 3 } incr badcnt } elseif {$badcnt > -5} { incr badcnt -1 } #if {[sct] eq "/r/tb" && abs(log10(abs($vex) / $exref)) > 0.04} { #clientput "[sct] [expr $vref / $exref] [expr $vex / $exref] bad $badcnt rngcnt $rngcnt $r $status" #} sct badcnt $badcnt if {$auto && $bad == 0 && $mode == 2} { if {$rngcnt > 5} { if {$rng < $rmax} { incr rng } set rngcnt 0 } elseif {$rngcnt < -5} { if {$rng > $rmin} { incr rng -1 } set rngcnt 0 } } sct rngcnt $rngcnt updateval [sct]/filter [format %.1g [expr 0.32 * pow(10, $tcon * 0.5)]] if {$exci != [hvali [sct]/excitation]} { hsetprop [sct]/excitation label "excit. ([rexci $exci])" updateval [sct]/excitation $exci sct rngcnt 0 sct badcnt 0 sct cnvcnt 0 } if {$bad == 3 && ($mode == 0 || $sensorcheck == 0 || $now < [sct last_range_change] + 20)} { clientput "adjust gain on [sct] (rng=[rohm $oldrng] exci=[rexci $exci])" sct badcnt 0 sct cnvcnt 0 sct send "agai 1;agai?" return stdSct::complete } if {$rng < $rmin} { set rng $rmin } elseif {$rng > $rmax} { set rng $rmax } if {$rng != $oldrng} { clientput "[sct] new range $rng" hset [sct]/range $rng } elseif {$rng != [hvali [sct]/range]} { clientput "[sct] range changed to $rng" hsetprop [sct]/range label "range ([rohm $rng])" updateval [sct]/range $rng sct rngcnt 0 sct badcnt 0 sct modcnt 0 sct cnvcnt 0 } return idle } proc sim921::wrrange {chan} { sendto $chan "rang [sct target];rang?" sct update [sct target] hsetprop [sct parent] rngcnt 0 hsetprop [sct parent] badcnt 0 hsetprop [sct parent] modcnt 0 hsetprop [sct parent] cnvcnt 0 sct label "range ([rohm [sct target]])" return stdSct::complete } proc sim921::wrexci {chan} { sendto $chan "exci [sct target];exon 1;exci?" sct update [sct target] hsetprop [sct parent] rngcnt 0 hsetprop [sct parent] badcnt 0 hsetprop [sct parent] cnvcnt 0 sct label "excit. ([rexci [sct target]])" return stdSct::complete } proc sim921::wrmode {chan} { sendto $chan "mode [sct target];mode?" sct update [sct target] hsetprop [sct parent] last_range_change [DoubleTime] return stdSct::complete } proc sim921::wrtcon {chan} { set filt [sct target] if {$filt < 0.1} { set filt 0.1 } set tcon [expr round(log10($filt) * 2 + 1)] sct update [format %.1g [expr 0.32 * pow(10, $tcon * 0.5)]] sendto $chan "tcon $tcon;tcon?" return stdSct::complete } proc sim921::set_curve {} { sendto [sct chan] "cini?1;cini?2;cini?3{3}" return sim921::set_curve2 } proc sim921::set_curve2 {} { # download always log log format sct logT 1 sct logR 1 set z 3 set points [hvali [sct]/points] set crc [lrange [lsc::crc_code $points] 0 15] set nam [string toupper [sct target]] set short $nam if {[string length $short] > 5} { if {[string index $short 0] eq "R"} { set short [string range $short 1 end] } if {[string index $short 0] eq "X"} { set short [string range $short 1 end] } } set n [expr [llength $points] / 2] set ini "$z,$short/$crc,$n" if {[sicsdescriptor sim921] eq "notfound"} { makeobject sim921 array } set id [sct parent] if {[sim921 exists ${id}_lastno] == 0} { sim921 makeitem ${id}_lastno 0 sim921 makeitem ${id}_lastno2 0 } set lastno [result sim921 ${id}_lastno] set lastno2 [result sim921 ${id}_lastno2] set no 1 set emptyno 0 set changedno 0 foreach iniold [split [sct result] |] { sct curve$no $iniold if {$iniold eq $ini} { sct print "[sct parent]: activate curve $nam (already loaded as no $no)" sct update [sct target] if {$no != $lastno} { sim921 ${id}_lastno2 $lastno sim921 ${id}_lastno $no } sendto [sct chan] "curv $no;*OPC?" return stdSct::complete } if {[string match "*,$short/*" $iniold]} { set changedno $no } elseif {[lindex [split $iniold ","] 2] == 0} { set emptyno $no } incr no } if {$changedno != 0} { set no $changedno sct print "[sct parent]: curve $nam has changed - start loading" } elseif {$emptyno > 0} { set no $emptyno sct print "[sct parent]: start loading curve $nam to no $no" } else { set no $lastno incr no if {$no > 3} { set no 1 } if {$no == $lastno2} { incr no if {$no > 3} { set no 1 } } sct print "[sct parent]: start loading curve $nam overwriting no $no" } if {$no != $lastno} { sim921 ${id}_lastno2 $lastno sim921 ${id}_lastno $no } sct no $no sendto [sct chan] "cini $no,$z,$short/$crc;*OPC?" return "sim921::load_pt 0" } proc sim921::load_pt {i} { set points [hvali [sct]/points] if {$i >= [llength $points]} { sct print "[sct parent]: loading finished" sct update [sct target] sendto [sct chan] "curv [sct no];*OPC?" return stdSct::complete } set r [lindex $points $i] if {[sct logR]} { set r [expr log10($r)] } incr i set t [lindex $points $i] if {[sct logR]} { set t [expr log10($t)] } incr i sendto [sct chan] "capt [sct no],[format %.7g $r],[format %.7g $t]\n*OPC?" return "sim921::load_pt $i" } proc sim921::reset {chan} { sendto $chan "*RST;*OPC?" return sim921::resetupdate } proc sim921::resetupdate {} { sct udpate 0 return idle }