#!/bin/sh
# \
  exec oagwish "$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)]
set CVSRevisionAuthor "\$Revision: 1.64 $ \$Author: soliday $"

set magnetlist {BM QF QD SF-U SD} 
set magvarlist {BM QF QD SFU SD} 
set bcontrollist {Slope Zero}
set bcontrolvarlist {slope zero}
set archiveDirectory /home/helios/oagData/booster/rampLogFiles/VRamp/archivedData
set rampCorrectionErrorDirectory /home/helios/oagData/booster/rampLogFiles/VRamp/rampCorrErrorFiles
set allowedAccountList "booster carwar cyao sereno"

set ControlStatus "Ready"
set Gain .4
set SFU 0
set SF 0
set SD 0
set BM 0
set QD 0
set QF 0
set SDU 0
set magnetDelayPVList [list {It:Ddg8chan6.DLY} {It:Ddg6chan3.DLY} {It:Ddg8chan7.DLY} {It:Ddg9chan2.DLY} {It:Ddg9chan3.DLY} {It:Ddg9chan3.DLY}]

proc CheckSDorSDU {args} {
    global SD SDU SD0
    if [catch {exec cavget -list=B:SD-U:PoweredM -pend=10 -printErrors } SDstatus] {
        return -code error "Error reading B:SD-U:PoweredM: $SDstatus"
    }
    set SD $SD0
    set SDU $SD0
    switch $SDstatus {
        B:SD {
            set SDU 0
            #SD state
        }
        B:SD-U {
            #SD-U state
            set SD 0
        }
        default {
            #unknow state
            set SD 0
            set SDU 0
        }
    }
}
proc UpdateGlobals {args} {
    global rampCorrectionErrorDirectory IRamp archiveDirectory
    if $IRamp {
        set rampCorrectionErrorDirectory /home/helios/oagData/booster/rampLogFiles/IRamp/rampErrLogFiles
        set archiveDirectory /home/helios/oagData/booster/rampLogFiles/IRamp/archivedData
    } else {
        set rampCorrectionErrorDirectory /home/helios/oagData/booster/rampLogFiles/VRamp/rampErrLogFiles
        set archiveDirectory /home/helios/oagData/booster/rampLogFiles/VRamp/archivedData
    }
}
proc MakeBRampCorrMenuAndStatus {} {
    
    global ControlStatus CVSRevisionNumber CVSRevisionAuthor
    
    APSApplication . -name "Booster Ramp Control and Correction" -version $CVSRevisionAuthor \
      -overview "Operator Interface to the Booster Control and Correction Programs."
    
    APSMenubarAddMenu .correctors -parent .menu -text "Correctors"
    
    .menu.correctors.menu add command -label "Corrector Power Supply Control" \
      -command {exec BoosterCorrectorControl &}
    
    APSMenubarAddMenu .pstestramps -parent .menu -text "PS Test Ramps"

    .menu.pstestramps.menu add command -label "Load BM PS Test Ramp" \
      -command {LoadMagnetPSTestRamp -statusCallback SetStatus -supply BM}

    .menu.pstestramps.menu add command -label "Load QF PS Test Ramp" \
      -command {LoadMagnetPSTestRamp -statusCallback SetStatus -supply QF}

    .menu.pstestramps.menu add command -label "Load QD PS Test Ramp" \
      -command {LoadMagnetPSTestRamp -statusCallback SetStatus -supply QD}

    .menu.pstestramps.menu add command -label "Load SF-U PS Test Ramp" \
      -command {LoadMagnetPSTestRamp -statusCallback SetStatus -supply SF-U}

    .menu.pstestramps.menu add command -label "Load SD PS Test Ramp" \
      -command {LoadMagnetPSTestRamp -statusCallback SetStatus -supply SD}

    .menu.pstestramps.menu add command -label "Plot BM PS Test Ramp" \
      -command {PlotMagnetPSTestRamp -statusCallback SetStatus -supply BM}

    APSScrolledStatus .status -parent .userFrame -textVariable ControlStatus -width 75 -packOption {-side top}
}

proc MakePSRampControlFrameWidget {widget args} {

    set parent ""
    APSParseArguments {parent}

    APSFrame $widget -parent $parent \
      -height 30 \
      -packOption {-side left -expand 1}

    set w $parent$widget.frame
    MakeMagOnOffFrameWidget .magOnOff -parent $w
    MakeRampFunctionsFrameWidget .rampFunctionsFrame -parent $w
}

proc MakeMagOnOffFrameWidget {widget args} {

    set parent ""
    APSParseArguments {parent}

    APSFrame $widget -parent $parent -label "Magnet Power Supply On/Off" \
      -height 30 \
      -packOption {-side top}
    set w $parent$widget.frame

    APSButton .magson -parent $w \
      -text "On" \
      -command {magsonoff on -statusCallback SetStatus} \
      -packOption {-side left -expand 1} \
      -contextHelp "This button turns the booster magnet power supplies selected ON.  Will NOT turn the power supplies on if the ramps are enabled."

    APSButton .magsoff -parent $w \
      -text "Off" \
      -command {magsonoff off -statusCallback SetStatus} \
      -packOption {-side left -expand 1} \
      -contextHelp "This button turns the booster magnet power supplies selected OFF."
}

proc MakeRampFunctionsFrameWidget {widget args} {

    set parent ""
    APSParseArguments {parent}

    APSFrame $widget -parent $parent -label "Basic Ramp Control Functions" \
      -height 30 \
      -packOption {-side top -fill x} 
    set w $parent$widget.frame
    MakeAFGGainFrameWidget .gainFrame -parent $w
    MakeSwapSyncEnableDisableFrameWidget .swapSyncEnableDisableFrame -parent $w
    MakeRampPlotFrameWidget .rampPlotFrame -parent $w
}

proc MakeAFGGainFrameWidget {widget args} {

    set parent ""
    APSParseArguments {parent}

    APSFrame $widget -parent $parent \
      -height 30 \
      -packOption {-side top -fill x} 

    set w $parent$widget.frame
    APSLabeledEntry .gain -parent $w -width 7 \
      -textVariable Gain \
      -packOption {-side left} \
      -label "AFG Gain."

    APSButton .setgain -parent $w \
      -text "Set" \
      -command {setPSGain $Gain -statusCallback SetStatus} \
      -packOption {-side left} \
      -contextHelp "This button sets gain factor for the selected booster magnet power supply.  The new ramps are automatically \"Swapped\" and \"Synced\"."
    APSButton .transfer -parent $w -text "Transfer" \
      -command "TransferAFGGain" \
      -packOption {-side left} \
      -contextHelp "Transfer current afg gain for selected magnets to the safe ramps."
}

proc MakeSwapSyncEnableDisableFrameWidget {widget args} {

    set parent ""
    APSParseArguments {parent}

    APSFrame $widget -parent $parent \
      -height 30 \
      -packOption {-side top} 

    set w $parent$widget.frame

    APSButton .swap -parent $w \
      -text "Swap" \
      -command {swapsyncRamps swap -statusCallback SetStatus} \
      -packOption {-side left -expand 1} \
      -contextHelp "This button is used to swap the selected booster magnet power supply ramp to the foreground buffer."

    APSButton .sync -parent $w \
      -text "Sync" \
      -command {swapsyncRamps sync -statusCallback SetStatus} \
      -packOption {-side left -expand 1} \
      -contextHelp "This button synchronizes all booster magnet power supply ramps."

    APSButton .enable -parent $w \
      -text "Enable" \
      -command {enabledisableRamps enable -statusCallback SetStatus} \
      -packOption {-side left -expand 1} \
      -contextHelp "This button enables selected booster magnet power supply ramps."

    APSButton .disable -parent $w \
      -text "Disable" \
      -command {enabledisableRamps disable -statusCallback SetStatus} \
      -packOption {-side left -expand 1} \
      -contextHelp "This button disables selected booster magnet power supply ramps."
}

set ArchiveFlag 0
proc MakeRampPlotFrameWidget {widget args} {

    global ArchiveFlag
    set parent ""
    APSParseArguments {parent}

    APSFrame $widget -parent $parent -label "Plot Magnet Ramp Data" \
      -height 30 \
      -packOption {-side top} 
    
    set w $parent$widget.frame

    APSFrame .dIRampFrame -parent $w \
      -height 30 \
      -packOption {-side top}

    APSButton .plotdelInorm -parent $w.dIRampFrame.frame -text "dI/I" \
      -command "plotMagnetRamps dI/I -file {} -statusCallback SetStatus" \
      -packOption {-side left -expand 1} \
      -contextHelp "This button plots the selected booster magnet current relative error dI/I."

    APSButton .plotdelI -parent $w.dIRampFrame.frame  -text "dI" \
      -command "plotMagnetRamps dI -file {} -statusCallback SetStatus" \
      -packOption {-side left -expand 1} \
      -contextHelp "This button plots the selected booster magnet absolute current error dI."

    APSCheckButtonFrame .archiveWidget -parent $w.dIRampFrame.frame -label "" \
      -packOption {-side left -expand 1} \
      -buttonList "Archive" -variableList "ArchiveFlag" \
      -contextHelp "Checkbutton used to add the archive flag to the ramp plot data files."

    APSFrame .currentSafetyRampFrame -parent $w \
      -height 30 \
      -packOption {-side top}

    APSButton .plotCurrentRampsFrame -parent $w.currentSafetyRampFrame.frame \
      -text "Plot Output Voltage and Current Ramps" \
      -command "PlotCurrentRamps -statusCallback SetStatus" \
      -contextHelp "This button plots the magnet voltage and current ramps loaded in the ramping AFG's for comparison with the safety ramps." \
      -packOption "-side top"

    APSButton .plotsafetyramps -parent $w.currentSafetyRampFrame.frame \
      -text "Plot Safety Ramps" \
      -command "plotSafetyRamps -statusCallback SetStatus" \
      -packOption "-side top" \
      -contextHelp "This button plots selected booster magnet voltage safety ramps located in the directory /home/helios/oagData/booster/ramps/safety."
    
    APSButton .plotdifferenceramps -parent $w.currentSafetyRampFrame.frame \
      -text "Plot Voltage and Safety Ramp Difference" \
      -packOption "-side top"\
      -command "plotDifferenceRamps -statusCallback SetStatus" \
      -contextHelp "This button plots the difference between selected magnet voltage and current ramps and safety ramps."
    APSFrame .plot -parent $w.currentSafetyRampFrame.frame \
      -packOption "-side top"
    set plotFrame $w.currentSafetyRampFrame.frame.plot.frame
    APSCheckButtonFrame .cb -parent $plotFrame \
      -label "" -buttonList {"Display Magnet Electrical Parameters"} \
      -variableList displayMagnetPar  
    APSButton .plotarchivedramps -parent $plotFrame \
      -text "Plot Archived Ramps" \
      -command "plotArchivedRamps -statusCallback SetStatus" \
      -contextHelp "This button plots the selected magnet current ramps and safety ramps."
    
    
    #  APSButton .setreferenceramps -parent $w.currentSafetyRampFrame.frame \
      #    -text "Set Reference Ramp File" \
      #    -command "setReferenceRamps -statusCallback SetStatus" \
      #    -packOption "-side top" \
      #    -contextHelp "This button is used to set and define the reference ramp file"
}

proc MakePSSeletionCheckButtonFrameWidget {widget args} {

    global magnetlist magvarlist        
    set parent ""
    APSParseArguments {parent}

    APSFrame $widget -parent $parent -label "Booster Magnet\nPower Supplies" -width 50 \
      -height 30 \
      -packOption {-side left -expand 1}

    set w $parent$widget.frame
    APSCheckButtonFrame .bmags -parent $w -label "" \
      -packOption {-side top} \
      -buttonList {BM QF QD SF-U SD/SD-U} -variableList {BM QF QD SFU SD0} \
      -allNone 1 \
      -contextHelp "These checkbuttons are used to select the booster power supplies to be controlled."
}

proc MakeRampCorrectionBcontrolFrameWidget {widget args} {

    set parent ""
    APSParseArguments {parent}

    APSFrame $widget -parent $parent \
      -height 30 \
      -packOption {-side left -expand 1}
    set w $parent$widget.frame
    MakeSafetyRampControlFrameWidget .safetyRampFrame -parent $w
    MakeRampCorrectionFrameWidget .rampCorrectionFrame -parent $w
    MakeBcontrolFrameWidget .bconFrameWidget -parent $w
}

set IRamp 1
proc MakeSafetyRampControlFrameWidget {widget args} {

    set parent ""
    APSParseArguments {parent}
    global IRamp
    
    APSFrame $widget -parent $parent 
    $parent$widget.frame configure -bd 0
    
    APSRadioButtonFrame .ramptype -parent $parent$widget.frame  -label "Ramp type:"  -buttonList {VRamp IRamp} -valueList {0 1} \
      -variable IRamp -orientation horizontal -commandList {UpdateGlobals UpdateGlobals} 

    APSFrame .safety -parent $parent$widget.frame -label "Load/Generate Magnet Safety Ramps" \
      -height 30 \
      -packOption {-side top} 

    set w $parent$widget.frame.safety.frame
    
    APSButton .loadsafetyramps -parent $w \
      -text "Load" \
      -command "loadSafetyRamps -statusCallback SetStatus" \
      -packOption "-side left -expand 1" \
      -contextHelp "This button loads selected booster magnet safety ramps (using the program rampload) and copies the safety ramp files to the /home/helios/oagData/ramps/current directory." 

    APSButton .generatesafetyramps -parent $w \
      -text "Generate" \
      -command "GenerateSafetyRamps -statusCallback SetStatus" \
      -packOption "-side left -expand 1" \
      -contextHelp "This button generates selected booster magnet safety ramps (using the program rampload) through copung the ramps from current-IRamp to safety for BM, QF, QD, SF-U, and SD. For SD-U and SF-U, the safety ramp is generated from IRef." 
    # APSButton .resetafterIOCreboot -parent $w -text "Reset" -command "resetAfterIOCReboot -statusCallback SetStatus" -packOption "-side left -expand 1" -contextHelp "This button pushes Init for the selected power supplies, loads safety ramps located in the directory /home/helios/oagData/booster/ramps/safety for the selected power supplies, and finally puts the selected power supplies in Auto.  This procedure should be used only after an AFG IOC reboot.  Note:  Power supplies should be off when this button is pressed."
    #$w.resetafterIOCreboot.button configure -state disabled
}

proc CopyStartingRampTables {} {
    set currentrampdir "/home/helios/oagData/booster/ramps/current"
    set directory [APSInfoDialog [APSUniqueName .] -name "CopyStartingRampTables" \
                     -infoMessage "Enter the directory name to copy ramp tables from" \
                     -width 60]
    if {[string length $directory]==0 || ![file isdirectory $directory]} {
        return 
    }
    foreach root {BM QD QF SD SF} {
        global $root
        if {[subst \$$root]} {
            set filename $directory/${root}Vref.afg100
            if ![file exists $filename] {
                SetStatus "File for $root not found."
            } else {
                if [catch {file copy -force $currentrampdir/${root}Vref.afg100 \
                             $currentrampdir/${root}Vref.afg100.old
                    file delete -force $currentrampdir/${root}Vref.afg100
                    exec cp $filename $currentrampdir/${root}Vref.afg100} result] {
                    SetStatus "$result"
                    return
                } else {
                    SetStatus "$root copied from $directory."
                }
                # catch {exec chmod a+w $currentrampdir/${root}Vref.afg100}
            }
        }
    }
}

proc MakeRampCorrectionFrameWidget {widget args} {

    set parent ""
    APSParseArguments {parent}

    APSFrame $widget -parent $parent -label "Correct Magnet Ramps" \
      -height 30 \
      -packOption {-side top} 

    set w $parent$widget.frame
    APSButton .plotErrorRamps -parent $w -text "Correction\nError Plots" -command "plotRampCorrectionErrorData -statusCallback SetStatus" -contextHelp "This button allows selection and plotting of the archived correction error ramps for the main booster supplies."

    APSButton .vcorrectramps -parent $w \
      -text "Correct" \
      -command "correctMagnetRamps -statusCallback SetStatus" \
      -contextHelp "This button runs one iteration of the ramp correction script for the selected booster magnet power supplies (power supplies in voltage mode) and plots the magnet dI/I ramps.  The resulting corrected ramp is copied to /home/helios/oagData/booster/ramps/current directory." \
      -packOption "-side bottom"
}

proc MakeBcontrolFrameWidget {widget args} {

    set parent ""
    APSParseArguments {parent}

    APSFrame $widget -parent $parent -label "Bcontrol Startup\nand Control" \
      -height 30 \
      -packOption {-side top}

    set w $parent$widget.frame
    MakeBcontrolStartKillFrameWidget .bconStartKillFrame -parent $w
}

proc MakeBcontrolStartKillFrameWidget {widget args} {

    set parent ""
    APSParseArguments {parent}

    APSFrame $widget -parent $parent \
      -height 30 \
      -packOption {-side top -fill x} 

    set w $parent$widget.frame
    APSButton .start -parent $w \
      -text "Bcontrol Screen" \
      -command {startkillBcontrol start -statusCallback SetStatus} \
      -packOption {-side left -expand 1} \
      -contextHelp "This button starts the program Bcontrol on the current workstation.  Bcontrol corrects the magnet slope and zero parameters shot to shot."

    APSButton .kill -parent $w \
      -text "Kill" \
      -command {startkillBcontrol kill -statusCallback SetStatus} \
      -packOption {-side left -expand 1} \
      -contextHelp "This button kills the program Bcontrol if it is running.  Bcontrol corrects the magnet slope and zero parameters shot to shot."
    APSButton .info -parent $w \
      -text "Info" \
      -command "BControlInfo" \
      -packOption {-side left -expand 1} \
      -contextHelp "Bring up the medm screen of bcontrol."
}

proc BControlInfo {args} {
    
    exec medm -attach -x -macro RCPV=B:BMbcontrollawRC ./sr/psApp/APSRunControlSingle.adl &
    exec medm -attach -x -macro RCPV=B:QFbcontrollawRC ./sr/psApp/APSRunControlSingle.adl &
    exec medm -attach -x -macro RCPV=B:QDbcontrollawRC ./sr/psApp/APSRunControlSingle.adl &
    exec medm -attach -x -macro RCPV=B:SFbcontrollawRC ./sr/psApp/APSRunControlSingle.adl &
    exec medm -attach -x -macro RCPV=B:SDbcontrollawRC ./sr/psApp/APSRunControlSingle.adl &
}


proc SetStatus {text} {
    global ControlStatus
    set ControlStatus $text
    update
}

# Turns selected booster power supplies on and off.  Will not turn on any supply if the ramp is enabled or the DAC voltage
# is above 1 Volt.

proc magsonoff {state args} {
    
    global magvarlist magnetlist ControlStatus
    global BM QF QD SFU SD0 SD SDU

    APSParseArguments {statusCallback}

    set listindex 0
    set selectlist ""
    set onlist ""
    
    CheckSDorSDU
    set magList ""
    foreach magnet {BM QF QD SFU SD SDU} {
        if [set $magnet] {
            lappend magList $magnet
        }
    }
    if ![llength $magList] {
        if {$statusCallback!=""} {
            $statusCallback "No magnets selected."
        }
        return 1
    }
    foreach mag {SD-U SF-U} var {SDU SFU} rampPV {It:Ddg9chan3.GATE It:Ddg9chan2.GATE} {
        if [set $var] {
            if [catch {exec cavget -list=B:$mag:StatusCALC -printErrors -pend=20} onOffstatus] {
                return -code error "Error reading B:$mag:StatusCALC: $onOffstatus"
            }
            if {$state=="on"} {
                if !$onOffstatus {
                    if {$statusCallback!=""} {
                        $statusCallback "$mag is already on."
                    }
                } else {
                    SetStatus "Turning $mag on..."
                    if [catch {exec cavput -list=$rampPV=0 -pend=10 } result] {
                        return -code error "Error disable ramp before turning on SD-U: $result"
                    }
                    if [catch {exec cavput -list=B:$mag:Reset=1 -pend=10} result] {
                        return -code error "Error reset $mag: $result"
                    }
                    after 2000
                    if [catch {exec cavput -list=B:$mag:OnSEQ=1 -pend=10} result] {
                        return -code error "Error turn on $mag: $result"
                    }
                    after 2000
                    if [catch {exec cavget -list=B:$mag:StatusCALC -printErrors -pend=20} status] {
                        return -code error "Error reading B:$mag:StatusCALC: $status"
                    }
                    if !$status {
                        #   if [catch {exec cavput -list=$rampPV=1 -pend=10 } result] {
                        #       return -code error "Error enable ramp after turning on $mag: $result"
                        #   }
                    } else {
                        if {$statusCallback!=""} {
                            $statusCallback "$mag is not turned on, please check."
                        }
                    }
                    SetStatus "$mag is turned on."
                }
            } elseif {$state=="off"} {
                if $onOffstatus {
                    if {$statusCallback!=""} {
                        $statusCallback "$mag is already off."
                    }
                } else {
                    SetStatus "turning $mag off..."
                    if [catch {exec cavput -list=$rampPV=0 -pend=10} result] {
                        return -code error "Error disable ramp before turn off $mag: $result"
                    }
                    if [catch {exec cavput -list=B:$mag:OffSEQ=1 -pend=10} result] {
                        return -code error "Error turn off $mag: $result"
                    }
                    SetStatus "$mag is off."
                }
            }
        }
    }
    
    foreach magnet {BM QF QD SD} {
        if [set $magnet] {
            set cavgetCommand "exec cavget -list=It:Ddg4chan${listindex}.GATE"
            catch $cavgetCommand rampstate 
            set magnetDACVoltage [getPowerSupplyWformMax ${magnet}]
            set aboveThreshold [expr {($magnetDACVoltage > 1) ? 1 : 0}]
            lappend selectlist ${magnet}
            if {$state=="on" && $rampstate=="Disabled" && !${aboveThreshold}} {
                if {$statusCallback!=""} {
                    $statusCallback "Turning power supply $magnet on..."
                }
                if {[catch {exec cavput -list=B:${magnet}:ResetSEQ=1} results]} {
                    $statusCallback "Unable to connect to $magnet PV: $results"
                    bell
                }
                #catch {exec devSend B:$magnet on}
                lappend onlist ${magnet}
                after 1000
            } elseif {$state=="on" && $rampstate=="Enabled" && !${aboveThreshold}} {
                if {$statusCallback!=""} {
                    $statusCallback "$magnet ramp is enabled.  Disable before attempting to turn it on. Let this procedure finish before disabling the ramp.  The power supply $magnet will NOT be turned on."
                }
                APSAlertBox .alert -errorMessage "$magnet ramp is enabled.  Disable before attempting to turn it on.  Let this procedure finish before disabling the ramp.  The power supply $magnet will NOT be turned on."
                after 1000              
            } elseif {$state=="on" && $rampstate=="Enabled" && ${aboveThreshold}} {
                if {$statusCallback!=""} {
                    $statusCallback "$magnet ramp is enabled and DAC voltage is $magnetDACVoltage which is above the threshold level of 1 Volt.  To reset the DAC, toggle the ramp enable/disable for $magnet and leave the ramp DISABLED.  Let this procedure finish before trying to reset the DAC."
                }
                APSAlertBox .alert -errorMessage "$magnet ramp is enabled and DAC voltage is $magnetDACVoltage which is above the threshold level of 1 Volt.  To reset the DAC, toggle the ramp enable/disable for $magnet and leave the ramp DISABLED.  Let this procedure finish before trying to reset the DAC."
                after 1000              
            } elseif {$state=="on" && $rampstate!="Enabled" && ${aboveThreshold}} {
                if {$statusCallback!=""} {
                    $statusCallback "$magnet ramp DAC voltage is $magnetDACVoltage which is above the threshold level of 1 Volt.  To reset the DAC, toggle the ramp enable/disable for $magnet and leave the ramp DISABLED.  Let this procedure finish before trying to reset the DAC."
                }
                APSAlertBox .alert -errorMessage "$magnet ramp DAC voltage is $magnetDACVoltage which is above the threshold level of 1 Volt.  To reset the DAC, toggle the ramp enable/disable for $magnet and leave the ramp DISABLED.  Let this procedure finish before trying to reset the DAC."
                after 1000              
            } elseif {$state=="off"} {
                if {$statusCallback!=""} {
                    $statusCallback "Turning power supply $magnet off..."
                }
                if {[catch {exec cavput -list=B:${magnet}:OffBO=OFF} results]} {
                    $statusCallback "Unable to connect to $magnet PV: $results"
                    bell
                }
                #catch {exec devSend B:$magnet off}
                after 1000
            }
        }
        incr listindex
    }
    if {$state=="on" && $selectlist!="" && $onlist!=""} { 
        if {$statusCallback!=""} {
            $statusCallback "Magnet power supply(s) $selectlist selected.  $onlist power supplies turned on."
        }
        return 1
    } elseif {$state=="on" && $selectlist!="" && $onlist==""} {
        if {$statusCallback!=""} {
            $statusCallback "Magnet power supply(s) $selectlist selected.  No power supplies turned on."
        }
        return 1
    } elseif {$state=="off" && $selectlist!=""} {
        if {$statusCallback!=""} {
            $statusCallback "Magnet power supply(s) $selectlist turned off."
        }
        return 1
    } elseif {$selectlist==""} {
        if {$statusCallback!=""} {
            #  $statusCallback "No magnet power supply(s) selected."
        }
        return 0
    }
}

#transfer current AFG gain to safte ramps
proc TransferAFGGain {args} {
    global BM QF QD SFU SD0 IRamp SD SDU
    
    CheckSDorSDU
    
    if $IRamp {
        set safetyrampdir /home/helios/oagData/booster/ramps/IRamp
    } else {
        set safetyrampdir /home/helios/oagData/booster/ramps/VRamp
    }
    if ![APSYesNoPopUp "Are you sure to transfer current AFG gains and triggers to safety ramps?"] {
        return
    }
    foreach mag {SD-U SF-U} var {SDU SFU} delayPV {It:Ddg9chan3.DLY It:Ddg9chan2.DLY} {
        if [set $var] {
            SetStatus "transfer $mag AFG to safety ramp..."
            if [catch {exec cavget -list=B:$mag:CurrentRT.GAIN -pend=30} gain] {
                return -code error "Error in reading $mag I AFG gain: $gain"
            }
            if [catch {exec cavget -list=$delayPV -pend=10 } delay] {
                return -code error "Error in reading $mag I AFG delay: $delay"
            }
            set rampDir /home/helios/oagData/booster/ramps/IRamp/safety
            set newFile [APSNextGenerationedName -name ${mag}Iref.afg100-0000  -separator - -directory $rampDir -newFile 1]
            
            if [catch {exec sddsprocess $rampDir/${mag}Iref.afg100 $rampDir/$newFile -redefine=par,afgGain,$gain \
                         "-redefine=par,afgTrigger,$delay" -nowarnings } result] {
                return -code error "Error in transfer current afg gain to safety ramp: $result"
            }
            cd $rampDir 
            exec rm ${mag}Iref.afg100
            exec ln -s $newFile ${mag}Iref.afg100
            SetStatus "done for $mag."
        }
    }
    foreach magnet {BM QF QD SD} {
        if [set $magnet] {
            SetStatus "transfer $magnet AFG to safety ramp..."
            if [catch {exec cavget -list=B:${magnet}:VoltageRT.GAIN -pend=30} gain] {
                return -code error "Error in reading $magnet AFG gain: $gain"
            }
            set magnet1 [string index $magnet 0][string tolower [string index $magnet 1]]
            if [catch {exec cavget -list=It:Bs:${magnet1}VafgTrigAO.VAL -pend=30} trigger] {
                return -code error "Error in reading $magnet AFG trigger: $trigger"
            }
            if [catch {exec sddsprocess $safetyrampdir/safety/${magnet}Vref.afg100 -redefine=par,afgGain,$gain \
                         "-redefine=par,afgTrigger,$trigger" -nowarnings } result] {
                return -code error "Error in transfer current afg gain to safety ramp: $result"
            }
            SetStatus "done."
        }
    }
}

# Sets the gain for selected power supplies then hits Swap and Sync.

proc setPSGain {gainfactor args} {
    
    global magvarlist magnetlist ControlStatus
    global BM QF QD SFU SD0 SD SDU

    APSParseArguments {statusCallback}

    set gainList ""
    
    CheckSDorSDU
    
    if {$gainfactor > 1 || $gainfactor < 0} {
        if {$statusCallback!=""} {
            $statusCallback "Set power supply gain in the range 0 <= gain <= 1."
        }
        APSAlertBox .alert -errorMessage "Allowable gain range for the power supplies is 0 <= gain <= 1."
        return 0
    } else {
        foreach magnet {BM QF QD SD SD-U SF-U} var {BM QF QD SD SDU SFU} {
            if [set $var] {
                if {$magnet=="SD-U" || $magnet=="SF-U"} {
                    lappend gainList B:$magnet:CurrentRT
                } else {
                    lappend gainList B:$magnet:VoltageRT
                }
            }
        }
        if ![llength $gainList] {
            SetStatus "Error no magnet is chosen."
            return
        }
        if [catch {exec cavput -list=[join $gainList ,] -list=.GAIN=$gainfactor -pend=30} result] {
            return -code error "Error setting AFG gain: $result"
        }
        after 1000
        swapsyncRamps swap -statusCallback SetStatus
        swapsyncRamps sync -statusCallback SetStatus
        SetStatus "set AFG gain done."
    }
}

# Swaps and synchronizes selected booster magnet ramps.

proc swapsyncRamps {action args} {
    
    global magvarlist magnetlist ControlStatus
    global BM QF QD SFU SD0 SD SDU

    APSParseArguments {statusCallback}

    #check if swapsync server is running
    if [catch {exec cavget -list=B:SwapSyncRC.RUN -pend=30 -printErrors} swapServer] {
        return -code error "Error reading B:SwapSyncRC.RUN : $swapServer"
    }
    if $swapServer {
        #no need to swap when swap sever is running
        return
    }

    set listindex 0
    set selectlist ""
    set swaperrorlist ""
    set swapCommands ""
    set swapStateCommands ""
    set swapState ""
    set selectlist ""
    
    CheckSDorSDU
    
    if {$action=="swap"} {
        foreach magnet {BM QF QD SF-U SD SD-U} var {BM QF QD SFU SD SDU} {
            if [set $var] {
                lappend selectlist $magnet
                if {$magnet=="SD-U" || $magnet=="SF-U"} {
                    lappend swapPV "B:$magnet:CurrentRT"
                } else {
                    lappend swapPV "B:${magnet}:VoltageRT"
                }
            } 
        }
        if {$selectlist!=""} {
            if [catch {exec cavput -list=[join $swapPV ,] -list=.SWAP=1 } result] {
                return -code error "Error swap ramps: $result"
            }
            foreach magnet $selectlist {
                if {$magnet=="SD-U" || $magnet=="SF-U"} {
                    lappend swapState "B:${magnet}:CurrentRT"
                } else {
                    lappend swapState "B:${magnet}:VoltageRT"
                }
            }
            if [catch {exec cavget -list=[join $swapState ,] -list=.SEVR -pend=30 } swapList] {
                return -code error "Error reading swap state: $swapList"
            }
            foreach magnet $selectlist swap $swapList {
                if {$swap=="MAJOR"} {
                    lappend swaperrorlist $magnet
                }
            }
        }
        if {$swaperrorlist=="" && $selectlist!=""} { 
            if {$statusCallback!=""} {
                $statusCallback "Ramp(s) for magnet(s) $selectlist swapped."
            }
            return 1
        } elseif {$swaperrorlist!="" && $selectlist!=""} {
            if {$statusCallback!=""} {
                $statusCallback "Ramp(s) for $selectlist swapped. Swap error(s) for $swaperrorlist."
            }
            APSAlertBox .alert -errorMessage "Swap errors indicated for $swaperrorlist.  Check the ramp(s) and/or AFG gain setting(s) for $swaperrorlist."
            return 0
        } elseif {$selectlist==""} {
            if {$statusCallback!=""} {
                $statusCallback "No magnet power supply(s) selected."
            }
            return 0
        }
    } elseif {$action=="sync"} {
        if {$statusCallback!=""} {
            $statusCallback "Synchronizing all magnet ramps..."
        }
        exec cavput -list=B:PSAFG100SyncBO=1 -numerical
        after 1000
        if {$statusCallback!=""} {
            $statusCallback "Magnet ramps synchronized."
        }
        return 1
    }
}

#Enables or disables selected booster magnet ramps.

proc enabledisableRamps {action args} {

    global magvarlist magnetlist ControlStatus
    global BM QF QD SFU SD0 SD SDU

    APSParseArguments {statusCallback}
    
    set setList ""
    CheckSDorSDU
    set index 0
    foreach magnet {BM QF QD SF-U SD SD-U} var {BM QF QD SFU SD SDU} {
        if [set $var] {
            if {$magnet=="SD-U"} {
                set pv It:Ddg9chan3.GATE
            } elseif {$magnet=="SF-U"} {
                set pv It:Ddg9chan2.GATE
            }  else {
                set pv It:Ddg4chan$index.GATE
            }
            set rampstate [exec cavget -list=$pv]
            lappend selectlist $magnet
            
            if {$action=="enable" && $rampstate=="Disabled"} {
                lappend setList $pv=Enabled
            } elseif {$action=="disable" && $rampstate=="Enabled"} {
                lappend setList $pv=Disabled
            }
        }
        incr index
    }
    if ![llength $setList] {
        SetStatus "No magnets are selected or needed to be $action"
        return
    }
    if [catch {exec cavput -list=[join $setList ,] -pend=30 } result] {
        SetStatus "Error $action ramps: $result"
        return
    }
}

# Loads booster magnet power supply test ramps

proc LoadMagnetPSTestRamp {args} {

    global env
    APSStrictParseArguments {statusCallback supply}
    set psTestRampDir "/home/helios/OAG/oagData/booster/ramps/psTestRamps"
    
    if {$env(USER) != "psgroup"} {
        if {$statusCallback!=""} {
            $statusCallback "You must be logged in as the ps group account to use this procedure."
            $statusCallback "You also must be authorized by the ps group to load magnet test ramps."
        }
        return 0
    }
    set bcontrolstate [exec cavget -list=B:PSBcontrolRC.RUN]
    
    switch ${supply} {
        BM {
            if {$statusCallback!=""} {
                $statusCallback "Loading test ramp for $supply..."
            }
            if [catch {exec rampload ${psTestRampDir}/${supply}Vref_Test.afg100} result] {
                if {$statusCallback!=""} {
                    $statusCallback "Error loading test ramp for ${supply}: $result"
                }
                return -code error "$result"
            }
            if !$bcontrolstate {
                $statusCallback "Apply swamp and sync due to bcontrol not running."
                after 2000
                if [catch {exec cavput -list=B:BM:VoltageRT.SWAP=1 } result] {
                    return -code error "$result"
                }
                after 2000
                if [catch {exec cavput -list=B:PSAFG100SyncBO=1 } result] {
                    return -code error $result
                }
            } else {
                $statusCallback "bcontrol is running, skip swap and sync."
            }
            if {$statusCallback!=""} {
                $statusCallback "Test ramp for $supply loaded."
            }
            return 1
        }
        QF {
            if {$statusCallback!=""} {
                $statusCallback "Magnet $supply does not have a test ramp defined.  No action taken."
            }
            return 0
        }
        QD {
            if {$statusCallback!=""} {
                $statusCallback "Magnet $supply does not have a test ramp defined  No action taken."
            }
            return 0
        }
        SF {
            if {$statusCallback!=""} {
                $statusCallback "Magnet $supply does not have a test ramp defined.  No action taken."
            }
            return 0
        }
        SD {
            if {$statusCallback!=""} {
                $statusCallback "Magnet $supply does not have a test ramp defined.  No action taken."
            }
            return 0
        }
        default {
            if {$statusCallback!=""} {
                $statusCallback "Power supply $supply does not exist.\nPower supply must be one of BM, QF, QD, SF or SD."
            }
            return 0
        }
    }
}

proc PlotMagnetPSTestRamp {args} {

    global env
    APSStrictParseArguments {statusCallback supply}
    set psTestRampDir "/home/helios/OAG/oagData/booster/ramps/psTestRamps"
    
    switch ${supply} {
        BM {
            if {$statusCallback!=""} {
                $statusCallback "Plotting test ramp for $supply..."
            }
            if {[catch {exec sddsplot ${psTestRampDir}/${supply}Vref_Test.afg100 -col=RampTime,RampSetpoint} result]} {
                if {$statusCallback!=""} {
                    $statusCallback "Error plotting test ramp for ${supply}: $result"
                }
                return -code error "$result"

            }
            if {$statusCallback!=""} {
                $statusCallback "Test ramp for $supply plotted."
            }
            return 1
        }
        QF {
            if {$statusCallback!=""} {
                $statusCallback "Magnet $supply does not have a test ramp defined.  No action taken."
            }
            return 0
        }
        QD {
            if {$statusCallback!=""} {
                $statusCallback "Magnet $supply does not have a test ramp defined  No action taken."
            }
            return 0
        }
        SF {
            if {$statusCallback!=""} {
                $statusCallback "Magnet $supply does not have a test ramp defined.  No action taken."
            }
            return 0
        }
        SD {
            if {$statusCallback!=""} {
                $statusCallback "Magnet $supply does not have a test ramp defined.  No action taken."
            }
            return 0
        }
        default {
            if {$statusCallback!=""} {
                $statusCallback "Power supply $supply does not exist.\nPower supply must be one of BM, QF, QD, SF or SD."
            }
            return 0
        }
    }
}

proc GenerateSafetyRamps {args} {
    global BM QF QD SF SD0 IRamp SD SDU

    set statusCallback ""
    APSParseArguments {statusCallback}
    
    CheckSDorSDU
    
    set rampDir /home/helios/oagData/booster/ramps/IRamp
    foreach magnet {BM QF QD SD} {
        if [set $magnet] {
            if {$statusCallback!=""} {
                $statusCallback "Generating safety ramp for $magnet."
            }
            # exec cp $rampDir/safety/${magnet}Vref.afg100 $rampDir/safety/${magnet}Vref.afg100.old
            set newFile [APSNextGenerationedName -name ${magnet}Vref.afg100-0000 -separator - -directory $rampDir/safety -newFile 1]
            
            exec cp $rampDir/current-IRamp/${magnet}Vref.afg100 $rampDir/safety/$newFile
            cd $rampDir/safety
            exec rm ${magnet}Vref.afg100 
            exec ln -s $newFile ${magnet}Vref.afg100
        }
    }
    return
    foreach magnet {SD-U SF-U} var {SDU SFU} {
        if [set $var] {
            if {$statusCallback!=""} {
                $statusCallback "Generating safety ramp for $magnet."
            }
            set newFile [APSNextGenerationedName -name ${magnet}Iref.afg100-0000 -separator - -directory $rampDir/safety -newFile 1]
            if [catch {exec sddsprocess $rampDir/current-IRamp/IRef -pipe=out -redefine=par,afgGain,${magnet}AfgGain \
                         -redefine=par,afgTrigger,${magnet}TriggerDelay \
                         -redefine=col,RampTime,time -define=col,RampSetpoint,B:$magnet:CurrentWF \
                         -reprint=par,ControlName,B:$magnet:CurrentRT \
                         -reprint=par,ControlType,pv \
                         -redefine=par,RampBias,0 \
                         | sddsconvert -pipe -retain=col,RampTime,RampSetpoint \
                         -retain=par,afg*,ControlName,ControlType,RampBias \
                         | sddsprocess -pipe -proc=RampSetpoint,baselevel,Base -proc=RampSetpoint,max,Max \
                         | sddsprocess -pipe "-redefine=col,RampSetpoint,RampSetpoint Base - Max Base - / 0.95 *" \
                         | sddsinterp -pipe=in $rampDir/safety/$newFile -col=RampTime,RampSetpoint \
                         -sequence=2028,0,475 } result] {
                return -code error "Error generating SD-U safety: $result"
            }
            cd $rampDir/safety
            exec rm ${magnet}Iref.afg100
            exec ln -s $newFile ${magnet}Iref.afg100
        }
    }
}

#Loads selected booster magnet safety ramps.

proc loadSafetyRamps {args} {
    global BM QF QD SFU SD0 IRamp SD SDU
    APSParseArguments {statusCallback}

    if $IRamp {
        set desc IRamp
    } else {
        set desc VRamp
    }
    
    CheckSDorSDU
    
    foreach magnet {BM QF QD SD} {
        if [set $magnet] {
            if [catch {exec cavget -list=B:$magnet:AutoCorrectionControlRC.RUN -pend=10} running] {
                return -code error "Error reading  B:$magnet:AutoCorrectionControlRC.RUN: $running"
            }
            if $running {
                if [catch {exec cavget -list=B:$magnet:AutoCorrectionControlRC.DESC -pend=10} desc0] {
                    return -code error "Error reading  B:$magnet:AutoCorrectionControlRC.DESC: $desc0"
                }
                if [regexp {IRamp} $desc0] {
                    set IRamp0 1
                } else {
                    set IRamp0 0
                }
            } else {
                set IRamp0 $IRamp
            }
            if {$IRamp0 != $IRamp} {
                if ![APSYesNoPopUp "Warning, you are correcting $magnet in $desc mode, which is different from the auto ramp correction, do you really want to continue?"] {
                    if {$statusCallback!=""} {
                        $statusCallback "Correcting $desc for $magnet was aborted."
                    }
                    set $magnet 0
                    continue
                }
            }
            
        }
        
    }
    
    set selected ""
    foreach magnet {BM QF QD SFU SD SDU} {
        if [set $magnet] {
            lappend selected $magnet
        }
    }
    if ![llength $selected] {
        if {$statusCallback!=""} {
            $statusCallback "no magnets selected."
        }
        return
    }
    
    if {$statusCallback!=""} {
        $statusCallback "loading $selected safety ramps..."
    }
    
    if {$BM || $QF || $QD || $SD} {
        if [catch {APSBoosterLoadSafetyRamp -BM $BM -QF $QF -QD $QD -SF 0 -SD $SD -IRamp $IRamp \
                     -statusCallback "$statusCallback" -description "load safety ramps from BRampControl" } result] {
            return -code error $result
        }
    }
    if {$SDU} {
        if {$statusCallback!=""} {
            $statusCallback "loading SD-U safety ramps..."
        }
        if [catch {APSBoosterLoadSDUSafetyRamp -magnet SD-U} result] {
            return -code error "Error loading safety ramp for SD-U: $result"
        }
    }
    if {$SFU} {
        if {$statusCallback!=""} {
            $statusCallback "loading SF-U safety ramps..."
        }
        if [catch {APSBoosterLoadSDUSafetyRamp -magnet SF-U} result] {
            return -code error "Error loading safety ramp for SF-U: $result"
        }
    }
    if {$statusCallback!=""} {
        $statusCallback "done."
    }
}

#Plot selected booster magnet safety ramps.

proc plotSafetyRamps {args} {
    
    global magvarlist magnetlist ControlStatus magnetDelayPVList
    global BM QF QD SFU SD0 SD SDU

    APSParseArguments {statusCallback}
    
    CheckSDorSDU
    
    set listindex 0
    set selectlist ""
    
    set safetyrampdir "/home/helios/oagData/booster/ramps"
    set sddsplotCommand sddsplot
    set commonPlotCommands "-col=RampTime,RampSetpoint -sub=5,5 -graph=line,type=1"

    foreach magnet {BM QF QD SD} {
        if [set $magnet] {
            lappend selectlist $magnet
            set magnetDelayPV [lindex $magnetDelayPVList $listindex]
            set magnetInjTime [computeBeamInjectionTime $magnetDelayPV] 
            set magnetExtTime [computeBeamExtrationTime $magnetInjTime]
            set injStringCommand "-string=\$s5\$e,x=$magnetInjTime,y=0,scale=1,justify=rc,angle=90,linetype=4"
            set extStringCommand "-string=\$s5\$e,x=$magnetExtTime,y=0,scale=1,justify=rc,angle=90,linetype=6"
            set toplineCommand "-topline=Safety Ramp for $magnet"
            set filename "${safetyrampdir}/safety/${magnet}Vref.afg100 -end"
            set sddsplotCommand "$sddsplotCommand $commonPlotCommands \"$toplineCommand\" \"$injStringCommand\" \"$extStringCommand\" $filename "
        }
        incr listindex
    }
    if $SDU {
        lappend selectlist SDU
        #plot SDU safety ramp...
        exec sddsplot -col=RampTime,RampSetpoint /home/helios/oagData/booster/ramps/IRamp/safety/SD-UIref.afg100 "-topline=SD-U Safety Ramp"  &
    }
    if $SFU {
        lappend selectlist SDF
        #plot SDF safety ramp...
        exec sddsplot -col=RampTime,RampSetpoint /home/helios/oagData/booster/ramps/IRamp/safety/SF-UIref.afg100 "-topline=SD-F Safety Ramp"  &
    }
    if {$selectlist!=""} { 
        if {$statusCallback!=""} {
            $statusCallback "Plotting safety ramp(s) for $selectlist..."
        }
        APSExec -unixCommand "$sddsplotCommand"
        return 1
    } elseif {$selectlist==""} {
        if {$statusCallback!=""} {
            $statusCallback "No magnet power supply(s) selected."
        }
        return 0
    }
}

#Plot difference between selected booster magnet current and safety ramps.

proc plotDifferenceRamps {args} {
    
    global magvarlist magnetlist ControlStatus magnetDelayPVList
    global BM QF QD SFU SD0 SD SDU

    APSParseArguments {statusCallback}
    
    set listindex 0
    set selectlist ""
    #BM QF QD SF SD SD-U delay pv list
    
    set safetyrampdir "/home/helios/oagData/booster/ramps"
    set tmpfileName [APSTmpString]
    set sddsplotCommand sddsplot
    set commonPlotCommands "-col=RampTime,Difference -sub=5,5 -graph=line,type=1"
    set SD $SD0
    
    CheckSDorSDU
    
    set index 0
    foreach magnet {BM QF QD SD} {
        if [set $magnet] {
            lappend selectlist $magnet
            exec sddsconvert ${safetyrampdir}/current/${magnet}Vref.afg100 \
              ./${tmpfileName}_${magnet}VrefCurrent.afg100 \
              -rename=col,RampSetpoint=CurrentRampSetpoint
            exec sddsconvert ${safetyrampdir}/safety/${magnet}Vref.afg100 \
              ./${tmpfileName}_${magnet}VrefSafety.afg100 \
              -rename=col,RampSetpoint=SafetyRampSetpoint
            exec sddsxref -pipe=out ./${tmpfileName}_${magnet}VrefCurrent.afg100 \
              ./${tmpfileName}_${magnet}VrefSafety.afg100 \
              -take=SafetyRampSetpoint \
              | sddsprocess -pipe=in ./${tmpfileName}_${magnet}VrefCurrSafety.afg100 \
              "-define=col,Difference,CurrentRampSetpoint SafetyRampSetpoint -"
            APSAddToTempFileList ./${tmpfileName}_${magnet}VrefCurrent.afg100 ./${tmpfileName}_${magnet}VrefSafety.afg100 ./${tmpfileName}_${magnet}VrefCurrSafety.afg100
            set magnetDelayPV [lindex $magnetDelayPVList $index]
            set magnetInjTime [computeBeamInjectionTime $magnetDelayPV] 
            set magnetExtTime [computeBeamExtrationTime $magnetInjTime]
            set injStringCommand "-string=\\\$s5\\\$e,x=$magnetInjTime,y=0,scale=1,justify=rc,angle=90,linetype=4"
            set extStringCommand "-string=\\\$s5\\\$e,x=$magnetExtTime,y=0,scale=1,justify=rc,angle=90,linetype=6"
            set toplineCommand "-topline=Difference Between Current and Safety Ramps for $magnet"
            set filename "./${tmpfileName}_${magnet}VrefCurrSafety.afg100 -end"
            set sddsplotCommand "$sddsplotCommand $commonPlotCommands \"$toplineCommand\" \"$injStringCommand\" \"$extStringCommand\" $filename "
        }
        incr index
    }
    if {$selectlist!=""} { 
        if {$statusCallback!=""} {
            $statusCallback "Plotting difference between current and safety ramps for $selectlist..."
        }
        eval exec $sddsplotCommand &
        # APSDeleteTempFiles
        if {$statusCallback!=""} {
            $statusCallback "Done."
        }
        return 1
    } elseif {$selectlist==""} {
        if {$statusCallback!=""} {
            $statusCallback "No magnet power supply(s) selected."
        }
        return 0
    }
}

#Plot archived ramp data

proc plotArchivedRamps {args} {
    
    global archiveDirectory displayMagnetPar

    APSParseArguments {statusCallback}


    set dataFile [APSFileSelectDialog .dataFileSelectWidget \
                    -path ${archiveDirectory} \
                    -pattern bmon*.gz \
                    -title "Ramp data file selection"]
    
    plotMagnetRamps dI/I -file $dataFile -statusCallback SetStatus
    plotMagnetRamps dI -file $dataFile -statusCallback SetStatus
    if $displayMagnetPar {
        set tmpRoot /tmp/[APSTmpString]
        if [catch {exec sddsderiv -pipe=out $dataFile \
                     -differentiate=*current \
                     -versus=time \
                     | sddsxref -pipe $dataFile -transfer=par,* \
                     -take=*vout,*current \
                     | sddsprocess -pipe=in $tmpRoot.proc \
                     "-redefine=col,BMvoutModel,BM_R BMcurrent * BM_L BMcurrentDeriv * +,units=Volts" \
                     "-redefine=col,QFvoutModel,QF_R QFcurrent * QF_L QFcurrentDeriv * +,units=Volts" \
                     "-redefine=col,QDvoutModel,QD_R QDcurrent * QD_L QDcurrentDeriv * +,units=Volts" \
                     "-redefine=col,SFvoutModel,SF_R SFcurrent * SF_L SFcurrentDeriv * +,units=Volts" \
                     "-redefine=col,SDvoutModel,SD_R SDcurrent * SD_L SDcurrentDeriv * +,units=Volts" \
                     "-print=param,BM_RString,Resistance = %0.3f %s   Inductance = %0.3f %s\n,BM_R,BM_R.units,BM_L,BM_L.units" \
                     "-print=param,QF_RString,Resistance = %0.3f %s   Inductance = %0.3f %s\n,QF_R,QF_R.units,QF_L,QF_L.units" \
                     "-print=param,QD_RString,Resistance = %0.3f %s   Inductance = %0.3f %s\n,QD_R,QD_R.units,QD_L,QD_L.units" \
                     "-print=param,SF_RString,Resistance = %0.3f %s   Inductance = %0.3f %s\n,SF_R,SF_R.units,SF_L,SF_L.units" \
                     "-print=param,SD_RString,Resistance = %0.3f %s   Inductance = %0.3f %s\n,SD_R,SD_R.units,SD_L,SD_L.units" \
                 } result] {
            return -code error $result
        }
        if [catch {exec sddsprintout $tmpRoot.proc $tmpRoot.print \
                     "-title=Magnet Electrical Parameters measured from $dataFile." \
                     -par=*_RString } result] {
            return -code error $result
        }
        APSAddToTmpFileList -ID brampcontrol -fileList "$tmpRoot.proc $tmpRoot.print"
        APSFileDisplayWindow [APSUniqueName .] -fileName $tmpRoot.print \
          -width 80 -printCommand "enscript -r" 
        catch {exec sddsplot -layout=2,3 -graph=line,vary \
                 "-title=Comparison of Measured Voltage and Derived Voltage From Model" \
                 $tmpRoot.proc \
                 -col=time,BMvout  -leg=spec=Data \
                 -col=time,BMvoutModel  -leg=spec=Model \
                 -topline=@BM_RString -end \
                 -col=time,QFvout   -leg=spec=Data \
                 -col=time,QFvoutModel   -leg=spec=Model \
                 -topline=@QF_RString -end \
                 -col=time,QDvout   -leg=spec=Data \
                 -col=time,QDvoutModel   -leg=spec=Model \
                 -topline=@QD_RString -end \
                 -col=time,SFvout   -leg=spec=Data \
                 -col=time,SFvoutModel  -leg=spec=Model \
                 -topline=@SF_RString -end \
                 -col=time,SDvout  -leg=spec=Data \
                 -col=time,SDvoutModel  -leg=spec=Model \
                 -topline=@SD_RString & } result 
    }  
    set userCustomArguments "-groupBy=nameString -separate=nameString -scales=0,275,0,0"
    #    APSExec -unixCommand "quickSDDSplot -dataFileList $dataFile -userCustomArguments [list $userCustomArguments] -xNameFilter time -yNameFilter *"
    
    return 1
}


# Plot archived ramp correction error data and/or reference.

proc plotRampCorrectionErrorData {args} {
    
    global rampCorrectionErrorDirectory IRamp

    APSParseArguments {statusCallback}
    
    if {$statusCallback!=""} {
        $statusCallback "Select error file to plot."
    }
    set dataFile ""
    set dataFile [APSFileSelectDialog .dataFileSelectWidget \
                    -path ${rampCorrectionErrorDirectory} \
                    -pattern *.* \
                    -title "Ramp correction error file selection"]
    if {![string compare $dataFile ""]} {
        if {$statusCallback!=""} {
            $statusCallback "No file selected."
        }
        return 1
    } else {
        set dataFileRoot [file rootname [file tail $dataFile]]
        exec sddsplot -graph=line,vary -subticksettings=xdivisions=5,ydivisions=5 -title=${dataFileRoot} \
          -yScalesGroup=namestring "-xLabel=Time (ms)" "-topline=Correction Safety Difference Voltage Ramps" \
          -col=RampTime,RampSetpointCorrection $dataFile "-legend=specified=Correction" \
          -col=RampTime,RampSetpointSafety $dataFile "-legend=specified=Safety" \
          -col=RampTime,ChangeInRampSetpoint $dataFile "-legend=specified=Difference" \
          -yLabel=Difference \&
        
        if {$statusCallback!=""} {
            $statusCallback "Done."
        }
    }
    return 0
}

# Set the reference ramp file

proc setReferenceRamps {args} {
    
    global archiveDirectory allowedAccountList

    APSParseArguments {statusCallback}

    set currentUserAccount [exec whoami]
    if {![string compare [lsearch -exact $allowedAccountList $currentUserAccount] -1]} {
        if {$statusCallback!=""} {
            $statusCallback "Account $currentUserAccount does not have permission to change\nthe reference ramp file."
            $statusCallback "Accounts with permission are $allowedAccountList."
        }
        return 0
    }

    if {$statusCallback!=""} {
        $statusCallback "Select a file to define as the reference file."
    }

    set dataFile [APSFileSelectDialog .dataFileSelectWidget \
                    -path ${archiveDirectory} \
                    -pattern bmon*.sdds* \
                    -title "Ramp data file selection"]

    if {[file exists ${archiveDirectory}/Reference/bmonReference-0001.gz]} {
        set referenceFileList [lsort [glob ${archiveDirectory}/Reference/bmonReference-????.gz]]
        set currentReferenceFile [lindex $referenceFileList [expr [llength $referenceFileList] - 1]]
        set currentReferenceIndex [format %4.0f [lindex [split [lindex [split $currentReferenceFile "-"] 1] "."] 0]]
        set newReferenceIndex [format %04ld [expr $currentReferenceIndex + 1]]
        set newReferenceFile ${archiveDirectory}/Reference/bmonReference-${newReferenceIndex}.gz
    } else {
        set newReferenceFile ${archiveDirectory}/Reference/bmonReference-0001.gz
    }
    if {[file exists ${archiveDirectory}/Reference/bmonReference.gz]} {
        file delete -force ${archiveDirectory}/Reference/bmonReference.gz
    }
    exec cp $dataFile $newReferenceFile
    # catch {exec chmod a+w $newReferenceFile}
    set newReferenceFileRoot [file tail $newReferenceFile]
    exec ln -s $newReferenceFileRoot bmonReference
    file rename -force bmonReference ${archiveDirectory}/Reference/bmonReference.gz
    # catch {exec chmod a+w ${archiveDirectory}/Reference/bmonReference.gz}

    if {$statusCallback!=""} {
        $statusCallback "Reference file $newReferenceFile created."
    }

    return 1
}

# Correct selected booster magnet ramps using the shell procedure VcorrectAndCheck.

proc correctMagnetRamps {args} {
    
    global magvarlist magnetlist ControlStatus
    global BM QF QD SFU SD0 IRamp SD SDU

    APSParseArguments {statusCallback}
    if $IRamp {
        set desc IRamp
    } else {
        set desc VRamp
    }
    
    CheckSDorSDU
    
    set currenttime [clock format [clock seconds]]
    foreach param "currenttime BM QF QD SD" {
        append paramString "$param=\"[set $param]\" "
    }
    if {[catch {APSLogScriptAction \
                  -procedure BRampControl \
                  -action Correct \
                  -state ok \
                  -parameters $paramString} results]} {
    }
    

    set listindex 0
    set selectlist ""
    set errorList ""
    set sddsplotCommand sddsplot
    set commonPlotCommands "-col=RampTime,RampSetpoint -sub=5,5 -graph=line,type=1"
    foreach magnet {BM QF QD SD} {
        if [set $magnet] {
            if {$statusCallback!=""} {
                $statusCallback "Correcting $desc for $magnet."
            }
            if [catch {exec cavget -list=B:$magnet:AutoCorrectionControlRC.RUN -pend=10} running] {
                return -code error "Error reading  B:$magnet:AutoCorrectionControlRC.RUN: $running"
            }
            if $running {
                if [catch {exec cavget -list=B:$magnet:AutoCorrectionControlRC.DESC -pend=10} desc0] {
                    return -code error "Error reading  B:$magnet:AutoCorrectionControlRC.DESC: $desc0"
                }
                if [regexp {IRamp} $desc0] {
                    set IRamp0 1
                } else {
                    set IRamp0 0
                }
            } else {
                set IRamp0 $IRamp
            }
            if {$IRamp0 != $IRamp} {
                if ![APSYesNoPopUp "Warning, you are correcting $magnet in $desc mode, which is different from the auto ramp correction, do you really want to continue?"] {
                    if {$statusCallback!=""} {
                        $statusCallback "Correcting $desc for $magnet was aborted."
                    }
                    continue
                }
            }
            if $IRamp {
                if [catch {BoosterRampVCurrentCorrectAndCheck -supply $magnet -statusCallback SetStatus} result] {
                    APSAlertBox .alert -errorMessage "BoosterRampVCurrentCorrectAndCheck: $result"
                    after 2000
                    lappend errorList $magnet
                } else {
                    lappend selectlist $magnet
                }
            } else {
                if [catch {BoosterRampVCorrectAndCheck -supply $magnet -statusCallback SetStatus} result] {
                    APSAlertBox .alert -errorMessage "$result"
                    after 2000
                    lappend errorList $magnet
                } else {
                    lappend selectlist $magnet
                }
            }
        }
        incr listindex
    }
    if {$selectlist!="" && $errorList==""} { 
        if {$statusCallback!=""} {
            $statusCallback "$selectlist ramp(s) corrected."
        }
        return 1
    } elseif {$selectlist!="" && $errorList!=""} {
        if {$statusCallback!=""} {
            $statusCallback "$selectlist ramp(s) corrected.  $errorList ramp(s) had errors."
        }
        return 0
    } elseif {$selectlist=="" && $errorList!=""} {
        if {$statusCallback!=""} {
            $statusCallback "$errorList ramp(s) had errors."
        }
        return 0
    } elseif {$selectlist=="" && $errorList==""} {
        if {$statusCallback!=""} {
            $statusCallback "No magnet power supply(s) selected."
        }
        return 0
    }
}

#Plot selected booster magnet ramps (dI/I and dI).

proc plotMagnetRamps {quantity args} {
    
    global magvarlist magnetlist ControlStatus ArchiveFlag magnetDelayPVList 
    global BM QF QD SFU SD0 archiveDirectory IRamp SD SDU
    
    set file ""
    APSParseArguments {file statusCallback}
    
    set listindex 0
    set selectlist ""
    set dataFileUniqueLabel [APSOffsetDateInfo -today 1 -dateFormat Y-M-D]_[lindex [exec date] 3]

    global apsNetworkDomain
    if {(![string compare $apsNetworkDomain "accel.ntw0rk"]) || (![string compare $apsNetworkDomain "aps4.anl.gov"])} {
        set adir $archiveDirectory
    } else {
        set adir /tmp
    }
    
    if {![string compare $file ""]} {
        set archiveDataFile "${adir}/bmon${dataFileUniqueLabel}.sdds.gz"
    } else {
        set archiveDataFile $file
    }
    
    if {$quantity=="dI/I"} {
        set relCommonPlotCommands "-scale=0,270,-0.01,0.01 -sub=5,5"
        lappend sddsplotCommand $relCommonPlotCommands
    } elseif {$quantity=="dI"} {
        set absCommonPlotCommands "-scale=0,270,-1,1 -sub=5,5"
        lappend sddsplotCommand  $absCommonPlotCommands
    }
    
    if {$statusCallback!=""} {
        $statusCallback "Setting up to plot $quantity..."
        update
    }
    
    CheckSDorSDU
    set SD-U $SDU
    set SF-U $SFU

    foreach magnet {BM QF QD SF-U SD SD-U} {
        if [set $magnet] {
            lappend selectlist $magnet
            set magnetDelayPV [lindex $magnetDelayPVList $listindex]
            set magnetInjTime [computeBeamInjectionTime $magnetDelayPV]
            set magnetExtTime [computeBeamExtrationTime $magnetInjTime]
            set injStringCommand "-string=\$s5\$e,x=$magnetInjTime,y=0,scale=1.5,justify=rc,angle=90,linety=4"
            set extStringCommand "-string=\$s5\$e,x=$magnetExtTime,y=0,scale=1.5,justify=rc,angle=90,linety=6"
            if {$quantity=="dI/I"} {
                lappend sddsplotCommand "-col=time,${magnet}deltaI/I" "-graph=line,type=1"
            } elseif {$quantity=="dI"} {
                lappend sddsplotCommand "-col=time,${magnet}fitError" "-graph=line,type=1"
            } else {return 0}
            lappend sddsplotCommand "-topline=$quantity for $magnet" $injStringCommand $extStringCommand 
            set opt ""
            if {$quantity=="dI/I"} {
                if [file exist $archiveDataFile] {
                    set pars [exec sddsquery -par $archiveDataFile]
                    if [regexp {dI/I_rms} $pars] {
                        set opt -string=@${magnet}dI/I_rms,p=0.5,q=0.85,scale=1.5 
                    } 
                } else {
                    set opt -string=@${magnet}dI/I_rms,p=0.5,q=0.85,scale=1.5 
                }
            }
            if [string length $opt] {
                lappend sddsplotCommand $opt $archiveDataFile -end
            } else {
                lappend sddsplotCommand $archiveDataFile -end
            }
        }
        incr listindex
    }
    if {$selectlist!=""} { 
        if {$statusCallback!=""} {
            $statusCallback "Plotting $quantity for $selectlist..."
            update
        }
        if {![string compare $file ""]} {
            set startDir [exec pwd]
            cd $adir
            if $IRamp {
                if  [catch {exec BIRampWaveformMon -filename bmon${dataFileUniqueLabel}.sdds} result] {
                    return -code error "Error reading booster Iramp waveforms: $result"
                }
            } else {
                if  [catch {exec BRampWaveformMon -filename bmon${dataFileUniqueLabel}.sdds} result] {
                    return -code error "Error reading booster ramp waveforms: $result"
                }
            }
            
            cd $startDir
            catch {exec sddsprocess ${adir}/bmon${dataFileUniqueLabel}.sdds -define=param,ArchiveData,$ArchiveFlag,type=long}
            catch {exec rm ${adir}/bmon${dataFileUniqueLabel}.sdds~}
            catch {exec gzip ${adir}/bmon${dataFileUniqueLabel}.sdds}
            
            set pars [exec sddsquery -par $archiveDataFile]
            
            if [lsearch -exact $pars "Description"]>=0 {
                set opt1 -title=@Description
            } else {
                set opt1  ""
            }
            eval exec sddsplot $opt1 $sddsplotCommand  &
        } else {
            set pars [exec sddsquery -par $archiveDataFile]
            if [lsearch "Description" $pars] {
                set opt1 -title=@Description
            } else {
                set opt1  ""
            }
            eval exec sddsplot $opt1 $sddsplotCommand &
        }
        return 1
    } elseif {$selectlist==""} {
        if {$statusCallback!=""} {
            $statusCallback "No magnet power supply(s) selected."
            update
        }
        return 0
    }
}

# Acquire ramp data and do dI/I processing.

proc acquireAndProcessRampData {args} {

    global ControlStatus
    set filename ""
    if {![APSStrictParseArguments {filename}] || {$filename==""}} {
        print stderr "Please enter a valid filename."
        $statusCallback "Please enter a valid filename."
    }
    exec sddswmonitor -PVnames=B:BM:PSVoltageWF,B:QF:PSVoltageWF,B:QD:PSVoltageWF,B:SF:PSVoltageWF,B:SD:PSVoltageWF,B:BM:CurrentWF,B:QF:CurrentWF,B:QD:CurrentWF,B:SF:CurrentWF,B:SD:CurrentWF -dataType=short test.sdds


}

#Start and kill the ramp correction program Bcontrol.

proc startkillBcontrol {action args} {

    global ControlStatus BM QD QF SD SF SD SDU

    APSParseArguments {statusCallback}

    CheckSDorSDU
    
    if {$action=="start"} {
        exec controllaw -controlList bcontrollaw &
    } else {
        foreach magnet {BM SD QD QF} {
            global $magnet
            if [set $magnet] {
                if [catch {exec cavput -list=B:${magnet}bcontrollawRC.ABRT=1 -pend=30} result] {
                    return -code error "Error in killing $magnet bcontrol1: $result"
                }
                exec cawait -waitFor=B:${magnet}bcontrollawRC.RUN,equal=0
                if [catch {exec cavput -list=B:${magnet}bcontrollawRC.CLR=1 -pend=30} result] {
                    return -code error "Error in killing $magnet bcontrol2: $result"
                }
                if {$statusCallback!=""} {
                    $statusCallback "$magnet Bcontrol killed on $host."
                }
            }
        }
        return 1
    }
}


#Reinitialize selected AFGs after an IOC reboot.

proc resetAfterIOCReboot {args} {

    global magvarlist magnetlist ControlStatus
    global BM QF QD SFU SD SDU

    APSParseArguments {statusCallback}

    set listindex 0
    set initList ""
    CheckSDorSDU
    
    foreach magnet {BM QF QD SD} {
        if [set $magneet] {
            lappend selectlist $magnet
            lappend initList B:${magnet}:VoltageRT
            lappend initCommands "B:${magnet}:VoltageRT.MODE=INIT" ","
        }
    }
    if {$selectlist!=""} {
        if [catch {exec cavput -list=[join $initList ,] -list=.MODE=INIT -pend=30} result] {
            return -code error "Error initialize ramp: $result"
        }
        after 1000        
        loadSafetyRamps -statusCallback SetStatus -ignoreAuto 1
        after 1000
        if [catch {exec cavput -list=[join $initList ,] -list=.MODE=AUTO -pend=30} result] {
            return -code error "Error auto ramp: $result"
        }
        SetStatus "$selectlist AFG(s) set to AUTO. Reset procedure completed."
        return 1
    } elseif {$selectlist==""} {
        SetStatus "No magnet power supply(s) selected."
        return 0
    }
}


#Compute power supply DAC output voltage (max).

proc getPowerSupplyWformMax {magnet} {

    eval exec sddswmonitor /tmp/${magnet}.wf -PVnames=B:${magnet}:VoltageRefWF
    eval exec sddsprocess /tmp/${magnet}.wf /tmp/${magnet}Max.wf -process=B:${magnet}:VoltageRefWF,maximum,${magnet}Max
    set sddsCmd "exec sdds2stream /tmp/${magnet}Max.wf -param=${magnet}Max"
    catch $sddsCmd DACMax
    eval exec rm /tmp/${magnet}.wf
    eval exec rm /tmp/${magnet}Max.wf
    set maxMagnetDACVoltage [expr abs(($DACMax * 20 / 4096) - 10)]
    return [format "%.2f" $maxMagnetDACVoltage]
}

proc computeBeamInjectionTime {pvname} {
    #after start digitizer mode, now the start ramp and injection time are at the same point
    if [catch {exec  cavget -list=It:Bs:StartRamp2BsIp.VAL -pend=20 -printErrors } rampstart] {
        return -code error "Error reading rampstart It:Bs:StartRamp2BsIp.VAL: $rampstart"
    }
    if [catch {exec cavget -list=It:Ddg4chan5CC -pend=10 -printErrors} lastBunch] {
        return -code error "Error reading It:Ddg4chan5CC : $lastBunch"
    }
    return [format "%.1f" [expr $rampstart - $lastBunch]]
    if [catch {exec cavget -list=$pvname -pend=20 -printErrors} magnetDelay] {
        return -code error "Error reading $pvname : $magnetDelay"
    }
    set injTime [expr $rampstart - $magnetDelay]
    return [format "%.1f" $injTime]
}

proc computeBeamExtrationTime {injTime} {
    if [catch {exec cavget -list=A014-IETS:BTC:BInjectionCycleM,A014-IETS:BTC:BExtractionCycleM,A014-IETS:BTC:SRSetFreqM -pend=20 -printErrors -floatformat=%lf} results] {
        return -code error "Error reading A014-IETS:BTC:BInjectionCycleM,A014-IETS:BTC:BExtractionCycleM,A014-IETS:BTC:SRSetFreqM: $results"
    }
    set bInjectionCycle [lindex $results 0]
    set bExtractionCycle [lindex $results 1]
    set srFreq [lindex $results 2]
    set extTime [expr $injTime + (1000 * ($bExtractionCycle - $bInjectionCycle) / $srFreq)]
    
    return [format "%.1f" $extTime]
}

# Procedure to plot current booster magnet ramps

proc PlotCurrentRamps {args} {

    global magvarlist magnetlist ControlStatus  magnetDelayPVList
    global BM QF QD SF SD0 SD SDU SF-U SFU

    APSParseArguments {statusCallback}
    
    CheckSDorSDU 
    
    set SD-U $SDU
    set SF-U $SFU
    
    set listindex 0
    set timeStep [exec rpnl 514.609386800000038 527.0 /]
    set selectlist ""
    set filename "/tmp/BCurrentRamps[APSTmpString]"
    set sddswmonitorCommand ""
    set sddsconvertCommand ""
    set sddsplotCommand "sddsplot -yScalesGroup=nameString -graph=line,vary -leg -mode=y=norm"
    set sddsprocessCommand ""
    set sddscombineCommand ""

    if {$statusCallback!=""} {
        $statusCallback "Acquiring and processing current ramp data--please stand by..."
    }
    foreach magnet {BM QF QD SF SD SD-U SF-U} {
        if [set $magnet] {
            lappend selectlist $magnet
            set magnetDelayPV [lindex $magnetDelayPVList $listindex]
            set magnetInjTime [computeBeamInjectionTime $magnetDelayPV]
            set magnetExtTime [computeBeamExtrationTime $magnetInjTime]
            set injStringCommand "-string=\$s5\$e,x=$magnetInjTime,y=0,scale=1,justify=rc,angle=90,linetype=4"
            set extStringCommand "-string=\$s5\$e,x=$magnetExtTime,y=0,scale=1,justify=rc,angle=90,linetype=6"
            set toplineCommand "-topline=Reference Voltage and Current Ramps for $magnet"
            set titleCommand "-title=Magnet ${magnet}"
            set commonPlotCommands "-col=Time,${magnet}:Voltage -col=Time,${magnet}:Current -sub=5,5"
            set commonprocessCommands "-convert=col,${magnet}:Voltage,Volts,Volts,1 -convert=col,${magnet}:Current,Amps,Volts,1 {-redefine=col,Time,Index $timeStep * 20.0 -,units=ms}"
            lappend currPVList B:${magnet}:sCurrentWF
            lappend voltPVList B:${magnet}:sPSVoltageWF
            lappend sddsconvertCommand "B:${magnet}:sPSVoltageWF=${magnet}:Voltage,B:${magnet}:sCurrentWF=${magnet}:Current"
            lappend sddsprocessCommand "$commonprocessCommands"
            set sddsplotCommand "$sddsplotCommand $commonPlotCommands \"$toplineCommand\" \"$titleCommand\" \"$injStringCommand\" \"$extStringCommand\" ${filename}ConvUnits.sdds -end"
        }
        incr listindex
    }
    if {$selectlist!=""} { 
        set sddsconvertCommand [join $sddsconvertCommand {,}]
        set sddsconvertCommand "-rename=col, $sddsconvertCommand"
        set sddsconvertCommand [join $sddsconvertCommand {}]
        set sddsconvertCommand "sddsconvert $filename ${filename}Conv.sdds $sddsconvertCommand"
        set sddswmonitorCommand [join $sddswmonitorCommand {,}]
        set sddswmonitorCommand "-PVnames= $sddswmonitorCommand" 
        set sddswmonitorCommand [join $sddswmonitorCommand {}]
        set sddswmonitorCommand "sddswmonitor $filename $sddswmonitorCommand -steps=1"
        set sddsprocessCommand [join $sddsprocessCommand { }]
        set sddsprocessCommand "sddsprocess ${filename}Conv.sdds ${filename}ConvUnits.sdds $sddsprocessCommand"
        #eval exec $sddswmonitorCommand
        if [catch {exec sddswmonitor $filename.1 -erase -steps=1 -pv=[join $currPVList ,],[join $voltPVList ,] } result] {
            return -code error "Error in reading current and voltage waveforms: $result"
        }
        #here use index scaling instead of time interval scaling and ignores the timeshift of quards.
        if [catch {exec sddsprocess $filename.1 -pipe=out "-redefine=col,Index,Index 0.822896900695762 /" \
                     | sddsinterp -pipe=in $filename -sequence=527,0,526 \
                     -col=Index,*WF -aboveRange=saturate} result] {
            return -code error"Error interpolating voltage waveforms: $result"
        }
        file delete -force $filename.1
        eval exec $sddsconvertCommand
        eval exec $sddsprocessCommand
        if {$statusCallback!=""} {
            $statusCallback "Plotting Current ramp(s) for $selectlist..."
        }
        APSExec -unixCommand "$sddsplotCommand"
        return 1
    } elseif {$selectlist==""} {
        if {$statusCallback!=""} {
            $statusCallback "No magnet power supply(s) selected."
        }
        return 0
    }
}
UpdateGlobals
# Build Application
set displayMagnetPar 0
MakeBRampCorrMenuAndStatus
MakePSRampControlFrameWidget .psRampControl -parent .userFrame
MakePSSeletionCheckButtonFrameWidget .psSelectionCButtons -parent .userFrame
MakeRampCorrectionBcontrolFrameWidget .rampCorrBconFrame -parent .userFrame
