#!/bin/sh
# \
exec oagwish "$0" "$@"

#
# $Log: not supported by cvs2svn $
# Revision 1.8  2000/06/25 22:03:03  borland
# Now waits 2 seconds before checking supply readback afte ramping.
#
# Revision 1.7  2000/06/25 21:58:15  borland
# Fixed bug: was always starting the ramp at 0 for some cases.
#
# Revision 1.6  2000/06/22 16:14:28  borland
# Now checks to see if the power supply is on before doing anything.
# Also, checks the power supply output after ramping.
#
# Revision 1.5  2000/05/11 18:40:45  borland
# Now use APScaRamp to ramp magnet around.  Faster and more reliable than
# IOC standardization.
#
# Revision 1.4  2000/05/02 21:25:32  borland
# Now use APSLinkToLINACPVs since it is faster.
#
# Revision 1.3  2000/05/01 22:00:29  borland
# Added button to compute and report current for desired momentum.
#
# Revision 1.2  2000/04/25 20:07:03  borland
# Improved version.
#
# Revision 1.1  2000/04/25 19:44:41  borland
# First version.
#
#

set auto_path [linsert $auto_path 0  /usr/local/oag/apps/lib/$env(HOST_ARCH)]
set auto_path [linsert $auto_path 0  /usr/local/oag/lib_patch/$env(HOST_ARCH)]
APSDebugPath
set CVSRevisionAuthor "\$Author: borland $"

APSApplication . -name ManageLinacAnalyzingMagnet \
  -overview "Manages one or more linac analyzing magnets, allowing measurement of beam momentum while staying on the excitation curve.  Also degausses the magnets."
set status Ready.
APSScrolledStatus .status -parent .userFrame -textVariable status -width 60

proc setStatus {text} {
    APSSetVarAndUpdate status $text
}

set apsLinacPSDeviceFile /home/helios/oagData/deviceConfig/linac/PSOps.pvTable
APSLinkToLINACPVs

set apsLinacMagnetsDir /home/helios/oagData/linac/magnets/

# returns excitation filename] and bend angle

proc GetAnalyzingMagnetInfo {args} {
    global apsLinacMagnetsDir
    set magnet L3:AM1
    set setVars 0
    APSStrictParseArguments {magnet setVars}

    switch $magnet {
        L3:AM1 {
            set angle [expr 13.409/180.0*4*atan(1)]
        }
        L5:AM1 {
            set angle [expr 13.7/180*4*atan(1)]
        }
    }
    set excitationFile $apsLinacMagnetsDir/$magnet.excitation
    if ![file exists $excitationFile] {
        return -code error "GetAnalyzingMagnetInfo: Not found: $excitationFile"
    }
    if $setVars {
        uplevel set excitationFile $excitationFile
        uplevel set angle $angle
    }
    return [list $excitationFile $angle]
}
    
proc DetermineMomentumReadback {args} {
    global apsLinacMagnetsDir
    set magnet L3:AM1
    APSStrictParseArguments {magnet}

    if [catch {GetAnalyzingMagnetInfo -magnet $magnet -setVars 1} result] {
        return -code error "$result"
    }

    if [catch {APSDevSend -releaseLinks 1  -timeout 30 \
                 -group LinacPS -deviceList $magnet -operation SetCurrent -forceRead 1} current] {
        return -code error "DetermineMomentumReadback: $current"
    }
    setStatus "$magnet current setpoint is $current A"

    if [catch {exec sddsinterp -atValue=$current -column=Current,IntegratedStrength $excitationFile /dev/null -print=bare,stdout} BL] {
        return -code error "DetermineMomentumReadback: $BL"
    }
    set BL [lindex [split [string trim $BL] " "] end]
    return [expr $BL/$angle*299.792458]
}

proc ChangeMomentum {args} {
    set magnet L3:AM1
    set momentum 0
    set reportOnly 0
    APSStrictParseArguments {magnet momentum reportOnly}

    if $momentum<=0 {
        return -code error "ChangeMomentum: momentum zero or negative"
    }
    if [catch {GetAnalyzingMagnetInfo -magnet $magnet -setVars 1} result] {
        return -code error "ChangeMomentum: $result"
    }
    set BL [expr $momentum/299.792458*$angle]
    if [catch {exec sddsinterp -atValue=$BL -column=IntegratedStrength,Current \
                 $excitationFile /dev/null -print=bare,stdout} current] {
        return -code error "ChangeMomentum: $current"
    }
    set current [lindex $current 1]
    setStatus "Current should be $current for $momentum MeV/C"
    if $reportOnly return

    return [RampToNewCurrent -current $current -magnet $magnet]
}

proc RampToNewCurrent {args} {
    set current 0
    set magnet L3:AM1
    APSStrictParseArguments {current magnet}

    if [catch {APSDevSend -releaseLinks 1 -timeout 30 \
                 -group LinacPS -deviceList $magnet -operation SetCurrent \
                 -forceRead 1} presentCurrent] {
        return -code error "ChangeMomentum: $presentCurrent"
    }
    if [expr abs($current-$presentCurrent)<1e-6] {
        setStatus "Done."
        return
    }
    if [catch {APSDevSend -releaseLinks 1 -timeout 30 -group LinacPS -deviceList $magnet \
                 -operation QueryOn} isOn] {
        return -code error "ChangeMomentum: $presentCurrent"
    }
    if !$isOn {
        return -code error "ChangeMomentum: $magnet isn't turned on."
    }
    if [catch {APSDevSend -releaseLinks 1  -timeout 30 \
                 -group LinacPS -deviceList $magnet -operation QueryConditioning} result] {
        return -code error "ChangeMomentum: $result"
    }
    if $result {
        return -code error "ChangeMomentum: $magnet is presently conditioning"
    }
    if [catch {APSDevSend -releaseLinks 1  -timeout 30 \
                 -group LinacPS -deviceList $magnet -operation ReadConditioningUpperLimit} upperLimit] {
        return -code error "ChangeMomentum: $result"
    }
    global globalCurrent
    set globalCurrent 0
    if $current>$upperLimit {
        return -code error "Can't go to $current---beyond upper limit"
    }
    if $presentCurrent>$current {
        # ramp up to max, then to zero, then to value  
        set steps [expr int(($upperLimit-$presentCurrent)/3.0)+2]
        setStatus "Ramping to $upperLimit..."
        APScaRamp -pvList $magnet:CurrentAO -variableList globalCurrent \
          -steps $steps -beginList $presentCurrent -endList $upperLimit -pause 1.0
        set steps [expr int($upperLimit/3.0)+2]
        setStatus "Ramping to 0..."
        APScaRamp -pvList $magnet:CurrentAO -variableList globalCurrent \
          -steps $steps -beginList $upperLimit -endList 0.0 -pause 1.0
        if [expr abs($current)>1e-6] {
            set steps [expr int($current/3.0)+2]
            setStatus "Ramping to $current..."
            APScaRamp -pvList $magnet:CurrentAO -variableList globalCurrent \
              -steps $steps -beginList 0.0 -endList $current -pause 1.0
        }
    } else {
        # ramp to value 
        set steps [expr int(($current-$presentCurrent)/3.0)+2]
        setStatus "Ramping to $current..."
        APScaRamp -pvList $magnet:CurrentAO -variableList globalCurrent \
          -steps $steps -beginList $presentCurrent -endList $current -pause 1.0
    }

    APSWaitWithUpdate -waitSeconds 2 -updateInterval 1
    if [catch {APSDevSend -releaseLinks 1 -timeout 30 -group LinacPS \
                 -deviceList $magnet -operation ReadCurrent} actualCurrent] {
        return -code error "Problem reading current for $magnet: $actualCurrent"
    }
    set delta [expr abs($current-$actualCurrent)]
    if $delta>1 {
        return -code error "Power supply output is $actualCurrent but setpoint is $current"
    } elseif $delta>0.1 {
        setStatus "Warning: power supply output is $actualCurrent but setpoint is $current"
    } else {
        setStatus "Done."
    }
}

proc GoStraightThrough {args} {
    set magnet L3:AM1
    APSStrictParseArguments {magnet}

    return [RampToNewCurrent -magnet $magnet -current 0]
}

set magnetList "L3:AM1 L5:AM1"
set momentumSetpoint(L3:AM1) 160
set momentumReadback(L3:AM1) [DetermineMomentumReadback -magnet L3:AM1]
set momentumSetpoint(L5:AM1) 217
set momentumReadback(L5:AM1) [DetermineMomentumReadback -magnet L5:AM1]

set index 0
foreach magnet $magnetList {
    APSFrame .f$index -parent .userFrame -label "$magnet"
    set w .userFrame.f$index.frame
    incr index
    
    APSLabeledEntry .momentumSetpoint -parent $w -label "Momentum setpoint (MeV): " \
      -textVariable momentumSetpoint($magnet) -contextHelp "Enter the beam momentum to set $magnet for."
    APSLabeledOutput .momentumReadback -parent $w -label "Momentum readback (MeV): " \
      -textVariable momentumReadback($magnet) \
      -contextHelp "Shows the beam momentum for which $magnet is presently set."
    APSButton .update -parent $w -text "Update" \
      -command "set momentumReadback($magnet) \[DetermineMomentumReadback -magnet $magnet\]" \
      -contextHelp "Updates the momentum readback value."
    APSButton .change -parent $w -text "Change to setpoint" \
      -command "ChangeMomentum -magnet $magnet -momentum \[set momentumSetpoint($magnet)\] 
          set momentumReadback($magnet) \[DetermineMomentumReadback -magnet $magnet\]" \
      -contextHelp "Changes the momentum to the momentum setpoint for $magnet."
    APSButton .eval -parent $w -text "Give current for setpoint" \
      -command "ChangeMomentum -magnet $magnet -momentum \[set momentumSetpoint($magnet)\] -reportOnly 1" \
      -contextHelp "Reports the current value for a given momentum setpoint."
    APSButton .goStraight -parent $w -text "Go straight through" \
      -command "RampToNewCurrent -magnet $magnet
          set momentumReadback($magnet) 0" \
      -contextHelp "Sets the main supply to zero and degausses $magnet."
}


