

proc APSMpSRFillFromZeroInfo {} {
    return "This procedure fills the ring from 0 mA to 102 mA. Standard bunch pattern is used. Several pre-injection checks are performed."
}
proc APSMpSRReFillInfo {} {
    return "This procedure fills the ring from to 102 mA. Standard bunch pattern is used. Several pre-injection checks are performed."
}
proc APSMpSRTopupInfo {} {
    return "This procedure starts top-up injection with a target of 102 mA. Standard bunch pattern is used. Several pre-injection checks are performed."
}
proc APSMpSRAbortTopupInfo {} {
    return "This procedure aborts top-up injection with a target of 102 mA. Standard bunch pattern is used. Several pre-injection checks are performed."
}

proc APSMpStartSIS1FeedforwardInfo {} {
    return "This procedure starts feedforward on S:IS1. The feedforward is based on the enable trigger history, with a low-pass filtered value calculated by sddscontrollaw. This replaces the temperature-based feedforward."
}

proc APSMpStopSIS1FeedforwardInfo {} {
    return "This procedure stops feedforward on S:IS1. The feedforward is based on the enable trigger history, with a low-pass filtered value calculated by sddscontrollaw. This replaces the temperature-based feedforward."
}

proc APSMpStartBES2FeedforwardInfo {} {
    return "This procedure starts feedforward on B:ES2. The feedforward is based on the enable trigger history, with a low-pass filtered value calculated by sddscontrollaw. The temperature-based feedforward is impossible to implement because the thermal probe doesn't respond to the pulsing."
}

proc APSMpStopBES2FeedforwardInfo {} {
    return "This procedure stops feedforward on B:ES2. The feedforward is based on the enable trigger history, with a low-pass filtered value calculated by sddscontrollaw. The temperature-based feedforward is impossible to implement because the thermal probe doesn't respond to the pulsing."
}

proc APSMpStartID11FeedforwardInfo {} {
    return "This procedure starts H1 feedforward on ID11 AC supply"
}

proc APSMpStopID11FeedforwardInfo {} {
    return "This procedure stops H1 feedforward on ID11 AC supply"
}

proc APSMpStartIDOffsetFeedforwardInfo {} {
    return "This procedure starts offset feedforward on ID gaps"
}

proc APSMpStopIDOffsetFeedforwardInfo {} {
    return "This procedure stops offset feedforward on ID gaps"
}

#Not used
proc APSMpSRFillFromZero {} {
    global apsTopupTarget apsBPMGroupCurrent
    APSMpStep PreInjectionChecks
    APSMpDoPreinjectionChecks -gapLimit 100

    APSMpStep StartSIS1Feedforward
    APSMpSIS1Feedforward -action start

    APSMpStep RetimeP0IfAppropriate
    APSMpRetimeP0IfAppropriate

    APSMpStep TogglePulsedMagnetEnables
    TogglePulsedMagnetEnables -location GuntoBoosterExt

    APSMpStep Inject
    DoIOCBunchTrainInjection -start 0 -interval 1 \
      -number 6 -multiplet 1 \
      -callback SetBunchTrainStatus \
      -stopAt $apsBPMGroupCurrent -useSum 0 -cycles 100 \
      -stopMode Estop \
      -keepWarm 0

    APSMpStep CreateAbortButton
    DoIOCBunchTrainInjection -start 54 -interval 54 \
      -number 21 -multiplet 1 \
      -callback SetBunchTrainStatus \
      -stopAt $apsTopupTarget -useSum 0 -cycles 100 \
      -stopMode Estop \
      -keepWarm 0
    APSMpSIS1Feedforward -action stop
    APSMpReturn ok 0
}

#Not used
proc APSMpSRReFill {} {
    global apsTopupTarget apsBPMSumTarget
    APSMpStep PreInjectionChecks
    APSMpDoPreinjectionChecks -gapLimit 10

    APSMpStep MoveScrapersIn
    APSMpSRToggleScrapers -position in

    APSMpStep StartSIS1Feedforward
    APSMpSIS1Feedforward -action start

    APSMpStep Inject
    DoIOCBunchTrainInjection -start 0 -interval 1 \
      -number 6 -multiplet 1 \
      -callback SetBunchTrainStatus \
      -stopAtSum $apsBPMSumTarget -useSum 1 -cycles 100 \
      -stopMode Estop \
      -keepWarm 0

    APSMpStep CreateAbortButton
    DoIOCBunchTrainInjection -start 54 -interval 54 \
      -number 21 -multiplet 1 \
      -callback SetBunchTrainStatus \
      -stopAt $apsTopupTarget -useSum 0 -cycles 100 \
      -stopMode Estop \
      -keepWarm 0

    APSMpSIS1Feedforward -action stop

    APSMpStep MoveScrapersOut
    APSMpSRToggleScrapers -position out
    APSMpReturn ok 0
}

#Not used
proc APSMpSRTopup {} {
    APSMpStep PreTopupChecks
    if [catch {APSMpPreTopupChecks} results] {
        APSReturn error "APSMpSRTopup: $results"
    }

    if [catch {APSTopupReadbackConnect} result] {
        APSSetVarAndUpdate bunchTrainStatus "$result"
    }

    APSMpStep SetupTopup
    APSMpSetupTopup

    APSMpStep StartSIS1Feedforward
    APSMpSIS1Feedforward -action start

    APSMpStep StartTopup
    APSMpStartTopup

    APSMpReturn ok 0
}

#Not used
proc APSMpStartTopup {} {
    set patternDir /home/helios/oagData/sr/bunchPatterns
    set targetPatternFile $patternDir/target
    set patternFile $patternDir/pattern
    set sortedPatternFile $patternDir/sorted

    set currentThreshold 0.1
    pv getw S35BeamCurrent
    if {$S35BeamCurrent < $currentThreshold} {
        APSMpReturn error "Beam current is too low for topup injection."
    }
    APSMpMakeTargetBunchPattern
}

#Not used
proc APSMpSRAbortTopup {} {
    APSMpStep StopTopup
    APSMpSIS1Feedforward -action stop
    APSMpReturn ok 0
}

#Used by SR PEM, APSMpOperator1Hz2HzSwitch and SROptimizeInjection
proc APSMpStartSIS1Feedforward {args} {
    APSMpStep init -promptDialog "APSMpPromptInitDialog"
    if [catch {APSMpSIS1Feedforward -action start} result ] {
        APSMpReturn error "APSMpStartSIS1Feedforward: $result"
    }
    APSMpReturn ok 0
}

#Used by SR PEM, APSMpOperator1Hz2HzSwitch and SROptimizeInjection
proc APSMpStopSIS1Feedforward {args} {
    APSMpStep init -promptDialog "APSMpPromptInitDialog"
    if [catch {APSMpSIS1Feedforward -action stop} result ] {
        APSMpReturn error "APSMpStopSIS1Feedforward: $result"
    }
    APSMpReturn ok 0
}

#Used by SR PEM and APSMpOperator1Hz2HzSwitch
proc APSMpStartBES2Feedforward {args} {
    APSMpStep init -promptDialog "APSMpPromptInitDialog"
    if [catch {APSMpBES2Feedforward -action start} result ] {
        APSMpReturn error "APSMpStartBES2Feedforward: $result"
    }
    APSMpReturn ok 0
}

#Used by SR PEM and APSMpOperator1Hz2HzSwitch
proc APSMpStopBES2Feedforward {args} {
    APSMpStep init -promptDialog "APSMpPromptInitDialog"
    if [catch {APSMpBES2Feedforward -action stop} result ] {
        APSMpReturn error "APSMpStopBES2Feedforward: $result"
    }
    APSMpReturn ok 0
}

#Used by SR PEM
proc APSMpStartIDOffsetFeedforward {args} {
    APSMpStep init -promptDialog "APSMpPromptInitDialog"
    if {0} {
        #check the bpm mode - scalar or vector
        if [catch {APSSRCheckCorrectorMode -plane h} hCorrMode] {
            APSMpReturn error "APSMpStartIDOffsetFeedforward :$hCorrMode"
        }
        if {$hCorrMode=="vector"} {
            #check if offset transfer is running
            if [catch {exec cavget -list=SR:CorrectorFFTransferRC.RUN -pend=30} result] {
                APSMpReturn error "APSMpStartIDOffsetFeedforward: $result"
            }
            if $result {
                if [catch {exec cavget -list=SR:CorrectorFFTransferRC.DESC -pend=30} description] {
                    APSMpReturn error "APSMpStartIDOffsetFeedforward: $description"
                }
                set desc "transferScalarstoWaveform"
                if [string compare $description $desc]!=0 {
                    set result 0
                }
            }
            if !$result {
                APSAlertBox .alert -errorMessage "DP offset transfer is not running, please run it first!"
                APSMpReturn ok
            }
        }
    }

    if [catch {APSMpIDOffsetFeedforward -action clear} result ] {
        APSMpReturn error "APSMpStartIDOffsetFeedforward: $result"
    }
    if [catch {APSMpIDOffsetFeedforward -action start} result ] {
        APSMpReturn error "APSMpStartIDOffsetFeedforward: $result"
    }
    APSMpReturn ok 0
}

#Used by SR PEM
proc APSMpStopIDOffsetFeedforward {args} {
    APSMpStep init -promptDialog "APSMpPromptInitDialog"
    if [catch {APSMpIDOffsetFeedforward -action stop} result ] {
        APSMpReturn error "APSMpStopIDOffsetFeedforward: $result"
    }
    APSMpReturn ok 0
}

#Used by SR PEM and SRBunchTrain
#Mode is never actually used when calling this procedure
proc APSMpSIS1Feedforward {args} {
    set mode TriggerHistory
    APSStrictParseArguments {action mode}
    set runControlPV S:IS1:ControlLawRC
    switch $action {
        start {
            set dataDir /home/helios/oagData/feedForwardFiles
            switch $mode {
                TriggerHistory {
                    # Gain is time interval divided by time constant.
                    # new time constant 5/13/2024 using first turn trajectory.
                    if [file exists $dataDir/.doFilter] {
                        if ![file exists $dataDir/SIS1.filter] {
                            APSMpReturn error "APSMpSIS1Feedforward: though filtering was requested (via existence of  .doFilter), file SIS1.filter doesn't exist."
                        }
                        set pid [exec sddscontrollaw $dataDir/SIS1.response \
                                   -proport \
                                   -interval=1 \
                                   -infinite \
                                   -gain=-1 \
                                   -filter=$dataDir/SIS1.filter \
                                   -runcontrolPV=string=${runControlPV} \
                                   "-runcontrolDescription=string=Trigger history feedforward"  &]
                    } else {
                        set pid [exec sddscontrollaw $dataDir/SIS1.response \
                                   -integral \
                                   -interval=1 \
                                   -infinite \
                                   -gain=-3.5e-02 \
                                   -runcontrolPV=string=${runControlPV} \
                                   "-runcontrolDescription=string=Trigger history feedforward"  &]
                    }
                }
                default {
                    set pid [exec sddsfeedforward $dataDir/SIS1.ffdata \
                               -interval=10 -infinite \
                               -averageOf=10,interval=1 \
                               -testValues=$dataDir/SIS1.tests -verb \
                               -runControlPV=string=$runControlPV,pingTimeout=12 \
                               "-runControlDescription=string=S:IS1 feedforward" &]
                }
            }
            if [catch {exec medm -x -attach -macro "RCPV=$runControlPV" \
                         /usr/local/iocapps/adlsys/sr/psApp/APSRunControlSingle.adl & } result ] {
                APSMpReturn error "APSMpSIS1Feedforward: $result"
            }
        }
        stop {
            if [catch {exec cavput -list=${runControlPV}.ABRT=1} result ] {
                APSMpReturn error "APSMpSIS1Feedforward: $result"
            }
            if [catch {exec medm -x -attach -macro "RCPV=$runControlPV" \
                         /usr/local/iocapps/adlsys/sr/psApp/APSRunControlSingle.adl & \
                     } result ] {
                APSMpReturn error "APSMpSIS1Feedforward: $result"
            }
        }
    }
    APSMpReturn ok 0
}

#Used by SR PEM and APSMpxBTSMatrix
#Mode is never actually used when calling this procedure
proc APSMpBES2Feedforward {args} {
    set mode TriggerHistory
    APSStrictParseArguments {action mode}
    set runControlPV B:ES2:ControlLawRC
    switch $action {
        start {
            switch $mode {
                TriggerHistory {
                    set dataDir /home/helios/oagData/feedForwardFiles
                    set pid [exec sddscontrollaw $dataDir/BES2.response \
                               -integral \
                               -interval=1 \
                               -infinite \
                               -gain=-6.789494e-03 \
                               -runcontrolPV=string=${runControlPV} \
                               "-runcontrolDescription=string=Trigger history feedforward"  &]
                    if [catch {exec medm -x -attach -macro "RCPV=$runControlPV" \
                                 /usr/local/iocapps/adlsys/sr/psApp/APSRunControlSingle.adl & \
                             } result ] {
                        APSMpReturn error "APSMpBES2Feedforward: $result"
                    }
                }
                default {
                    # temperature feedforward not working for BES2
                }
            }
        }
        stop {
            if [catch {exec cavput -list=${runControlPV}.ABRT=1} result ] {
                APSMpReturn error "APSMpBES2Feedforward: $result"
            }
            if [catch {exec medm -x -attach -macro "RCPV=$runControlPV" \
                         /usr/local/iocapps/adlsys/sr/psApp/APSRunControlSingle.adl & \
                     } result ] {
                APSMpReturn error "APSMpBES2Feedforward: $result"
            }
        }
    }
    APSMpReturn ok 0
}

#Not used
proc APSMpStartID11Feedforward {args} {
    APSMpStep init -promptDialog "APSMpPromptInitDialog"
    if [APSMultipleChoice [APSUniqueName .] -modal 1 \
          -question "Use of workstation-based ID11 feedforward should NOT be needed.  You should abort now unless you know there is a change in procedures for ID11." \
          -labelList "Abort Continue" \
          -returnList "1 0"] {
        APSMpReturn ok 0
    }
    APSMpStep StartingID11Feedforward
    if [catch {APSMpID11Feedforward -action start \
             } result ] {
        APSMpReturn error "APSMpStartID11Feedforward: $result"
    }
    APSMpReturn ok 0
}

#Not used
proc APSMpStopID11Feedforward {args} {
    APSMpStep init -promptDialog "APSMpPromptInitDialog"
    if [catch {APSMpID11Feedforward -action stop \
             } result ] {
        APSMpReturn error "APSMpStopID11Feedforward: $result"
    }
    APSMpReturn ok 0
}

#Not used
proc APSMpID11Feedforward {args} {
    APSStrictParseArguments {action}
    set dataDir /home/helios/oagData/feedForwardFiles
    set runControlPV S:ID11:FeedForward
    switch $action {
        start {
            set pid [exec sddsfeedforward $dataDir/ID11.ffdata \
                       -interval=0.5 -infinite \
                       -test=$dataDir/ID11.tests \
                       -runControlPV=string=$runControlPV,pingTimeout=12 \
                       "-runControlDescription=ID11 EMW feedforward" &]
            if [catch {exec medm -x -attach -macro "RCPV=$runControlPV" \
                         /usr/local/iocapps/adlsys/sr/psApp/APSRunControlSingle.adl & \
                     } result ] {
                APSMpReturn error "APSMpID11Feedforward: $result"
            }

        }
        stop {
            if [catch {exec cavput -list=${runControlPV}.ABRT=1} result ] {
                APSMpReturn error "APSMpID11Feedforward: $result"
            }
        }
    }
    APSMpReturn ok 0
}

#Used by SR PEM
proc APSMpStartIDFFExpert {args} {
    if [catch {APSMpIDOffsetFeedforward -action start -expert 1} result] {
        APSMpReturn error "Error start ID FF: $result"
    }
    APSMpReturn ok 0
}

#Used by SR PEM
proc APSMpIDOffsetFeedforward {args} {
    set action start
    set expert 0
    APSStrictParseArguments {action expert}
    set runControlPV S:ID:GapFeedForwardRC
    set runControlDESC GapFeedforward
    set FFfile FF
    set dataDir /home/helios/oagData/feedForwardFiles/IDgap
    set IDFFdone 0
    switch $action {
        start {

            if [catch {exec medm -x -attach -macro "RCPV=$runControlPV" \
                         /usr/local/iocapps/adlsys/sr/psApp/APSRunControlSingle.adl &} result ] {
                APSMpReturn error "APSMpIDOffsetFeedforward: $result"
            }
            if $expert {
                APSExecLog .idgapff -name "ID gap Feedforward"  -width 80 -lineLimit 1024 -height 30 \
                  -unixCommand "sddsfeedforward $dataDir/$FFfile \
                    -interval=1 \
                    -infinite \
                    -runcontrolPV=string=$runControlPV,pingTimeout=12 \
                    -runcontrolDescription=$runControlDESC -verbose" \
                  -abortCallback "set IDFFdone aborted" -cancelCallback "set IDFFdone cancelled" \
                  -callback "set IDFFdone 1"
                tkwait variable IDFFdone
                if {$IDFFdone!=1} {
                    APSMpReturn error "ID FF was $dispersionDone ."
                }
            } else {
                exec sddsfeedforward $dataDir/$FFfile \
                  -interval=1 \
                  -infinite \
                  -runcontrolPV=string=$runControlPV,pingTimeout=12 \
                  -runcontrolDescription=$runControlDESC  &
            }
        }
        abort -
        stop {
            if [catch {exec cavput -list=$runControlPV.ABRT=1 \
                     } result ] {
                APSMpReturn error "APSMpIDOffsetFeedforward: $result"
            }
        }
        clear {
            if [catch {exec cavput -list=$runControlPV.CLR=1 \
                     } result ] {
                APSMpReturn error "APSMpIDOffsetFeedforward: $result"
            }
        }
    }
    APSMpReturn ok 0
}

#Not used
proc APSMpSRToggleScrapers {args} {
    APSStrictParseArguments {position}
    set snapshotDir /home/helios/oagData/SCR/snapshots/SR
    switch $position {
        in {
            set file $snapshotDir/scrapersIn
        }
        out {
            set file $snapshotDir/scrapersOut
        }
    }
    if ![file exists $file] {
        APSMpReturn error "APSMpSRToggleScrapers: Can't find file $file."
    }
    exec sddscasr -restore $file
    APSMpReturn ok
}

#Not used
proc APSMpDoPreinjectionChecks {args} {
    global  bpmGroupSumUse
    set snapDir /home/helios/oagData/SCR/snapshots/SR
    set gapLimit 0
    APSStrictParseArguments {gapLimit}

    set BPLDList [APSIDSectorList -numberFormat %ld]
    if [catch {exec cavput -list=S -list=[join $BPLDList ,] \
                 -list=BPLD:ResetBO=1 -pendIoTime=5
        exec cavput -list=S -range=beg=1,end=40,interval=2 -list=:MPS:resetBO=1 -pendIoTime=5
        exec cavput -list=S:MPS:resetSQ.PROC=1  -pendIoTime=5
        exec cavput -list=S: -range=beg=1,end=40,format=%02ld -list=:MPS:LC: -list=1 \
                 -list=:RstLatchBO=1 -pend=10
        #        exec cavput -list=S: -range=beg=15,end=34,format=%02ld -list=:MPS:LC: -list=2 -list=:RstLatchBO=1 -pend=10
    } result] {
        APSMpReturn error "APSMpDoPreinjectionChecks: Problem resetting the MPS: $result"
    }
    APSMpStep "Checking ID gap and BTS state prior to injection..."
    if {$gapLimit>0} {
        set gapLimitData [APSIDMinimumActualGap]
        if {[lindex $gapLimitData 0]<$gapLimit} {
            APSMpReturn error "Can't inject with gap below $gapLimit (ID[lindex $gapLimitData 1])"
        }
    }
    if [catch {exec cavget -numerical -list=BTS:FS -list=2,3,4,5,6 \
                 -list=:act_cont_bo} BTSFlagStatus] {
        APSMpReturn error "Can't read BTS flag statuses: $BTSFlagStatus."
    }
    set i 0
    set flagIsIn 0
    foreach flag {2 3 4 5 6} {
        if [expr [lindex $BTSFlagStatus $i] == 1] {
            set flagIsIn 1
            APSMpReturn error "BTS Flag BTS:FS${flag} is in."
        }
        incr i
    }
    if $flagIsIn {
        APSMpReturn error "A BTS Flag is in."
    }
    APSMpStep "Checking kicker status..."
    if [catch {exec cavget -pend=5 -numerical -list=S:IK -list=1,2,3,4 \
                 -list=:StatusCALC} kickerStatus] {
        APSMpReturn error "Can't read kicker statuses: $kickerStatus"
    }
    set i 0
    set kickerIsOff 0
    foreach kicker {1 2 3 4} {
        if [expr [lindex $kickerStatus $i] != 0] {
            set kickerIsOff 1
            APSMpReturn error "Kicker S:IK${kicker} is off."
        }
        incr i
    }
    if $kickerIsOff {
        APSMpReturn error "Kicker S:IK${kicker} is off."
    }
    # compare present kicker settings with User beam prefered file
    # for re-fills only.
    if $bpmGroupSumUse {
        APSMpStep "Checking kicker setpoint against SR-UserBeamPreferred.gz..."
        set kickerFile /tmp/[APSTmpString]
        exec sddsprocess $snapDir/SR-UserBeamPreferred.gz ${kickerFile}.userSetpoint \
          -match=col,ControlName=S:IK?:VoltageSetSendAO \
          -scan=col,UserValue,ValueString,%lf
        exec sddsprocess ${kickerFile}.userSetpoint ${kickerFile}.userDAC \
          -reedit=col,ControlName,%/VoltageSetSendAO/DacAI/
        exec sddscombine ${kickerFile}.userSetpoint ${kickerFile}.userDAC \
          ${kickerFile}.user -merge
        exec burtrb  -f ${kickerFile}.user -o ${kickerFile}.settings
        exec sddsxref ${kickerFile}.settings $kickerFile.user -pipe=out \
          -match=ControlName -take=UserValue \
          | sddsprocess -pipe=in ${kickerFile}.diff \
          -scan=col,PresentValue,ValueString,%lf \
          "-def=col,DeltaValue,PresentValue UserValue -,description=Difference between present settings and saved User setting" \
          -proc=DeltaValue,largest,DeltaValueLargest \
          -proc=DeltaValue,largest,BadKicker,position,functionOf=ControlName
        set largestDelta [exec sdds2stream ${kickerFile}.diff -para=DeltaValueLargest]
        set badKicker [exec sdds2stream ${kickerFile}.diff -para=BadKicker]
        if {abs($largestDelta) > 1.0 } {
            APSMpReturn error "Kicker PV $badKicker is different from the corresponding UserBeamPrefered setpoint by $largestDelta"
        }
    }
    APSMpStep "Checking BPLD status..."
    if [catch {exec cavget -list=S:MPS:readyCC} MPSstatus] {
        APSMpReturn error "Can't read MPS status: $MPSstatus."
    }
    if !$MPSstatus {
        APSMpReturn error "MPS is tripped.  Can't inject."
    }
    # set nameList [list "configuration error" "limit error" "lock off" "pending trip"]
    # set PVSuffixList [list BPLD:SCDUconfigErrCC.VAL BPLD:LimitErrCC.VAL \
      #                        BPLD:limitsLockBI.VAL BPLD:TripPendingCC.VAL]
    # 06/12/2013 H. Shang BPLD:SCDUconfigErrCC.VAL BPLD:LimitErrCC.VAL no longer exist
    set nameList [list "lock off" "pending trip"]
    set PVSuffixList [list BPLD:limitsLockBI.VAL BPLD:TripPendingCC.VAL]
    set index -1
    foreach name $nameList {
        incr index
        if [catch {exec cavget -list=S -list=[join $BPLDList ,] \
                     -list=[lindex $PVSuffixList $index]} result] {
            APSMpReturn error "Problem reading [lindex $nameList $index] status: $result"
        }
        if [string first 1 [join $result] ]!=-1 {
            setStatus "One or more BPLDs have a [lindex $nameList $index]."
            APSMpReturn error 0
        }
    }
    APSMpReturn ok
}

#Not used
proc APSMpPreTopupChecks {} {
    APSMpStep "Make sure of beam switch state."
    if [catch {APSSRGetBeamSwitchState} switchState] {
        APSMpReturn error "APSMpPreTopupChecks: $switchState"
    }
    if [string compare $switchState dump]==0 {
        APSMpReturn error "APSMpPreTopupChecks: Error: beam is at the dump."
    }
    APSMpReturn ok
}

#Not used
proc APSMpSetupTopup {} {
    global apsPreTopupControllawMode apsTopupTarget apsTopupBunches
    APSMpStep "Move booster H scraper in."
    catch {exec cavput -list=B:HSC2:SM:sm=1}
    APSMpStep "Saving pre-topup controllaw mode"
    if [catch {exec cavget -list=S: \
                 -list=S:IS1:ControlLaw,BTS:ControlLawX,BTS:ControlLawY \
                 -list=RC.SUSP -cavputForm} \
          controllawMode] {
        APSMpReturn error "APSMpSetupTopup: $result"
    }
    # set up SIS1 to pulse with every pulsed magnet
    catch {exec cavput -list=Mt:SRinjectMultiExcludSIS1BO=0}
    catch {APSMpApplySIS1Setpoints}
    catch {TogglePulsedMagnetEnables -location GuntoBoosterExt}
    catch {APSMpSetupMultiBunchInject}
    APSMpReturn ok
}

#Not used
proc APSMpApplySIS1Setpoints {} {
    global apsTopupBunches apsSIS1Setpoint1 apsSIS1Setpoint2
    if {$apsTopupBunches>1} {
        set SIS1Setpoint $apsSIS1Setpoint2
    } else {
        set SIS1Setpoint $apsSIS1Setpoint1
    }
    APSMPStep "Setting IS1 to $SIS1Setpoint"
    if [catch {exec cavput -pend=10 -list=S:IS1:VoltageSetSendAO=$SIS1Setpoint} result] {
        APSMpReturn error "APSMpApplySIS1Setpoints: Error setting up septum: $result"
    }
    APSMpReturn ok
}

#Not used
proc APSMpSetupMultiBunchInject {} {
    global apsTopupTarget apsTopupTolerance apsTopupBunches
    if [catch {exec cavput -pend=10 -list=Mt:SR \
                 -list=injectCurrentLimitAO=$apsTopupTarget,injectMaxCyclesAO=1,injectModeBO=Single,CurrentLimitModeBO=Estop,injectNumBunchesAO.VAL=$apsTopupBunches \
             } result] {
        APSMpReturn error "APSMpSetupMultiBunchInject: Error setting IOC parameters: $result"
    }
    if [catch {exec cavput -list=Mt:SRinjectMultiExcludSIS1BO=0,Mt:SRinjectZeroBucketsBO=1 \
             } result] {
        APSMpReturn error "APSMpSetupMultiBunchInject: $result"
    }
    APSMpReturn ok
}

#Not used
proc APSMpRestoreNonTopupState {} {
    global apsPreTopupControllawMode
    APSMpStep "Move booster H scraper back."
    catch {exec cavput -list=B:HSC2:SM:sm=0}
    catch {exec cavput -list=$apsPreTopupControllawMode,Mt:SRinjectMultiExcludSIS1BO=0}
    catch {exec cavput -pend=10 -list=S:IS1:VoltageSetSendAO=$apsMpSIS1Setpoint2}

    APSMpReturn ok
}

#Not used
proc APSMpSetupBunchMonitor {} {
    # set threshold to 32 counts
    # set averaging to 48
    # Select bucket #0 for single bunch
    # "Fine tune"
    # Calibrate
    if [catch {exec cavput -list=BNCHI:NumTurns2AveAO.VAL=48,BNCHI:ThresholdAO.VAL=-20,BNCHI:BunchISelectAO.VAL=0} result] {
        APSMpReturn error "APSMpSetupBunchMonitor: $result"
    }
    if [catch {exec cavput -list=BNCHI:FineTuneTimingBO=1} result] {
        APSMpReturn error "APSMpSetupBunchMonitor: $result"
    }
    after 5000
    if [catch {exec cavput -list=BNCHI:CalibrateBunchIBO=1} result] {
        APSMpReturn error "APSMpSetupBunchMonitor: $result"
    }
    APSMpReturn ok
}

#Not used
proc APSMpRetimeP0IfAppropriate {} {
    if [catch {exec cavget -list=S-DCCT:CurrentM -repeat=number=4,pause=1,average} current] {
        APSMpReturn error "APSMpRetimeP0IfAppropriate: $result"
    }
    if [expr abs($current)>0.05] {
        APSMpReturn ok
    }
    if [catch {exec cavput -list=Mt:P0:resync_counters_bo=1} result] {
        APSMpReturn ok
    }
    APSMpReturn ok
}

#Not used
proc APSMpMakeTargetBunchPattern {} {
    global apsPatternDir apsTopupTarget apsBPMGroupCurrent apsBPMGroupMode
    set targetPatternFile $apsPatternDir/target
    file delete $targetPatternFile
    if [catch {APSSRMakeTargetFillPattern \
                 -targetCurrent $apsTopupTarget \
                 -BPMGroupCurrent $apsBPMGroupCurrent \
                 -BPMGroupMode $apsBPMGroupMode \
                 -output $targetPatternFile
        file attributes $targetPatternFile -permissions 00666 \
             } result] {
        APSMpReturn error "APSMpMakeTargetBunchPattern: $result"
    }
    APSMpReturn ok
}

proc APSMpIDOffsetFeedforwardStatusInfo {args} {
    return "display the run control information of ID Offset feedforward"
}

#Used by SR PEM
proc APSMpIDOffsetFeedforwardStatus {args} {
    set runControlPV  S:ID:GapFeedForwardRC
    exec medm -x -attach -macro RCPV=$runControlPV \
      /usr/local/iocapps/adlsys/sr/psApp/APSRunControlSingle.adl &
    APSMpReturn ok
}

proc APSMpUpdateS27GapFFTableInfo {args} {
    return "update S27 gap FF table, set the S27ID:P1 setpoint to the adjust value to zero the orbit."
}

#Used by SR PEM
proc APSMpUpdateS27GapFFTable {args} {
    APSMpStep "Check if S27ID P1 is in orbit controllaw lattice config already..."
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTmpFileList -ID idff -fileList "$tmpRoot.x $tmpRoot.y"
    if [catch {exec sddsprocess /home/helios/oagData/sr/orbitControllaw/lattices/default/h.default/config $tmpRoot.x \
                 -match=par,NameType=MonitorNames -match=col,Name=S27ID* } result] {
        #continue  S27ID P1 does not exist, continue
    } else {
        APSMpStep "S27ID:P1 x is in orbit controllaw lattice config, cancel update FF."
        APSMpReturn ok
    }
    if [catch {exec sddsprocess /home/helios/oagData/sr/orbitControllaw/lattices/default/h.default/config $tmpRoot.y \
                 -match=par,NameType=MonitorNames -match=col,Name=S27ID* } result] {
        #S27ID P1 does not exist, continue
    } else {
        APSMpStep "S27ID:P1 y is in orbit controllaw lattice config, cancel update FF."
        APSMpReturn ok
    }
    APSMpStep "Reading S27ID:P1 adjust values..."
    if [catch {exec cavget -list=S27ID:P1: -list=x,y -list=:AdjustedM -pend=30 -printErrors} valList] {
        APSMpReturn error "Error reading adjust values: $valList"
    }
    set xsetpoint [lindex $valList 0]
    set ysetpoint [lindex $valList 1]
    set FFdir /home/helios/oagData/feedForwardFiles/IDgap
    set filename [APSNextGenerationedName -directory  $FFdir  -name FF.0001 -newFile 1 -separator .]
    if [catch {exec sddsprocess $FFdir/FF $FFdir/$filename \
                 "-redefine=col,ActuatorValue,ActuatorName \"S27ID:P1:y:SetpointC\" streq ReadbackValue 30.01 < && ? $ysetpoint : ActuatorValue $ " \
                 "-redefine=col,ActuatorValue,ActuatorName \"S27ID:P1:x:SetpointC\" streq ReadbackValue 30.01 < && ? $xsetpoint : ActuatorValue $ " } result] {
        APSMpReturn error "Error processing FF: $result"
    }
    if ![APSYesNoPopUp "FF is being update, do you want to install it now?"] {
        APSMpReturn error "FF is not being updated."
    }
    cd $FFdir
    exec rm FF
    exec ln -s $filename FF
    if ![APSYesNoPopUp "FF table is being updated for S27ID P1, do you want to restart ID feedforward now?"] {
        APSInfoWindow .[APSTmpString] -infoMessage "FF table is being updated for S27ID P1, you need to restart ID gap feedforward to take effect" -modal 1
        APSMpReturn ok
    }
    if [catch {APSMpIDOffsetFeedforward -action stop } result] {
        APSMpReturn error "Error stop ID feedforward: $result"
    }
    after 1000
    if [catch {APSMpIDOffsetFeedforward -action start} result] {
        APSMpReturn error "Error start ID feedforward: $result"
    }
    if ![APSYesNoPopUp "FF table is being update for S27ID P1 and ID feedforward is started, do you want to add S27ID P1 to orbit controllaw lattice config?"] {
        APSInfoWindow .[APSTmpString] -infoMessage "FF table is being updated for S27ID P1 and ID feedforward is started, you will need to add S27ID P1 back to orbit controllaw lattice config and restart the orbit correction. Press OK when it is done" -modal 1
        APSMpReturn ok
    }
    if [catch {APSAddDeviceToDefaultConfigs -deviceList "S27ID:P1" -reason "update FF for S27ID:P1" } result] {
        APSMpReturn error "Error adding S27ID:P1 to default configs: $result"
    }
    if ![APSYesNoPopUp "Restart orbit correction now?"] {
        APSInfoWindow .[APSTmpString] -infoMessage "FF table is being updated for S27ID P1, ID feedforward is started, and S27ID:P1 is added to orbit controllaw lattice config. Now you need restart orbit correction. Press OK when it is done" -modal 1
        APSMpReturn ok
    }
    if [catch {exec generateControllawFiles -configList h.default v.default -debug 0 } result] {
        APSMpReturn error "Error generating controllaw files: $result"
    }
    foreach coord {X Y} {
        catch {exec logMessage -sourceId=steeringAudit \
                 -tag=Instance S:OrbitControlLaw${Coord}SDDS -tag=Action Abort}
        if [catch {exec cavput -list=S:OrbitControlLaw${Coord}SDDS.ABRT=1 -pend=30 } result] {
            return -code error "APSSRRemoveXrayBPMFromOrbitCorrection4: error aborting $plane orbit correction: $result"
        }
        after 2000
        #restart controllaw
        catch {exec logMessage -sourceId=steeringAudit \
                 -tag=Instance S:OrbitControlLaw${Coord}SDDS -tag=Action Start}
        if [catch {exec cavput -list=S:OrbitControlLaw${Coord}SDDS.CMND=1 -pend=30} result] {
            return -code error "APSSRRemoveXrayBPMFromOrbitCorrection7: error starting $plane orbit correction."
        }
    }
    #FIX THIS this PV will probably change for the APSU
    if [catch {exec cavput -list=S27ID:P1: -list=x,y -list=:InUseBO=1 -pend=10 } result] {
        APSMpReturn error "Error setting inuse : $result"
    }
    APSMpReturn ok
}

#Used by SR PEM
proc APSMpSRDispCorrectionInfo {} {
    set runControlPV S:XDPoffsetTransferRC
    if [catch {exec medm -x -attach -macro "RCPV=$runControlPV" \
                 /usr/local/iocapps/adlsys/sr/psApp/APSRunControlSingle.adl & \
             } result ] {
        APSMpReturn error "APSMpSIS1Feedforward: $result"
    }
    APSMpReturn ok
    #  return "start dispersion correction for bpm setpoints when scanning gaps."
}

proc APSMpSRStartDispCorrectionInitDialog {frame} {
    global APSMpSRStartDispCorrection
    set APSMpSRStartDispCorrection(interval) 1
    set APSMpSRStartDispCorrection(beamEnergy) 7
    set APSMpSRStartDispCorrection(ShortFilename) SR-UserBeamPreferred.gz
    APSFrame .f1 -parent $frame -name "Parameters"
    set parent $frame.f1.frame
    APSLabeledEntry .interval -parent $parent -label "Interval (seconds):" -textVariable APSMpSRStartDispCorrection(interval) -width 10
    APSLabeledEntry .energy -parent $parent -label "Beam Energy (GeV):" -textVariable APSMpSRStartDispCorrection(beamEnergy) -width 10

    APSAddSCRDialog .scr -parent $frame -system SR -arrayName  APSMpSRStartDispCorrection\
      -defaultFile $APSMpSRStartDispCorrection(ShortFilename)
}

#Used by SR PEM
proc APSMpSRStartDispCorrection {args} {
    set interval 1
    set beamEnergy 7
    set ShortFilename SR-UserBeamPreferred.gz
    APSMpStep init -promptDialog  APSMpSRStartDispCorrectionInitDialog \
      -vars {interval beamEnergy ShortFilename}

    set runControlPV S:XDPoffsetTransferRC
    global dispersionDone
    set disperionDone 0
    APSExecLog .dispCorr -name "Disperion Correction"  -width 80 -lineLimit 1024 -height 30 \
      -unixCommand "sddsSubtractDispersionOrbit /home/helios/oagData/sr/orbitControllaw/waveforms/dispersionBpmInfo.sdds -verbose -SCRFile=/home/helios/oagData/SCR/snapshots/SR/$ShortFilename -runControl=pv=$runControlPV,pingTimeInterval=1,pingTimeOut=5,description=DispersionCorrectionForGapScan -infinite -interval=$interval -beamEnergy=$beamEnergy" \
      -abortCallback "set dispersionDone aborted" -cancelCallback "set dispersionDone cancelled" \
      -callback "set dispersionDone 1"
    tkwait variable dispersionDone
    if {$dispersionDone!=1} {
        APSMpReturn error "Disperion correction was $dispersionDone ."
    }
    APSMpReturn ok
}

#Used by SR PEM
proc APSMpSRStopDispCorrection {} {
    set runControlPV S:XDPoffsetTransferRC
    if [catch {exec cavput -list=$runControlPV.ABRT=1 -pend=10 } result] {
        APSMpReturn error "Error aborting dispersion correction."
    }
    APSMpReturn ok
}


#Used by SR PEM, SRBunchTrain, SRTopupBucketAssignment
set apsTopupTarget 102
set apsTopupInterval 120
set apsTopupWarningTime 10
set apsBPMGroupCurrent 12
set apsBPMGroupMode First
set apsBPMSumTarget 1340
# one 1nC pulse
set apsTopupTolerance 0.27
set apsTopupBunches 1
set apsSIS1Setpoint1 652
set apsSIS1Setpoint2 646
