## # @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