374 lines
9.3 KiB
Tcl
Executable File
374 lines
9.3 KiB
Tcl
Executable File
##
|
|
# @file Implements control for the Ordela high voltage power supply using the odrhvps protocol handler.
|
|
#
|
|
# This controller implements voltage ramping and always reads the current value before
|
|
# attempting to set the new voltage.
|
|
|
|
MakeSicsObj so_dhv1 SCT_OBJECT
|
|
|
|
namespace eval ::scobj::dethvps { }
|
|
|
|
|
|
##
|
|
# @brief Requests a value using the given command.
|
|
#
|
|
# @param nextSubState, Specifies the state which will handle the reply.
|
|
# @param cmd, The query command.
|
|
proc ::scobj::dethvps::rqValue {nextSubState cmd} {
|
|
set catch_status [ catch {
|
|
sct send $cmd
|
|
return $nextSubState
|
|
} msg ]
|
|
handle_exception $catch_status $msg
|
|
}
|
|
|
|
##
|
|
# @brief Processes replies from the voltage controller and controls the
|
|
# transition between the ramping superstates.
|
|
#
|
|
# @param vPath, Hdb node path for the voltage.
|
|
proc ::scobj::dethvps::rdValue {vPath} {
|
|
variable RAMPIDLE
|
|
variable RAMPSTOP
|
|
variable RAMPSTART
|
|
variable RAMPBUSY
|
|
variable MAXPOTVAL
|
|
variable RAMPINTEREST
|
|
|
|
set catch_status [ catch {
|
|
set data [sct result]
|
|
set currSuperState [sct ramping]
|
|
|
|
switch -glob -- $data {
|
|
"ASCERR:*" {
|
|
sct geterror $data
|
|
if {$currSuperState == $RAMPBUSY || $currSuperState == $RAMPSTART} {
|
|
broadcast "DHVERROR: $data, dhv1 stopped ramping detector voltage"
|
|
statemon stop dhv1
|
|
} else {
|
|
# broadcast "DHVERROR: $data"
|
|
}
|
|
if {$currSuperState != $RAMPIDLE} {
|
|
sct ramping $RAMPIDLE
|
|
}
|
|
return idle
|
|
}
|
|
default {
|
|
if {$data != [sct oldval]} {
|
|
sct geterror ""
|
|
sct oldval $data
|
|
sct update $data
|
|
set voltage [expr [sct max] * $data / double($MAXPOTVAL) ]
|
|
hset $vPath $voltage
|
|
if {$RAMPINTEREST} {
|
|
broadcast "dhv1 = $voltage"
|
|
}
|
|
sct utime readtime
|
|
}
|
|
}
|
|
}
|
|
switch $currSuperState [ subst {
|
|
$RAMPSTART {
|
|
sct ramping $RAMPBUSY
|
|
statemon start dhv1
|
|
return ramp
|
|
}
|
|
$RAMPBUSY {
|
|
return ramp
|
|
}
|
|
$RAMPSTOP {
|
|
sct ramping $RAMPIDLE
|
|
statemon stop dhv1
|
|
return idle
|
|
}
|
|
$RAMPIDLE {
|
|
return idle
|
|
}
|
|
default {
|
|
broadcast "DHVERROR: dhv1([info level 0]) sct ramping = [sct ramping], STOPPING"
|
|
sct ramping $RAMPIDLE
|
|
statemon stop dhv1
|
|
return idle
|
|
}
|
|
} ]
|
|
} msg ]
|
|
handle_exception $catch_status $msg
|
|
}
|
|
|
|
##
|
|
# @brief Checks the target voltage and sets the ramping superstate and ramp direction.
|
|
proc ::scobj::dethvps::setValue {nextSubState} {
|
|
variable RAMPIDLE
|
|
variable RAMPSTOP
|
|
variable RAMPSTART
|
|
variable RAMPBUSY
|
|
|
|
set catch_status [ catch {
|
|
set par [sct target]
|
|
set maxV [sct max]
|
|
if {$par < 0 || $par > $maxV} {
|
|
broadcast "DHVERROR: dhv1 target must be between 0 and $maxV"
|
|
sct seterror "DHVERROR: dhv1 target must be between 0 and $maxV"
|
|
return idle
|
|
}
|
|
set currSuperState [sct ramping]
|
|
set oldval [sct oldval]
|
|
if {$par == $oldval} {
|
|
if {$currSuperState == $RAMPBUSY || $currSuperState == $RAMPSTART} {
|
|
sct ramping $RAMPSTOP
|
|
}
|
|
return idle
|
|
}
|
|
if {$par < $oldval} {
|
|
sct rampstep -1
|
|
} else {
|
|
sct rampstep 1
|
|
}
|
|
if {$currSuperState != $RAMPBUSY && $currSuperState != $RAMPSTART} {
|
|
sct ramping $RAMPSTART
|
|
}
|
|
return $nextSubState
|
|
} msg ]
|
|
handle_exception $catch_status $msg
|
|
}
|
|
|
|
##
|
|
# @brief Checks that a command has been acknowledged
|
|
proc ::scobj::dethvps::getACK {} {
|
|
variable RAMPIDLE
|
|
variable RAMPSTOP
|
|
variable RAMPSTART
|
|
variable RAMPBUSY
|
|
|
|
set catch_status [ catch {
|
|
set currSuperState [sct ramping]
|
|
set data [sct result]
|
|
switch -glob $data {
|
|
"ASCERR:*" {
|
|
sct seterror $data
|
|
if {$currSuperState == $RAMPBUSY || $currSuperState == $RAMPSTART} {
|
|
broadcast "DHVERROR: $data, dhv1 stopped ramping detector voltage"
|
|
statemon stop dhv1
|
|
} else {
|
|
# broadcast "DHVERROR: $data"
|
|
}
|
|
if {$currSuperState != $RAMPSTOP} {
|
|
sct ramping $RAMPSTOP
|
|
}
|
|
return idle
|
|
}
|
|
ACK {
|
|
return idle
|
|
}
|
|
default {
|
|
return idle
|
|
}
|
|
}
|
|
} msg ]
|
|
handle_exception $catch_status $msg
|
|
}
|
|
|
|
##
|
|
# @brief Increments or decrements voltage until target has been reached
|
|
#
|
|
# @param cmd, The set voltage command
|
|
proc ::scobj::dethvps::ramping {cmd} {
|
|
variable RAMPIDLE
|
|
variable RAMPSTOP
|
|
variable RAMPSTART
|
|
variable RAMPBUSY
|
|
variable MINRAMPINTERVAL
|
|
|
|
set catch_status [ catch {
|
|
set rampstep [sct rampstep]
|
|
set target [sct target]
|
|
set oldval [sct oldval]
|
|
switch -- $rampstep {
|
|
1 {
|
|
if {$oldval >= $target} {
|
|
sct ramping $RAMPSTOP
|
|
return idle
|
|
}
|
|
}
|
|
-1 {
|
|
if {$oldval <= $target} {
|
|
sct ramping $RAMPSTOP
|
|
return idle
|
|
}
|
|
}
|
|
default {
|
|
sct ramping $RAMPSTOP
|
|
broadcast "DHVERROR: dhv1, Invalid ramp step: $rampstep STOPPING"
|
|
sct seterror "DHVERROR: dhv1, Invalid ramp step: $rampstep"
|
|
return idle
|
|
}
|
|
}
|
|
set target [expr [sct oldval] + [sct rampstep]]
|
|
sct send "$cmd $target"
|
|
return getACK
|
|
} msg ]
|
|
handle_exception $catch_status $msg
|
|
}
|
|
|
|
##
|
|
# @brief Command interface for voltage controller
|
|
proc ::scobj::dethvps::drvCmd {} {
|
|
variable RAMPIDLE
|
|
variable RAMPSTOP
|
|
variable RAMPSTART
|
|
variable RAMPBUSY
|
|
variable potValPath
|
|
|
|
set catch_status [ catch {
|
|
set cmd [sct target]
|
|
switch -- $cmd {
|
|
"halt" - "stop" {
|
|
hsetprop $potValPath ramping $RAMPSTOP
|
|
}
|
|
"up" {
|
|
hset $potValPath [sct upper]
|
|
}
|
|
"down" {
|
|
hset $potValPath [sct lower]
|
|
}
|
|
"off" {
|
|
hset $potValPath 0
|
|
}
|
|
default {
|
|
clientput "DHVERROR: Unknown command $cmd"
|
|
sct seterror "DHVERROR: Unknown command $cmd"
|
|
return idle
|
|
}
|
|
}
|
|
return idle
|
|
} msg ]
|
|
handle_exception $catch_status $msg
|
|
}
|
|
|
|
##
|
|
# @brief Implements the old command line interface for the dhv1 voltage controller.
|
|
proc ::scobj::dethvps::dhv1 {{CMD getVoltage} {val ""} } {
|
|
variable RAMPINTEREST
|
|
variable potValPath
|
|
variable voltagePath
|
|
variable cmdPath
|
|
|
|
set catch_status [ catch {
|
|
set qsObjPath ""
|
|
switch -- $CMD {
|
|
"list" {
|
|
clientput "dhv1.interval = [hgetpropval $potValPath interval]"
|
|
clientput "dhv1.upper = [hgetpropval $cmdPath upper]"
|
|
clientput "dhv1.lower = [hgetpropval $cmdPath lower]"
|
|
clientput "dhv1.max = [hgetpropval $potValPath max]"
|
|
return
|
|
}
|
|
"interval" {
|
|
return "dhv1.interval = [hgetpropval $potValPath interval]"
|
|
}
|
|
"max" {
|
|
set qsObjPath $potValPath
|
|
}
|
|
"upper" {
|
|
if {$val > 63.0} {
|
|
error "dhv1 upper must be no greater than 63"
|
|
}
|
|
set qsObjPath $cmdPath
|
|
}
|
|
"lower" {
|
|
if {$val > 63.0} {
|
|
error "dhv1 lower must be no greater than 63"
|
|
}
|
|
set qsObjPath $cmdPath
|
|
}
|
|
"getVoltage" {
|
|
return "[info level 0 ] = [hval $voltagePath]"
|
|
}
|
|
"interest" {
|
|
set RAMPINTEREST 1
|
|
statemon interest
|
|
}
|
|
"uninterest" {
|
|
set RAMPINTEREST 0
|
|
statemon uninterest
|
|
}
|
|
"reset" - "lock" - "unlock" - "debug" {
|
|
return
|
|
}
|
|
default {
|
|
hset $cmdPath $CMD
|
|
}
|
|
}
|
|
if {$qsObjPath != ""} {
|
|
if {$val != ""} {
|
|
if {[SplitReply [config myrights]] == 0} {
|
|
hsetprop $qsObjPath $CMD $val
|
|
} else {
|
|
error "DHVERROR: $CMD can only be initialised from a configuration file"
|
|
}
|
|
} else {
|
|
return "dhv1.$CMD = [hgetpropval $qsObjPath $CMD]"
|
|
}
|
|
}
|
|
} msg ]
|
|
handle_exception $catch_status $msg
|
|
}
|
|
|
|
namespace eval ::scobj::dethvps {
|
|
variable RAMPIDLE 0
|
|
variable RAMPSTOP 1
|
|
variable RAMPSTART 2
|
|
variable RAMPBUSY 3
|
|
variable MINRAMPINTERVAL 10
|
|
variable RAMPINTEREST 0
|
|
variable MAXPOTVAL 63.0
|
|
variable INITMAXVOLTAGE 2600.0
|
|
variable INITUPPERPOTVAL 57
|
|
variable INITLOWERPOTVAL 19
|
|
variable potValPath /sics/so_dhv1/potval
|
|
variable voltagePath /sics/so_dhv1/voltage
|
|
variable cmdPath /sics/so_dhv1/cmd
|
|
|
|
namespace export dhv1
|
|
|
|
hfactory $potValPath plain user int
|
|
hsetprop $potValPath read ::scobj::dethvps::rqValue rdValue "H"
|
|
hsetprop $potValPath rdValue ::scobj::dethvps::rdValue $voltagePath
|
|
hsetprop $potValPath write ::scobj::dethvps::setValue idle
|
|
hsetprop $potValPath getACK ::scobj::dethvps::getACK
|
|
hsetprop $potValPath ramp ::scobj::dethvps::ramping "h"
|
|
hsetprop $potValPath ramping $RAMPIDLE
|
|
hsetprop $potValPath rampstep 0
|
|
hsetprop $potValPath oldval -1
|
|
hsetprop $potValPath max $INITMAXVOLTAGE
|
|
hsetprop $potValPath interval -1
|
|
|
|
hfactory $voltagePath plain internal float
|
|
hset $voltagePath -1
|
|
|
|
hfactory $cmdPath plain user text
|
|
hsetprop $cmdPath write ::scobj::dethvps::drvCmd
|
|
hsetprop $cmdPath upper $INITUPPERPOTVAL
|
|
hsetprop $cmdPath lower $INITLOWERPOTVAL
|
|
|
|
}
|
|
|
|
proc ::scobj::dethvps::init {host ip rampinterval} {
|
|
variable potValPath
|
|
variable voltagePath
|
|
variable cmdPath
|
|
variable MINRAMPINTERVAL
|
|
|
|
if {[SplitReply [detector_simulation]] == "false"} {
|
|
makesctcontroller sct_dhv ordhvps $host:$ip
|
|
set MINRAMPINTERVAL $rampinterval
|
|
hsetprop $potValPath interval $rampinterval
|
|
sct_dhv poll $potValPath $rampinterval
|
|
sct_dhv write $potValPath
|
|
sct_dhv write $cmdPath
|
|
}
|
|
}
|
|
|
|
namespace import ::scobj::dethvps::dhv1
|
|
publish dhv1 user
|