remove quokka stuff
r3094 | jgn | 2011-04-08 12:15:13 +1000 (Fri, 08 Apr 2011) | 1 line
This commit is contained in:
committed by
Douglas Clowes
parent
665adbf4a6
commit
cf9a94abd3
@@ -1,4 +0,0 @@
|
||||
all:
|
||||
|
||||
|
||||
clean:
|
||||
@@ -1,418 +0,0 @@
|
||||
##
|
||||
# @file Spin flipper control for Quokka
|
||||
#
|
||||
# Author: Ferdi Franceschini (ffr@ansto.gov.au) May 2010
|
||||
#
|
||||
# The spin flipper can be installed with the following command,
|
||||
# ::scobj::rfgen::mkFlipper {
|
||||
# name "flipper"
|
||||
# address 1
|
||||
# opCurr 68
|
||||
# opFreq 241
|
||||
# IP localhost
|
||||
# PORT 65123
|
||||
# tuning 1
|
||||
# currtol 1
|
||||
# interval 2
|
||||
# }
|
||||
#
|
||||
# NOTE:
|
||||
# If tuning=1 this will generate flipper/set_current and flipper/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 spin flipper on or off
|
||||
proc ::scobj::rfgen::set_flip_on {basePath} {
|
||||
variable RAMPSTART
|
||||
variable RAMPTOZERO
|
||||
|
||||
set flipState [sct target]
|
||||
switch $flipState {
|
||||
"0" {
|
||||
hsetprop $basePath targetCurr 0
|
||||
hsetprop $basePath OutputState 0
|
||||
hsetprop $basePath ramping $RAMPSTART
|
||||
sct update 0
|
||||
sct utime readtime
|
||||
}
|
||||
"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 readtime
|
||||
}
|
||||
default {
|
||||
set ErrMsg "[sct] invalid input $flipState, 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 "spin-flipper" object 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 "spin-flipper" object 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
|
||||
}
|
||||
if {[string is integer $v]} {
|
||||
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 readtime
|
||||
sct oldStateRep $statList
|
||||
}
|
||||
if {$currSuperState != $FLIPOFF && $stateArr(curr) > [sct currTol] && $stateArr(O) && $stateArr(CV)} {
|
||||
broadcast "WARNING: spin flipper 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]
|
||||
|
||||
set targetCurr [sct targetCurr]
|
||||
set targetFreq [sct targetFreq]
|
||||
set output [sct OutputState]
|
||||
|
||||
if { [expr {abs($stateArr(curr) - [sct targetCurr])}] <= [sct currTol] } {
|
||||
set curr $stateArr(curr)
|
||||
} 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=$stateArr(K3):K2=$stateArr(K2):K1=$stateArr(K1):O=$output"]
|
||||
|
||||
return idle
|
||||
}
|
||||
|
||||
|
||||
##
|
||||
# @brief Make a spin flipper control object
|
||||
#
|
||||
# @param argList, {name "flipper" address "1" opCurr 68 opFreq 241 IP localhost PORT 65123 tuning 0 interval 1}
|
||||
#
|
||||
# name: name of spin flipper object
|
||||
# address: address assigned to RF generator 1-9
|
||||
# opCurr: the operating current, when you switch the spin flipper on it will ramp to this current
|
||||
# opFreq: the operating frequency, when you switch on the spin flipper 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::mkFlipper {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) 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)/set_flip_on plain user int
|
||||
hsetprop /sics/$pa(NAME)/set_flip_on write ::scobj::rfgen::set_flip_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"} {
|
||||
makesctcontroller sct_rfgen rfamp $pa(IP):$pa(PORT)
|
||||
mkStatArr stateArr [split [sct_rfgen transact "L:$pa(ADDRESS)"] "|="]
|
||||
|
||||
hset /sics/$pa(NAME)/flip_current [expr {$stateArr(curr) / 10.0}]
|
||||
hset /sics/$pa(NAME)/flip_frequency $stateArr(freq)
|
||||
hset /sics/$pa(NAME)/flip_voltage $stateArr(voltage)
|
||||
hset /sics/$pa(NAME)/flip_on $stateArr(O)
|
||||
hsetprop /sics/$pa(NAME) targetFreq $stateArr(freq)
|
||||
hsetprop /sics/$pa(NAME) targetCurr [expr {$stateArr(curr) / 10.0}]
|
||||
|
||||
sct_rfgen poll /sics/$pa(NAME) $pa(INTERVAL)
|
||||
sct_rfgen write /sics/$pa(NAME)/set_flip_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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
fileeval $cfPath(beamline)/sct_flipper.tcl
|
||||
|
||||
# NOTE: opCurr is 10 * your operating current, ie if the current is 7.1 then opCurr = 71
|
||||
::scobj::rfgen::mkFlipper {
|
||||
name "flipper"
|
||||
address 1
|
||||
opCurr 71
|
||||
opFreq 407
|
||||
IP 137.157.202.86
|
||||
PORT 4001
|
||||
tuning 1
|
||||
interval 2
|
||||
currtol 1
|
||||
compCurr 1
|
||||
guideCurr 1
|
||||
thickness 1
|
||||
}
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
##
|
||||
# @file Goniometer controller
|
||||
#
|
||||
# Author: Jing Chen (jgn@ansto.gov.au) June 2010
|
||||
#
|
||||
# The Goniometer controller can be installed with the following command,
|
||||
# ::scobj::goniometer::mkGoniometer {
|
||||
# name "goniometer"
|
||||
# IP localhost
|
||||
# PORT 62944
|
||||
# tuning 1
|
||||
# interval 1
|
||||
# }
|
||||
#
|
||||
# NOTE:
|
||||
# If tuning=1 this will generate gom/set_gom, gchi/set_gchi and gphi/set_gphi
|
||||
# nodes for the instrument scientists.
|
||||
# The tuning parameter should be set to 0 for the users.
|
||||
#
|
||||
|
||||
namespace eval ::scobj::goniometer {
|
||||
}
|
||||
|
||||
proc ::scobj::goniometer::set_gom {basePath} {
|
||||
set newGOM [sct target]
|
||||
hsetprop $basePath targetGom $newGOM
|
||||
return idle
|
||||
}
|
||||
|
||||
proc ::scobj::goniometer::set_gchi {basePath} {
|
||||
set newGCHI [sct target]
|
||||
hsetprop $basePath targetGchi $newGCHI
|
||||
return idle
|
||||
}
|
||||
|
||||
proc ::scobj::goniometer::set_gphi {basePath} {
|
||||
set newGPHI [sct target]
|
||||
hsetprop $basePath targetGphi $newGPHI
|
||||
return idle
|
||||
}
|
||||
|
||||
##
|
||||
# @brief Request a state report from the PLC controller by sending a get_prop command
|
||||
proc ::scobj::goniometer::rqStatFunc {} {
|
||||
set comm "<get><var>gom,gchi,gphi</var></get>\n"
|
||||
sct send $comm
|
||||
return rdState
|
||||
}
|
||||
|
||||
##
|
||||
# @brief Read and record the state report from the PLC server
|
||||
proc ::scobj::goniometer::rdStatFunc {basePath} {
|
||||
set replyStr [sct result]
|
||||
#broadcast $replyStr
|
||||
if {[string first "err" $replyStr] != -1} {
|
||||
broadcast "ERROR: cannot get the value to the PLC server, check again!"
|
||||
} else {
|
||||
set s1 [string map {<get> | <gom> gom: </gom> | <gchi> gchi: </gchi> | <gphi> gphi: </gphi> | </get> |} $replyStr]
|
||||
set s2 [string trim $s1 "|\n"]
|
||||
set s3 [split $s2 "|:"]
|
||||
|
||||
array set stateArr $s3
|
||||
|
||||
hset $basePath/gom $stateArr(gom)
|
||||
hset $basePath/gchi $stateArr(gchi)
|
||||
hset $basePath/gphi $stateArr(gphi)
|
||||
|
||||
hsetprop $basePath currGom $stateArr(gom)
|
||||
hsetprop $basePath currGchi $stateArr(gchi)
|
||||
hsetprop $basePath currGphi $stateArr(gphi)
|
||||
|
||||
#sct update $s3
|
||||
sct utime readtime
|
||||
}
|
||||
return idle
|
||||
}
|
||||
|
||||
##
|
||||
# @Check if any of gom/gchi/gphi has been changed by client
|
||||
proc ::scobj::goniometer::checkStatusFunc {basePath} {
|
||||
set targetGom [hgetpropval $basePath targetGom]
|
||||
set targetGchi [hgetpropval $basePath targetGchi]
|
||||
set targetGphi [hgetpropval $basePath targetGphi]
|
||||
|
||||
set currGom [hgetpropval $basePath currGom]
|
||||
set currGchi [hgetpropval $basePath currGchi]
|
||||
set currGphi [hgetpropval $basePath currGphi]
|
||||
|
||||
if {$targetGom != $currGom} {
|
||||
set comm "<set><var>gom</var><val>$targetGom</val></set>\n"
|
||||
} elseif {$targetGchi != $currGchi} {
|
||||
set comm "<set><var>gchi</var><val>$targetGchi</val></set>\n"
|
||||
} elseif {$targetGphi != $currGphi} {
|
||||
set comm "<set><var>gphi</var><val>$targetGphi</val></set>\n"
|
||||
} else {
|
||||
return idle
|
||||
}
|
||||
|
||||
sct send $comm
|
||||
return CheckReply
|
||||
}
|
||||
|
||||
proc ::scobj::goniometer::checkReplyFunc {} {
|
||||
set replyStr [sct result]
|
||||
broadcast $replyStr
|
||||
|
||||
if {[string first "<err>var</err>" $replyStr] != -1} {
|
||||
broadcast "ERROR: the varaible does not exist!"
|
||||
} elseif {[string first "<err>set</err>" $replyStr] != -1} {
|
||||
broadcast "ERROR: PLC cannot write new values for variable due to internal reason!"
|
||||
} else {
|
||||
sct utime readtime
|
||||
}
|
||||
|
||||
return idle
|
||||
}
|
||||
|
||||
##
|
||||
# @brief Make a Goniometer controller
|
||||
#
|
||||
# @param argList, {name "goniometer" IP localhost PORT 62944 tuning 1 interval 1}
|
||||
#
|
||||
# name: name of goniometer controller object
|
||||
# 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 axe positions
|
||||
# interval: polling and ramping interval in seconds.
|
||||
proc ::scobj::goniometer::mkGoniometer {argList} {
|
||||
# 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)/gom plain internal int
|
||||
hfactory /sics/$pa(NAME)/gchi plain internal int
|
||||
hfactory /sics/$pa(NAME)/gphi plain internal int
|
||||
|
||||
hfactory /sics/$pa(NAME)/set_gom plain user int
|
||||
hfactory /sics/$pa(NAME)/set_gchi plain user int
|
||||
hfactory /sics/$pa(NAME)/set_gphi plain user int
|
||||
|
||||
makesctcontroller sct_goniometer std $pa(IP):$pa(PORT)
|
||||
|
||||
hset /sics/$pa(NAME)/gom 0
|
||||
hset /sics/$pa(NAME)/gchi 0
|
||||
hset /sics/$pa(NAME)/gphi 0
|
||||
|
||||
hsetprop /sics/$pa(NAME) currGom 0
|
||||
hsetprop /sics/$pa(NAME) currGchi 0
|
||||
hsetprop /sics/$pa(NAME) currGphi 0
|
||||
|
||||
hsetprop /sics/$pa(NAME) targetGom 10
|
||||
hsetprop /sics/$pa(NAME) targetGchi 15
|
||||
hsetprop /sics/$pa(NAME) targetGphi 20
|
||||
|
||||
hsetprop /sics/$pa(NAME)/gom read ::scobj::goniometer::rqStatFunc
|
||||
hsetprop /sics/$pa(NAME)/gom rdState ::scobj::goniometer::rdStatFunc /sics/$pa(NAME)
|
||||
|
||||
hsetprop /sics/$pa(NAME)/gchi read ::scobj::goniometer::checkStatusFunc /sics/$pa(NAME)
|
||||
hsetprop /sics/$pa(NAME)/gchi CheckReply ::scobj::goniometer::checkReplyFunc
|
||||
|
||||
# Initialise properties required for generating the API for GumTree and to save data
|
||||
::scobj::hinitprops $pa(NAME) gom gchi gphi
|
||||
|
||||
sct_goniometer poll /sics/$pa(NAME)/gom $pa(INTERVAL)
|
||||
sct_goniometer poll /sics/$pa(NAME)/gchi $pa(INTERVAL)
|
||||
|
||||
if {$pa(TUNING)} {
|
||||
hsetprop /sics/$pa(NAME)/set_gom write ::scobj::goniometer::set_gom /sics/$pa(NAME)
|
||||
hsetprop /sics/$pa(NAME)/set_gchi write ::scobj::goniometer::set_gchi /sics/$pa(NAME)
|
||||
hsetprop /sics/$pa(NAME)/set_gphi write ::scobj::goniometer::set_gphi /sics/$pa(NAME)
|
||||
|
||||
sct_goniometer write /sics/$pa(NAME)/set_gom
|
||||
sct_goniometer write /sics/$pa(NAME)/set_gchi
|
||||
sct_goniometer write /sics/$pa(NAME)/set_gphi
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
fileeval $cfPath(goniometer)/sct_goniometer.tcl
|
||||
|
||||
::scobj::goniometer::mkGoniometer {
|
||||
name "goniometer"
|
||||
IP localhost
|
||||
PORT 62944
|
||||
tuning 1
|
||||
interval 3
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
mot_name=xxx
|
||||
mot_units=xxx
|
||||
mot_long_name=xxx
|
||||
#--------------- NXmonochromator
|
||||
nxcrystal_mot=/$(entryName),NXentry/$(inst),NXinstrument/$(monochromator),NXcrystal/SDS $(mot_name) -type NX_FLOAT32 -attr {units,$(mot_units)} -attr {long_name,$(mot_long_name)}
|
||||
#XXX add units command to configurable virtual motors.
|
||||
mth=/$(entryName),NXentry/$(inst),NXinstrument/$(monochromator),NXcrystal/SDS mth -type NX_FLOAT32 -attr {units,degree} -attr {long_name,mth}
|
||||
#--------------- NXsample
|
||||
nxsample_mot=/$(entryName),NXentry/sample,NXsample/SDS $(mot_name) -type NX_FLOAT32 -attr {units,$(mot_units)} -attr {long_name,$(mot_long_name)}
|
||||
#XXX add units command to configurable virtual motors.
|
||||
sth=/$(entryName),NXentry/sample,NXsample/SDS sth -type NX_FLOAT32 -attr {units,degree} -attr {long_name,sth}
|
||||
# Slit motors
|
||||
nxfilter_mot=/$(entryName),NXentry/slits,NXfilter/SDS $(mot_name) -type NX_FLOAT32 -attr {units,$(mot_units)} -attr {long_name,$(mot_long_name)}
|
||||
#XXX add units command to configurable virtual motors.
|
||||
ss1vg=/$(entryName),NXentry/slits,NXfilter/SDS ss1vg -type NX_FLOAT32 -attr {units,degree} -attr {long_name,ss1vg}
|
||||
ss1vo=/$(entryName),NXentry/slits,NXfilter/SDS ss1vo -type NX_FLOAT32 -attr {units,degree} -attr {long_name,ss1vo}
|
||||
ss1hg=/$(entryName),NXentry/slits,NXfilter/SDS ss1hg -type NX_FLOAT32 -attr {units,degree} -attr {long_name,ss1hg}
|
||||
ss1ho=/$(entryName),NXentry/slits,NXfilter/SDS ss1ho -type NX_FLOAT32 -attr {units,degree} -attr {long_name,ss1ho}
|
||||
ss2vg=/$(entryName),NXentry/slits,NXfilter/SDS ss2vg -type NX_FLOAT32 -attr {units,degree} -attr {long_name,ss2vg}
|
||||
ss2vo=/$(entryName),NXentry/slits,NXfilter/SDS ss2vo -type NX_FLOAT32 -attr {units,degree} -attr {long_name,ss2vo}
|
||||
ss2hg=/$(entryName),NXentry/slits,NXfilter/SDS ss2hg -type NX_FLOAT32 -attr {units,degree} -attr {long_name,ss2hg}
|
||||
ss2ho=/$(entryName),NXentry/slits,NXfilter/SDS ss2ho -type NX_FLOAT32 -attr {units,degree} -attr {long_name,ss2ho}
|
||||
@@ -1,156 +0,0 @@
|
||||
# TODO Make readonly getset macro for AttFactor
|
||||
|
||||
##
|
||||
# @file The velocity selector position is used as the reference for other instrument
|
||||
# component positions. For simplicity we set it as the origin x=y=z=0.
|
||||
|
||||
##
|
||||
# Note EndFacePosY and RotApPosY are surveyed positions
|
||||
foreach {var lname type priv units klass} {
|
||||
BeamCenterX BeamCenterX float user mm reduce
|
||||
BeamCenterZ BeamCenterZ float user mm reduce
|
||||
BeamStop BeamStop int user none parameter
|
||||
BSdiam BSdiam float user mm parameter
|
||||
DetPosYOffset DetPosYOffset float user mm parameter
|
||||
EApPosY EApPosY float user mm parameter
|
||||
EndFacePosY EndFacePosY float readonly mm parameter
|
||||
GuideConfig GuideConfig text user none parameter
|
||||
magnetic_field magnetic_field float user T sample
|
||||
RotApPosY RotApPosY float readonly mm @none
|
||||
SampleThickness SampleThickness float user mm sample
|
||||
SamYOffset SamYOffset float user mm parameter
|
||||
Transmission Transmission float user 1 parameter
|
||||
TransmissionFlag TransmissionFlag int user none sample
|
||||
} {
|
||||
::utility::mkVar $var $type $priv $lname true $klass true true
|
||||
if {$units != "none"} {
|
||||
sicslist setatt $var units $units
|
||||
}
|
||||
}
|
||||
sicslist setatt Transmission link data_set
|
||||
|
||||
proc sicsmsgfmt {args} {return "[info level -1] = $args"}
|
||||
|
||||
::utility::macro::getset float Plex {} {
|
||||
return [sicsmsgfmt [ ::optics::AttRotLookup [SplitReply [att]] "plex" [SplitReply [att precision]] ]]
|
||||
}
|
||||
sicslist setatt Plex units mm
|
||||
sicslist setatt Plex long_name Plex
|
||||
sicslist setatt Plex klass parameter
|
||||
|
||||
::utility::macro::getset float AttFactor {} {
|
||||
return [sicsmsgfmt [ ::optics::AttRotLookup [SplitReply [att]] "attfactor" [SplitReply [att precision]] ]]
|
||||
}
|
||||
sicslist setatt AttFactor long_name AttFactor
|
||||
sicslist setatt AttFactor klass parameter
|
||||
|
||||
::utility::macro::getset float EApX {} {
|
||||
return [sicsmsgfmt [::optics::EApLookUp [SplitReply [srce]] "size" [SplitReply [srce precision]] ]]
|
||||
}
|
||||
sicslist setatt EApX units mm
|
||||
sicslist setatt EApX long_name EApX
|
||||
sicslist setatt EApX klass parameter
|
||||
|
||||
::utility::macro::getset float EApZ {} {
|
||||
return [sicsmsgfmt [::optics::EApLookUp [SplitReply [srce]] "size" [SplitReply [srce precision]] ]]
|
||||
}
|
||||
sicslist setatt EApZ units mm
|
||||
sicslist setatt EApZ long_name EApZ
|
||||
sicslist setatt EApZ klass parameter
|
||||
|
||||
::utility::macro::getset text EApShape {} {
|
||||
return [sicsmsgfmt [::optics::EApLookUp [SplitReply [srce]] "shape" [SplitReply [srce precision]] ]]
|
||||
}
|
||||
sicslist setatt EApShape long_name EApShape
|
||||
sicslist setatt EApShape klass parameter
|
||||
sicslist setatt EApShape mutable false
|
||||
|
||||
::utility::macro::getset float L1 {} {
|
||||
set efpy [SplitReply [EndFacePosY]]
|
||||
set samposy [SplitReply [samy]]
|
||||
set eapy [SplitReply [EApPosY]]
|
||||
return [sicsmsgfmt [expr {$efpy + $samposy - $eapy}]]
|
||||
}
|
||||
sicslist setatt L1 long_name L1
|
||||
sicslist setatt L1 klass parameter
|
||||
sicslist setatt L1 units mm
|
||||
|
||||
::utility::macro::getset float L2 {} {
|
||||
set detpy [SplitReply [det]]
|
||||
set detpyos [SplitReply [DetPosYOffset]]
|
||||
set sapy [SplitReply [samy]]
|
||||
return [sicsmsgfmt [expr {$detpy + $detpyos - $sapy}]]
|
||||
}
|
||||
sicslist setatt L2 long_name L2
|
||||
sicslist setatt L2 klass parameter
|
||||
sicslist setatt L2 units mm
|
||||
|
||||
|
||||
################################################################################
|
||||
# INITIALISE PARAMETERS
|
||||
# The collimation system aperture positions
|
||||
# Reference position is outer wall of velocity selector bunker, ie EndFacePosY
|
||||
array set collapposmm {
|
||||
inputguide 633
|
||||
apwheel 675
|
||||
ap1 4929
|
||||
ap2 6934
|
||||
ap3 8949
|
||||
ap4 10955
|
||||
ap5 12943
|
||||
ap6 14970
|
||||
ap7 16971
|
||||
ap9 19925
|
||||
}
|
||||
|
||||
EndFacePosY 20095
|
||||
RotApPosY 675
|
||||
|
||||
################################################################################
|
||||
# Check Config
|
||||
namespace eval parameters {
|
||||
set paramlist {
|
||||
AttFactor
|
||||
BSdiam
|
||||
DetPosYOffset
|
||||
EApPosY
|
||||
EApShape
|
||||
EApX
|
||||
EApZ
|
||||
EndFacePosY
|
||||
L1
|
||||
L2
|
||||
Plex
|
||||
SamYOffset
|
||||
Transmission
|
||||
}
|
||||
}
|
||||
##
|
||||
# @brief List undefined parameters
|
||||
proc ::parameters::missingparams {} {
|
||||
variable paramlist
|
||||
set num 0
|
||||
foreach param $paramlist {
|
||||
if {[sicslist match $param] == " "} {
|
||||
clientput $param
|
||||
incr num
|
||||
}
|
||||
}
|
||||
if {$num > 0} {
|
||||
clientput "There are $num missing parameters"
|
||||
} else {
|
||||
clientput "OK"
|
||||
}
|
||||
}
|
||||
|
||||
##
|
||||
# @brief Check list
|
||||
proc check {args} {
|
||||
switch $args {
|
||||
"missing" {
|
||||
::parameters::missingparams
|
||||
}
|
||||
}
|
||||
}
|
||||
publish check user
|
||||
|
||||
@@ -1,616 +0,0 @@
|
||||
# TODO Check if requested tilt-angle is within range
|
||||
# TODO What should be reported for the wavelength if the tilt angle is 999.99
|
||||
##
|
||||
# @file
|
||||
# The velocity selector control is split into two objects,
|
||||
# 1. velsel_poller: This object polls the velocity selector to get its
|
||||
# current state. The first time that it gets valid state info it will
|
||||
# register the read and write parameters for the velocity_selector object
|
||||
# and create nvs_speed and nvs_lambda drivable adapters.
|
||||
# 2. velocity_selector: This object manages a set of status nodes which
|
||||
# correspond to the state parameters read by the velsel_poller object.
|
||||
# It also provides commands to set the speed, wavelength and angle for the velocity
|
||||
# selector and provides drivable interfaces for the speed and wavelength.
|
||||
#
|
||||
# You can drive the velocity selector speed via the driveable object called nvs_speed
|
||||
# You can drive the wavelength via the driveable object called nvs_lambda
|
||||
|
||||
# NOTE Doesn't provide the power loss command. Do we need it?
|
||||
|
||||
# Test by adding the following to barebones.tcl
|
||||
# InstallHdb
|
||||
# source config/velocity_selector/xsct_velsel.tcl
|
||||
# hfactory /velocity_selector link velocity_selector
|
||||
|
||||
# The velocity selector doesn't close client connections
|
||||
# if the connection is broken. It only closes the connection
|
||||
# when a client logs off with "#SES#bye", NOTE bye must be lowercase.
|
||||
|
||||
namespace eval ::scobj::velocity_selector {
|
||||
variable UID
|
||||
variable PWD
|
||||
variable sim_mode
|
||||
variable paramindex
|
||||
variable paramtype
|
||||
variable pollrate 7
|
||||
|
||||
#from NVSOptions.cpp nha
|
||||
# m_dTwistAngle degrees
|
||||
# m_dTwistAngle m
|
||||
# m_iMaxSpeed rpm
|
||||
variable m_dTwistAngle
|
||||
variable m_dLength
|
||||
variable m_iMaxSpeed
|
||||
variable rBeamCenter
|
||||
variable VNeutron
|
||||
variable blocked_speeds
|
||||
|
||||
set sim_mode [SplitReply [velsel_simulation]]
|
||||
|
||||
proc AngleSpeedToWavelength {angle VsVarSpeed} {
|
||||
variable m_dTwistAngle
|
||||
variable m_dLength
|
||||
variable m_iMaxSpeed
|
||||
variable rBeamCenter
|
||||
variable VNeutron
|
||||
|
||||
if {$VsVarSpeed < 3100} {
|
||||
return -code error "Minimum speed is 3100 rpm"
|
||||
}
|
||||
|
||||
set lambda0 [expr ($m_dTwistAngle*60.0*$VNeutron)/(360.0*$m_dLength*$m_iMaxSpeed)]
|
||||
set pi [expr acos(-1)]
|
||||
# set pi = 3.14159265358979;
|
||||
|
||||
set A [expr (2.0 * $rBeamCenter * $pi) / (60.0 * $VNeutron)]
|
||||
set angle_rad [expr ($angle * $pi) / 180.0]
|
||||
set lambda1 [expr ( tan($angle_rad)+($A * $m_iMaxSpeed * $lambda0) ) / ((-($A*$A) * $m_iMaxSpeed * $VsVarSpeed * $lambda0 * tan($angle_rad) )+($A * $VsVarSpeed))]
|
||||
|
||||
return [format "%#.5g" $lambda1]
|
||||
}
|
||||
|
||||
proc WavelengthToSpeed {angle lambda1} {
|
||||
variable m_dTwistAngle
|
||||
variable m_dLength
|
||||
variable m_iMaxSpeed
|
||||
variable rBeamCenter
|
||||
variable VNeutron
|
||||
|
||||
if {$lambda1 < 4.6125} {
|
||||
return -code error "Minimum wavelength is 4.6125 Angstrom"
|
||||
}
|
||||
|
||||
set lambda0 [expr ($m_dTwistAngle*60.0*$VNeutron)/(360.0*$m_dLength*$m_iMaxSpeed)]
|
||||
set pi [expr acos(-1)]
|
||||
# set pi = 3.14159265358979;
|
||||
|
||||
set A [expr (2.0 * $rBeamCenter * $pi) / (60.0 * $VNeutron)]
|
||||
set angle_rad [expr ($angle * $pi) / 180.0]
|
||||
set VsVarSpeed [expr ( tan($angle_rad)+($A * $m_iMaxSpeed * $lambda0) ) / ((-($A*$A) * $m_iMaxSpeed * $lambda1 * $lambda0 * tan($angle_rad) )+($A * $lambda1))]
|
||||
|
||||
return [expr round($VsVarSpeed)]
|
||||
}
|
||||
|
||||
|
||||
foreach {
|
||||
param index type units } {
|
||||
state 0 text @none
|
||||
rspeed 1 float rpm
|
||||
aspeed 2 float rpm
|
||||
sspeed 3 float Hz
|
||||
aveto 4 text @none
|
||||
ploss 5 float @none
|
||||
splos 6 float @none
|
||||
ttang 7 float degrees
|
||||
rtemp 8 float degrees
|
||||
wflow 9 float @none
|
||||
winlt 10 float @none
|
||||
woutt 11 float @none
|
||||
vacum 12 float @none
|
||||
wvalv 13 text @none
|
||||
vvalv 14 text @none
|
||||
vibrt 15 float @none
|
||||
bcuun 16 float @none
|
||||
} {
|
||||
set paramindex($param) $index
|
||||
set paramtype($param) $type
|
||||
set paramunits($param) $units
|
||||
}
|
||||
|
||||
MakeSICSObj velsel_poller SCT_OBJECT
|
||||
MakeSICSObj velocity_selector SCT_OBJECT
|
||||
sicslist setatt velocity_selector klass NXvelocity_selector
|
||||
sicslist setatt velocity_selector long_name velocity_selector
|
||||
|
||||
proc sendUID {user} {
|
||||
sct send $user
|
||||
return rdPwdChallenge
|
||||
}
|
||||
|
||||
proc rdPwdChallenge {} {
|
||||
set challenge [sct result]
|
||||
return sndPwd
|
||||
}
|
||||
proc sndPwd {pwd} {
|
||||
sct send $pwd
|
||||
return rdPwdAck
|
||||
}
|
||||
proc rdPwdAck {} {
|
||||
set ack [sct result]
|
||||
return idle
|
||||
}
|
||||
##
|
||||
# @brief Request a state report from the velocity selector
|
||||
proc getStatus {} {
|
||||
sct send "N#SOS#STATE "
|
||||
return rdState
|
||||
}
|
||||
|
||||
##
|
||||
# @brief Read the current state report from the velocity selector.
|
||||
proc rdState {root statuspath} {
|
||||
variable paramindex
|
||||
|
||||
set staterep [sct result]
|
||||
if {[string match {ASCERR:*} $staterep]} {
|
||||
hset $root/device_error $staterep
|
||||
return idle
|
||||
}
|
||||
if {[string match {*#SES#You are not a valid user*} $staterep]} {
|
||||
return sendUID
|
||||
}
|
||||
if {[string match {N#SOS#*} $staterep] == 0 } {
|
||||
hset $root/device_error $staterep
|
||||
return idle
|
||||
}
|
||||
set status [lrange [split $staterep "#"] 3 end-1]
|
||||
set rspeed [lindex $status $paramindex(rspeed) end]
|
||||
set aspeed [lindex $status $paramindex(aspeed) end]
|
||||
set speedvar [expr 0.2*$rspeed/100]
|
||||
if {[hval $root/status] == "busy"} {
|
||||
set target [hgetpropval $root/setspeed target]
|
||||
if {$rspeed != $target} {
|
||||
hset $root/device_error "Resending target speed $target"
|
||||
hset $root/setspeed $target"
|
||||
return idle
|
||||
}
|
||||
if {[expr abs($rspeed - $aspeed)] <= $speedvar} {
|
||||
hset $root/status "idle"
|
||||
statemon stop nvs_speed
|
||||
statemon stop nvs_lambda
|
||||
if [hgetpropval $root/setspeed driving] {
|
||||
hsetprop $root/setspeed driving 0
|
||||
hsetprop $root/setLambda driving 0
|
||||
}
|
||||
}
|
||||
}
|
||||
if {$staterep != [sct oldval]} {
|
||||
set state [lindex $status $paramindex(state) end]
|
||||
if {$state != [sct oldstate]} {
|
||||
if {[string match {*CONTROL*} $state] && [expr abs($rspeed - $aspeed)] > $speedvar} {
|
||||
# hset $root/status "busy"
|
||||
} elseif {[string match {*CONTROL*} $state]==0 && $aspeed == 0} {
|
||||
hset $root/status "idle"
|
||||
statemon stop nvs_speed
|
||||
statemon stop nvs_lambda
|
||||
if [hgetpropval $root/setspeed driving] {
|
||||
hsetprop $root/setspeed driving 0
|
||||
hsetprop $root/setLambda driving 0
|
||||
}
|
||||
}
|
||||
sct oldstate $state
|
||||
}
|
||||
if {[sct oldval] == "UNKNOWN"} {
|
||||
sct_velsel_init $root
|
||||
}
|
||||
sct oldval $staterep
|
||||
sct update $status
|
||||
sct utime readtime
|
||||
}
|
||||
if {[hval $root/device_error] != ""} {
|
||||
hset $root/device_error ""
|
||||
}
|
||||
return idle
|
||||
}
|
||||
|
||||
##
|
||||
# @brief This dummy read command forces a transition to a state which
|
||||
# will update a parameter from the current status.
|
||||
proc getpar {nextstate} {
|
||||
return $nextstate
|
||||
}
|
||||
|
||||
proc noResponse {} {
|
||||
sct result
|
||||
return idle
|
||||
}
|
||||
##
|
||||
# @brief Looks up a parameter in the current status and updates the
|
||||
# parameter node.
|
||||
# @param statuspath, path to the poller object's status node.
|
||||
# @param parindex, index of the required parameter
|
||||
proc updatepar {statuspath parindex} {
|
||||
set data [lindex [hval $statuspath] $parindex end]
|
||||
if {$data != [sct oldval]} {
|
||||
sct oldval $data
|
||||
sct update $data
|
||||
sct utime readtime
|
||||
}
|
||||
return idle
|
||||
}
|
||||
|
||||
proc setSpeed {vs_root statuspath nextState} {
|
||||
variable paramindex
|
||||
set speed [format "%5d" [sct target]]
|
||||
|
||||
sct send "N#SOS#SPEED $speed"
|
||||
set angle [lindex [hval $statuspath] $paramindex(ttang) end]
|
||||
set lambda [AngleSpeedToWavelength $angle $speed]
|
||||
sct target $speed
|
||||
hsetprop $vs_root/setLambda target $lambda
|
||||
hset $vs_root/status "busy"
|
||||
statemon start nvs_speed
|
||||
statemon start nvs_lambda
|
||||
if {[sct writestatus] == "start"} {
|
||||
# Called by drive adapter
|
||||
hsetprop $vs_root/setspeed driving 1
|
||||
hsetprop $vs_root/setLambda driving 1
|
||||
}
|
||||
return $nextState
|
||||
}
|
||||
|
||||
proc sendCommand {nextState} {
|
||||
set state [string tolower [sct target]]
|
||||
switch $state {
|
||||
"idle" {
|
||||
sct send "N#SOS#IDLE "
|
||||
}
|
||||
"brake" {
|
||||
sct send "N#SOS#BRAKE "
|
||||
}
|
||||
"init" {
|
||||
sct send "N#SOS#TTINIT"
|
||||
}
|
||||
default {
|
||||
return idle
|
||||
}
|
||||
}
|
||||
return $nextState
|
||||
}
|
||||
|
||||
|
||||
proc readLambda {statuspath} {
|
||||
variable paramindex
|
||||
|
||||
set angle [lindex [hval $statuspath] $paramindex(ttang) end]
|
||||
set aspeed [lindex [hval $statuspath] $paramindex(aspeed) end]
|
||||
if {$aspeed >= 800} {
|
||||
set lambda [AngleSpeedToWavelength $angle $aspeed]
|
||||
} else {
|
||||
set lambda 9999
|
||||
}
|
||||
if {$lambda != [sct oldval]} {
|
||||
sct oldval $lambda
|
||||
sct update $lambda
|
||||
sct utime readtime
|
||||
}
|
||||
return idle
|
||||
}
|
||||
|
||||
##
|
||||
# @brief This will check if turntable operation is allowed
|
||||
proc ttableCheck {statuspath nextState} {
|
||||
variable paramindex
|
||||
|
||||
set state [lindex [hval $statuspath] $paramindex(state) end]
|
||||
set aspeed [lindex [hval $statuspath] $paramindex(aspeed) end]
|
||||
if {[string match {*CONTROL*} $state] || $aspeed != 0} {
|
||||
error "Not allowed while the velocity selector is running"
|
||||
}
|
||||
return OK
|
||||
}
|
||||
|
||||
proc is_Speed_in_blocked_range {speed} {
|
||||
variable blocked_speeds
|
||||
foreach {min max} $blocked_speeds {
|
||||
if {$min <= $speed && $speed <= $max} {
|
||||
error "Speed of $speed rpm is within the blocked range of $min to $max rpm"
|
||||
}
|
||||
}
|
||||
return OK
|
||||
}
|
||||
proc get_nearest_allowed_speed {speed} {
|
||||
variable blocked_speeds
|
||||
set speed_ok true
|
||||
|
||||
foreach {min max} $blocked_speeds {
|
||||
if {$min <= $speed && $speed <= $max} {
|
||||
set speed_ok false
|
||||
break
|
||||
}
|
||||
}
|
||||
if {$speed_ok} {
|
||||
return $speed
|
||||
} else {
|
||||
foreach {min max} $blocked_speeds {
|
||||
if {$min <= $speed && $speed <= $max} {
|
||||
if {$min == -inf} {
|
||||
return [expr $max+10]
|
||||
}
|
||||
if {$max == inf} {
|
||||
return [expr $min-10]
|
||||
}
|
||||
if {[expr $max - $speed] > [expr $speed - $min]} {
|
||||
return [expr $min-10]
|
||||
} else {
|
||||
return [expr $max+10]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
##
|
||||
# @brief This will check if the requested speed is allowed
|
||||
proc checkBlockedSpeeds {statuspath} {
|
||||
variable paramindex
|
||||
|
||||
set speed [sct target]
|
||||
set ttang [lindex [hval $statuspath] $paramindex(ttang) end]
|
||||
if {$ttang > 90} {
|
||||
error "ERROR: You must first initialise the turntable"
|
||||
}
|
||||
|
||||
return [is_Speed_in_blocked_range $speed]
|
||||
}
|
||||
|
||||
##
|
||||
# @brief This will check if target wavelength is allowed
|
||||
proc checkBlockedWavelengths {statuspath} {
|
||||
variable paramindex
|
||||
|
||||
set lambda [sct target]
|
||||
set ttang [lindex [hval $statuspath] $paramindex(ttang) end]
|
||||
if {$ttang > 90} {
|
||||
error "ERROR: You must first initialise the turntable"
|
||||
}
|
||||
set angle [lindex [hval $statuspath] $paramindex(ttang) end]
|
||||
set speed [WavelengthToSpeed $angle $lambda]
|
||||
return [is_Speed_in_blocked_range $speed]
|
||||
}
|
||||
##
|
||||
# @brief Implement the checkstatus command for the drivable interface
|
||||
#
|
||||
# NOTE: The drive adapter initially sets the writestatus to "start" and will
|
||||
# only call this when writestatus!="start"
|
||||
# TODO Do we need to handle hardware faults or is the state check in rdstate enough?
|
||||
proc drivestatus {} {
|
||||
if [sct driving] {
|
||||
return busy
|
||||
} else {
|
||||
return idle
|
||||
}
|
||||
}
|
||||
|
||||
proc halt {root} {
|
||||
hsetprop $root/setspeed driving 0
|
||||
hsetprop $root/setLambda driving 0
|
||||
hset $root/status "idle"
|
||||
statemon stop nvs_speed
|
||||
statemon stop nvs_lambda
|
||||
set speed [get_nearest_allowed_speed [hval $root/aspeed]]
|
||||
broadcast halt: set speed to $speed
|
||||
catch {hset $root/setspeed $speed} msg
|
||||
broadcast $msg
|
||||
return idle
|
||||
}
|
||||
|
||||
proc setPar {par nextState} {
|
||||
set val [sct target]
|
||||
sct send "N#SOS#$par $val"
|
||||
return $nextState
|
||||
}
|
||||
|
||||
proc setLambda {vs_root statuspath nextState} {
|
||||
variable paramindex
|
||||
set lambda [sct target]
|
||||
|
||||
set angle [lindex [hval $statuspath] $paramindex(ttang) end]
|
||||
set speed [WavelengthToSpeed $angle $lambda]
|
||||
set fmtspeed [format "%5d" $speed]
|
||||
sct send "N#SOS#SPEED $fmtspeed"
|
||||
sct target $lambda
|
||||
hsetprop $vs_root/setspeed target $speed
|
||||
hset $vs_root/status "busy"
|
||||
statemon start nvs_speed
|
||||
statemon start nvs_lambda
|
||||
if {[sct writestatus] == "start"} {
|
||||
# Called by drive adapter
|
||||
hsetprop $vs_root/setLambda driving 1
|
||||
hsetprop $vs_root/setspeed driving 1
|
||||
}
|
||||
return $nextState
|
||||
}
|
||||
|
||||
# Create Velocity selector control
|
||||
set scobjNS ::scobj::velocity_selector
|
||||
set statusPath /sics/velsel_poller/status
|
||||
set velselPath /sics/velocity_selector
|
||||
|
||||
hfactory $statusPath plain internal text
|
||||
hsetprop $statusPath read ${scobjNS}::getStatus
|
||||
hsetprop $statusPath rdState ${scobjNS}::rdState $velselPath $statusPath
|
||||
hsetprop $statusPath sendUID ${scobjNS}::sendUID $UID
|
||||
hsetprop $statusPath rdPwdChallenge ${scobjNS}::rdPwdChallenge
|
||||
hsetprop $statusPath sndPwd ${scobjNS}::sndPwd $PWD
|
||||
hsetprop $statusPath rdPwdAck ${scobjNS}::rdPwdAck
|
||||
hsetprop $statusPath oldval "UNKNOWN"
|
||||
hsetprop $statusPath oldstate "UNKNOWN"
|
||||
|
||||
# Set identifier
|
||||
hfactory $velselPath/ID plain spy text
|
||||
hset $velselPath/ID $velsel_ID
|
||||
|
||||
# Abstract status info for GumTree
|
||||
hfactory $velselPath/status plain spy text
|
||||
hset $velselPath/status "UNKNOWN"
|
||||
hsetprop $velselPath/status values busy,idle
|
||||
hfactory $velselPath/device_error plain spy text
|
||||
hset $velselPath/device_error ""
|
||||
|
||||
# Must be set by user
|
||||
hfactory $velselPath/LambdaResFWHM_percent plain user float
|
||||
hfactory $velselPath/geometry plain spy none
|
||||
hfactory $velselPath/geometry/position plain spy none
|
||||
hfactory $velselPath/geometry/position/VelSelPosX plain user float
|
||||
hsetprop $velselPath/geometry/position/VelSelPosX units "mm"
|
||||
hfactory $velselPath/geometry/position/VelSelPosY plain user float
|
||||
hsetprop $velselPath/geometry/position/VelSelPosY units "mm"
|
||||
hfactory $velselPath/geometry/position/VelSelPosZ plain user float
|
||||
hsetprop $velselPath/geometry/position/VelSelPosZ units "mm"
|
||||
hfactory $velselPath/geometry/position/VelSelCoordScheme plain user text
|
||||
|
||||
# Setup nodes for state report parameters
|
||||
foreach par [lsort [array names paramindex]] {
|
||||
hfactory $velselPath/$par plain spy $paramtype($par)
|
||||
hsetprop $velselPath/$par read ${scobjNS}::getpar rdpar
|
||||
hsetprop $velselPath/$par rdpar ${scobjNS}::updatepar $statusPath $paramindex($par)
|
||||
hsetprop $velselPath/$par oldval "UNKNOWN"
|
||||
if {$paramunits($par) != "@none"} {
|
||||
hsetprop $velselPath/$par units $paramunits($par)
|
||||
}
|
||||
}
|
||||
# Initialise turntable command
|
||||
hfactory $velselPath/ttinit plain spy none
|
||||
hsetprop $velselPath/ttinit check ${scobjNS}::ttableCheck $statusPath ignore
|
||||
hsetprop $velselPath/ttinit write ${scobjNS}::sendCommand ignore
|
||||
hsetprop $velselPath/ttinit ignore ${scobjNS}::noResponse
|
||||
hsetprop $velselPath/ttinit values init
|
||||
|
||||
# Set tilt angle
|
||||
# TODO Can we set "check" to test if angle is within range then chain to ttableCheck
|
||||
hfactory $velselPath/set_ttang plain spy float
|
||||
hsetprop $velselPath/set_ttang check ${scobjNS}::ttableCheck $statusPath ignore
|
||||
hsetprop $velselPath/set_ttang write ${scobjNS}::setPar TTANGL ignore
|
||||
hsetprop $velselPath/set_ttang ignore ${scobjNS}::noResponse
|
||||
hsetprop $velselPath/set_ttang units "degrees"
|
||||
|
||||
|
||||
# Get Lambda
|
||||
hfactory $velselPath/Lambda plain spy float
|
||||
hsetprop $velselPath/Lambda read ${scobjNS}::getpar rdpar
|
||||
hsetprop $velselPath/Lambda rdpar ${scobjNS}::readLambda $statusPath
|
||||
hsetprop $velselPath/Lambda oldval "UNKNOWN"
|
||||
hsetprop $velselPath/Lambda units "Angstrom"
|
||||
hsetprop $velselPath/Lambda permlink data_set
|
||||
|
||||
# Set Lambda
|
||||
hfactory $velselPath/setLambda plain spy float
|
||||
hsetprop $velselPath/setLambda check ${scobjNS}::checkBlockedWavelengths $statusPath
|
||||
hsetprop $velselPath/setLambda write ${scobjNS}::setLambda $velselPath $statusPath ignore
|
||||
hsetprop $velselPath/setLambda ignore ${scobjNS}::noResponse
|
||||
hsetprop $velselPath/setLambda driving 0
|
||||
#TODO WARNING remove sicsdev and type if setLambda gets a drive addapter
|
||||
# hsetprop $velselPath/setLambda sicsdev "nvs_lambda"
|
||||
hsetprop $velselPath/setLambda type "drivable"
|
||||
hsetprop $velselPath/setLambda target 0
|
||||
hsetprop $velselPath/setLambda writestatus "UNKNOWN"
|
||||
hsetprop $velselPath/setLambda units "Angstrom"
|
||||
|
||||
# Set speed
|
||||
hfactory $velselPath/setspeed plain spy int
|
||||
hsetprop $velselPath/setspeed check ${scobjNS}::checkBlockedSpeeds $statusPath
|
||||
hsetprop $velselPath/setspeed write ${scobjNS}::setSpeed $velselPath $statusPath ignore
|
||||
hsetprop $velselPath/setspeed ignore ${scobjNS}::noResponse
|
||||
hsetprop $velselPath/setspeed driving 0
|
||||
hsetprop $velselPath/setspeed type "drivable"
|
||||
hsetprop $velselPath/setspeed target 0
|
||||
hsetprop $velselPath/setspeed writestatus "UNKNOWN"
|
||||
hsetprop $velselPath/setspeed units "rpm"
|
||||
|
||||
# Stop velocity selector (brake or idle)
|
||||
hfactory $velselPath/cmd plain spy text
|
||||
hsetprop $velselPath/cmd write ${scobjNS}::sendCommand ignore
|
||||
hsetprop $velselPath/cmd ignore ${scobjNS}::noResponse
|
||||
hsetprop $velselPath/cmd values brake,idle
|
||||
|
||||
#XXX ::scobj::hinitprops velocity_selector
|
||||
::scobj::set_required_props $velselPath
|
||||
hsetprop $velselPath klass NXvelocity_selector
|
||||
hsetprop $velselPath privilege spy
|
||||
hsetprop $velselPath type part
|
||||
hsetprop $velselPath control true
|
||||
hsetprop $velselPath data true
|
||||
hsetprop $velselPath/geometry klass NXgeometry
|
||||
hsetprop $velselPath/geometry privilege spy
|
||||
hsetprop $velselPath/geometry type instrument
|
||||
hsetprop $velselPath/geometry data true
|
||||
hsetprop $velselPath/geometry control true
|
||||
hsetprop $velselPath/geometry/position klass NXtranslation
|
||||
hsetprop $velselPath/geometry/position privilege spy
|
||||
hsetprop $velselPath/geometry/position type instrument
|
||||
hsetprop $velselPath/geometry/position data true
|
||||
hsetprop $velselPath/geometry/position control true
|
||||
foreach {
|
||||
hpath klass control data nxsave mutable priv alias
|
||||
} {
|
||||
Lambda parameter true true true true user velsel_lambdaa
|
||||
LambdaResFWHM_percent parameter true true true true spy velsel_lambdaresfwhm_percent
|
||||
rspeed parameter true true true true spy velsel_rspeed
|
||||
aspeed parameter true true true true user velsel_aspeed
|
||||
ttang parameter true true true true user velsel_ttang
|
||||
ttinit parameter true false false true user velsel_ttang
|
||||
geometry/position/VelSelPosX parameter true true true false user VelSelPosX
|
||||
geometry/position/VelSelPosY parameter true true true false user VelSelPosY
|
||||
geometry/position/VelSelPosZ parameter true true true false user VelSelPosZ
|
||||
geometry/position/VelSelCoordScheme parameter true true true false user VelSelCoordScheme
|
||||
} {
|
||||
hsetprop $velselPath/$hpath nxalias $alias
|
||||
hsetprop $velselPath/$hpath klass $klass
|
||||
hsetprop $velselPath/$hpath privilege $priv
|
||||
hsetprop $velselPath/$hpath control $control
|
||||
hsetprop $velselPath/$hpath data $data
|
||||
hsetprop $velselPath/$hpath nxsave $nxsave
|
||||
hsetprop $velselPath/$hpath mutable $mutable
|
||||
hsetprop $velselPath/$hpath sdsinfo ::nexus::scobj::sdsinfo
|
||||
}
|
||||
|
||||
hsetprop $velselPath/setspeed checklimits ${scobjNS}::checkBlockedSpeeds $statusPath
|
||||
hsetprop $velselPath/setspeed checkstatus ${scobjNS}::drivestatus
|
||||
hsetprop $velselPath/setspeed halt ${scobjNS}::halt $velselPath
|
||||
|
||||
hsetprop $velselPath/setLambda checklimits ${scobjNS}::checkBlockedWavelengths $statusPath
|
||||
hsetprop $velselPath/setLambda checkstatus ${scobjNS}::drivestatus
|
||||
hsetprop $velselPath/setLambda halt ${scobjNS}::halt $velselPath
|
||||
|
||||
##
|
||||
# @brief This is the position of the velocity selector bunker face. It is used
|
||||
# as the reference for other positions. x=y=z=0.
|
||||
hset $velselPath/geometry/position/VelSelPosX 0.0
|
||||
hset $velselPath/geometry/position/VelSelPosY 0.0
|
||||
hset $velselPath/geometry/position/VelSelPosZ 0.0
|
||||
hset $velselPath/geometry/position/VelSelCoordScheme "Cartesian"
|
||||
|
||||
|
||||
|
||||
proc sct_velsel_init {velselPath } {
|
||||
variable pollrate
|
||||
variable paramindex
|
||||
|
||||
foreach par [lsort [array names paramindex]] {
|
||||
sct_velsel poll $velselPath/$par $pollrate
|
||||
}
|
||||
sct_velsel write $velselPath/ttinit
|
||||
sct_velsel write $velselPath/set_ttang
|
||||
sct_velsel poll $velselPath/Lambda $pollrate
|
||||
sct_velsel write $velselPath/setLambda
|
||||
sct_velsel write $velselPath/setspeed
|
||||
sct_velsel write $velselPath/cmd
|
||||
ansto_makesctdrive nvs_speed $velselPath/setspeed $velselPath/aspeed sct_velsel
|
||||
ansto_makesctdrive nvs_lambda $velselPath/setLambda $velselPath/Lambda sct_velsel
|
||||
}
|
||||
if {$sim_mode == "false"} {
|
||||
makesctcontroller sct_velsel astvelsel $velsel_IP:$velsel_port "" 10
|
||||
sct_velsel poll $statusPath $pollrate
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
# Set currVelSel to select either the NVS40 or NVS43
|
||||
set currVelSel 43
|
||||
|
||||
namespace eval ::scobj::velocity_selector {
|
||||
variable blocked_speeds
|
||||
variable velsel_IP
|
||||
variable velsel_port
|
||||
|
||||
# Set configuration parameters for either the NVS40 or NVS43 velocity selector
|
||||
set ::currVelSel [string tolower $::currVelSel]
|
||||
switch $::currVelSel {
|
||||
40 {
|
||||
set velsel_ID "NVS40"
|
||||
set velsel_IP "137.157.202.73"
|
||||
set velsel_port 10000
|
||||
set m_dTwistAngle 48.30
|
||||
set m_dLength 0.250
|
||||
set m_iMaxSpeed 28300.0
|
||||
set rBeamCenter 0.1100
|
||||
set VNeutron 3955.98
|
||||
set ::scobj::velocity_selector::UID "NVS"
|
||||
set ::scobj::velocity_selector::PWD "NVS"
|
||||
set ::scobj::velocity_selector::blocked_speeds {
|
||||
-inf 3099
|
||||
3600 4999
|
||||
7800 10599
|
||||
28301 inf
|
||||
}
|
||||
}
|
||||
43 {
|
||||
# dc2-taipan.nbi.ansto.gov.au
|
||||
set velsel_ID "NVS43"
|
||||
set velsel_IP "137.157.202.74"
|
||||
set velsel_port 10000
|
||||
set m_dTwistAngle 37.6
|
||||
set m_dLength 0.250
|
||||
set m_iMaxSpeed 21000.0
|
||||
set rBeamCenter 0.1100
|
||||
set VNeutron 3955.98
|
||||
set ::scobj::velocity_selector::UID "NVS"
|
||||
set ::scobj::velocity_selector::PWD "NVS"
|
||||
set ::scobj::velocity_selector::blocked_speeds {
|
||||
-inf 3099
|
||||
3600 4999
|
||||
7800 9699
|
||||
21500 inf
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source $cfPath(velsel)/sct_velsel.tcl
|
||||
Reference in New Issue
Block a user