420 lines
10 KiB
Tcl
420 lines
10 KiB
Tcl
|
|
namespace eval ccu4ext {
|
|
}
|
|
|
|
# automatic fill with level reading from external source
|
|
proc stdConfig::ccu4ext {type {readpath 0}} {
|
|
|
|
variable node
|
|
variable ctrl
|
|
|
|
controller syncedprot
|
|
|
|
obj fillccu wr -int
|
|
default -1
|
|
prop write ccu4ext::writeExt $type
|
|
prop read ccu4ext::fillExt $type
|
|
|
|
prop enum watching=0,filling=1,inactive=2,manualfill=3
|
|
prop label "filling state"
|
|
|
|
if {$type eq "n2"} {
|
|
set text LN2
|
|
} else {
|
|
set text LHe
|
|
}
|
|
kids "$text fill settings" {
|
|
|
|
node state upd -text
|
|
|
|
node readpath -text par $readpath
|
|
prop visible false
|
|
node lowlevel par 10
|
|
node highlevel par 100
|
|
|
|
node smooth upd
|
|
prop fmt %.7g
|
|
prop geterror undefined
|
|
default -1
|
|
|
|
node minfillminutes par 3.0
|
|
node maxfillminutes par 30.0
|
|
node minholdhours par 12.0
|
|
node maxholdhours par 120.0
|
|
node tolerance par 20.0
|
|
node badreadingminutes par 30.0
|
|
node tubecoolingminutes par 3.0
|
|
if {$type eq "he"} {
|
|
node vessellimit par 10.0
|
|
node vext upd
|
|
}
|
|
}
|
|
set node /sics/$ctrl
|
|
return "$text fill with CCU4 and external level meter"
|
|
}
|
|
|
|
proc ccu4ext::changestate {type state} {
|
|
switch $type {
|
|
n2 {
|
|
set cmd nc
|
|
set auto na
|
|
}
|
|
he {
|
|
set cmd hcd
|
|
set auto ha
|
|
}
|
|
default {
|
|
error "illegal level meter type: $type"
|
|
}
|
|
}
|
|
switch $state {
|
|
stop {
|
|
cc $cmd 0
|
|
cc $auto 1
|
|
}
|
|
fill {
|
|
cc $cmd 1
|
|
cc $auto 1
|
|
}
|
|
off {
|
|
cc $cmd 2
|
|
cc $auto 0
|
|
}
|
|
watch {
|
|
cc $cmd 3
|
|
cc $auto 1
|
|
}
|
|
}
|
|
sct change_time [DoubleTime]
|
|
}
|
|
|
|
proc ccu4ext::calcsmooth {level minspeed maxspeed} {
|
|
if {![string is double $level]} {
|
|
return 199
|
|
}
|
|
set now [clock seconds]
|
|
set lasttime [silent 0 sct lasttime]
|
|
if {$lasttime == 0} {
|
|
set lasttime $now
|
|
}
|
|
set delta [expr $now - $lasttime]
|
|
sct lasttime $now
|
|
set smooth [silent $level hvali [sct]/smooth]
|
|
set gs [expr $smooth + $delta * $maxspeed]
|
|
if {$level > $gs} {
|
|
set smooth $gs
|
|
} else {
|
|
set gs [expr $smooth + $delta * $minspeed]
|
|
if {$level < $gs} {
|
|
set smooth $gs
|
|
} else {
|
|
set smooth $level
|
|
}
|
|
}
|
|
set badtime [silent 0 sct badtime]
|
|
if {abs($smooth - $level) > [hvali [sct]/tolerance]} {
|
|
if {$badtime < [hvali [sct]/badreadingminutes] * 60 * 2} {
|
|
sct badtime [expr $badtime + $delta]
|
|
}
|
|
} else {
|
|
if {$badtime > $delta} {
|
|
sct badtime [expr $badtime - $delta]
|
|
} else {
|
|
sct badtime 0
|
|
}
|
|
}
|
|
hupdate [sct]/smooth $smooth
|
|
hdelprop [sct]/smooth geterror
|
|
return $smooth
|
|
}
|
|
|
|
proc ccu4ext::setmode {type state} {
|
|
if {[sctval [sct]] != $state} {
|
|
sct target $state
|
|
writeExt $type 0
|
|
}
|
|
}
|
|
|
|
proc ccu4ext::fillExt {type} {
|
|
if {$type eq "n2"} {
|
|
set valve [sctval /cc/nv]
|
|
set auto [sctval /cc/na]
|
|
} else {
|
|
set valve [sctval /cc/hv]
|
|
set auto [sctval /cc/ha]
|
|
if {[sctval /cc/hav] != 2} { # must be on 2=ext
|
|
hset /cc/hav 2
|
|
}
|
|
}
|
|
set errtxt ""
|
|
set now [DoubleTime]
|
|
set sm [expr $now > [silent 0 sct change_time] + 10]
|
|
switch -- $valve {
|
|
0 {
|
|
set txt "fill valve off"
|
|
if {$sm} {
|
|
if {$auto} {
|
|
setmode $type 0
|
|
} else {
|
|
setmode $type 2
|
|
}
|
|
}
|
|
}
|
|
1 {
|
|
set txt "filling"
|
|
if {$sm} {setmode $type 1}
|
|
}
|
|
2 {
|
|
set txt "no fill valve"
|
|
if {$sm} {setmode $type 2}
|
|
}
|
|
3 {
|
|
set errtxt timeout
|
|
}
|
|
4 {
|
|
set errtxt timeout1
|
|
}
|
|
default {
|
|
set errtxt "unknown error"
|
|
}
|
|
}
|
|
set rdpath [hvali [sct]/readpath]
|
|
set level [hvali $rdpath]
|
|
set levelerror [silent "" hgetpropval $rdpath geterror]
|
|
if {$levelerror ne "" && $errtxt eq "" && [hvali [sct]] < 2} {
|
|
set errtxt "$txt ($rdpath $levelerror)"
|
|
}
|
|
if {$errtxt eq ""} {
|
|
updateval [sct]/state $txt
|
|
hupdate [sct]/status ""
|
|
} else {
|
|
hupdate [sct]/status $errtxt
|
|
updateval [sct]/state $errtxt
|
|
}
|
|
if {[sctval [sct]] == 3} { # manualfill
|
|
changestate $type fill
|
|
return idle
|
|
}
|
|
set state [sctval [sct]]
|
|
set now [clock seconds]
|
|
set lowlevel [hvali [sct]/lowlevel]
|
|
if {$lowlevel < 0.0} {
|
|
hupdate [sct]/lowlevel 0.0
|
|
}
|
|
if {$lowlevel > 90.0} {
|
|
hupdate [sct]/lowlevel 90.0
|
|
}
|
|
set highlevel [hvali [sct]/highlevel]
|
|
if {$highlevel > 100.0} {
|
|
hupdate [sct]/highlevel 100.0
|
|
}
|
|
if {$highlevel < $lowlevel + 10.0} {
|
|
hupdate [sct]/highlevel [expr $lowlevel + 10.0]
|
|
}
|
|
switch -- $state {
|
|
-1 { # initializing
|
|
hupdate [sct]/status "automatic $type filling off"
|
|
hset [sct] 0
|
|
sct lasttime 0
|
|
changestate $type watch
|
|
return idle
|
|
}
|
|
0 { # watching
|
|
validated_level
|
|
set minspeed [expr - 100.0 / [hvali [sct]/minholdhours] / 3600.]
|
|
set maxspeed [expr - 100.0 / [hvali [sct]/maxholdhours] / 3600.]
|
|
set s [calcsmooth $level $minspeed $maxspeed]
|
|
if {$s < $lowlevel} {
|
|
if {[sct badtime] > [hvali [sct]/badreadingminutes] * 60} {
|
|
hupdate [sct]/status "automatic $type filling off - continuos bad reading"
|
|
hset [sct] 2
|
|
changestate $type off
|
|
return idle
|
|
}
|
|
# start fill
|
|
hset [sct] 1
|
|
clientput "$type level low ($level smooth $s) - start fill"
|
|
} else {
|
|
changestate $type stop
|
|
}
|
|
return idle
|
|
}
|
|
1 { # filling
|
|
if {[validated_level] eq ""} {
|
|
hset [sct] 2
|
|
changestate $type off
|
|
return idle
|
|
}
|
|
set vcmd [silent 0 sct vessel_cmd]
|
|
# check that vessel command works
|
|
if {$vcmd ne "0" && [catch {[result $vcmd]}]} {
|
|
clientput "WARNING: He vessel reading is configured, but not connected"
|
|
sct vessel_cmd 0
|
|
set vmd 0
|
|
}
|
|
set now [clock seconds]
|
|
set s [silent $level hval [sct]/smooth]
|
|
sct minlevel [silent 999 sct minlevel]
|
|
if {$s < [sct minlevel]} {
|
|
sct minlevel $s
|
|
}
|
|
set vessel 999
|
|
set maxspeed [expr 100.0 / [hvali [sct]/minfillminutes] / 60.]
|
|
if {[sct tubecooling] && $now < [sct startfill] + [hvali [sct]/tubecoolingminutes] * 60 && $s < [sct minlevel] + 5} {
|
|
# allow fill tube to get cold
|
|
set minspeed [expr - 100.0 / [hvali [sct]/maxfillminutes] / 60.]
|
|
} else {
|
|
if {[sct tubecooling]} {
|
|
sct tubecooling 0
|
|
if {$vcmd ne "0"} {
|
|
sct vstart_level [expr [result $vcmd]]
|
|
# start time - 2 minutes
|
|
sct vstart_time [expr $now - 120]
|
|
sct vlast_time $now
|
|
hupdate [sct]/vext [sct vstart_level]
|
|
}
|
|
}
|
|
set minspeed [expr + 100.0 / [hvali [sct]/maxfillminutes] / 60.]
|
|
if {$vcmd ne "0"} {
|
|
set dt [expr $now - [sct vlast_time]]
|
|
if {$dt > 0} {
|
|
set slope [expr ([hvali [sct]/vext] - [sct vstart_level])/([sct vlast_time] - [sct vstart_time])]
|
|
} else {
|
|
set slope 0
|
|
}
|
|
set vessel [result $vcmd]
|
|
set vext [expr [hvali [sct]/vext] + $slope * $dt]
|
|
if {$vext < $vessel} {
|
|
if {$vext < $vessel - 2.0} {
|
|
set errcnt [silent 0 sct errcnt]
|
|
incr errcnt
|
|
if {$errcnt > 3} {
|
|
hupdate [sct]/status "not enough progress on $type vessel - automatic ${type} filling off ($vext < $vessel - 2)"
|
|
hset [sct] 2
|
|
changestate $type off
|
|
return idle
|
|
}
|
|
sct errcnt $errcnt
|
|
} else {
|
|
set vessel $vext
|
|
}
|
|
}
|
|
hupdate [sct]/vext $vessel
|
|
sct vlast_time $now
|
|
}
|
|
}
|
|
if {$vessel < [silent 0 hvali [sct]/vessellimit]} {
|
|
hupdate [sct]/status "$type vessel empty - automatic ${type} filling off"
|
|
hset [sct] 2
|
|
changestate $type off
|
|
return idle
|
|
}
|
|
if {[calcsmooth $level $minspeed $maxspeed] <= $highlevel} {
|
|
# continue filling
|
|
changestate $type fill
|
|
return idle
|
|
}
|
|
clientput "$type level high - stop fill"
|
|
hset [sct] 0
|
|
changestate $type watch
|
|
return idle
|
|
}
|
|
2 {
|
|
set minspeed [expr - 100.0 / [hvali [sct]/minholdhours] / 3600.]
|
|
set maxspeed [expr + 100.0 / [hvali [sct]/minfillminutes] / 60.]
|
|
calcsmooth $level $minspeed $maxspeed
|
|
}
|
|
}
|
|
return idle
|
|
}
|
|
|
|
proc ccu4ext::validated_level {} {
|
|
set rdpath [hval [sct]/readpath]
|
|
if {[DoubleTime] < [silent 0 hgetpropval $rdpath read_time] + 30} {
|
|
return [hval $rdpath]
|
|
}
|
|
if {[silent "" hgetpropval $rdpath geterror] eq ""} {
|
|
clientlog "ERROR: no reading of $rdpath within 30 sec"
|
|
}
|
|
hsetprop $rdpath geterror not_available
|
|
return ""
|
|
}
|
|
|
|
proc ccu4ext::writeExt {type {activate 1}} {
|
|
sct update [sct target]
|
|
switch -- [sct target] {
|
|
# watching
|
|
0 {
|
|
set level [validated_level]
|
|
if {$level eq ""} {
|
|
changestate $type off
|
|
sct update 2
|
|
return idle
|
|
}
|
|
hupdate [sct]/smooth $level
|
|
catch {logsetup [sct]/vext clear}
|
|
hupdate [sct]/status ""
|
|
eval [silent "expr 0" sct slow_cmd]
|
|
if {$activate} {
|
|
changestate $type watch
|
|
}
|
|
return idle
|
|
}
|
|
# inactive
|
|
2 {
|
|
catch {logsetup [sct]/vext clear}
|
|
eval [silent "expr 0" sct slow_cmd]
|
|
if {[hvali [sct]/status] eq ""} {
|
|
hupdate [sct]/status "automatic ${type} filling off"
|
|
}
|
|
clientput "ERROR: [hvali [sct]/status]"
|
|
if {$activate} {
|
|
changestate $type off
|
|
}
|
|
return idle
|
|
}
|
|
# fill
|
|
1 {
|
|
set level [validated_level]
|
|
if {$level eq ""} {
|
|
changestate $type off
|
|
sct update 2
|
|
return idle
|
|
}
|
|
hupdate [sct]/smooth $level
|
|
hupdate [sct]/status ""
|
|
set vcmd [silent 0 sct vessel_cmd]
|
|
if {$vcmd ne "0"} {
|
|
set vlev [silent 60 result $vcmd]
|
|
if {$vlev == 60} {
|
|
clientput "WARNING: vessel level meter not connected - proceed without it"
|
|
sct vessel_cmd 0
|
|
} elseif {$vlev < [hvali [sct]/vessellimit] + 3.0} {
|
|
hupdate [sct]/status "vessel not full enough - automatic ${type} filling off"
|
|
clientput [hvali [sct]/status]
|
|
sct update 2
|
|
if {$activate} {
|
|
changestate $type off
|
|
}
|
|
return idle
|
|
}
|
|
}
|
|
sct minlevel 100
|
|
sct errcnt 0
|
|
sct startfill [clock seconds]
|
|
sct tubecooling 1
|
|
# eval [split [silent "expr 0" sct fast_cmd]]
|
|
eval [silent "expr 0" sct fast_cmd]
|
|
if {$activate} {
|
|
changestate $type fill
|
|
}
|
|
return idle
|
|
}
|
|
# manualfill
|
|
3 {
|
|
changestate $type fill
|
|
}
|
|
}
|
|
return idle
|
|
}
|