Files
sea/tcl/drivers/sim921.tcl
2022-08-18 15:04:28 +02:00

510 lines
12 KiB
Tcl

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
}