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

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 "\$Revision: 1.23 $ \$Author: borland $"

# PAR PEM procedures require these
package require comm
set cwd [pwd]
set abortRequest ""

set debugPARscrub 0

proc APSSetPARScrubStatus {text} {
    global apsPARScrubStatus
    set apsPARScrubStatus "[clock format [clock seconds] -format %T]: $text"
    update
}


set thresholdCharge 5.0
set targetCharge 5.5
set timeLimit 30
set linacPulses 1
set verticalCorrectorSave [exec cavget -list=P1V1,P1V2,P1V3,P2V1,P2V2,P2V3,P3V1,P3V2,P4V1,P4V2 -list=:CurrentAO -cavputForm]
set controllawSave [exec cavget -list=PAR:OrbitControlLaw -list=X,Y -list=SDDS.SUSP -cavputForm]
set topUpWarningTime [exec cavget -list=Mt:TopUpWarnTime2CalcP.VAL -pendIoTime=10]

#
# Below here are machine procedures
#

set apsStoreBeamInPARInitialized 0
set nLinacBunches 1

proc SafeSetLinacBunches {args} {
    set number -1
    APSStrictParseArguments {number}
    if [scan $number "%d" n]!=1 {
        APSSetPARScrubStatus "Problem with number of bunches for linac: $number"
        set n 1
    } 
    set number $n

    APSParseArguments {number}
    if {$number <0 } {set number 0}
    if {$number > 15} {set number 15}
    set endBunch [expr $number * 2 - 2]
    set endBunchp2 [expr $number * 2 ]
    if [catch {exec cavput -list=It:L:B \
                 -range=begin=0,end=$endBunch,interval=2,format=%02ld \
                 -list=_enb_bo=On -pendIoTime=10 \
             } result] {
        return -code error $result
    }
    if [catch {exec cavput -list=It:L:B \
                 -range=begin=$endBunchp2,end=28,interval=2,format=%02ld \
                 -list=_enb_bo=Off -pendIoTime=10 \
             } result] {
        return -code error $result
    }
}

proc APSControlGunState {args} {
    set mode 0
    set bunches 1
    set statusCallback APSNoOp
    APSStrictParseArguments {statusCallback mode bunches}

    set origModes [exec cavget -list=L1:RG1:KIK:chargeTrigC,L1:RG2:KIK:chargeTrigC -num]
    set origMode1 [lindex $origModes 0]
    set origMode2 [lindex $origModes 1]

    if {(($origMode1 || $origMode2) && $mode) || (!$origMode1 && !$origMode2 && !$mode)} {
        return
    }
    if $mode {
        SafeSetLinacBunches -number $bunches
        exec cavput -list=L1:RG1:KIK:chargeTrigC=1,L1:RG2:KIK:chargeTrigC=1
        $statusCallback "Gun kicker pulsing started, $bunches bunches."
    } else {
        SafeSetLinacBunches -number $bunches
        exec cavput -list=L1:RG1:KIK:chargeTrigC=0,L1:RG2:KIK:chargeTrigC=0
        $statusCallback "Gun kicker pulsing stopped, $bunches bunches."
    }
    after 1000
    return $origMode
}


proc APSScrubPAR {args} {
    set targetCharge 0
    set timeLimit 0
    set topUp 1
    set statusCallback APSNoOp
    set thresholdCharge 0
    set srTopUpCompatibility 0
    set sweepAmplitude -1
    set linacPulses 1
    APSStrictParseArguments {targetCharge timeLimit topUp statusCallback thresholdCharge srTopUpCompatibility sweepAmplitude linacPulses}

    global debugPARscrub verticalCorrectorSave
    global TopUpSecondsToWarn TopUpEnabled

    if {$srTopUpCompatibility && [expr $targetCharge>6]} {
        $statusCallback "Target charge > 6nC. Not allowed in SR top-up compatibility mode."
        return
    }

    if $debugPARscrub { puts stderr "APSScrubPAR called" }
    APSStoreBeamInPARInit
    set verticalCorrectorSave [exec cavget -list=P1V1,P1V2,P1V3,P2V1,P2V2,P2V3,P3V1,P3V2,P4V1,P4V2 -list=:CurrentAO -cavputForm]
    set controllawSave [exec cavget -list=PAR:OrbitControlLaw -list=X,Y -list=SDDS.SUSP -cavputForm]

    $statusCallback "Scrubbing starting..."
    if $thresholdCharge<=0 {
        $statusCallback "Error: threshold is not positive."
        return
    }

    if {[pv getw TopUpSecondsToWarn]!=0 || [pv getw TopUpEnabled]!=0} {
        $statusCallback "Error: problem reading top-up warning countdown or top-up state (1)"
        return
    }
    if {[string compare $TopUpEnabled Enable]==0  && $srTopUpCompatibility!=1} {
        $statusCallback "Error: SR top-up is running. You must run in SR top-up compatibility mode."
        return
    }

    global apsStoreBeamInPARAbort
    global PCMqTotal nLinacBunches topUpWarningTime

    set firstInjection 1
    set sentToPTB 0
    set sweepState [list 0 $sweepAmplitude 0]
    set nLinacBunches [exec cavget -list=It:L:bunch_countCC -pendIoTime=10]
    #$statusCallback "$nLinacBunches linac bunches"
    
    while 1 {
        if {[pv getw TopUpSecondsToWarn]!=0 || [pv getw TopUpEnabled]!=0} {
            $statusCallback "Error: problem reading top-up warning countdown or top-up state (1)"
            return
        }
        if {[string compare $TopUpEnabled Enable]==0 && $srTopUpCompatibility!=1} {
            $statusCallback "Error: SR top-up is running. You must run in SR top-up compatibility mode."
            return
        }
        if {[string compare $TopUpEnabled Enable]==0 && $TopUpSecondsToWarn<$topUpWarningTime} {
            $statusCallback "Holding off for SR top-up."
            if !$sentToPTB {
                APSSendBeamToPTB
                after 2000
                set sentToPTB 1
            }
            after 2000
            continue
        }
        if $debugPARscrub { puts stderr "APSScrubPAR looping" }
        if !$firstInjection {
            set topUp 1
        }
        if [expr $sweepAmplitude>0] {
            eval exec cavput -list=$verticalCorrectorSave
            exec cavput -list=PAR:OrbitControlLaw -list=X,Y -list=SDDS.SUSP=Suspend
            after 2000
        }
        catch {APSStoreBeamInPAR -targetCharge $targetCharge -linacPulses $linacPulses \
                 -timeLimit $timeLimit -topUp $topUp -srTopUpCompatibility $srTopUpCompatibility \
                 -statusCallback $statusCallback}  result
        set sentToPTB 0
        if $debugPARscrub { puts stderr "APSScrubPAR beam stored" }
        switch $result {
            error -
            abort -
            timeout {
                SafeSetLinacBunches -number $nLinacBunches
                return
            }
        }
        set firstInjection 0
        while 1 {
            if {[pv getw TopUpEnabled]!=0} {
                $statusCallback "Error: problem reading top-up warning countdown or top-up state (2)"
                SafeSetLinacBunches -number $nLinacBunches
                return
            }
            if {[string compare $TopUpEnabled Enable]==0} {
                if {[pv getw TopUpSecondsToWarn]!=0} {
                    $statusCallback "Error: problem reading top-up warning countdown (3)"
                    SafeSetLinacBunches -number $nLinacBunches
                    return
                }
                if {[expr $TopUpSecondsToWarn<$topUpWarningTime]} {
                    SafeSetLinacBunches -number $nLinacBunches
                    break
                }
            }
            if {[pv getw PCMqTotal]!=0} {
                SafeSetLinacBunches -number $nLinacBunches
                return
            }
            set charge [expr abs($PCMqTotal)]
            $statusCallback "Waiting for charge ([format %.2f $charge]) to fall below $thresholdCharge."
            set countDown 10
            while {$countDown} {
                if [expr $sweepAmplitude>0] {
                    exec cavput -list=PAR:OrbitControlLaw -list=X,Y -list=SDDS.SUSP=Suspend
                    set sweepState [eval APSPARNextSweepState $sweepState]
                }
                if {[string compare $TopUpEnabled Enable]==0} {
                    if {[pv getw TopUpSecondsToWarn]!=0} {
                        $statusCallback "Error: problem reading top-up warning countdown (4)"
                        if [expr $sweepAmplitude>0] {
                            eval exec cavput -list=$verticalCorrectorSave
                            eval exec cavput -list=$controllawSave
                            set sweepState [eval APSPARNextSweepKnob $sweepState]
                        }
                        SafeSetLinacBunches -number $nLinacBunches
                        return
                    }
                    if {[expr $TopUpSecondsToWarn<$topUpWarningTime]} {
                        SafeSetLinacBunches -number $nLinacBunches
                        break
                    }
                }
                incr countDown -1
                if $debugPARscrub { puts stderr "APSScrubPAR test loop" }
                if {[pv getw PCMqTotal]!=0} {
                    $statusCallback "Aborted scrubbing due to problem getting PAR CM data."
                    set apsStoreBeamInPARAbort 1
                    if [expr $sweepAmplitude>0] {
                        eval exec cavput -list=$verticalCorrectorSave
                        eval exec cavput -list=$controllawSave
                        set sweepState [eval APSPARNextSweepKnob $sweepState]
                    }
                    SafeSetLinacBunches -number $nLinacBunches
                    return
                }
                set charge [expr abs($PCMqTotal)]
                if $charge<$thresholdCharge {
                    SafeSetLinacBunches -number $nLinacBunches
                    break
                } 
                after 500
                update
                if {$apsStoreBeamInPARAbort} {
                    $statusCallback "Aborted scrubbing."
                    if $debugPARscrub { puts stderr "APSScrubPAR returning" }
                    if [expr $sweepAmplitude>0] {
                        eval exec cavput -list=$verticalCorrectorSave
                        eval exec cavput -list=$controllawSave
                        set sweepState [eval APSPARNextSweepKnob $sweepState]
                    }
                    SafeSetLinacBunches -number $nLinacBunches
                    return
                }
            }
            if [expr $sweepAmplitude>0] {
                set sweepState [eval APSPARNextSweepKnob $sweepState]
            }
            if $charge<$thresholdCharge {
                if [expr $sweepAmplitude>0] {
                    eval exec cavput -list=$verticalCorrectorSave
                }
                break
            } 
        }
    }
    SafeSetLinacBunches -number $nLinacBunches
}

set knobElementList [list P1V1 P1V2 P1V3,P2V3 P2V1 P2V2 P3V1 P3V2 P4V1 P4V2]
set knobFactorList  [list    1    1   -3,3       1    1    1    1    1    1]

proc APSPARNextSweepKnob {knob strength dphase} {
    global knobElementList knobFactorList 
    set dphase 0
    set knob [expr $knob+1]
    if [expr $knob==[llength $knobElementList]] {
        set knob 0
    }
    return [list $knob $strength $dphase]
}

proc APSPARNextSweepState {knob strength dphase} {
    global knobElementList knobFactorList 
    global baseValueList
    if [expr $dphase==0] {
        APSSetPARScrubStatus "Using [lindex $knobElementList $knob] for vertical orbit sweep"
        set baseValueList [exec cavget -list=[lindex $knobElementList $knob] -list=:CurrentAO]
        #APSSetPARScrubStatus "Saving: $baseValueList"
    }
    if [expr $dphase==360] {
        # Reset to base values
        foreach knobElement [split [lindex $knobElementList $knob] ,] baseValue $baseValueList {
            lappend valueList $knobElement=$baseValue
        }
        #APSSetPARScrubStatus "Resetting $valueList"
        exec cavput -list=$valueList -list=:CurrentAO
        set dphase 0
        set knob [expr $knob+1]
        if [expr $knob==[llength $knobElementList]] {
            set knob 0
        }
        #APSSetPARScrubStatus "Switching to correctors [lindex $knobElementList $knob]"
        set baseValueList [exec cavget -list=[lindex $knobElementList $knob] -list=:CurrentAO]
        #APSSetPARScrubStatus "Saving: $baseValueList"
    } else {
        set dphase [expr $dphase+15]
    }
    set valueList ""
    set pi [expr 4*tan(1)]
    set phase [expr $dphase*$pi/180.0]
    set sum [expr sin($phase)-sin($phase*3)/9.+sin($phase*5)/25.]
    #APSSetPARScrubStatus "dphase=$dphase  sum=$sum"
    foreach knobElement [split [lindex $knobElementList $knob] ,] factor [split [lindex $knobFactorList $knob] ,] baseValue $baseValueList {
        lappend valueList $knobElement=[expr $sum*$factor*$strength/5.0+$baseValue]
    }
    #APSSetPARScrubStatus "setting: $valueList"
    eval exec cavput -list=[join $valueList ,] -list=:CurrentAO
    return [list $knob $strength $dphase]
}

proc APSStoreBeamInPARInit {} {
    global apsStoreBeamInPARInitialized  debugPARscrub

    if !$apsStoreBeamInPARInitialized {
        if $debugPARscrub { puts stderr "Initializing CA connections"}

        global apsStoreBeamInPARInitialized apsStoreBeamInPARStop apsStoreBeamInPARAbort
        global PCMqTotal LTPqTotal TopUpEnabled
        #global IKcharge EKcharge PSPcharge PAR2Hz
        global IKcharge EKcharge PSPcharge
        global TopUpSecondsToWarn

        # connect to PVs
#        if {[pv linkw {PCMqTotal LTPqTotal PAR2Hz} {P:bpmSum:ChargeM LTP:FCM:qTotalAI It:L:2Hz_rate_bo.VAL}]!=0} {
#            return -code error 0
#        }
        if {[pv linkw {PCMqTotal LTPqTotal TopUpEnabled TopUpSecondsToWarn PARYControlLaw} {P:bpmSum:ChargeM LTP:FCM:qTotalAI Mt:TopUpAutoEnableC.VAL Mt:TopUpTime2WarnInjector.VAL PAR:OrbitControlLawXSDDS.SUSP}]!=0} {
            return -code error 0
        }
        if {[pv linkw \
               {IKcharge EKcharge PSPcharge} \
               {It:Ddg2chan4.GATE It:ER1:er.OTL2 It:Par:PSPchargeBO.VAL}]!=0} {
            return -code error 0
        }
        set apsStoreBeamInPARInitialized 1
    }

}

proc APSStoreBeamInPAR {args} {
    global debugPARscrub
    set targetCharge 0
    set timeLimit 0
    set topUp 1
    set statusCallback APSNoOp
    set srTopUpCompatibility 0
    set linacPulses 1
    APSStrictParseArguments {targetCharge timeLimit topUp statusCallback srToUp srTopUpCompatibility linacPulses}
    if $debugPARscrub { puts stderr "APSStoreBeamInPAR called"}

    if !$srTopUpCompatibility {
        APSChangeRF12State 0
        if [catch {exec cavput -list=P:BnchCln:Mux11mbbo=Off} result] {
            $statusCallback "WARNING: failed to turn off bunch cleaner: $result"
        } else {
            $statusCallback "Turned off bunch cleaner."
        }
    } else {
        if [expr $targetCharge>6] {
            $statusCallback "Target charge > 6nC. Not allowed in SR top-up compatibility mode."
            return
        }
    }
    
    if {$targetCharge<=0} {
        $statusCallback "Error: target charge value is not positive."
        return -code error -errorinfo "targetCharge value is not positive" error
    }
    if {$timeLimit<0} {
        $statusCallback "Error: time limit is negative."
        return -code error -errorinfo "timeLimit is negative" "error"
    }

    $statusCallback "Injection started."

    global apsStoreBeamInPARInitialized apsStoreBeamInPARStop apsStoreBeamInPARAbort
    global PCMqTotal LTPqTotal nLinacBunches
    global IKcharge EKcharge PSPcharge
    #global PAR2Hz 
    APSStoreBeamInPARInit

    set apsStoreBeamInPARStop 0
    set apsStoreBeamInPARAbort 0
    #set PAR2Hz 1
    #catch {pv putw PAR2Hz}

    if !$topUp {
        # dump any beam that might be present
        set EKcharge 1
        set IKcharge 0
        set PSPcharge 0
        if {[pv putw {EKcharge IKcharge PSPcharge}]!=0} {
            return -code error 0
        }
        after 1000
    }

    set endTime 1e300
    if $timeLimit {
        set endTime [expr [clock seconds]+$timeLimit]
    }

    set nLinacBunches [exec cavget -list=It:L:bunch_countCC.VAL -pendIoTime=10]
    APSControlGunState -mode 1 -statusCallback $statusCallback -bunches $linacPulses

    while 1 {
        if $debugPARscrub { puts stderr "APSStoreBeamInPAR loop"}
        if {[pv getw {PCMqTotal LTPqTotal}]!=0} {
            set EKcharge 0
            set IKcharge 0
            set PSPcharge 0
            pv putw {EKcharge IKcharge PSPcharge}
            APSControlGunState -mode 0 -statusCallback $statusCallback -bunches $nLinacBunches
            return -code error error
        }
        set charge [expr abs($PCMqTotal)]
        set timedOut [expr [clock seconds]>$endTime ? 1 : 0 ]
        if {$charge>$targetCharge  || $timedOut || $apsStoreBeamInPARAbort} {
            puts "$charge $targetCharge; $timedOut $timeLimit; $apsStoreBeamInPARAbort"
            set statusValue "$charge $targetCharge; $timedOut $timeLimit; $apsStoreBeamInPARAbort"
            if {$timedOut} {
                set returnValue timeout
                set statusValue "Stopping injection due to timeout. Consider using more linac bunches."
            } elseif $apsStoreBeamInPARAbort {
                set returnValue abort
                set statusValue "Stopping injection due to abort command."
            } else {
                set returnValue ok
                set statusValue "Target charge has been achieved."
            }
            $statusCallback $statusValue
            set EKcharge 0
            set IKcharge 0
            set PSPcharge 0
            if {[pv putw {EKcharge IKcharge PSPcharge}]!=0} {
                APSControlGunState -mode 0 -statusCallback $statusCallback -bunches $nLinacBunches
                return -code error error
            }
            APSControlGunState -mode 0 -statusCallback $statusCallback -bunches $nLinacBunches
            return $returnValue
        }
        after 500
        update
        # turn on injection and turn off extraction kicker
        set EKcharge 0
        set IKcharge 1
        set PSPcharge 1
        if {[pv putw {EKcharge IKcharge PSPcharge}]!=0} {
            APSControlGunState -mode 0 -statusCallback $statusCallback -bunches $nLinacBunches
            return -code error error
        }
    }
}

proc APSAbortStoringBeamInPAR {} {
    global apsStoreBeamInPARAbort 
    set apsStoreBeamInPARAbort 1
}

proc APSChangeRF12State {mode} {
    global apsRF12Idled apsRF12Tuner
    if [catch {exec cavget -list=PAR:RF12:abBoA1C5S2 -numerical} state] {
        APSSetPARScrubStatus "Problem turning rf12 on: $state"
        return
    }
    if {$state==$mode} {
        if $mode {
            APSSetPARScrubStatus "Rf12 apparently on, leaving as is."
        } else {
            APSSetPARScrubStatus "Rf12 apparently off, leaving as is."
        }
        return
    }
    if {$mode} {
        global apsStoreBeamInPARAbort 1
        APSDumpPARBeam
        APSSetPARScrubStatus "Turning rf12 on"
        if {[catch {APSMpPARTurnOnRf12 -useSystemReference 1} result]} {
            APSSetPARScrubStatus "Problem turning rf12 on: $result"
            return 
        }
        APSSetPARScrubStatus "Turned rf12 on."
        return
    } else {
        APSSetPARScrubStatus "Turning rf12 off"
        if [catch {APSMpPARTurnOffRf12} result] {
            APSSetPARScrubStatus "Problem turning rf12 off: $result"
            return
        }
        if [catch {exec cavput -list=PAR:Har:RemoteStandBy=1} result] {
            APSSetPARScrubStatus "Problem setting rf12 to remote standby: $result"
            return
        }
        APSSetPARScrubStatus "Turned rf12 off."
        return 
    }
}


proc APSSendBeamToPTB {args} {
    global IKcharge EKcharge PSPcharge srTopUpCompatibility nLinacBunches
    set statusCallback APSNoOp
    APSStrictParseArguments {statusCallback}

    APSStoreBeamInPARInit
    APSAbortStoringBeamInPAR
    if !$srTopUpCompatibility {
        APSChangeRF12State 1
        if [catch {exec cavput -list=P:BnchCln:Mux11mbbo=On} result] {
            $statusCallback "WARNING: failed to turn on bunch cleaner: $result"
        } else {
            $statusCallback "Turned on bunch cleaner."
        }
    }
    APSControlGunState -mode 1 -statusCallback $statusCallback
    SafeSetLinacBunches -number $nLinacBunches
    set EKcharge 1
    set IKcharge 1
    set PSPcharge 1
    pv putw {EKcharge IKcharge PSPcharge}
}

proc APSStandbyPAR {args} {
    global IKcharge EKcharge PSPcharge srTopUpCompatibility
    set statusCallback APSNoOp
    APSStrictParseArguments {statusCallback}

    APSStoreBeamInPARInit
    APSAbortStoringBeamInPAR
    APSControlGunState -mode 0 -statusCallback $statusCallback
    set EKcharge 0
    set IKcharge 0
    set PSPcharge 0
    $statusCallback "Disabling pulsed magnets..."
    pv putw {EKcharge IKcharge PSPcharge}
    if !$srTopUpCompatibility {
        APSChangeRF12State 1
        if [catch {exec cavput -list=P:BnchCln:Mux11mbbo=On} result] {
            $statusCallback "WARNING: failed to turn on bunch cleaner: $result"
        } else {
            $statusCallback "Turned on bunch cleaner."
        }
    }
}

proc APSDumpPARBeam {} {
    global IKcharge EKcharge PSPcharge

    APSStoreBeamInPARInit
    APSAbortStoringBeamInPAR
    set EKcharge 1
    set IKcharge 0
    set PSPcharge 0
    pv putw {EKcharge IKcharge PSPcharge}
    after 1000
    set EKcharge 0
    set IKcharge 0
    set PSPcharge 0
    pv putw {EKcharge IKcharge PSPcharge}
}


APSApplication . -name PARScrub -version $CVSRevisionAuthor \
  -overview {This application provides for scrubbing of the PAR vacuum system by repeatedly filling the ring and letting the beam decay.  It can be used only when the PAR is not required to deliver beam to the booster.}

set apsPARScrubStatus "Ready."
APSScrolledStatus .record -parent .userFrame -width 60 \
  -height 4 -textVariable apsPARScrubStatus -lineLimit 1000

APSLabeledEntry .lowlim -parent .userFrame \
  -textVariable thresholdCharge \
  -label "Refill threshold (nC): " \
  -contextHelp "Enter the threshold on the stored charge at which to begin injection again.  The program will try to keep the stored beam above this level at all times"

APSLabeledEntry .uplim -parent .userFrame \
  -textVariable targetCharge \
  -label "Fill target (nC): " \
  -contextHelp "Enter the target value for the stored charge for each file.  \
The program will try to reach this value before it goes into stored beam mode."

APSLabeledEntry .timelim  -parent .userFrame \
  -textVariable timeLimit \
  -label "Time limit for continuous injection (sec): " \
  -contextHelp "Enter the time limit in seconds for injection. \
The program will inject for no more than this time in attempting to reach the target charge level."

APSLabeledEntry .pulses  -parent .userFrame \
  -textVariable linacPulses \
  -label "Number of linac bunches: " \
  -contextHelp "Enter the number of linac bunches to enable."

set srTopUpCompatibility 1
APSRadioButtonFrame .rb -parent .userFrame \
    -label "SR top-up compatibility mode? " \
    -variable srTopUpCompatibility \
    -buttonList "Yes No" -valueList "1 0" \
    -commandList [list limitChargeSettings ""] \
    -orientation horizontal \
    -contextHelp "This script can run during storage ring top-up, but only if RF12 and the bunch cleaner are left alone. Select \"Yes\" to enable this mode. The charge is limited to 6 nC."

set verticalSweep 0
set sweepAmplitude 1.5

if 0 {
APSRadioButtonFrame .rb2 -parent .userFrame \
    -label "Vertical orbit sweep? " \
    -variable verticalSweep \
    -buttonList "Yes No" -valueList "1 0" \
    -commandList [list "APSEnableWidget .userFrame.sweepAmp.entry; set thresholdCharge 5.0" "APSDisableWidget .userFrame.sweepAmp.entry; set thresholdCharge 5.9"] \
    -orientation horizontal \
    -contextHelp "If enabled, vertical orbit is swept using vertical correctors."

APSLabeledEntry .sweepAmp  -parent .userFrame \
  -textVariable sweepAmplitude \
  -label "Orbit sweep amplitude (A): " \
  -contextHelp "Enter the amplitude of the orbit sweep. The units correspond to amps on the V3 correctors, which are ganged. V1 and V2 correctors use lower current, since respond is higher."
APSDisableWidget .userFrame.sweepAmp.entry
}

proc limitChargeSettings {} {
    global thresholdCharge targetCharge
    set targetCharge 6.0
    if [expr ($thresholdCharge-0.5)>$targetCharge] {
        set thresholdCharge [expr $targetCharge-0.5]
    }

}

proc SetButtonState {args} {
    set mode inactive
    APSStrictParseArguments {mode}
    switch $mode {
        locked {
            APSDisableWidget .userFrame.ops
        }
        scrub {
            APSDisableWidget .userFrame.ops
            APSEnableWidget .userFrame.ops.abort
        }
        inactive {
            APSEnableWidget .userFrame.ops
            APSDisableWidget .userFrame.ops.abort
        }
    }
    update
}

frame .userFrame.ops
pack .userFrame.ops -side top
APSButton .store -parent .userFrame.ops \
  -text STORE \
  -command {APSStoreBeamInPAR -targetCharge $targetCharge -timeLimit $timeLimit -linacPulses $linacPulses \
              -topUp 1 -statusCallback APSSetPARScrubStatus -srTopUpCompatibility $srTopUpCompatibility } \
  -contextHelp "Injects and stores beam in the PAR. \
Continues until the target is reached or until the time limit expires."

APSButton .scrub -parent .userFrame.ops \
  -text SCRUB \
  -command {SetButtonState -mode scrub ; APSScrubPAR -targetCharge $targetCharge -timeLimit $timeLimit \
    -linacPulses $linacPulses -topUp 1 -statusCallback APSSetPARScrubStatus -srTopUpCompatibility $srTopUpCompatibility \
              -thresholdCharge $thresholdCharge -sweepAmplitude [expr $verticalSweep?$sweepAmplitude:-1] ; \
              SetButtonState -mode inactive} \
  -contextHelp "Repeatedly injects and stores beam in the PAR.  Deactivates RF12.  Trys to reach the \
target level, but won't inject for longer than the time limit in doing so."

APSButton .abort -parent .userFrame.ops \
  -text ABORT \
  -command {set apsStoreBeamInPARAbort 1} \
  -contextHelp "Aborts filling of the PAR.  Does not kill any beam that may be stored.  Does NOT reactivate RF12."

APSButton .dump -parent .userFrame.ops \
  -text "DUMP" \
  -command APSDumpPARBeam \
  -contextHelp "Dumps the PAR stored beam using the extraction kickers.  Aborts scrubbing or sending of beam to PTB."

APSButton .toPTB -parent .userFrame.ops \
  -text "TO PTB" \
  -command "SetButtonState -mode locked; APSSendBeamToPTB -statusCallback APSSetPARScrubStatus; SetButtonState -mode inactive" \
  -contextHelp "Enables extraction and injection pulses and (if necessary) returns RF12 to active state.  Used to deliver beam to the booster for normal operation."

APSButton .standby -parent .userFrame.ops \
  -text "STANDBY" \
  -command "APSStandbyPAR -statusCallback APSSetPARScrubStatus" \
  -contextHelp "Puts the PAR in standby mode by disabling the kickers and septum.  Also disables the gun kicker, but leaves the harmonic cavity on."

APSButton .offRF12 -parent .userFrame.ops \
  -text "RF12 OFF" \
  -command {APSChangeRF12State 0} \
  -contextHelp "Puts RF12 in an off state by turning off the rf input and putting the tuner setpoint to -10.  The tuner setpoint is saved and may be restored with the RF12 ON button."

APSButton .onRF12 -parent .userFrame.ops \
  -text "RF12 ON" \
  -command {SetButtonState -mode locked; APSChangeRF12State 1; SetButtonState -mode inactive} \
  -contextHelp "Returns RF12 from off state by turning on the rf input and setting the tuner setpoint to what it was when the RF12 OFF button was pressed."

SetButtonState -mode inactive
