

# This procedure turns the booster power supplies on.  It first checks
# the power supply to make sure it is not already on.  It also checks
# to make sure that the ramps are disabled and checks that the DAC
# output voltage is not railed.

# Procedure launches parallel procedures to turn on/off each power supply selected.

proc APSMpBoosterPSOnOff {args} {

    global status
    
    set BM 0
    set QF 0
    set QD 0
    set SF 0
    set SD 0
    set state1 off
    
    APSStrictParseArguments {BM QF QD SF SD state1}

    set magnetlist {BM QF QD SF SD}
    
    set listindex 0

    foreach magnet $magnetlist {
        if {[set $magnet]} {
            APSMpStep "Turn $magnet $state1" -desc "Turn on or off selected magnets"
            set ${magnet}OnOffID [APSMpParallel -procedure "APSMpBoosterPSOnOffNormal -magnet $magnet -state1 $state1" -mode Automatic]
            update
        }
    }
    #    APSMpAbort all -onError 1
    foreach magnet $magnetlist {
        if {[set $magnet]} {
            if {[catch {APSMpJoin [set ${magnet}OnOffID]} magnetStatus]} {
                if {[APSPEMTKDialog .warningDialog -text "APSMpBoosterPSOnOff: Problem occurred while turning $magnet on\n$magnetStatus"] == 1} {
                    APSMpReturn error "APSMpBoosterPSOnOff: $magnetStatus"
                }
            }
        }
    }
    APSWaitWithUpdate -waitSeconds 3
    APSMpReturn ok
}

# procedure turns on/off supplies selected in procedure
# APSMpBoosterPSOnOffDialog.  Performs checks on DAC voltage and
# disables the ramp enable/disable state before turning a given supply
# on/off.  This will prevent power supply damage due to hard turn on
# due to enabled ramps and/or dac voltage railed conditions.

proc APSMpBoosterPSOnOffNormal {args} {

    global status
    
    set magnet ""
    set state1 off
    
    APSStrictParseArguments {magnet state1}

    set magnetlist {BM QF QD SF SD}

    set isMagnetPSValid [lsearch -exact "BM QF QD SF SD" $magnet]
    if {![string compare $isMagnetPSValid -1]} {
        APSMpReturn ok
    }

    if {[catch {APScavget -list=It:Ddg4chan${isMagnetPSValid}.GATE -pendIoTime=20} rampstate]} {
        APSMpReturn error "APSMpBoosterPSOnOffNormal: $rampstate"
    }
    if {[catch {APScavget -list=B:${magnet}:StatusCALC -pendIoTime=20} onState]} {
        APSMpReturn error "APSMpBoosterPSOnOffNormal: $onState"
    }
    if {$onState == "?"} {
        APSMpReturn error "APSMpBoosterPSOnOffNormal: Problem reading B:${magnet}:StatusCALC"
    }
    update
    if {$state1=="on" && !${onState}} {
        #Supply is on
        APSMpStep "$magnet supply is already on."
        APSMpReturn ok
        #Supply is now on, ramp is unchanged
    } elseif {$state1=="off" && ${onState}} {
        #Supply is off
        APSMpStep "$magnet supply is already off."
        APSMpReturn ok
        #Supply is now off, ramp is unchanged
    }
    if {$state1=="on"} {
        #Supply is off
        if {$rampstate=="Enabled"} {
            #Ramp is enabled
            APSMpStep "$magnet ramp is enabled.  Disabling before turning on."
            if {[catch {APSMpBoosterPSEnableDisableRamps -magnet $magnet -state1 disable} results]} {
                if {[APSPEMTKDialog .warningDialog -text "APSMpBoosterPSOnOffNormal: Problem occurred while disabling ramp for $magnet \n$results"] == 1} {
                    APSMpReturn error "APSMpBoosterPSOnOffNormal: $results"
                }
            }
            APSWaitWithUpdate -waitSeconds 2
        }
        #Ramp is disabled
        set step 1
        set isAboveThreshold 1
        while {($isAboveThreshold) && ($step <= 6)} {
            if {$step > 1} {
                APSMpStep "$magnet ramp is disabled and DAC voltage is above the threshold level.  Toggling ramp enable-disable button to reset DAC.  Leaving ramp DISABLED before turning on the supply."
            }
            if {[catch {APSMpBoosterPSEnableDisableRamps -magnet $magnet -state1 enable} results]} {
                if {[APSPEMTKDialog .warningDialog -text "APSMpBoosterPSOnOffNormal: Problem occurred while enabling ramp for $magnet \n$results"] == 1} {
                    APSMpReturn error "APSMpBoosterPSOnOffNormal: $results"
                }
            }
            APSWaitWithUpdate -waitSeconds 2
            if {[catch {APSMpBoosterPSEnableDisableRamps -magnet $magnet -state1 disable} results]} {
                if {[APSPEMTKDialog .warningDialog -text "APSMpBoosterPSOnOffNormal: Problem occurred while disabling ramp for $magnet \n$results"] == 1} {
                    APSMpReturn error "APSMpBoosterPSOnOffNormal: $results"
                }
            }
            APSWaitWithUpdate -waitSeconds 2
            if {[catch {APSDetermineBPSDACThreshold -magnetPS ${magnet}} isAboveThreshold]} {
                if {[APSPEMTKDialog .warningDialog -text "APSMpBoosterPSOnOffNormal: Problem occurred while checking DAC threshold for $magnet \n$isAboveThreshold"] == 1} {
                    APSMpReturn error "APSMpBoosterPSOnOffNormal: $isAboveThreshold"
                } else {
                    set isAboveThreshold 1
                }
            }
            incr step
        }
        if {$isAboveThreshold} {
            if {[APSPEMTKDialog .warningDialog -text "$magnet DAC voltage is above the threshold level. The PEM could not reset the DAC. The DAC must be reset manually by an operator."] == 1} {
                APSMpReturn error "APSMpBoosterPSOnOffNormal: $magnet DAC voltage is above the threshold level."
            }
        }
        APSMpStep "Turning power supply $magnet on."
        if {[catch {exec cavput -list=B:${magnet}:ResetSEQ=1} results]} {
            if {[APSPEMTKDialog .warningDialog -text "APSMpBoosterPSOnOffNormal: Problem occurred while turning B:$magnet on\n$results"] == 1} {
                APSMpReturn error "APSMpBoosterPSOnOffNormal: $results"
            }
        }
        #Supply is now on, ramp is disabled
    } elseif {$state1=="off"} {
        #Supply is on
        if {$rampstate=="Enabled"} {
            #Ramp is Enabled
            APSMpStep "$magnet ramp is enabled.  Disabling before turning off."
            if {[catch {APSMpBoosterPSEnableDisableRamps -magnet $magnet -state1 disable} results]} {
                if {[APSPEMTKDialog .warningDialog -text "APSMpBoosterPSOnOffNormal: Problem occurred while disabling ramp for $magnet \n$results"] == 1} {
                    APSMpReturn error "APSMpBoosterPSOnOffNormal: $results"
                }
            }
        }
        APSMpStep "Turning power supply $magnet off."
        if {[catch {exec cavput -list=B:${magnet}:OffBO=OFF} results]} {
            if {[APSPEMTKDialog .warningDialog -text "APSMpBoosterPSOnOffNormal: Problem occurred while turning B:$magnet off\n$results"] == 1} {
                APSMpReturn error "APSMpBoosterPSOnOffNormal: $results"
            }
        }
        #Supply is now off, ramp is disabled
    }
    
    set step 0
    while {($state1=="on" && ${onState}) || ($state1=="off" && !${onState})} {
        if {$step >= 10} {
            if {[APSPEMTKDialog .warningDialog -text "APSMpBoosterPSOnOffNormal: $magnet failed to turn $state1"] == 1} {
                APSMpReturn error "APSMpBoosterPSOnOffNormal: $magnet failed to turn $state1"
            }
        }
        APSWaitWithUpdate -waitSeconds 1
        if {[catch {APScavget -list=B:${magnet}:StatusCALC -pendIoTime=20} onState]} {
            if {[APSPEMTKDialog .warningDialog -text "APSMpBoosterPSOnOffNormal: Channel access problem for B:${magnet}:StatusCALC\n$onState"] == 1} {
                APSMpReturn error "APSMpBoosterPSOnOffNormal: $onState"
            } else {
                if {$state1=="on"} {
                    set onState 1
                } else {
                    set onState 0
                }
            }
        }
        incr step
    }
    APSMpReturn ok
}

# Procedure computes maximum power supply DAC output voltage and determines weather
# or not it is greater than 1 volt.  If it is, return 1.  If not, return 0.
# Returns -1 if the power supply selected is not one of BM, QF, QD, SF, SD.

proc APSDetermineBPSDACThreshold {args} {

    global maxMagnetDACVoltage

    set magnetPS ""
    APSStrictParseArguments {magnetPS}

    set isMagnetPSValid [lsearch -exact "BM QF QD SF SD" ${magnetPS}]

    if {![string compare $isMagnetPSValid -1]} {
        APSMpReturn ok
    } else {
        if {[catch {exec sddswmonitor /tmp/${magnetPS}.wf -PVnames=B:${magnetPS}:VoltageRefWF} results]} {
            APSMpReturn error "APSDetermineBPSDACThreshold: $results"
        }
        if {[catch {exec sddsprocess /tmp/${magnetPS}.wf /tmp/${magnetPS}Max.wf -process=B:${magnetPS}:VoltageRefWF,maximum,${magnetPS}Max} results]} {
            APSMpReturn error "APSDetermineBPSDACThreshold: $results"
        }
        if {[catch {exec sdds2stream /tmp/${magnetPS}Max.wf -param=${magnetPS}Max} DACMax]} {
            APSMpReturn error "APSDetermineBPSDACThreshold: $DACMax"
        }
        file delete -force -- /tmp/${magnetPS}.wf /tmp/${magnetPS}Max.wf
        if {($DACMax <= .00001) && ($DACMax >= -.00001)} {
            set maxMagnetDACVoltage 0
        } else {
            set maxMagnetDACVoltage [format "%.2f" [expr abs(($DACMax * 20.0 / 4096) - 10)]]
        }
        set DACVoltageThresholdCondition [expr {($maxMagnetDACVoltage > 1.5) ? 1 : 0}]
        APSMpReturn ok ${DACVoltageThresholdCondition}
    }
}

# Sets selected booster power supplies ramping at full power.  Full
# power mode represents beam acceleration to 7 GeV.  The procedure
# starts the supplies from a cold start or from a warm or standby
# condition.  In the case of a cold start, each selected supply is
# stepped to full power in 6 steps that take a total of 25 minutes.
# In the case of going to full power from standby or any other ramping
# mode (defined as AFG gain = 0.4 and supply ramping), each supply is
# brought to full power in 6 steps in 6 minutes.
# This program also turns on the horizontal and/or vertical 
# booster corrector power supplies or raw supplies.
# This program turns the booster corrector raw supplies on
# at 65 Volts, loads zero ramp tables, and either turns
# selected correctors on or off.  "Fast" mode does not
# load zero ramps when turning the supplies off.  "Fast"
# mode will not perform INIT/AUTO/ACTIVATE procedure before
# turning on.  "Raw Only" turns on only the raw supplies,
# loads 65 Volts as their setpoint and does this in "Fast" mode.
# If on is selected it loads the booster corrector ramps
# for both horizontal and vertical planes.

proc APSMpBoosterPSAndCorrOnFullPowerInfo {} { 
    return "This procedure runs APSMpBoosterPSSetFullPower under the \"Booster Main Ramped Supplies\" menu in parallel with APSMpBoosterSetCorrAndRampsOnOff under the \"Booster Correctors\" menu.  See the documents associated with these procedures for a detailed description of their function."
}

proc APSMpBoosterPSAndCorrOnFullPowerDialog {frame} {
    
    global status
    pack [frame $frame.top]
    set bottom $frame
    set frame $frame.top
    APSFrame .left -parent $frame -packOption "-side left"
    APSFrame .right -parent $frame -packOption "-side left"
    set status "Select booster power supplies..."

    APSCheckButtonFrame .magnetSelectButton -parent $frame.left.frame -label "Select magnet\npower supplies" \
      -variableList {APSMpBoosterPSAndCorrOnFullPower(BM)    \
                       APSMpBoosterPSAndCorrOnFullPower(QF)  \
                       APSMpBoosterPSAndCorrOnFullPower(QD)  \
                       APSMpBoosterPSAndCorrOnFullPower(SF)  \
                       APSMpBoosterPSAndCorrOnFullPower(SD)} \
      -buttonList {BM QF QD SF SD} \
      -allNone 1 \
      -gridPack "-column 0 -row 0 -columnspan 2 -padx .05i"
    
    APSRadioButtonFrame .bindTime -parent $frame.left.frame -label "Present state of\npower supplies" \
      -variable APSMpBoosterPSAndCorrOnFullPower(coldStart) \
      -buttonList {"Cold Start" "Standby"} \
      -valueList {1 0} \
      -contextHelp "Choose the current state." \
      -gridPack "-column 2 -row 0 -columnspan 2 -sticky n -padx .05i"

    bind $frame.left.frame.bindTime.frame.button1 <Button-1> {set APSMpBoosterPSAndCorrOnFullPower(startupTime) 12.0}
    bind $frame.left.frame.bindTime.frame.button2 <Button-1> {set APSMpBoosterPSAndCorrOnFullPower(startupTime) 6.0}
    
    APSLabeledOutput .timeSelectEntry -parent $frame.left.frame -label "Total starting time (m):" \
      -textVariable APSMpBoosterPSAndCorrOnFullPower(startupTime) -width 5 \
      -gridPack "-column 0 -row 1 -columnspan 3"
    
    APSLabeledOutput .stepsSelectEntry -parent $frame.left.frame -label "        Number of Steps:" \
      -textVariable APSMpBoosterPSAndCorrOnFullPower(startupSteps) -width 5 \
      -gridPack "-column 0 -row 2 -columnspan 3"
    
    APSButton .changeDefaultTime -parent $frame.left.frame -text "Change" \
      -gridPack "-column 3 -row 1" -command "if {\[tk_messageBox -message {This value should only be changed when permission has been attained} -type okcancel\] == {ok}} \"$frame.left.frame.timeSelectEntry.entry configure -state normal -relief sunken\" "

    APSButton .changeDefaultSteps -parent $frame.left.frame -text "Change" \
      -gridPack "-column 3 -row 2" -command "if {\[tk_messageBox -message {This value should only be changed when permission has been attained} -type okcancel\] == {ok}} \"$frame.left.frame.stepsSelectEntry.entry configure -state normal -relief sunken\" "

    label $frame.right.frame.la1 -text "Set Booster Corrector\nPower Supply Options"
    grid $frame.right.frame.la1 -column 0 -row 0 -columnspan 4
    
    APSRadioButtonFrame .rb2 -parent $frame.right.frame -label "" \
      -variable APSMpBoosterPSAndCorrOnFullPower(selection) \
      -buttonList {Horizontal Vertical Both} \
      -valueList {h v b} \
      -packOption {-side top} \
      -contextHelp "These buttons select various combinations of booster corrector supplies." \
      -gridPack "-column 0 -row 1 -columnspan 4"
    
    APSCheckButtonFrame .cb1 -parent $frame.right.frame -label "" \
      -packOption {-side top} \
      -buttonList {Fast "Raw Only"} \
      -variableList "APSMpBoosterPSAndCorrOnFullPower(Fast) APSMpBoosterPSAndCorrOnFullPower(RawOnly)" \
      -contextHelp "\"Fast\" mode does not load zero ramps when turning the supplies off.  \"Fast\" mode will not perform INIT/AUTO/ACTIVATE procedure before turning on.  \"Raw Only\" turns on only the raw supplies, loads 65 Volts as their setpoint and does this in \"Fast\" mode." \
      -gridPack "-column 0 -row 2 -columnspan 4"

    APSCheckButtonFrame .categorys -parent $bottom -label "Select SCR categories\nto restore" \
      -variableList {APSMpBoosterPSAndCorrOnFullPower(SCRAFG)    \
                       APSMpBoosterPSAndCorrOnFullPower(SCRBPM)  \
                       APSMpBoosterPSAndCorrOnFullPower(SCRBcontrol)  \
                       APSMpBoosterPSAndCorrOnFullPower(SCRRampTiming)  \
                       APSMpBoosterPSAndCorrOnFullPower(SCRDiag)  \
                       APSMpBoosterPSAndCorrOnFullPower(SCRExtPulsedPS) \
                       APSMpBoosterPSAndCorrOnFullPower(SCRExtTiming) \
                       APSMpBoosterPSAndCorrOnFullPower(SCRGlobalParameter) \
                       APSMpBoosterPSAndCorrOnFullPower(SCRInjPulsedPS) \
                       APSMpBoosterPSAndCorrOnFullPower(SCRInjTiming) \
                       APSMpBoosterPSAndCorrOnFullPower(SCRMainPS) \
                       APSMpBoosterPSAndCorrOnFullPower(SCRReadback) \
                       APSMpBoosterPSAndCorrOnFullPower(SCRScrapers) \
                       APSMpBoosterPSAndCorrOnFullPower(SCRSetpoint) \
                       APSMpBoosterPSAndCorrOnFullPower(SCRStatus) \
                       APSMpBoosterPSAndCorrOnFullPower(SCRSteeringPS) \
                       APSMpBoosterPSAndCorrOnFullPower(SCRSteeringSetpoint) \
                       APSMpBoosterPSAndCorrOnFullPower(SCRTiming) \
                       APSMpBoosterPSAndCorrOnFullPower(SCRTuneMeas)} \
      -buttonList {AFG BPM Bcontrol RampTiming Diag ExtPulsedPS ExtTiming GlobalParameter InjPulsedPS InjTiming MainPS Readback Scrapers Setpoint Status SteeringPS SteeringSetpoint Timing TuneMeas} \
      -limitPerRow 7 -orientation horizontal -allNone 1

    APSCheckButtonFrame .beamlines -parent $bottom -label "Select SCR beamline\nto restore" \
      -variableList {APSMpBoosterPSAndCorrOnFullPower(SCRBTS)    \
                       APSMpBoosterPSAndCorrOnFullPower(SCRBooster)  \
                       APSMpBoosterPSAndCorrOnFullPower(SCRPTB)  \
                       APSMpBoosterPSAndCorrOnFullPower(SCRPTB1)  \
                       APSMpBoosterPSAndCorrOnFullPower(SCRPTB2) \
                       APSMpBoosterPSAndCorrOnFullPower(SCRPTB3)} \
      -buttonList {BTS Booster PTB PTB1 PTB2 PTB3} \
      -limitPerRow 7 -orientation horizontal -allNone 1


    return
}

# Procedure launches parallel procedures to turn on/off each power supply selected.

proc APSMpBoosterPSAndCorrOnFullPower {args} {

    global status
    
    set BM 0
    set QF 0
    set QD 0
    set SF 0
    set SD 0
    set startupTime 12.0
    set startupSteps 6
    set selection b
    set Fast 0
    set RawOnly 0
    set coldStart 1
    set SCRFile ""
    foreach n {SCRAFG SCRBPM SCRBcontrol SCRDiag SCRExtPulsedPS SCRExtTiming SCRGlobalParameter SCRInjPulsedPS SCRInjTiming SCRMainPS SCRReadback SCRScrapers SCRSetpoint SCRStatus SCRSteeringPS SCRSteeringSetpoint SCRTiming SCRTuneMeas} {
        set $n 0
    }
    set SCRBcontrol 1
    set SCRRampTiming 1
    foreach n {SCRBTS SCRBooster SCRPTB SCRPTB1 SCRPTB2 SCRPTB3} {
        set $n 0
    }
    set SCRBooster 1
    APSStrictParseArguments {BM QF QD SF SD startupTime startupSteps selection Fast RawOnly coldStart SCRFile}

    global execMode

    if {$execMode != "Automatic"} {
        if {[catch {APScavget -list=BOO-ACIS:MCR:ExtInhibitLedM,BOO-ACIS:Status:AaTripM,BOO-ACIS:Status:CaTripM -num -printErrors -pend=10} acisState]} {
            APSMpReturn error "APSMpBoosterPSAndCorrOnFullPower: $acisState"
        }
        if {[lindex $acisState 0] != 0} {
            if {[APSPEMTKDialog .warningDialog -text "Booster is in an acis inhibit state."] == 1} {
                APSMpReturn error "APSMpBoosterPSAndCorrOnFullPower: Booster is in an acis inhibit state."
            }
        }
        if {([lindex $acisState 1] != 0) || ([lindex $acisState 2] != 0)} {
            if {[APSPEMTKDialog .warningDialog -text "Booster is in an acis trip state."] == 1} {
                APSMpReturn error "APSMpBoosterPSAndCorrOnFullPower: Booster is in an acis trip state."
            }
        }
    }

    set arrayName APSBPSControlPS
    global $arrayName
    APSMpGenericPSArraySetup -arrayName $arrayName \
      -SCRFile $SCRFile -system booster

    APSMpStep init -promptDialog "APSMpGenericPSDialog -packProc APSMpBoosterPSAndCorrOnFullPowerDialog -chooseSCR 1 -arrayName $arrayName -system Booster -frame " -vars {BM QF QD SF SD startupTime startupSteps selection Fast RawOnly coldStart SCRAFG SCRBPM SCRBcontrol SCRRampTiming SCRDiag SCRExtPulsedPS SCRExtTiming SCRGlobalParameter SCRInjPulsedPS SCRInjTiming SCRMainPS SCRReadback SCRScrapers SCRSetpoint SCRStatus SCRSteeringPS SCRSteeringSetpoint SCRTiming SCRTuneMeas SCRBTS SCRBooster SCRPTB SCRPTB1 SCRPTB2 SCRPTB3}
    #    APSMpStep init -promptDialog APSMpBoosterPSAndCorrOnFullPowerDialog -vars {BM QF QD SF SD startupTime startupSteps selection Fast RawOnly coldStart}

    set SCRFile $APSBPSControlPS(Filename)
    if {![file exists $SCRFile]} {
        APSMpReturn error "APSMpBoosterPSAndCorrOnFullPower: No SCR file selected"
    }

    set paramString ""
    foreach param {BM QF QD SF SD startupTime startupSteps selection Fast RawOnly coldStart SCRAFG SCRBPM SCRBcontrol SCRRampTiming SCRDiag SCRExtPulsedPS SCRExtTiming SCRGlobalParameter SCRInjPulsedPS SCRInjTiming SCRMainPS SCRReadback SCRScrapers SCRSetpoint SCRStatus SCRSteeringPS SCRSteeringSetpoint SCRTiming SCRTuneMeas SCRBTS SCRBooster SCRPTB SCRPTB1 SCRPTB2 SCRPTB3 SCRFile} {
        append paramString "$param=\"[set $param]\" "
    }
    catch {APSLogScriptAction \
             -procedure APSMpBoosterPSAndCorrOnFullPower \
             -action initialize \
             -state ok \
             -parameters $paramString}

    if {[catch {exec sdds2stream $SCRFile -parameter=SnapshotDescription -page=1 -noquotes} results]} {
        APSMpReturn error "APSMpBoosterPSAndCorrOnFullPower:: Invalid SCR file"
    }    
    if {[string first "Limited save:" $results] != -1} {
        APSMpReturn error "APSMpBoosterPSAndCorrOnFullPower:: LIMITED SAVE SCR files cannot be used for this procedure."
    }

    foreach magnet "BM QF QD SF SD" {
        lappend getStateCommand "B:${magnet}:VoltageRT.MODE"
    }
    if {[catch {APScavget -list=[join $getStateCommand ,] -num -pend=20} results]} {
        APSMpReturn error "APSMpBoosterPSAndCorrOnFullPower: $results"
    }
    set afgmode ""
    foreach result $results magnet "BM QF QD SF SD" {
        if {([set $magnet]) && ($result != 0)} {
            append afgmode "$magnet "
        }
    }
    foreach result $results magnet "BM QF QD SF SD" {
        if {([set $magnet]) && ($result != 0)} {
            if {[tk_dialog2 .warningDialog "Warning Message" \
                   "[join $afgmode ,] Voltage AFGs are in manual mode. These must be reset." \
                   warning -1 Continue "Abort Procedure"] == 1} {
                APSMpReturn error "APSMpBoosterPSAndCorrOnFullPower: User aborted"
                
                break
            }
        }
    }

    APSMpStep "Set booster power supplies ramping at full power" \
      -proc APSMpBoosterPSSetFullPower
    set PSOnOffID [APSMpParallel -procedure "APSMpBoosterPSSetFullPower -BM $BM -QF $QF -QD $QD -SF $SF -SD $SD -startupTime $startupTime -startupSteps $startupSteps -coldStart \"$coldStart\" -SCRFile $SCRFile -doRestore 0" -mode Automatic]
    update
    APSMpStep "Turn on corrector power supplies and load ramps" -proc APSMpBoosterSetCorrAndRampsOnOff
    set CorrectorOnOffID [APSMpParallel -procedure "APSMpBoosterSetCorrAndRampsOnOff -state1 on -selection $selection -Fast $Fast -RawOnly $RawOnly -SCRFile $SCRFile" -mode Automatic]

    APSMpAbort all -onError 1
    
    
    if {[catch {APSMpJoin [set PSOnOffID]} runStatus]} {
        APSSetVarAndUpdate status $runStatus
        set returnCode error
    }
    if {[catch {APSMpJoin [set CorrectorOnOffID]} runStatus]} {
        APSSetVarAndUpdate status $runStatus
        set returnCode error
    }

    set options ""
    set noptions 0
    set SCRBcontrol 1
    set SCRRampTiming 1
    foreach n {SCRAFG SCRBPM SCRBcontrol SCRDiag SCRExtPulsedPS SCRExtTiming SCRGlobalParameter SCRInjPulsedPS SCRInjTiming SCRMainPS SCRReadback SCRScrapers SCRSetpoint SCRStatus SCRSteeringPS SCRSteeringSetpoint SCRTiming SCRTuneMeas} m {AFG BPM Bcontrol RampTiming Diag ExtPulsedPS ExtTiming GlobalParameter InjPulsedPS InjTiming MainPS Readback Scrapers Setpoint Status SteeringPS SteeringSetpoint Timing TuneMeas} {
        if {[set $n]} {
            if {$noptions == 0} {
                set options "-match=column,Category=$m"
                incr noptions
            } else {
                append options ",Category=${m},|"
            }
        }
    }

    set options2 ""
    set noptions 0
    foreach n {SCRBTS SCRBooster SCRPTB SCRPTB1 SCRPTB2 SCRPTB3} m {BTS Booster PTB PTB1 PTB2 PTB3} {
        if {[set $n]} {
            if {$noptions == 0} {
                set options2 "-match=column,Beamline=$m"
                incr noptions
            } else {
                append options2 ",Beamline=${m},|"
            }
        }
    }

    if {([string length $SCRFile]) && ([llength $options]) && ([llength $options2])} {
        APSMpStep "Booster: Restore SCR Data"
        set tmpFile /tmp/[APSTmpString]
        if {[catch {exec sddsprocess $SCRFile $tmpFile \
                      -match=column,IsReadOnly=+y,! -match=column,IsProtected=+y,! \
                      -match=column,ControlName=BTS:?B:CurrentAO,! \
                      $options2 \
                      $options} result]} {
            APSMpReturn error "Error preparing data from $restoreFile for Booster: $result"
        }
        if {[catch {exec sddscasr -restore $tmpFile} result]} {
            tk_dialog2 .warningDialog "Warning Message" \
              "Problem restoring SCR file: APSMpBoosterPSAndCorrOnFullPower: $result" \
              warning -1 Continue
            catch {APSSendEMail -address soliday \
                     -subject "Problem restoring SCR file."  \
                     -message "Problem restore SCR file\nAPSMpPARStartUp\n${$SCRFile}\n$result"} 	    
        }
        if {[catch {exec rm $tmpFile} result]} {
            APSMpReturn error "Error cleaning up after file restore for Booster: $result"
        }
    }

    set returnCode ok

    APSMpReturn $returnCode
}

# This program first calls both APSMpBoosterPSSetNoPower and
# APSMpBoosterSetCorrAndRampsOnOff to turn both the main power
# supplies off with the corrector power supplies.

proc APSMpBoosterPSandCorrSetNoPowerInfo {} {

    return "This procedure runs APSMpBoosterPSSetNoPower under the \"Booster Main Ramped Supplies\" menu in parallel with APSMpBoosterSetCorrAndRampsOnOff under the \"Booster Correctors\" menu.  See the documents associated with these procedures for a detailed description of their function."
}

proc APSMpBoosterPSandCorrSetNoPowerDialog {frame} {

    APSSetVarAndUpdate status "Select booster power supplies..."

    APSCheckButtonFrame .magnetSelectButton -parent $frame -label "Select magnet\npower supplies" \
      -variableList {APSMpBoosterPSandCorrSetNoPower(BM)    \
                       APSMpBoosterPSandCorrSetNoPower(QF)  \
                       APSMpBoosterPSandCorrSetNoPower(QD)  \
                       APSMpBoosterPSandCorrSetNoPower(SF)  \
                       APSMpBoosterPSandCorrSetNoPower(SD)} \
      -buttonList {BM QF QD SF SD} \
      -allNone 1 \
      -packOption {-side top}

    label $frame.la1 -text "Set Booster Corrector\nPower Supply Options"
    pack $frame.la1 -side top

    APSRadioButtonFrame .rb2 -parent $frame -label "" \
      -variable APSMpBoosterPSandCorrSetNoPower(selection) \
      -buttonList {Horizontal Vertical Both} \
      -valueList {h v b} \
      -packOption {-side top} \
      -contextHelp "These buttons select various combinations of booster corrector supplies."
    
    return
}

# Sets selected booster power supplies ramping at full power.

proc APSMpBoosterPSandCorrSetNoPower {args} {

    set BM 0
    set QF 0
    set QD 0
    set SF 0
    set SD 0
    set selection b

    APSStrictParseArguments {BM QF QD SF SD selection}

    APSMpStep init -promptDialog APSMpBoosterPSandCorrSetNoPowerDialog -vars {BM QF QD SF SD selection}

    set paramString ""
    foreach param {BM QF QD SF SD selection} {
        append paramString "$param=\"[set $param]\" "
    }
    catch {APSLogScriptAction \
             -procedure APSMpBoosterPSandCorrSetNoPower \
             -action initialize \
             -state ok \
             -parameters $paramString}

    APSMpStep "Set booster power supplies to no power" \
      -proc APSMpBoosterPSSetNoPower
    set PSOffID [APSMpParallel -procedure "APSMpBoosterPSSetNoPower -BM $BM -QF $QF -QD $QD -SF $SF -SD $SD" -mode Automatic]
    update
    APSMpStep "Turn off corrector power supplies"
    set CorrectorOffID [APSMpParallel -procedure "APSMpBoosterSetCorrAndRampsOnOff -state1 off -selection $selection" -mode Automatic]

    APSMpAbort all -onError 1
    if {[catch {APSMpJoin [set CorrectorOffID]} runStatus]} {
        APSSetVarAndUpdate status $runStatus
        APSMpReturn error "APSMpBoosterPSandCorrSetNoPower: $runStatus"
    }
    if {[catch {APSMpJoin [set PSOffID]} runStatus]} {
        APSSetVarAndUpdate status $runStatus
        APSMpReturn error "APSMpBoosterPSandCorrSetNoPower: $runStatus"
    }

    APSMpReturn ok
}

#Check for one of four valid states
#1. Off with ramps disabled
#2. On in standby with ramps enabled
#3. On in DC standby with ramps enabled
#4. On in full power with ramps enabled
proc APSMpBoosterPSDetectValidStates {args} {
    set BM 0
    set QF 0
    set QD 0
    set SF 0
    set SD 0
    
    APSStrictParseArguments {BM QF QD SF SD}

    set magnets ""
    foreach m "BM QF QD SF SD" {
        if {[set $m]} {
            append magnets "$m "
        }
    }
    if {![llength $magnets]} {
        APSMpReturn ok
    }

    foreach magnet $magnets {
        set magnetIndex [lsearch -exact "BM QF QD SF SD" $magnet]
        if {[catch {APScavget -list=B:${magnet}:StatusCALC -pendIoTime=20} onState]} {
            APSMpReturn error "APSMpBoosterPSDetectState: $onState"
        }
        if {[catch {APScavget -list=It:Ddg4chan${magnetIndex}.GATE -pendIoTime=20} rampstate]} {
            APSMpReturn error "APSMpBoosterPSDetectState: $rampstate"
        }
        if {[catch {APScavget -list=B:${magnet}:VoltageRT.GAIN -pendIoTime=20 -numerical} presentPowerAFGGain]} {
            APSMpReturn error "APSMpBoosterPSDetectState: $presentPowerAFGGain"
        }
        if {$onState} {
            #Disable ramp to get PS into valid state
            APSMpStep "Disable slope and zero for $magnet" -desc "Disable slope and zero for magnet"
            if {[catch {APSMpBoosterDisableSlopeAndZero -magnet $magnet} results]} {
                APSMpReturn error "APSMpBoosterPSDetectState: $results"
            }
            APSMpStep "Disable ramp for $magnet" -desc "Disable ramp for magnet"
            if {[catch {APSMpBoosterPSEnableDisableRamps -magnet $magnet -state1 disable} results]} {
                APSMpReturn error "APSMpBoosterPSDetectState: $results"
            }
            #PS is off with ramps disabled
            continue
        }
        #PS is on
        if {$rampstate != "Enabled"} {
            APSMpReturn error "APSMpBoosterPSDetectState: $magnet is on but ramp is not enabled"
        }
        if {[catch {APSMpBoosterPSCheckIfDCStandbyPower -magnet $magnet} result]} {
            APSMpReturn error "APSMpBoosterPSDetectState: $result"
        }
        if {$result == 1} {
            #PS is in DC standby mode
            continue
        }
        if {$presentPowerAFGGain == .4} {
            #PS is in standby mode
            continue
        } elseif {$presentPowerAFGGain > .4} {
            #PS in in full power mode
            continue
        }
    }
    APSMpReturn ok
}








proc APSMpBPSTurnOnPulsedSuppliesInfo {} {
    return "This procedure turns on the B:IK B:EK kickers and the B:IS B:ES1 B:ES2 septums."
}


proc APSMpBPSTurnOnPulsedSuppliesDialog {frame} {
    global status APSMpBPSTurnOnPulsedSupplies
    APSCheckButtonFrame .ikButtons \
      -parent $frame \
      -label "Select Booster Kickers" \
      -variableList {APSMpBPSTurnOnPulsedSupplies(IK) APSMpBPSTurnOnPulsedSupplies(EK)} \
      -buttonList "B:IK B:EK" \
      -allNone 1
    APSCheckButtonFrame .isButtons \
      -parent $frame \
      -label "Select Booster Septums" \
      -variableList {APSMpBPSTurnOnPulsedSupplies(IS) \
                       APSMpBPSTurnOnPulsedSupplies(ES1) \
                       APSMpBPSTurnOnPulsedSupplies(ES2)} \
      -buttonList "B:IS B:ES1 B:ES2" \
      -allNone 1
    return 
}

proc APSMpBPSTurnOnPulsedSupplies {args} {
    set IS 0
    set IK 0
    set ES1 0
    set ES2 0
    set EK 0
    set SCRFile ""
    set doRestore 1
    APSStrictParseArguments {IS IK ES1 ES2 EK SCRFile doRestore}

    set arrayName APSBPSControlPS
    global $arrayName
    APSMpGenericPSArraySetup -arrayName $arrayName \
      -SCRFile $SCRFile -system booster

    APSMpStep init -promptDialog "APSMpGenericPSDialog -packProc APSMpBPSTurnOnPulsedSuppliesDialog -chooseSCR 1 -arrayName $arrayName -system Booster -frame " -vars "IS IK ES1 ES2 EK"

    set SCRFile $APSBPSControlPS(Filename)
    if {![file exists $SCRFile]} {
        APSMpReturn error "APSMpBPSTurnOnPulsedSupplies: No SCR file selected"
    }

    if {$doRestore} {
        if {[catch {exec sddsprocess $SCRFile -pipe=out "-match=column,ControlName=B:ES1:VoltageSetSendAO,ControlName=B:ES2:VoltageSetSendAO,|,ControlName=B:IS:VoltageSetSendAO,|,ControlName=B:IK:VoltageSetSendAO,|,ControlName=B:EK:VoltageSetSendAO,|" | sdds2stream -pipe=in -col=ControlName,ValueString} results]} {
            APSPEMTKDialog .warningDialog -strings Continue -default 0 -text "Problem restoring kicker and septum setpoints: $results"
        } else {
            foreach "vname vvalue" $results {
                set voltageSetPoints($vname) $vvalue
            }
        }
    }

    set KList ""
    set SList ""
    foreach k "IK EK" {
        if [set $k] {
            append KList "B:$k "
        }
    }
    foreach s "IS ES1 ES2" {
        if [set $s] {
            append SList "B:$s "
        }
    }
    if {(![llength $KList]) && (![llength $SList])} {
        APSMpReturn ok
    }

    if {[llength $SList]} {
        APSMpStep "Booster: Turn on Septums"
        foreach s $SList {
            APSMpStep "Booster: Turn on $s septum"
            set retries 10
            while {$retries} {
                if {![APScavget -list=${s}:StatusCALC]}  break
                if {[catch {APScavput -list=${s}:ResetSEQ=1} result]} {
                    APSMpReturn error "APSMpBPSTurnOnPulsedSupplies: Error sending on signal to $s septum: $result"
                }
                APSMpStep "Booster: Wait 30 seconds for $s septum to warmup"
                APSWaitWithUpdate -waitSeconds 30
                incr retries -1
            }
            if {!$retries} {
                if {[APSPEMTKDialog .warningDialog -text "Unknown problem turning on septum ${s}.\nYou may attempt to turn it on by hand and then click continue."] == 1} {
                    APSMpReturn error "APSMpBPSTurnOnPulsedSupplies: Unknown problem turning on septum."
                }
                set retries 1
            }
            if {$doRestore} {
                if {[catch {APScavput -list=${s}:VoltageSetSendAO=$voltageSetPoints(${s}:VoltageSetSendAO)} result]} {
                    APSMpReturn error "APSMpBPSTurnOnPulsedSupplies: $result"
                }
                if {[catch {APSMpBPSPulsedPSDischargeEnable -PSList [string range $s 2 end]} results]} {
                    APSMpReturn error "APSMpBPSTurnOnPulsedSupplies: $results"
                }
                APSMpStep "Booster: Wait for $s septum to reach operating voltage"
                set retries 180
                while {$retries} {
                    after 1000
                    if {[catch {APScavget -list=${s}:VoltageSetSendAO,${s}:DacAI} results]} {
                        APSMpReturn error "APSMpBPSTurnOnPulsedSupplies: $results"
                    }
                    set percentage [expr [lindex $results 1] / [lindex $results 0]]
                    if {$percentage > .95} {
                        break
                    }
                    incr retries -1
                }
                if {[catch {APSMpBPSPulsedPSDischargeEnable -PSList [string range $s 2 end] -disable 1} results]} {
                    APSMpReturn error "APSMpBPSTurnOnPulsedSupplies: $results"
                }
            }
            APSMpStep "Booster: Turn on $s septum succeeded"
        }
    }
    if {[llength $KList]} {
        APSMpStep "Booster: Warmup Kicker"
        if {[catch {APSMpWarmupKickers \
                      -kickerList $KList} result]} {
            if {[APSPEMTKDialog .warningDialog -text "APSMpSRTurnOnKickers: $result"] == 1} {
                APSMpReturn error "APSMpBPSTurnOnPulsedSupplies: $result"
            }
        }

        APSWaitWithUpdate -waitSeconds 5
        APSMpStep "Booster: Turn On Kickers HV"
        if {[catch {APScavput \
                      -list=[join $KList ,] \
                      -list=:OnBO=ON } result]} {
            APSMpReturn error "APSMpBPSTurnOnPulsedSupplies: $result"
        }
        APSWaitWithUpdate -waitSeconds 5
        if {[catch {APScavput -list=[join $KList ,] -list=:ResetBO=1} result]} {
            APSMpReturn error "APSMpBPSTurnOnPulsedSupplies: $result"
        }
        if {$doRestore} {
            foreach k $KList {
                if {[catch {APScavput -list=${k}:VoltageSetSendAO=$voltageSetPoints(${k}:VoltageSetSendAO)} result]} {
                    APSMpReturn error "APSMpBPSTurnOnPulsedSupplies: $result"
                }
            }
        }
    }
    
    APSMpReturn ok
}

proc APSMpBPSTurnOffPulsedSuppliesInfo {} {
    return "This procedure turns off the B:IK B:EK kickers and the B:IS B:ES1 B:ES2 septums."
}


proc APSMpBPSTurnOffPulsedSuppliesDialog {frame} {
    global status APSMpBPSTurnOffPulsedSupplies
    APSCheckButtonFrame .ikButtons \
      -parent $frame \
      -label "Select Booster Kickers" \
      -variableList {APSMpBPSTurnOffPulsedSupplies(IK) \
                       APSMpBPSTurnOffPulsedSupplies(EK)} \
      -buttonList "B:IK B:EK" \
      -allNone 1
    APSCheckButtonFrame .isButtons \
      -parent $frame \
      -label "Select Booster Septums" \
      -variableList {APSMpBPSTurnOffPulsedSupplies(IS) \
                       APSMpBPSTurnOffPulsedSupplies(ES1) \
                       APSMpBPSTurnOffPulsedSupplies(ES2)} \
      -buttonList "B:IS B:ES1 B:ES2" \
      -allNone 1
    return 
}
proc APSMpBPSTurnOffPulsedSupplies {args} {
    set IS 1
    set IK 1
    set ES1 1
    set ES2 1
    set EK 1
    APSStrictParseArguments {IS IK ES1 ES2 EK}

    set arrayName APSBPSControlPS
    global $arrayName
    APSMpGenericPSArraySetup -arrayName $arrayName -system booster

    APSMpStep init -promptDialog "APSMpGenericPSDialog -packProc APSMpBPSTurnOffPulsedSuppliesDialog -chooseSCR 0 -arrayName $arrayName -system Booster -frame " -vars "IS IK ES1 ES2 EK"

    APSMpStep "Turning off Booster pulsed power supplies"
    if {$IS} {
        APSMpStep "Turning off B:IS"
        if {[catch {APScavget -list=B:IS:StatusCALC} result]} {
            set result 1
        }
        if {[string equal 0 $result]} {
            if {[catch {APScavget -list=B:IS:DacAI} result]} {
                set result 0
            }
            if {$result >= 700} {
                APSMpStep "Lowering B:IS voltage"
                if {[catch {APScavput -list=B:IS:VoltageSetSendAO=690} result]} {
                }
                set try 1
                while {$try < 20} {
                    incr try
                    APSWaitWithUpdate -waitSeconds 1
                    if {[catch {APScavget -list=B:IS:DacAI} result]} {
                    } else {
                        if {$result >= 695} {
                            continue
                        }
                    }
                    break
                }
            }
            if {[catch {APScavput -list=B:IS:OffBO=1} result]} {
                APSMpReturn error "Error turning off B:IS: $result"
            }
        }
    }
    if {$IK} {
        APSMpStep "Turning off B:IK"
        if {[catch {APScavget -list=B:IK:StatusCALC} result]} {
            set result 1
        }
        if {[string equal 0 $result]} {
            if {[catch {APScavput -list=B:IK:OnBO=OFF} result]} {
                APSMpReturn error "Error turning off B:IK: $result"
            }
        }
    }
    if {$ES1} {
        APSMpStep "Turning off B:ES1"
        if {[catch {APScavget -list=B:ES1:StatusCALC} result]} {
            set result 1
        }
        if {[string equal 0 $result]} {
            if {[catch {APScavget -list=B:ES1:DacAI} result]} {
                set result 0
            }
            if {$result >= 700} {
                APSMpStep "Lowering B:ES1 voltage"
                if {[catch {APScavput -list=B:ES1:VoltageSetSendAO=690} result]} {
                }
                set try 1
                while {$try < 20} {
                    incr try
                    APSWaitWithUpdate -waitSeconds 1
                    if {[catch {APScavget -list=B:ES1:DacAI} result]} {
                    } else {
                        if {$result >= 695} {
                            continue
                        }
                    }
                    break
                }
            }
            if {[catch {APScavput -list=B:ES1:OffBO=1} result]} {
                APSMpReturn error "Error turning off B:ES1: $result"
            }
        }
    }
    if {$ES2} {
        APSMpStep "Turning off B:ES2"
        if {[catch {APScavget -list=B:ES2:StatusCALC} result]} {
            set result 1
        }
        if {[string equal 0 $result]} {
            if {[catch {APScavget -list=B:ES2:DacAI} result]} {
                set result 0
            }
            if {$result >= 700} {
                APSMpStep "Lowering B:ES2 voltage"
                if {[catch {APScavput -list=B:ES2:VoltageSetSendAO=690} result]} {
                }
                set try 1
                while {$try < 20} {
                    incr try
                    APSWaitWithUpdate -waitSeconds 1
                    if {[catch {APScavget -list=B:ES2:DacAI} result]} {
                    } else {
                        if {$result >= 695} {
                            continue
                        }
                    }
                    break
                }
            }
            if {[catch {APScavput -list=B:ES2:OffBO=1} result]} {
                APSMpReturn error "Error turning off B:ES2: $result"
            }
        }
    }
    if {$EK} {
        APSMpStep "Turning off B:EK"
        if {[catch {APScavget -list=B:EK:StatusCALC} result]} {
            set result 1
        }
        if {[string equal 0 $result]} {
            if {[catch {APScavput -list=B:EK:OnBO=OFF} result]} {
                APSMpReturn error "Error turning off B:EK: $result"
            }
        }
    }
    
    APSMpStep "Waiting up to 60 seconds for Booster Pulsed PS to turn off"
    set try 1
    while {$try < 60} {
        incr try
        APSWaitWithUpdate -waitSeconds 1
        if {$IS} {
            if {[catch {APScavget -list=B:IS:StatusCALC} result]} {
                set result 1
            }
            if {[string equal 0 $result]} {
                continue
            }
        }
        if {$IK} {
            if {[catch {APScavget -list=B:IK:StatusCALC} result]} {
                set result 1
            }
            if {[string equal 0 $result]} {
                continue
            }
        }
        if {$ES1} {
            if {[catch {APScavget -list=B:ES1:StatusCALC} result]} {
                set result 1
            }
            if {[string equal 0 $result]} {
                continue
            }
        }
        if {$ES2} {
            if {[catch {APScavget -list=B:ES2:StatusCALC} result]} {
                set result 1
            }
            if {[string equal 0 $result]} {
                continue
            }
        }
        if {$EK} {
            if {[catch {APScavget -list=B:EK:StatusCALC} result]} {
                set result 1
            }
            if {[string equal 0 $result]} {
                continue
            }
        }
        break
    }
    if {$try == 60} {
        if {[APSPEMTKDialog .warningDialog -text "Unable to turn off Booster pulsed power supplies"] == 1} {
            APSMpReturn error "Unable to turn off Booster pulsed power supplies"
        }
    }

    APSMpReturn ok
}


proc APSMpBPSPulsedPSDischargeEnable {args} {
    set PSList ""
    set disable 0
    APSStrictParseArguments {PSList disable}
    if [llength $PSList]==0 {
        return -code error "Empty PSList to APSMpBPSPulsedPSDischargeEnable."
    }

    # IS  It:Ddg3chan2.GATE
    # ES1 Mt:Ddg1chan4.GATE
    # ES2 Mt:Ddg1chan5.GATE
    # IK  It:Ddg2chan6.GATE
    # EK  Mt:Ddg1chan0.GATE
    set numList ""
    foreach elem $PSList {
        switch $elem {
            IS  { lappend numList It:Ddg3chan2 }
            ES1 { lappend numList Mt:Ddg1chan4 }
            ES2 { lappend numList Mt:Ddg1chan5 }
            IK  { lappend numList It:Ddg2chan6 }
            EK  { lappend numList Mt:Ddg1chan0 }
            default {
                return -code error "Invalid Pulsed PS: $elem"
            }
        }
    }

    if [catch {exec cavput -pend=10 -list=[join $numList ,] -list=.GATE=[expr !$disable]} result] {
        return -code error "Problem changing state of pulsed PS discharge: $result"
    }
}
