Set the current to the target value when we're within one step rather than within tolerance to avoid undershooting the target. Do not try and get the state when initialising the driver because it will fail to create the driver properly if the RF generator is unavailable on SICS startup. The current is zero when the RF gen is power cycled so it is safe to set the current reading and target current as zero in initialisation so we just set the operating frequency and everything else is left at zero. r3228 | ffr | 2011-06-26 12:18:27 +1000 (Sun, 26 Jun 2011) | 3 lines
432 lines
13 KiB
Tcl
432 lines
13 KiB
Tcl
##
|
|
# @file Mirrotron RF Generator control
|
|
#
|
|
# Author: Ferdi Franceschini (ffr@ansto.gov.au) May 2010
|
|
#
|
|
# The controller can be installed with the following command,
|
|
# ::scobj::rfgen::mkRFGen {
|
|
# name "anal"
|
|
# address 1
|
|
# opCurr 68
|
|
# opFreq 241
|
|
# IP localhost
|
|
# PORT 65123
|
|
# tuning 1
|
|
# currtol 1
|
|
# interval 2
|
|
# }
|
|
#
|
|
# NOTE:
|
|
# If tuning=1 this will generate xxx/set_current and xxx/set_frequency
|
|
# nodes for the instrument scientists.
|
|
# The tuning parameter should be set to 0 for the users.
|
|
#
|
|
# The operation_manual_Platypus_polarization_system.doc:Sec 3.1 states the following
|
|
# Attention
|
|
# a) Do not switch on the RF output with non-zero current setting (the current
|
|
# control becomes unstable)! If unsure, rotate the current setting
|
|
# potentiometer 10 turns counter-clockwise.
|
|
# b) In case of RF vacuum discharge (harmful for the system)
|
|
# " the main symptom is that the RF power source turns into CV mode, the
|
|
# voltage increases to 34 Vem and the current decreases;
|
|
# " switch off the RF output;
|
|
# " decrease current setting by rotating the potentiometer 10 turns counter-clockwise;
|
|
# " verify the vacuum level in the tank and restart the flipper operation only if it is below 0.01 mbar.
|
|
|
|
namespace eval ::scobj::rfgen {
|
|
# Control states
|
|
variable RAMPIDLE 0
|
|
variable RAMPSTOP 1
|
|
variable RAMPSTART 2
|
|
variable RAMPBUSY 3
|
|
variable RAMPTOZERO 4
|
|
variable FLIPOFF 5
|
|
variable MAXVOLTAGE 34
|
|
}
|
|
|
|
##
|
|
# @brief Utility for trimming zero padding from current and frequency readings.
|
|
# We do this to avoid misinterpreting numbers as octal
|
|
proc ::scobj::rfgen::mkStatArr {stateArrName stateReport} {
|
|
upvar $stateArrName stateArr
|
|
array set stateArr $stateReport
|
|
|
|
if {$stateArr(curr) != 0} {
|
|
set val [string trimleft $stateArr(curr) 0]
|
|
if {[string is integer $val]} {
|
|
set stateArr(curr) $val
|
|
} else {
|
|
set stateArr(curr) -1
|
|
}
|
|
}
|
|
if {$stateArr(freq) != 0} {
|
|
set val [string trimleft $stateArr(freq) 0]
|
|
if {[string is integer $val]} {
|
|
set stateArr(freq) $val
|
|
} else {
|
|
set stateArr(freq) -1
|
|
}
|
|
}
|
|
if {$stateArr(voltage) != 0} {
|
|
set val [string trimleft $stateArr(voltage) 0]
|
|
if {[string is integer $val]} {
|
|
set stateArr(voltage) $val
|
|
} else {
|
|
set stateArr(voltage) -1
|
|
}
|
|
}
|
|
}
|
|
|
|
##
|
|
# @brief Switch the generator on or off
|
|
proc ::scobj::rfgen::switch_on {basePath} {
|
|
variable RAMPSTART
|
|
variable RAMPTOZERO
|
|
|
|
set genState [sct target]
|
|
switch $genState {
|
|
"0" {
|
|
hsetprop $basePath targetCurr 0
|
|
hsetprop $basePath OutputState 0
|
|
hsetprop $basePath ramping $RAMPSTART
|
|
sct update 0
|
|
sct utime updatetime
|
|
}
|
|
"1" {
|
|
hsetprop $basePath targetCurr [hgetpropval $basePath opCurr]
|
|
hsetprop $basePath targetFreq [hgetpropval $basePath opFreq]
|
|
hsetprop $basePath OutputState 1
|
|
hsetprop $basePath ramping $RAMPSTART
|
|
sct update 1
|
|
sct utime updatetime
|
|
}
|
|
default {
|
|
set ErrMsg "[sct] invalid input $genState, Valid states for [sct] are 1 or 0"
|
|
sct seterror "ERROR: $ErrMsg"
|
|
return -code error $ErrMsg
|
|
}
|
|
}
|
|
return idle
|
|
}
|
|
|
|
##
|
|
# @brief Get the target current and scale it for the RF generator.
|
|
# Also updates the operating current for this session.
|
|
#
|
|
# @param basePath, The object base-path, this is where we keep our state variables.
|
|
proc ::scobj::rfgen::set_current {basePath} {
|
|
variable RAMPSTART
|
|
|
|
set newCurr [sct target]
|
|
|
|
set current [expr {round(10.0 * $newCurr)}]
|
|
hsetprop $basePath targetCurr $current
|
|
hsetprop $basePath opCurr $current
|
|
hsetprop $basePath ramping $RAMPSTART
|
|
hsetprop $basePath OutputState 1
|
|
return idle
|
|
}
|
|
|
|
##
|
|
# @brief Get the target frequency. Also updates the operating frequency for this session.
|
|
#
|
|
# @param basePath, The object base-path, this is where we keep our state variables.
|
|
proc ::scobj::rfgen::set_frequency {basePath} {
|
|
variable RAMPSTART
|
|
|
|
set newFreq [sct target]
|
|
|
|
hsetprop $basePath targetFreq $newFreq
|
|
hsetprop $basePath opFreq $newFreq
|
|
hsetprop $basePath ramping $RAMPSTART
|
|
hsetprop $basePath OutputState 1
|
|
return idle
|
|
}
|
|
|
|
##
|
|
# @brief Request a state report from the RF generator
|
|
proc ::scobj::rfgen::rqStatFunc {} {
|
|
sct send "L:[sct address]"
|
|
return rdState
|
|
}
|
|
|
|
##
|
|
# @brief Read and record the state report from the RF generator
|
|
proc ::scobj::rfgen::rdStatFunc {} {
|
|
variable RAMPBUSY
|
|
variable RAMPSTART
|
|
variable RAMPTOZERO
|
|
variable RAMPIDLE
|
|
variable FLIPOFF
|
|
variable MAXVOLTAGE
|
|
|
|
set basePath [sct]
|
|
|
|
set currSuperState [sct ramping]
|
|
set updateFlipper 0
|
|
set statStr [sct result]
|
|
if {[string match "ASCERR:*" $statStr]} {
|
|
sct geterror $statStr
|
|
sct ramping $RAMPIDLE
|
|
return stateChange
|
|
}
|
|
set statList [split $statStr "|="]
|
|
foreach {k v} $statList {
|
|
if {$k == "type"} {
|
|
lappend temp "$k $v"
|
|
continue
|
|
}
|
|
# trim leading zeroes to guard against interpreting as octal
|
|
if {[string is integer [string trimleft $v 0]]} {
|
|
lappend temp "$k $v"
|
|
} else {
|
|
lappend temp "$k -1"
|
|
}
|
|
}
|
|
set statList [join $temp]
|
|
mkStatArr stateArr $statList
|
|
|
|
if {$statList != [sct oldStateRep]} {
|
|
hset $basePath/flip_current [expr {$stateArr(curr) / 10.0}]
|
|
hset $basePath/flip_frequency $stateArr(freq)
|
|
hset $basePath/flip_voltage $stateArr(voltage)
|
|
hset $basePath/flip_on $stateArr(O)
|
|
hset $basePath/state_report $statList
|
|
sct update $statList
|
|
sct utime updatetime
|
|
sct oldStateRep $statList
|
|
}
|
|
if {$currSuperState != $FLIPOFF && $stateArr(curr) > [sct currTol] && $stateArr(O) && $stateArr(CV)} {
|
|
broadcast "WARNING: RF generator has switched to voltage control, voltage = $stateArr(voltage)"
|
|
if {$stateArr(voltage) >= $MAXVOLTAGE} {
|
|
sct ramping $FLIPOFF
|
|
}
|
|
}
|
|
|
|
return stateChange
|
|
}
|
|
|
|
##
|
|
# @brief State transition function
|
|
proc ::scobj::rfgen::stateFunc {} {
|
|
variable RAMPIDLE
|
|
variable RAMPSTOP
|
|
variable RAMPSTART
|
|
variable RAMPBUSY
|
|
variable RAMPTOZERO
|
|
variable FLIPOFF
|
|
variable MAXVOLTAGE
|
|
|
|
set basePath [sct]
|
|
|
|
set currSuperState [sct ramping]
|
|
mkStatArr stateArr [hval $basePath/state_report]
|
|
set currControlStatus [sct status]
|
|
|
|
|
|
switch $currSuperState [ subst -nocommands {
|
|
$RAMPSTART {
|
|
# broadcast RAMPSTART
|
|
if [string match $currControlStatus "IDLE"] {
|
|
statemon start flipper
|
|
sct status "BUSY"
|
|
sct ramping $RAMPBUSY
|
|
return ramp
|
|
} else {
|
|
# Flipper is off, set current to zero before switching on
|
|
sct origTargetCurr [sct targetCurr]
|
|
sct targetCurr 0
|
|
sct OutputState 0
|
|
sct ramping $RAMPTOZERO
|
|
return ramp
|
|
}
|
|
}
|
|
$RAMPTOZERO {
|
|
# broadcast RAMPTOZERO
|
|
if {$stateArr(curr) <= [sct currTol]} {
|
|
# We've reached a safe state so switch on and ramp to target current
|
|
sct targetCurr [sct origTargetCurr]
|
|
sct OutputState 1
|
|
sct ramping $RAMPBUSY
|
|
} else {
|
|
sct targetCurr 0
|
|
sct OutputState 0
|
|
}
|
|
return ramp
|
|
}
|
|
$RAMPBUSY {
|
|
# broadcast RAMPBUSY
|
|
if { [expr {abs($stateArr(curr) - [sct targetCurr])}] <= [sct currTol] } {
|
|
sct ramping $RAMPSTOP
|
|
return idle
|
|
}
|
|
return ramp
|
|
}
|
|
$FLIPOFF {
|
|
sct targetCurr 0
|
|
sct OutputState 0
|
|
if { $stateArr(curr) <= [sct currTol] } {
|
|
sct ramping $RAMPSTOP
|
|
broadcast "ERROR: Spin flipper switched off voltage exceeds $MAXVOLTAGE in voltage control state, check vacuum"
|
|
return idle
|
|
} else {
|
|
return ramp
|
|
}
|
|
}
|
|
$RAMPSTOP {
|
|
# broadcast RAMPSTOP
|
|
if [string match $currControlStatus "BUSY"] {
|
|
statemon stop flipper
|
|
sct status "IDLE"
|
|
}
|
|
sct ramping $RAMPIDLE
|
|
return idle
|
|
}
|
|
$RAMPIDLE {
|
|
# broadcast RAMPIDLE
|
|
return idle
|
|
}
|
|
}]
|
|
}
|
|
|
|
##
|
|
# @brief Ramps the current up or down in steps of 0.5A and/or sets the frequency
|
|
proc ::scobj::rfgen::rampFunc {} {
|
|
set basePath [sct]
|
|
set currSuperState [sct ramping]
|
|
mkStatArr stateArr [hval $basePath/state_report]
|
|
if {$stateArr(curr) == -1} {
|
|
# Got invalid current reading try again
|
|
return idle
|
|
}
|
|
|
|
set targetCurr [sct targetCurr]
|
|
set SCT_RFGEN [sct contname]
|
|
set K1 [sct K1]
|
|
set K2 [sct K2]
|
|
set K3 [sct K3]
|
|
set targetFreq [sct targetFreq]
|
|
set output [sct OutputState]
|
|
if { [expr {abs($stateArr(curr) - $targetCurr)}] <= 5 } {
|
|
set curr $targetCurr
|
|
} elseif {$targetCurr < $stateArr(curr)} {
|
|
set curr [expr $stateArr(curr)-5]
|
|
if {$curr < $targetCurr} {
|
|
set curr $targetCurr
|
|
}
|
|
} elseif {$targetCurr > $stateArr(curr)} {
|
|
set curr [expr $stateArr(curr)+5]
|
|
if {$curr > $targetCurr} {
|
|
set curr $targetCurr
|
|
}
|
|
}
|
|
set reply [$SCT_RFGEN send "S:[sct address]:I=$curr:F=$targetFreq:K3=$K3:K2=$K2:K1=$K1:O=$output"]
|
|
|
|
return idle
|
|
}
|
|
|
|
|
|
##
|
|
# @brief Make an RF generator control object
|
|
#
|
|
# @param argList, {name "analyser" address "1" opCurr 68 opFreq 241 IP localhost PORT 65123 tuning 0 interval 1}
|
|
#
|
|
# name: name of RF generator object
|
|
# address: address assigned to RF generator 1-9
|
|
# opCurr: the operating current, when you switch it on it will ramp to this current
|
|
# opFreq: the operating frequency, when you switch it on it will set this frequency
|
|
# IP: IP address of RF generator moxa box
|
|
# PORT: Port number assigned to the generator on the moxa-box
|
|
# tuning: boolean, set tuning=1 to allow instrument scientists to set the current and frequency
|
|
# interval: polling and ramping interval in seconds. One sets the ramp rate to 0.5A/s
|
|
proc ::scobj::rfgen::mkRFGen {argList} {
|
|
variable RAMPIDLE
|
|
|
|
# Generate parameter array from the argument list
|
|
foreach {k v} $argList {
|
|
set KEY [string toupper $k]
|
|
set pa($KEY) $v
|
|
}
|
|
|
|
MakeSICSObj $pa(NAME) SCT_OBJECT
|
|
sicslist setatt $pa(NAME) klass instrument
|
|
sicslist setatt $pa(NAME) long_name $pa(NAME)
|
|
|
|
# hfactory /sics/$pa(NAME)/status plain spy text
|
|
hsetprop /sics/$pa(NAME) status "IDLE"
|
|
hfactory /sics/$pa(NAME)/state_report plain internal text
|
|
hfactory /sics/$pa(NAME)/flip_current plain internal float
|
|
hfactory /sics/$pa(NAME)/flip_frequency plain internal int
|
|
hfactory /sics/$pa(NAME)/flip_voltage plain internal int
|
|
hfactory /sics/$pa(NAME)/flip_on plain internal int
|
|
|
|
hsetprop /sics/$pa(NAME) read ::scobj::rfgen::rqStatFunc
|
|
hsetprop /sics/$pa(NAME) rdState ::scobj::rfgen::rdStatFunc
|
|
hsetprop /sics/$pa(NAME) stateChange ::scobj::rfgen::stateFunc
|
|
hsetprop /sics/$pa(NAME) ramp ::scobj::rfgen::rampFunc
|
|
|
|
hsetprop /sics/$pa(NAME) address $pa(ADDRESS)
|
|
hsetprop /sics/$pa(NAME) tuning $pa(TUNING)
|
|
hsetprop /sics/$pa(NAME) ramping $RAMPIDLE
|
|
hsetprop /sics/$pa(NAME) opCurr $pa(OPCURR)
|
|
hsetprop /sics/$pa(NAME) opFreq $pa(OPFREQ)
|
|
hsetprop /sics/$pa(NAME) targetCurr 0
|
|
hsetprop /sics/$pa(NAME) origTargetCurr 0
|
|
hsetprop /sics/$pa(NAME) oldStateRep ""
|
|
|
|
hsetprop /sics/$pa(NAME) K1 $pa(K1)
|
|
hsetprop /sics/$pa(NAME) K2 $pa(K2)
|
|
hsetprop /sics/$pa(NAME) K3 $pa(K3)
|
|
hsetprop /sics/$pa(NAME) currTol $pa(CURRTOL)
|
|
|
|
hfactory /sics/$pa(NAME)/comp_current plain internal float
|
|
hsetprop /sics/$pa(NAME)/comp_current units "A"
|
|
hset /sics/$pa(NAME)/comp_current $pa(COMPCURR)
|
|
hfactory /sics/$pa(NAME)/guide_current plain internal float
|
|
hsetprop /sics/$pa(NAME)/guide_current units "A"
|
|
hset /sics/$pa(NAME)/guide_current $pa(GUIDECURR)
|
|
hfactory /sics/$pa(NAME)/thickness plain internal float
|
|
hsetprop /sics/$pa(NAME)/thickness units "mm"
|
|
hset /sics/$pa(NAME)/thickness $pa(THICKNESS)
|
|
|
|
hfactory /sics/$pa(NAME)/switch_on plain user int
|
|
hsetprop /sics/$pa(NAME)/switch_on write ::scobj::rfgen::switch_on /sics/$pa(NAME)
|
|
# Only create the set current and frequency nodes when commissioning
|
|
|
|
# Initialise properties required for generating the API for GumTree and to save data
|
|
::scobj::hinitprops $pa(NAME) flip_current flip_frequency flip_voltage flip_on comp_current guide_current thickness
|
|
hsetprop /sics/$pa(NAME)/comp_current mutable false
|
|
hsetprop /sics/$pa(NAME)/guide_current mutable false
|
|
hsetprop /sics/$pa(NAME)/thickness mutable false
|
|
|
|
if {[SplitReply [rfgen_simulation]] == "false"} {
|
|
set SCT_RFGEN sct_rfgen_$pa(NAME)
|
|
makesctcontroller $SCT_RFGEN rfamp $pa(IP):$pa(PORT)
|
|
hsetprop /sics/$pa(NAME) contname $SCT_RFGEN
|
|
# mkStatArr stateArr [split [$SCT_RFGEN transact "L:$pa(ADDRESS)"] "|="]
|
|
|
|
hset /sics/$pa(NAME)/flip_current 0
|
|
hset /sics/$pa(NAME)/flip_frequency $pa(OPFREQ)
|
|
hset /sics/$pa(NAME)/flip_voltage 0
|
|
hset /sics/$pa(NAME)/flip_on 0
|
|
hsetprop /sics/$pa(NAME) targetFreq $pa(OPFREQ)
|
|
hsetprop /sics/$pa(NAME) targetCurr 0
|
|
|
|
$SCT_RFGEN poll /sics/$pa(NAME) $pa(INTERVAL)
|
|
$SCT_RFGEN write /sics/$pa(NAME)/switch_on
|
|
}
|
|
|
|
if {$pa(TUNING)} {
|
|
hfactory /sics/$pa(NAME)/set_current plain user float
|
|
hfactory /sics/$pa(NAME)/set_frequency plain user int
|
|
|
|
hsetprop /sics/$pa(NAME)/set_current write ::scobj::rfgen::set_current /sics/$pa(NAME)
|
|
hsetprop /sics/$pa(NAME)/set_frequency write ::scobj::rfgen::set_frequency /sics/$pa(NAME)
|
|
|
|
if {[SplitReply [rfgen_simulation]] == "false"} {
|
|
$SCT_RFGEN write /sics/$pa(NAME)/set_current
|
|
$SCT_RFGEN write /sics/$pa(NAME)/set_frequency
|
|
}
|
|
}
|
|
}
|