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

set auto_path [linsert $auto_path 0 /usr/local/oag/apps/lib/$env(HOST_ARCH)]
set auto_path [linsert $auto_path 0 /usr/local/oag/lib_patch/$env(HOST_ARCH)]
APSDebugPath
wm withdraw .

# $Log: not supported by cvs2svn $
# Revision 1.98  2011/02/28 21:21:20  shang
# made a copy of target, pattern and sorted files with dated string for future post-mortem analysis.
#
# Revision 1.97  2010/07/06 15:33:56  soliday
# Fixed an issue on Linux. It was coping the static Solaris executables so
# I had to make static Linux executables available.
#
# Revision 1.96  2010/01/25 21:03:04  shang
# comment out printout author's name.
#
# Revision 1.95  2009/12/11 01:00:40  lemery
# Corrected a bug in last version where the log file wouldn't have been compressed as intended.
#
# Revision 1.94  2009/12/10 23:56:36  lemery
# Added logging of the pattern to /home/helios/oagData/sr/fillPatternLog/bucketAssignmentLog directory. For debugging purposes.
#
# Revision 1.93  2009/12/08 16:45:53  shang
# set the default value of includeBooterSeptum and includeParSeptum to 1 so that the booster/par septum will be enable/disabled along with the trigger.
#
# Revision 1.92  2009/12/03 23:05:35  shang
# added includeBoosterSeptum and includeParSeptum option to disable/enable the booster/par trigger and septum at the same item.
#
# Revision 1.91  2008/03/11 22:45:59  emery
# Fixed a { with a [.
#
# Revision 1.90  2008/03/11 22:06:58  emery
# Replaced use of apsTurnOnPARcleaning global variable, which has been
# removed from oag/apps/src/mplib/sr/SRBunchTrain.tcl and replaced it
# with a call to APSPARCleaning, whcih has been added to the above
# library.
#
# Revision 1.89  2008/02/20 12:23:22  emery
# Upon start, clean out /local/bin2 area and recopy.
# Check existence of allowPARcleaning at the dp_atexit command.
#
# Revision 1.88  2008/02/13 23:12:41  emery
# Added check of existence of /local disk, so that the script
# will run with network file service if /local doesn't exist.
#
# Revision 1.87  2008/02/13 22:59:28  emery
# Removed an extraneous brace in reversion 1.85
#
# Revision 1.86  2008/02/13 22:48:27  emery
# At the end of injection, increases the time between turning off the gun trigger
# and turning off the PAR kickers.
#
# Revision 1.85  2008/02/08 19:30:38  emery
# Copies over once the shared libraries to a local disk if necessary.
#
# Revision 1.84  2008/02/07 21:50:55  emery
# Removed exit command left over from debugging.
#
# Revision 1.83  2008/02/07 21:47:16  emery
# Using /local/bin2 instead of /local/bin for the executable.
# Use /usr/local/oag/apps/bin2 for original copies.
#
# Revision 1.82  2008/02/07 21:30:30  emery
# Returned the bunch pattern files to the /tmp directory
# since these are not critical to keep for a long time.
#
# Revision 1.81  2008/02/07 21:26:08  emery
# Changed /tmp to /local because /tmp will get periodically cleaned.
#
# Revision 1.80  2008/02/07 21:13:52  emery
# Added setting LD_LIBRARY_PATH to add the /tmp/bin2/lib
# for local copied of shared libraries.
#
# Revision 1.79  2008/02/07 18:56:23  emery
# Removed exit command added my mistake in previous version
#
# Revision 1.78  2008/02/07 18:47:49  emery
# Creates a /tmp/bin if necessary and copies the necessary
# sdds executables for bunch pattern generation for this application
# plus thoses needed in oag/apps/src/tcltklib/SRBunchCurrent.tcl
#
# Revision 1.77  2008/02/07 17:05:11  emery
# Added a local directory to path so that network file system
# may be bypassed.
#
# Revision 1.76  2008/02/06 23:10:19  emery
# replaced normal working directory for bunch patterns with
# /tmp directory
#
# Revision 1.75  2008/01/22 22:38:04  emery
# Added timeout to the commandline, removed allowPARcleaning from
# the commandline. Added PVs It:allowPARcleaningC It:allowBTSchargeC
# for reading at each iterations to modify the actions taken.
# Changes by Shang.
#
# Revision 1.74  2007/10/30 19:26:10  emery
# Added more deailts in error messages.
# Extended wait time in while loop to 1 second.
#
# Revision 1.73  2007/10/24 02:29:03  emery
# Change the procedure name for checking RTFB statuses.
# Realized that procedure for checking RTFB statuses
# already stopped topup, so removed the additional
# stop commands upon return of procedure.
# Changes some conditionals in procedure.
# Added more PVs to test.
#
# Revision 1.72  2007/10/24 00:49:23  emery
# Put inline code of RTFB status check into a procedure called CheckRTFBStatus.
# Add call to CheckRTFBStatus as close to injection as possible, just after
# injector warning time, which is usually 2 seconds.
# Also have the script explicitly sent a disable topup command
# which wasn't done before. Previously the assumption was that the topup
# runcontrol would time out, which would disable the topup injection
# eventually. This wasn't prompt enough under real conditions.
#
# Revision 1.71  2007/10/23 05:17:46  emery
# Replaced all exec cavget with APScavget in order to
# avoid timeout errors when a CA has to be reestablished.
#
# Revision 1.70  2007/10/16 21:51:31  emery
# Added -pend=5 argument to cavget commands for RTFB PVs.
# This will hopefully eliminate timeout errors.
#
# Revision 1.69  2007/09/29 00:08:55  emery
# Added commandline option to not allowPARCleaning
#
# Revision 1.68  2007/08/15 03:01:27  emery
# Added a clear S:TopupBucketAssignmentRC command at the beginning.
#
# Revision 1.67  2007/08/15 02:34:01  emery
# Added a break command after the determination that topup has to be aborted
# from teh rTFB statuses.
#
# Revision 1.66  2007/08/09 20:21:11  emery
# Added conditional checks on RTFB statuses before continuing with
# topup. Not tested.
#
# Revision 1.65  2007/06/12 18:34:57  emery
# Wrote instructions on what to do when the operators get
# the LI:pusles error.
#
# Revision 1.64  2007/04/06 18:38:10  emery
# Added -baselineCorrection 1 argument to read bucnh pattern.
#
# Revision 1.63  2007/04/03 18:31:48  emery
# Added check on values of LI:pulsesAO LI:P0pulsesAO.
#
# Revision 1.62  2006/04/19 11:01:09  emery
# Changed the limit of buckets to be injected from 200 to 324.
# Removed the twice repeated first bucket to be injected.\,
# now that the IS1 septum delivers the requested amplitude at every
# pulse.
#
# Revision 1.61  2005/11/30 01:07:05  emery
# Corrected the matching string in the switch -regexp statement.
#
# Revision 1.60  2005/11/30 01:03:00  emery
# Corrected the option for the switch statement from glob to regexp.
# Added revision printout.
#
# Revision 1.59  2005/11/30 00:55:05  emery
# Added script name to error messages.
#
# Revision 1.58  2005/11/29 22:18:41  emery
# Added -glob option to switch for hybrid mode pattern in case
# pattern labels for hybrid mode (1+8x7) change.
#
# Revision 1.57  2005/08/26 12:56:53  borland
# If 324 bunch pattern is detected, ignores the ADC bunch pattern data and
# instead just uses the staggered pattern.  Changes mostly by Emery.
#
# Revision 1.56  2005/07/18 17:46:39  soliday
# Changed the PAR Cleaning mux PV value back to Clean.
#
# Revision 1.55  2005/07/11 22:54:28  emery
# Changed the PAR cleaning mux PV value to "Ch. 2"
# as a temporary measure.
#
# Revision 1.54  2005/07/11 22:53:01  emery
# Removed allowPARcleaning flag, as the PAR is now
# always allowed to clean for all bunches.
#
# Revision 1.53  2005/06/21 08:21:32  emery
# Use PVs SR:bunchPatternSO LI:pulsesAO and LI:P0pulsesAO to
# vary the number of pulses for hybrid mode.
#
# Revision 1.52  2005/06/06 19:42:02  emery
# Added feature to change linac pulses for the P0 pulses.
# This version should be run only when hybrid mode is expected,
# and is not for 24 singlets usage, for example.
# Turn on PAR bunch cleaning upon exit.
#
# Revision 1.51  2005/03/25 22:35:22  emery
# Added 0.5 second of wait time before turning off PAR extraction.
#
# Revision 1.50  2005/03/15 11:39:58  emery
# Set the flag for PAR cleaning to on.
#
# Revision 1.49  2005/02/08 20:47:39  emery
# Created a flag to turn off PAR bunch cleaning. This version
# has PAR cleaning turned off.
#
# Revision 1.48  2004/12/01 18:55:51  emery
# Added "package require rpn" to make the rpn command work.
#
# Revision 1.47  2004/12/01 17:37:55  emery
# Added turning on and off PAR bunch cleaning when a PAR bucket of 0 or 6
# is injected into SR.
#
# Revision 1.46  2003/10/01 08:59:54  emery
# Included use of Mt:SRinjectMultiExcludBsEKBO for
# deciding to explicitly turning on of booster extraction kicker.
#
# Revision 1.45  2003/09/03 16:30:33  soliday
# Moved APSStandardSetup to the top.
#
# Revision 1.44  2003/08/06 00:10:53  emery
# Fixed typo
#
# Revision 1.43  2003/08/06 00:07:25  emery
# Added a test at the end of the main loop to make sure that the calculation
# warning time goes back up to a high value.
#
# Revision 1.42  2003/08/05 23:52:16  emery
# Made superficial changes in the hopes that the behavior
# of PVs that are linked through tcl variables return to normal.
#
# Revision 1.41  2003/08/05 21:56:41  emery
# Removed extra toggle boosterToExt command
# and removed extraneous pv-linked tcl variables
# taht are not used.
#
# Revision 1.40  2003/08/05 20:36:05  emery
# Fixed some bugs in last version.
#
# Revision 1.39  2003/08/05 19:33:21  emery
# Changed test for injection completion to use the PV Mt:SRinjectDoneBO
# which is linked to tcl variable apsInjectionDone.
#
# Revision 1.38  2003/07/30 08:57:59  emery
# Fixed bug with cavget with no results variable.
# Added missing $ to InjectorTimer variable.
# Make the calculation timer the run control timeout length.
# Start the injector (without effective booster extraction) at the same
# time as calculations.
# Moved sleep time in send while loop to hasten the pulsing
# of the booster extraction kicker.
# Use cavput instead of TogglePulsedMagnetEnables for
# time critical commands.
# Do check of sufficient time availablity with apsTopupTime2WarnCalc
# insetad of apsTopupTime2WarnInjector.
#
# Revision 1.37  2003/07/30 02:53:49  emery
# Added s second section in loop. The first section is for
# waiting for calculation time, and the second section is for
# waiting for injection time.
#
# Revision 1.36  2003/02/15 18:14:33  emery
# Fixed nesting of conditions for no bunches to inject into.
#
# Revision 1.35  2003/02/13 23:47:30  emery
# Check case where all bunches have too much current,
# i.e. weakBunches=0. Continue while loop in this case.
#
# Revision 1.34  2003/02/13 22:43:24  emery
# Added disabling of booster extraction after injection
# because there is a now a feedforward on the setpoint
# based on the trigger history.
#
# Revision 1.33  2002/11/20 23:31:15  emery
# Removed staggering of pulsed magnet turn-on and restored
# the TogglePulsedMagnetEnables for all pulsed magnets.
#
# Revision 1.32  2002/11/11 20:29:28  emery
# Forgto to secify the state for setting the gun-to-booster
# pulsed magnets.
#
# Revision 1.31  2002/11/11 20:27:37  emery
# Separated the turning of the injector pulsed magnets in
# steps with 3 second pauses.
#
# Revision 1.30  2002/03/26 17:14:33  emery
# Changed argument of togglePulseMagnet from PARto.. to Gunto..
#
# Revision 1.29  2002/03/26 15:18:12  emery
# Added command to turn off PAR kickers after injection.
#
# Revision 1.28  2002/03/06 04:37:29  emery
# Added a return -code error if the topup has been
# externally disabled.
#
# Revision 1.27  2001/11/15 22:57:41  borland
# Rewrote to use pv extension to alleviate connection problems.
# Also uses -noScalars option to APSSRReadBunchCM, for same reason.
#
# Revision 1.26  2001/11/10 04:18:16  borland
# Increased/added pend time of 60s on all cavget and cavput commands.
#
# Revision 1.25  2001/09/18 21:01:04  emery
# Added test of values of injection interval and warning time to
# injection. If warning time is too large, then a last cawait of
# the loop will never exit.
#
# Revision 1.24  2001/08/14 20:03:21  emery
# Corrected a typo(missing = in cawait command)
#
# Revision 1.23  2001/08/14 20:00:02  emery
# Changed calculation of cawaitTimeout
#
# Revision 1.22  2001/08/14 19:47:55  emery
# Changed other instances of the regular warning time
# to the injector warning time.
#
# Revision 1.21  2001/08/14 19:42:21  emery
# Changed the cawait PV to the warning-to-injector instead
# of the regular topup injection warning.
#
# Revision 1.20  2001/05/09 06:17:00  emery
# Need to repeat the first bucket three times becasue the septum
# first two pulses are not good enough.
#
# Revision 1.19  2001/03/20 23:46:19  emery
# Added runcontrol PV.
#
# Revision 1.18  2001/03/16 21:57:16  emery
# Replaced some exit command with return -code error
# so that the user can read the error messages that
# terminated the procedure.
#
# Revision 1.17  2000/12/06 15:37:29  emery
# Removed file attributes -permission command in favor
# of explicitly setting the directory default permissions
# outside of the application.
#
# Revision 1.16  2000/06/27 19:30:19  borland
# Enables RFG kicker charge and HV before injection, disables charge
# after injection.
#
# Revision 1.15  2000/06/21 12:56:12  emery
# Turn off gun kicker after injection.
#
# Revision 1.14  2000/03/27 22:23:49  emery
# Added turning on and turning off of resetting of
# RT feedback clock at injection pretrigger.
#
# Revision 1.13  2000/03/03 08:07:14  emery
# Changed permissions from 777 or 666 to 775 or 664
# to remove the world write access.
#
# Revision 1.12  2000/02/28 17:18:24  emery
# Added check of first 6 bucket as a group.
# If the sum of hte 6 bunchs is above the target, then
# don't inject in any of them.
# Added trigger disable of B:IK to reduce radiation
# dose in BTS line.
#
# Revision 1.11  1999/06/01 15:21:37  borland
# Now fills 200 slots for top-up injection, to allow for possibility that
# many pulses may be used.  Slot 0 and 1 are the same because in multibunch
# mode the first pulse never gets in.
#
# Revision 1.10  1999/06/01 14:21:29  emery
# Added the possibility of having a sequence of bucnhes
# injected. The first bunch is repeated since the septum
# does not pulse to full value on the first pulse.
#
# Revision 1.9  1999/05/31 09:05:42  emery
# Removed extraneous "}" at end of file.
#
# Revision 1.8  1999/05/31 08:52:38  emery
# Added a test of beam current. If there is no beam then procedure
# should exit.
#
# Revision 1.7  1999/05/26 21:27:15  borland
# Has more informative printouts.  cawaits include the top-up enable so
# it doesn't hang there.
#
# Revision 1.6  1999/03/02 08:06:10  emery
# Corrected an error in the cawait option for warning time.
#
# Revision 1.5  1999/03/02 06:09:17  emery
# Using the topup warning time pv to signal
# turning on of RF gun kicker, toggling of pulsed magnets,
# and start of bucket calculation.
# Added a command to turn off the RF gun kicker after injection is
# complete.
# Checks whether topup injection is disabled externally.
#
# Revision 1.4  1999/02/02 06:46:37  emery
# file commands replace some exec rm and exec chmod commands.
#
# Revision 1.3  1998/12/11 20:25:09  emery
# Added missing exec command to chmod command.
#
# Revision 1.2  1998/11/17 02:43:34  emery
# Added chmod a+rw statements for the target and bunch patterns.
#
# Revision 1.1  1998/11/17 02:35:51  emery
# First installation after debugging with beam.
#

set CVSRevisionAuthor "\$Revision: 1.99 $ \$Author: shang $"
#puts stderr "$CVSRevisionAuthor"

APSStandardSetup
if {[info exists tcl_pkgPath]} {
    set rpnLib [file join [lindex $tcl_pkgPath 0] rpn libtclRPN.so]
    if {($tcl_platform(os) == "Linux") && [file exists $rpnLib]} {
        load $rpnLib
    } else {
        package require rpn
    }
} else {
    package require rpn
}

set timeout 200
set args $argv
set includeBoosterSeptum 1
set includeParSeptum 1
set turnOnOffParBunchCleaning 0
set displayRunControl 0
APSParseArguments {timeout includeBoosterSeptum includeParSeptum turnOnOffParBunchCleaning displayRunControl}

global patternDir
set patternDir /home/helios/oagData/sr/bunchPatterns
# use local directory to path so avoid network file system
# when it is slow
set patternDir /tmp
set targetPatternFile $patternDir/target.$env(USER)
set patternFile $patternDir/pattern.$env(USER)
set sortedPatternFile $patternDir/sorted.$env(USER)
set toggleGunKicker 1

if {[file exists /local]} {
    # Add local directory to path in case the file system has delays
    set env(PATH) "/local/bin2:$env(PATH)"
    if {[info exists env(LD_LIBRARY_PATH)]} {
        set env(LD_LIBRARY_PATH) "/local/bin2/lib:$env(LD_LIBRARY_PATH)"
    } else {
        set env(LD_LIBRARY_PATH) "/local/bin2/lib"
    }
    # clean out directory and recopy
    catch {exec rm -rf /local/bin2}
    catch {exec mkdir -p /local/bin2 /local/bin2/lib}
    catch {exec chmod a+rwx /local/bin2}
    catch {exec chmod a+rwx /local/bin2/lib}
    # executables in /local/bin2
    set fileList {cavget cavput cawait sdds2stream sddsconvert sddsenvelope sddsprocess sddssort sddswmonitor sddsxref}
    foreach file $fileList {
        catch {exec cp /usr/local/oag/apps/bin2/$env(EPICS_HOST_ARCH)/$file /local/bin2/$file}
        catch {exec chmod a+rwx /local/bin2/$file}
    }
    # shared libraries in /local/bin2/lib
    if {[file exists /usr/local/oag/apps/bin2/$env(EPICS_HOST_ARCH)/lib]} {
	catch {exec cp /usr/local/oag/apps/bin2/$env(EPICS_HOST_ARCH)/lib/* /local/bin2/lib}
	catch {exec chmod a+rwx /local/bin2/lib/*}
    }
} else {
    puts stderr "Can't find disk /local, and cannot make local copies of executables and shared libraries. Script will use exectuables and shared libraries from the network file system..."
}


proc StopTopupFromRTFBStatus {} {
    set topupStopped 0
    # check whether SR is in a suitable state for topup during operations,
    # return a value of 0
    # If not, then return a value of 1.
    # check whether BPLDS are armed (S1BPLD:CH1:IDgapBI)
    # if yes, then check whether RTFB is running
    if [catch {APScavget -list=S -list=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,26,30,31,32,33,34,35 -list=BPLD:CH -list=1,2 -list=:IDgapBI} BPLDarmedStatus] {
        return -code error "SRTopupBucketAssignment36: Unable to read ID gap statuses: $BPLDarmedStatus"
    }
    if {-1 < [lsearch $BPLDarmedStatus "Closed"]} {
        # potentially unsafe
        set BPLDarmed 1
    } else {
        # unconditionally safe
        set BPLDarmed 0
        return 0
    }
    if $BPLDarmed {
        # check RTFB statuses
        set listArguments ""
        for {set i 1} {$i<41} {incr i} {
            set ioc [expr ($i - 1) / 2 * 2 + 1]
            lappend listArguments S${ioc}FB:GB${i}
        }
        # check only the h-plane
        if [catch {APScavget -list=[join $listArguments ","] -list=:Hor: -list=CloseLoopBO -pend=5} RTFBloopStatus] {
        return -code error "SRTopupBucketAssignment37: Unable to read h-plane RTFB loop statuses: $RTFBloopStatus"
        }
        if [catch {APScavget -list=SRFB:GBL:HLoopStatusBI -pend=5} moreRTFBloopStatus] {
            return -code error "SRTopupBucketAssignment38: Unable to read a h-plane RTFB loop statuses: $moreRTFBloopStatus"
        }
        if {-1 < [lsearch $RTFBloopStatus "Open"] || $moreRTFBloopStatus == "Off"} {
            # definitely unsafe for injection
            set RTFBrunning 0
        } else {
            # necessary but not sufficient for safe injection
            set RTFBrunning 1
        }
        if [catch {APScavget -list=S37FB:S38A:H3:feedForwardEnC,S39FB:S39A:H3:feedForwardEnC -pend=5} CorrectorFFstatus] {
            return -code error "SRTopupBucketAssignment39: Unable to read RTFB corrector FF statuses: $CorrectorFFstatus"
        }
        if {-1 < [lsearch $CorrectorFFstatus "Disable"]} {
            # definitely unsafe for injection
            set RTFBFFrunning 0
        } else {
            # necessary but not sufficient for safe injection
            set RTFBFFrunning 1
        }
        if [catch {APScavget -list=SRFB:GBL:DisableFreezeHBO -pend=5} FreezeSetting] {
            return -code error "SRTopupBucketAssignment40: Unable to read RTFB freeze setting: $FreezeSetting"
        }
        if {$RTFBrunning && $FreezeSetting == "Enable" && $RTFBFFrunning} {
            # RTFB correctly configured, proceed with topup injection
        } else {
            # stop topup
            if [catch {APScavput -list=Mt:TopUpAutoEnableC=0} result] {
                return -code error "SRTopupBucketAssignment41: $result"
            }
            if [catch {APScavput -list=S:TopupBucketAssignmentRC.ABRT=1} result] {
                return -code error "SRTopupBucketAssignment42: $result"
            } 
            puts stderr "Topup aborted because either RTFB loops are not all running, the freeze is disabled, or corrector FF waveforms not all enabled. Topup will have to be restarted manually after all bad conditions are corrected."
            # break out of the large (outermost) while loop
            set topupStopped 1
        }
    }
#    puts "BPLDarmed $BPLDarmed"
#    puts "RTFBrunning $RTFBrunning"
#    puts "RTFBFFrunning $RTFBFFrunning"
#    puts "FreezeSetting $FreezeSetting"
#    puts "topupStopped $topupStopped"
    return $topupStopped
}

proc ReadBunchCM {args} {
    # Reads the bunch-by-bunch current monitor and produces a file
    # giving the calibrated current in each bunch.  Optionally averages
    # several waveforms.  Does its own baseline subtraction and
    # calibration vs the DCCT.
    # Doesn't do any setup of the BBB current monitor.
    global env
    
    set output ""
    set average 1
    set targetFile ""
    set timeLimit 20
    set noScalars 0
    set useFillPattern 1
    set S35DCCT ""
    set ADCunit 1
    set baselineCorrection 1
    
    set monitorFilesDir /home/helios/oagData/sr/sddsmonitorFiles
    # To avoid using network file system, one can use the directory below
    # with files copied from above directory
    set monitorFilesDir /local/sddsmonitorFiles
    if ![file exists /local/sddsmonitorFiles] {
        exec mkdir /local/sddsmonitorFiles
        exec chmod a+rwx /local/sddsmonitorFiles
        set fileList {BunchCM.scalars}
        foreach file $fileList {
            exec cp /home/helios/oagData/sr/sddsmonitorFiles/$file /local/sddsmonitorFiles/$file
        }
    }
    set clockSecs [clock seconds]
    if {[APSStrictParseArguments {output average targetFile useFillPattern \
                                    noScalars S35DCCT ADCunit baselineCorrection}] || \
          ![string length $output] || $average<=0} {
        return -code error "APSSRReadBunchCM: bad arguments"
    }
    puts stderr "[exec date] Entering ReadBunchCM..."
    switch $ADCunit {
        1 { 
            set PVPrefix BNCHI:
            set WaveformPV ADC750:DataWF
        }
        2 {
            set PVPrefix ADC:2:
            set WaveformPV ADC750:2:DataWF
        }
        default {return -code error "APSSRReadBunchCMTurnByTurn: bad ADCunit value"}
    }
    
    if {$noScalars && (![string length $S35DCCT] || $S35DCCT<=0)} {
        return -code error "APSSRReadBunchCM: you must supply S35DCCT argument if you specify no scalars"
    }
    #    if [catch {exec cavput -list=${PVPrefix}SetTimingBO=1 -pend=10} result] {
    #        return -code error "APSSRReadBunchCM: $result"
    #    }
    puts stderr "[exec date] read ${PVPrefix}DataReadSQ.SCAN ..."
    if [catch {exec cavget -list=${PVPrefix}DataReadSQ.SCAN -pend=10 } intervalData] {
        return -code error "APSSRReadBunchCM: $intervalData"
    }
    if [scan [string trim $intervalData \"] "%lf" interval]==0 {
        return -code error "APSSRReadBunchCM: scan rate not understood: $intervalData.\nCheck value of BNCHI:waveFormScanMO"
    }
    set tmpFile /tmp/[APSTmpString]
    #    if [catch {exec cawait -waitfor=${PVPrefix}StatusMI.VAL,equal=7 -timeLimit=$timeLimit } result] {
    #        return -code error "APSSRReadBunchCM: $result"
    #    }
    set scalarsArg ""
    if !$noScalars {
        # that is, with scalars
        set scalarsArg -scalars=$monitorFilesDir/BunchCM.scalars 
    }
    puts stderr "[exec date] read $WaveformPV with sddswmonitor, write to $tmpFile"
    if [catch {eval exec sddswmonitor -PVnames=$WaveformPV,Mt:S:FillPatternWF \
                 $scalarsArg -step=$average -interval=$interval $tmpFile} result] {
        return -code error "APSSRReadBunchCM: (sddswmonitor) $result"
    }
    if [string length $targetFile] {
        set output1 $tmpFile.1
    } else {
        set output1 $output
    }
    if $useFillPattern {
        set factorName Mt:S:FillPatternWFMean
    } else {
        set factorName 1
    }
    if !$noScalars {
        # with scalars
        puts stderr "[exec date] get scalar pvs from $monitorFilesDir/BunchCM.scalars."
        set paramList [APSGetSDDSColumn -column ReadbackName -fileName \
                         $monitorFilesDir/BunchCM.scalars]
        set unitsList [APSGetSDDSColumn -column ReadbackUnits -fileName \
                         $monitorFilesDir/BunchCM.scalars]
        foreach param $paramList units $unitsList {
            lappend opt1List -define=column,${param}1,$param,units=$units
            lappend opt2List -process=${param}1Mean,first,${param}Mean
            lappend joinList ${param}1
        }
    } else {
        # no scalars
        set opt1List -define=column,S35DCCT1,$S35DCCT,units=mA
        set opt2List -process=S35DCCT1Mean,first,S35DCCTMean
        set joinList S35DCCT1
    }
    if $baselineCorrection {
        if !$useFillPattern {
            # removes data that is within +5 units from baseline
            # perhaps we need to determine the double band baseline and
            # subtract it.
            puts stderr "[exec date] process $tmpFile without useFillPattern, write to $output1"
            if [catch \
                  {eval exec sddsprocess $tmpFile -pipe=out $opt1List \
                     | sddsenvelope -pipe -copy=Index -nowarning \
                     -mean=[join [concat $joinList [list $WaveformPV Mt:S:FillPatternWF]] ,] \
                     | sddsprocess -pipe $opt2List \
                     -process=${WaveformPV}Mean,base,%sBase \
                     \"-define=column,AdjustedWF,${WaveformPV}Mean ${WaveformPV}MeanBase - 5 > ? pop : 0 $ $factorName * \" \
                     -process=AdjustedWF,sum,%sSum \
                     \"-define=parameter,BCMCalibration,AdjustedWFSum 0 == ? 0 : S35DCCTMean AdjustedWFSum / $ \" \
                     \"-define=column,BunchCurrent,AdjustedWF BCMCalibration *,units=mA\" \
                     -define=parameter,FillPatternApplied,$useFillPattern,type=long \
                     \"-define=parameter,Time,$clockSecs,units=s\" \
                     \"-print=parameter,TimeStamp,[clock format $clockSecs]\" \
                     | sddsconvert -pipe=in $output1 \
                     -rename=column,Index=Bucket \
                     -delete=column,*1Mean,AdjustedWF,${WaveformPV}Mean } result] {
                return -code error "APSSRReadBunchCM: $result"
            }
        } else {
            # use fill pattern
           # puts stderr "[exec date] process $tmpFile use fill pattern, write to $output1."
            puts stderr "[exec date] process $tmpFile use fill pattern, write to $tmpFile.env"
            if [catch \
                  {eval exec sddsprocess $tmpFile -pipe=out $opt1List \
                     | sddsenvelope -pipe -copy=Index -nowarning  \
                     -mean=[join [concat $joinList [list $WaveformPV Mt:S:FillPatternWF]] ,] \
                     | sddsprocess -pipe=in $tmpFile.env  $opt2List } result] {
                 return -code error "APSSRReadBunchCM1a: $result"
            }
            puts stderr "[exec date] process $tmpFile.env, write to $tmpFile.proc"
            if [catch { exec sddsprocess $tmpFile.env -pipe=out \
                          "-redef=col,WaveformShifted,i_row 1 - 0 < pop ? 1295 : \$ &Mt:S:FillPatternWFMean \[,type=long" \
                          | sddsprocess -pipe=in $tmpFile.proc \
                          "-redef=col,NewWaveform,Mt:S:FillPatternWFMean WaveformShifted +,type=long" } result] {
                return -code error "APSSRReadBunchCM1: $result"
            }
            puts stderr "[exec date] process $tmpFile.proc, write to $tmpFile.empty"
            if [catch {eval exec sddsprocess  $tmpFile.proc $tmpFile.empty \
                     -filter=col,NewWaveform,0,0 \
                         \"-def=col,IsOdd,Index 2 mod \" \
                         \"-def=col,IsEven,Index 1 + 2 mod \" \
                         \"-def=col,BaselineOddBucketsWF,${WaveformPV}Mean IsOdd * \" \
                         \"-def=col,BaselineEvenBucketsWF,${WaveformPV}Mean IsEven * \" \
                         -proc=BaselineOddBucketsWF,sum,BaselineOddBucketsWF \
                         -proc=BaselineEvenBucketsWF,sum,BaselineEvenBucketsWF \
                         -proc=IsOdd,sum,OddEmptyBuckets \
                         -proc=IsEven,sum,EvenEmptyBuckets \
                         \"-def=para,${WaveformPV}OddBase,BaselineOddBucketsWF OddEmptyBuckets  / \" \
                         \"-def=para,${WaveformPV}EvenBase,BaselineEvenBucketsWF EvenEmptyBuckets  / \" } result] {
                return -code error "APSSRReadBunchCM2: $result"
            }
            puts stderr "get results from $tmpFile.empty"
            set results [exec sdds2stream -para=${WaveformPV}OddBase,${WaveformPV}EvenBase $tmpFile.empty]
            foreach {oddBase evenBase} $results {}              
            puts stderr "[exec date] process $tmpFile.env, write to $tmpFile.adj"
            if [catch {exec sddsprocess $tmpFile.env -pipe=out \
                     "-def=col,IsOdd,Index 2 mod " \
                     "-def=col,IsEven,Index 1 + 2 mod "  \
                     "-def=col,Baseline,IsOdd 1 == pop pop ? $oddBase : $evenBase \$" \
                     "-def=col,AdjustedWF,${WaveformPV}Mean Baseline -" \
                      -process=AdjustedWF,sum,%sSum,weight=Mt:S:FillPatternWFMean \
                     "-define=parameter,BCMCalibration,AdjustedWFSum 0 == ? 0 : S35DCCTMean AdjustedWFSum / \$ " \
                     "-redefine=column,AdjustedWF,AdjustedWF Mt:S:FillPatternWFMean * " \
                     "-define=column,BunchCurrent,AdjustedWF BCMCalibration *,units=mA" \
                     -define=parameter,FillPatternApplied,$useFillPattern,type=long \
                     "-define=parameter,Time,$clockSecs,units=s" \
                     "-print=parameter,TimeStamp,[clock format $clockSecs]" \
                     | sddsconvert -pipe=in $tmpFile.adj \
                         -rename=column,Index=Bucket } result] {
                return -code error "APSSRReadBunchCM3: $result"
            }
            puts stderr "[exec date] creating /tmp/response.part1.$env(USER)"
            if [catch {exec sddsmakedataset /tmp/response.part1.$env(USER) \
                         -col=Waveform,type=double -data=1,-0.07 \
                         -col=Bucket,type=long -data=0,1 } result] {
                return -code error "APSSRReadBunchCM4: $result"
            }
            #exec chmod 666 /tmp/response.part1
            puts stderr "[exec date] creating /tmp/response.part2.$env(USER)"
            if [catch {exec sddssequence /tmp/response.part2.$env(USER) \
                         -def=Bucket,type=long \
                         -sequence=beg=2,end=1295,delta=1 } result] {
                 return -code error "APSSRReadBunchCM5: $result"
            }
            #exec chmod 666 /tmp/response.part2
            puts stderr "[exec date] combine /tmp/response.part1.$env(USER) /tmp/response.part2.$env(USER) to /tmp/response.$env(USER)"
            if [catch {exec sddscombine /tmp/response.part1.$env(USER) /tmp/response.part2.$env(USER) /tmp/response.$env(USER) \
                -merge -overWrite  } result] {
                return -code error "APSSRReadBunchCM6: $result"
            }
            puts stderr "deleting /tmp/response.part1.$env(USER) /tmp/response.part2.$env(USER)"
            catch {exec rm /tmp/response.part1.$env(USER) /tmp/response.part2.$env(USER)}
            #exec chmod 666 /tmp/response
            puts stderr "[exec date] convolve $tmpFile.adj /tmp/response.$env(USER),  write to $tmpFile.adj2"
            if [catch {exec sddsconvolve $tmpFile.adj  /tmp/response.$env(USER) $tmpFile.adj2 \
                         -signal=Bucket,AdjustedWF \
                         -response=Bucket,Waveform \
                         -output=Bucket,Waveform \
                         -deconvolve } result] {
                return -code error "APSSRReadBunchCM7: $result"
            }
            puts stderr "[exec date] deleting /tmp/response.$env(USER)"
            catch {exec rm /tmp/response.$env(USER) }
            # do some normalizin'
            puts stderr "[exec date] process $tmpFile.adj2, write to $output1"
            if [catch { exec sddsprocess $tmpFile.adj2 -pipe=out \
                          | sddsxref -pipe $tmpFile.env \
                          -take=Mt:S:FillPatternWFMean \
                          | sddsprocess -pipe=in $output1 \
                          -process=Waveform,sum,%sSum,weight=Mt:S:FillPatternWFMean \
                          "-redefine=parameter,BCMCalibration,WaveformSum 0 == ? 0 : S35DCCTMean WaveformSum / \$ " \
                          "-redefine=column,Waveform,Waveform Mt:S:FillPatternWFMean * " \
                          "-redefine=column,BunchCurrent,Waveform BCMCalibration *,units=mA" \
                          -redefine=parameter,FillPatternApplied,$useFillPattern,type=long \
                          "-redefine=parameter,Time,$clockSecs,units=s" \
                          "-reprint=parameter,TimeStamp,[clock format $clockSecs]" 
            } result] {
                return -code error "APSSRReadBunchCM8: $result"
            }
        }
    } else {
        # this would be used for 1296 fills
        # assume -27 as baseline, and no removal of bucket data
        puts stderr "[exec date] process $tmpFile without baseline correction."
        if [catch \
              {eval exec sddsprocess $tmpFile -pipe=out $opt1List \
                 | sddsenvelope -pipe -copy=Index -nowarning \
                 -mean=[join [concat $joinList [list $WaveformPV Mt:S:FillPatternWF]] ,] \
                 | sddsprocess -pipe $opt2List \
                 -define=para,${WaveformPV}MeanBase,-27 \
                 \"-define=column,AdjustedWF,${WaveformPV}Mean ${WaveformPV}MeanBase - $factorName * \" \
                 -process=AdjustedWF,sum,%sSum \
                 {"-define=parameter,BCMCalibration,AdjustedWFSum 0 == ? 0 : S35DCCTMean AdjustedWFSum / $ "} \
                 {"-define=column,BunchCurrent,AdjustedWF BCMCalibration *,units=mA"} \
                 -define=parameter,FillPatternApplied,$useFillPattern,type=long \
                 {"-define=parameter,Time,$clockSecs,units=s"} \
                 {"-print=parameter,TimeStamp,[clock format $clockSecs]"} \
                 | sddsconvert -pipe=in $output1 \
                 -rename=column,Index=Bucket \
                 -delete=column,*1Mean,AdjustedWF,${WaveformPV}Mean } result] {
            return -code error "APSSRReadBunchCM: $result"
        }
    }
    if [string length $targetFile] {
        puts stderr "[exec date] write to $targetFile"
        if [catch {exec sddsxref $output1 $targetFile -pipe=out \
                     -take=TargetCurrent \
                     | sddsprocess -pipe=in $output \
                     "-define=column,CurrentDeficit,TargetCurrent BunchCurrent -,units=mA" \
                     "-process=CurrentDeficit,max,CurrentDeficitMax" \
                     "-process=CurrentDeficit,max,CurrentDeficitMaxBucket,position,func=Bucket" \
                 } result] {
            return -code error "APSSRReadBunchCM: $result"
        }
    } 
    set files [glob ${tmpFile}*]
    catch {eval file delete -force $files}
    puts stderr "[exec date] exit ReadBunchCM."

}

if [catch {APSBunchTrainConnect} result] {
    puts stderr $result
    exit
}
puts stderr "Connected to Bunch Train PVs."

if [catch {APSTopupConnect} result] {
    puts stderr $result
    exit
}
puts stderr "Connected to Topup PVs."


set currentThreshold 0.1
if [catch {pv getw apsTopupEnabled} result] {
    puts stderr $result
    exit
}

if [catch {APScavget -list=Mt:TopUpWarnTime2 -list=InjectorP,CalcP \
             -pend=60 } results] {
    puts stderr $result
}
set InjectorTimer [lindex $results 0]
set CalculationTimer [lindex $results 1]

# 3 seconds padding for calculation to be completed before
# inejctors are turned on.
if {[expr $CalculationTimer < ($InjectorTimer + 3)]} {
    puts stderr "Value of calculation warning time must be larger than that of the injector for this script to work."
    exit
}

# make the calculation timer the run control timeout length.
set RCtimeout [expr 1.0 * $CalculationTimer]
set cawaitTimeout [expr $RCtimeout / 4]

puts stderr "Attempting to get run control permission"
set RCPV S:TopupBucketAssignmentRC
catch {APScavput -list=S:TopupBucketAssignmentRC.CLR=1}
if [catch {APSRunControlInit -pv $RCPV \
             -description "Topup Injection" \
             -timeout [expr $RCtimeout * 1000]} result] {
    puts stderr $result
}
if $displayRunControl {
    catch {exec medm -x -attach -macro RCPV=$RCPV \
             ./sr/psApp/APSRunControlSingle.adl &}
}

for {set i 0} {$i<324} {incr i} {
    lappend pvList Mt:SRbunch[format %03ld $i].VAL
    lappend varList SRBucket[format %03ld $i]
}
lappend pvList MtP0Cnt2AExtTrigEnbBo.VAL It:Ddg2chan6.GATE It:Ddg3chan2.GATE
lappend varList RTClockReset BoosterSeptumTrigger BoosterSeptumCharge

if [pv linkw $varList $pvList] {
    return -code error "SRTopupBucketAssignment0: Unable to connect to PVs: $errorCode"
}

# get string PV SR:bunchPatternSO
if [catch {APScavget -list=SR:bunchPatternSO} bunchPatternLabel ] {
    return -code error "SRTopupBucketAssignment0a: $bunchPatternLabel"
}
# with bunch pattern 1+8x7 the PVs LI:pulsesAO and LI:P0pulsesAO will
# be read at the calculation warning time in order to set the linac pulses.
# the "+" has to be escaped for regexp to work 
switch -regexp $bunchPatternLabel {
    {1\+8x7} {set stuffBucketZero 1} 
    default {set stuffBucketZero 0}
}

# This treats 324 bunch mode in a special way where the
# buckets will be selected based on last bucket injected
switch -glob $bunchPatternLabel {
    *324* {set doNotUseADC750 1}
    *432* {set doNotUseADC750 1}
    default {set doNotUseADC750 0}
}

if [catch {APScavget -list=LI:pulsesAO,LI:P0pulsesAO} result ] {
    return -code error "SRTopupBucketAssignment0b: $result"
}
set defaultLinacBunches [lindex $result 0]
set linacBunchesForP0 [lindex $result 1]
if {$defaultLinacBunches == 0} {
    return -code error "SRTopupBucketAssignment0c: Value of LI:pulsesAO zero. This PV is the number of linac pulses to inject into Bucket 0 for hybrid mode. To change values run the command medm -attach -x /usr/local/iocapps/adlsys/sr/bunchIApp/P0_1+8x7.adl. Suggested value is 3."
}
if {$linacBunchesForP0 == 0} {
    return -code error "SRTopupBucketAssignment0d: Value of LI:P0pulsesAO zero.  This PV is the number of linac pulses to inject buckets other than 0 for hybrid mode. To change values run the command medm -attach -x /usr/local/iocapps/adlsys/sr/bunchIApp/P0_1+8x7.adl. Suggested value is 3."
}

#enable soft interleaving pv so that topup can run interleaving mode when the interleaving key is turned on.
#otherwise, topup can not run interleaving even though the key is turned on but this soft pv is off 
if [catch {exec cavput -list=LI:iLeavePauseBO=0 -pend=10 } result] {
    return -code error "Error setting LI:iLeavePauseBO: $result"
}

puts stderr "[exec date] starting topup..."
while [string match $apsTopupEnabled Enable] {
    # checked whether beam is present
    # wait for warning time to drop to zero second in 
    # order to prepare for injection.
    # 1. turn on rf gun kicker
    # 2. toggle pulsed magnets.
    # 3. calculate bunch pattern deficit.
    puts stderr "[exec date] reading SR current..."
    if [catch {pv getw S35BeamCurrent} result] {
        return -code error "SRTopupBucketAssignment1: $result"
    }
    if {$S35BeamCurrent < $currentThreshold} {
        return -code error "SRTopupBucketAssignment2: Beam current is below threshold. Exiting procedure."
    }
    puts stderr  "[exec date] ping run control..."
    if [catch {APSRunControlPing} result] {
        return -code error "SRTopupBucketAssignment3: APSRunControlPing \#1, Run control denied: $result"
    }
    #
    #turn on par cleaning at 16s warning time
    
    if $turnOnOffParBunchCleaning {
        puts stderr "[exec date] turn on par bunch cleaning..."
        set first 1
        while 1 {
            if $first {
                puts stderr "[exec date] reading topuptime2warning before turn on par bunch cleaning..."
            }
            if [pv getw {apsTopupEnabled apsTopupTime2WarnCalc}] {
                return -code error "SRTopupBucketAssignment4: Unable to read PVs: $errorCode"
            }
            if ![string match $apsTopupEnabled Enable] {
                return
            }
            # wait for the calculation warning time.
            if {$apsTopupTime2WarnCalc==16} break
            if $first {
                puts  stderr "[exec date] ping runcontrol before turn on par bunch cleaning..."
            }
            if [catch {APSRunControlPing} result] {
                return -code error "SRTopupBucketAssignment5:  APSRunControlPing \#2a, Run control denied: $result"
            }
            set first 0
            after 1000
        }
        #turn on par bunch cleaning through setting the the delay to 20000 us
        
        set parBunchCleaningDelay 20000
        puts stderr "[exec date] set parBunchCleaningDelay to 20000"
        if [pv putw parBunchCleaningDelay] {
            return -code error "SRTopupBucketAssignment6: unable to turn on par bunch cleaning: $errorCode"
        }
    }
    puts "[exec date] check if in interleaving mode..."
    set first 1
    while 1 {
        if $first {
            puts stderr  "[exec date] read topup state, topuptime2warn apsTopupInterleaving..."
        }
        if [pv getw {apsTopupEnabled apsTopupTime2WarnCalc apsTopupInterleaving}] {
            return -code error "SRTopupBucketAssignment7: Unable to read PVs: $errorCode"
        }
        if ![string match $apsTopupEnabled Enable] {
            return
        }
        # wait for the calculation warning time.
        if {$apsTopupTime2WarnCalc<=10} break
        if $first {
            puts stderr "[exec date] ping runcontrol interleaving mode = $apsTopupInterleaving..."
        }
        if [catch {APSRunControlPing} result] {
            return -code error "SRTopupBucketAssignment8:  APSRunControlPing \#2, Run control denied: $result"
        }
        set first 0
        after 1000
    }
    if [pv getw apsTopupInterleaving] {
        return -code error "SRTopupBucketAssignment7a: Unable to read interleaving mode: $errorCode"
    }
    if $apsTopupInterleaving {
        puts stderr  "[exec date]interleaving mode, set RG2 alpha magnet to 140..."
        set apsTopupRG2AlphaMagnet 140
        if [pv putw apsTopupRG2AlphaMagnet] {
            puts stderr "SRTopupBucketAssignment8a:  Error setting RG2 alpha magnet to 140: $errorCode"
        }
    }
    
    # this while loop waits for topup calculation counter 
    # the loop is used instead fo cawait, for example, because we have to ping 
    # the run control PV every now and then to prevent it from
    # timing out.
    puts stderr "[exec date] wait for  topup calculation counter..."
    set first 1
    while 1 {
        if $first {
            puts stderr  "[exec date] read topup state and topupTime2warn..."
        }
        if [pv getw {apsTopupEnabled apsTopupTime2WarnCalc}] {
            return -code error "SRTopupBucketAssignment7: Unable to read PVs: $errorCode"
        }
        if ![string match $apsTopupEnabled Enable] {
            return
        }
        # wait for the calculation warning time.
        if {$apsTopupTime2WarnCalc==0} break
        if $first {
            puts stderr "[exec date] ping runcontrol at topup counter..."
        }
        if [catch {APSRunControlPing} result] {
            return -code error "SRTopupBucketAssignment8:  APSRunControlPing \#2, Run control denied: $result"
        }
        set first 0
        after 1000
    }
    puts stderr "[exec date] StopTopupFromRTFBStatus"
    if [catch {StopTopupFromRTFBStatus} result] {
       return -code error "SRTopupBucketAssignment9: Problem with checking RTFB statuses."
    }
    if $result {
        puts stderr "Topup disabled due to RTFB status."
        break
    }
    if [pv getw apsTopupInterleaving] {
        puts stderr "SRTopupBucketAssignment7a: error reading interleaving state: $errorCode"
    }
    # start injectors but not the booster extraction
    puts stderr "[exec date] Toggle all pulsed magnets in the injector and turn on gun kicker; interleaving mode $apsTopupInterleaving..."
    
    if [catch {TogglePulsedMagnetEnables -location GuntoBoosterInj} result] {
        return -code error "SRTopupBucketAssignment10: Problem with toggling pulsed magnets."
    }
    
    puts stderr "[exec date] Warm up booster extraction septums..."
    # Warm up booster extraction septums though we won't fire booster
    # extraction kicker yet.
    APScavput -list=Mt:Ddg1chan5,Mt:Ddg1chan4 -list=.GATE=1

    puts stderr "[exec date] Last delta current was $apsTopupDeltaI"
    if [pv getw {apsTopupDeltaI S35BeamCurrent}] {
        return -code error "SRTopupBucketAssignment11: Unable to read PVs: $errorCode"
    }

    if !$doNotUseADC750 {
        puts stderr "[exec date] Reading bunches (deleting patternFile sortedPatternFile)..."
        file delete $patternFile
        file delete $sortedPatternFile
        
        # ping here since it takes some time to read the bunch pattern.
        puts stderr "[exec date] ping runcontrol..."
        if [catch {APSRunControlPing} result] {
            return -code error "SRTopupBucketAssignment12:  APSRunControlPing \#3, Run control denied: $result"
        }
	set datestr [clock format [clock seconds] -format %Y-%m%d:%H%M%S]
        puts stderr "[exec date] read bunch current..."
        if [catch {ReadBunchCM -output $patternFile \
                     -noScalars 1 -average 1 -baselineCorrection 1 \
                     -S35DCCT $S35BeamCurrent \
                     -targetFile $targetPatternFile \
                 } result] {
            return -code error "SRTopupBucketAssignment13: $result"
        }
        puts stderr "[exec date] sorting pattern file..."
        if [catch {exec sddssort $patternFile -pipe=out \
		       -col=CurrentDeficit,decreasing \
		       | sddsprocess -pipe=in $sortedPatternFile \
		       -nowarning \
		       -filter=col,CurrentDeficit,1e-15,100 \
		       "-rpnexpre=0 sto index" \
		       "-def=col,Index,index 1 + sto index,type=long"
        } result ] {
            return -code error "SRTopupBucketAssignment14: $result"
        }
        puts stderr "[exec date] processing BPM group deficit..."
        if [catch {exec sddsprocess $patternFile -pipe=out \
                     -filter=col,Bucket,0,5 \
                     -proc=CurrentDeficit,sum,BPMGroupDeficit \
                     | sdds2stream -pipe -para=BPMGroupDeficit} BPMGroupDeficit] {
            return -code error "SRTopupBucketAssignment15: $BPMGroupDeficit"
        }
	
        if {$BPMGroupDeficit < 0 } {
            # remove buckets 0 to 5 from list to inject
            puts stderr "[exec date] processing pattern file, remove buckets 0 to 5..."
            if [catch {exec sddsprocess $patternFile -pipe=out \
                         -filter=col,Bucket,0,5,! \
                         | sddssort -pipe \
                         -col=CurrentDeficit,decreasing \
                         | sddsprocess -pipe=in $sortedPatternFile \
                         -noWarning \
                         -filter=col,CurrentDeficit,1e-15,100 \
                         "-rpnexpre=0 sto index" \
                         "-def=col,Index,index 1 + sto index,type=long"
            } result ] {
                return -code error "SRTopupBucketAssignment16: $result"
            }
        }
        puts stderr "[exec date] check sorting pattern file..."
        if [catch {exec sdds2stream -rows=bare $sortedPatternFile} rows] {
            return -code error "SRTopupBucketAssignment17: $rows"
        }
	puts stderr "[exec date] copy pattern file to  $patternDir ..."
	catch {exec cp $targetPatternFile $patternDir/target.$datestr }
	catch {exec cp $patternFile $patternDir/pattern.$datestr }
	catch {exec cp $sortedPatternFile $patternDir/sorted.$datestr }
	
        set weakBunches $rows 
        puts stderr "[exec date] Number of weak bunches: $weakBunches"
        if $weakBunches {
            puts stderr "[exec date] check bucket..."
            if [catch {exec sdds2stream $sortedPatternFile -col=Bucket \
                     } bucketList] {
                return -code error "SRTopupBucketAssignment18: $bucketList"
            }
        } else {
            # if there are no bunches to inject into, say because
            # we have too much current, then don't inject.
            puts stderr "[exec date] No bunches to inject into. Perhaps all bunches have too much current. Skipping..."
            after [expr 5 * 1000]
            continue
        }
        puts stderr "[exec date] copy pattern file to log file..."
        set logfilename /home/helios/oagData/sr/fillPatternLog/bucketAssignmentLog/BBCM-[clock format [clock seconds] -format %Y-%j-%m%d-%H%M%S]
        exec cp $patternFile $logfilename
        puts stderr "[exec date] gzip log file..."
        catch {exec gzip $logfilename}
    } else {
        # do not use ADC but determine buckets from the last-bucket-injected PV
        # skip all the above calculations
        puts stderr "[exec date] Determining buckets from last bucket injected..."
    }

    # for this mode of topup injection only one bunch is
    # injected at a time. At a later date when the septum
    # doesn't need a warm-up period, we can inject
    # more than one pulse in a sequence.
    puts stderr "[exec date] read apsNumToInject ..."
    pv getw apsNumToInject
    set numberToInject $apsNumToInject
    if $doNotUseADC750 {
        set bucketList ""
        # this is prime number 31 times 4 bucket interval
        set interval 124
        set lastBucketInjected [APScavget -list=Mt:SRlastInjectedBunchM.VAL]
        for {set i 1} {$i <= $apsNumToInject} {incr i} {
            lappend bucketList [expr ($lastBucketInjected + $i * $interval)%1296]
            
        }
    }
    puts stderr "[exec date] Sending bucket values ([lrange $bucketList 0 5] ...) to ioc."
    set bucketCount [llength $bucketList]
    set bucketVarList ""
    set bucket 0
    for {set i 0} {$i<$bucketCount} {incr i} {
        set SRBucket[format %03ld $bucket] [lindex $bucketList $i]
        lappend bucketVarList SRBucket[format %03ld $bucket]
        incr bucket
    }
    # turn on bunch cleaning for any buckets.
    puts stderr "[exec date] read It:allowPARcleaningC ..."
    if [catch {APScavget -list=It:allowPARcleaningC -pend=20} allowPARcleaning] {
        set allowParCleaning 0
    }
    if $allowPARcleaning {
        puts stderr "[exec date] turn on bunch cleaing for any buckets..."
        if [catch {APSPARCleaning -state 1} result] {
            return -code error "Unable to turn on PAR bunch cleaning: $result"
        }
    }
    if $stuffBucketZero {
        puts stderr "[exec date] read LI:pulsesAO,LI:P0pulsesAO"
        if [catch {APScavget -list=LI:pulsesAO,LI:P0pulsesAO} result ] {
            return -code error "SRTopupBucketAssignment19: $result"
        }
        set defaultLinacBunches [lindex $result 0]
        set linacBunchesForP0 [lindex $result 1]
        if {$SRBucket000 == 0} {
            puts stderr "[exec date] SetLinacBunches ..."
            if [catch {SetLinacBunches -number $linacBunchesForP0} result] {
                return -code error "SRTopupBucketAssignment20: $result"
            } 
        }
    }
    puts stderr "[exec date] set bucketVarList ..."
    if [pv putw $bucketVarList] {
        return -code error "Unable to set bucket values: $errorCode\nCommand: pv putw $bucketVarList"
    }

    #continual reset of RT clock during injection period
    set RTClockReset 1
    puts stderr "[exec date] reset RT clock..."
    if [pv putw RTClockReset] {
        return -code error "Unable to reset RT clock: $errorCode"
    }
    puts stderr "[exec date] read topup state..."
    if [pv getw apsTopupEnabled] {
        return -code error "Unable to read PV: $errorCode"
    }

    if [string match $apsTopupEnabled Disable] {
        continue
    }
    puts stderr "[exec date] ping runcontrol..."
    if [catch {APSRunControlPing} result] {
        return -code error "SRTopupBucketAssignment21: APSRunControlPing \#4, Run control denied: $result"
    }

    # set the injection status to Waiting (numerical value of 0)
    set apsInjectionDone Waiting
    puts stderr "[exec date] set apsInjectionDone..."
    if [catch {pv putw apsInjectionDone} result] {
        return -code error "Problem with putting value to apsInjectionDone"
    }

    # Prepare for booster extraction
    puts stderr "[exec date] prepare for booster extraction..."
    set first 1
    while 1 {
        after 500
        if $first {
            puts stderr "[exec date] read topuptime2warn, topup state before prepare for booster extraction..."
        }
        if [pv getw {apsTopupTime2WarnInjector apsTopupEnabled}] {
            return -code error "Unable to read PVs: $errorCode"
        }
        if ![string match $apsTopupEnabled Enable] {
            return
        }
        # wait for the injection warning time.
        if {$apsTopupTime2WarnInjector==0} break
        if $first {
            puts stderr "[exec date] ping runcontrol before prepare for booster extraction..."
        }
        if [catch {APSRunControlPing} result] {
            return -code error "SRTopupBucketAssignment22: APSRunControlPing #5, Run control denied: $result"       }
        set first 0
    }
    puts stderr "[exec date] StopTopupFromRTFBStatus..."
    if [catch {StopTopupFromRTFBStatus} result] {
       return -code error "StopTopupFromRTFBStatus: Problem with checking RTFB statuses."
    }
    if $result {
        puts stderr "Topup disabled due to RTFB status."
        break
    }
    
    # turn on booster extraction
    #    TogglePulsedMagnetEnables -location BoosterExt
    # this is faster than Toggle

    # If PV Mt:SRinjectMultiExcludBsEKBO.VAL = Include then
    # the beam automatically appears when SR kickers are fired.
    # The operators would have to manually turn on kicker for 
    # introducing beam in the BTS beamline for tuning purposes.
    # If PV Mt:SRinjectMultiExcludBsEKBO.VAL = Exclude then
    # we need to turn on extraction kicker at this stage.
    # Depending of the value of the warning to injectors
    # there will be some few pulses in the BTS beamline.
    puts stderr "[exec date] read apsBoosterEKexcluded..."
    pv getw apsBoosterEKexcluded
    if [string match $apsBoosterEKexcluded Exclude] {
        puts stderr "[exec date] set Mt:Ddg1chan0.GATE to 1..."
        APScavput -list=Mt:Ddg1chan0 -list=.GATE=1
    }
    # now wait for ioc-based injection to occur. Warn time is zero 
    # until injection is over
    puts stderr "[exec date] ping runcontrol..."
    catch {APSRunControlPing}
    puts stderr "[exec date] read topuptime2warn, topupinterval..."
    if [pv getw {apsTopupTime2WarnCalc apsTopupInterval}] {
        return -code error "Unable to read PVs: $errorCode"
    }
    if [expr ($apsTopupInterval - $apsTopupTime2WarnCalc) < 10 ] {
        return -code error "Error: the interval requested is not 10 seconds longer than the injector warning time.\n\nThis will cause problems with selecting the buckets to inject. Please reduce the warning time or increase the injection interval.Some details:\napsTopupInterval: $apsTopupInterval\napsTopupTime2WarnCalc: $apsTopupInterval"
    }

    # Wait for end of injection, indicated by Mt:SRinjectDoneBO
    # reading back "Done"
    puts stderr "[exec date] wait for end of injection..."
    set first 1
    while 1 {
        if $first {
            puts stderr "[exec date] read apsInjectionDone apsTopupEnabled at wait for end of injection"
        }
        if [pv getw {apsInjectionDone apsTopupEnabled}] {
            return -code error "SRTopupBucketAssignment23: Unable to read PVs: $errorCode"
        }
        if ![string match $apsTopupEnabled Enable] {
            return -code error "SRTopupBucketAssignment24: Topup has been externally disabled"
        }
        if {$apsInjectionDone=="Done"} break
        after 500
        if $first {
            puts stderr "[exec date] ping runcontrol at wait for end of injection ..."
        }
        if [catch {APSRunControlPing} result] {
            return -code error "SRTopupBucketAssignment25:  APSRunControlPing \#6, Run control denied: $result"
        }
        set first 0
    }
    puts stderr "[exec date] read It:allowBTSchargeC..."
    if [catch {APScavget -list=It:allowBTSchargeC -pend=20} allowBTScharge] {
        set allowBTScharge 0
    }
    puts stderr "[exec date] Top-up injection is done [clock format [clock seconds]]"
    
   
    if !$allowBTScharge {
        # Turn off booster extraction as soon as possible
        # to save the SR septum from charge being dumped there.
        puts stderr "[exec date] Turn off booster extraction "
        SetPulsedMagnetEnables -state 0 -location BoosterExt
        puts stderr "[exec date] read  apsTopupInterleaving"
        if [pv getw apsTopupInterleaving] {
            puts stderr "SRTopupBucketAssignment27a: error reading interleaving state: $errorCode"
        }
        if $apsTopupInterleaving {
            #set RG2 alpha magnet to 0
            puts stderr "[exec date] interleaving mode: set RF2 alpha magnet to 0"
            if {$toggleGunKicker} {
                puts stderr "Turn off RG2 alpha magnet..."
                set apsTopupRG2AlphaMagnet 0
                if [pv putw apsTopupRG2AlphaMagnet] {
                    puts stderr "SRTopupBucketAssignment27b:  Error setting RG2 alpha magnet to 0: $errorCode"
                }
            }
        } else {
            puts stderr "[exec date] non interleaving mode."
        }
        if {$toggleGunKicker} {
            puts stderr "[exec date] Disabling trigger to rf gun kickers..."
            set apsRFGunKickerTrigger Disabled
            if [pv putw apsRFGunKickerTrigger] {
                puts stderr "SRTopupBucketAssignment27: Problem toggling rf gun kicker: $errorCode"
            }
        }
        
        # and turn off booster septum pulsing.
        puts stderr "[exec date] turn off booster septum pulsing."
        set BoosterSeptumTrigger Disabled
        if [pv putw {BoosterSeptumTrigger}] {
            return -code error "SRTopupBucketAssignment28: Unable to set PVs: $errorCode"
        }
        if $includeBoosterSeptum {
            #turn off booster septum charge
            puts stderr "[exec date] turn off booster septum charge"
            set BoosterSeptumCharge Disabled
            if [pv putw {BoosterSeptumCharge}] {
                return -code error "SRTopupBucketAssignment29: Unable to set PVs: $errorCode"
            }
        }
        # waiting 1.0 seconds after turning off gun to ensure
        # that PAR is emptied of charge
        after 1000
        puts stderr "[exec date] waiting 1.0 seconds after turning off gun; then turn off par kicker..."
        if !$includeParSeptum {
            SetPulsedMagnetEnables -state 0 -location PARKicker 
        } else {
            SetPulsedMagnetEnables -state 0 -location PARKickerSeptum
        }
    }
    # turn off resetting of RT clock during injection period, 
    puts stderr "[exec date] turn off resetting of RT clock during injection period,"
    set RTClockReset 0
    if [pv putw {RTClockReset}] {
        return -code error "SRTopupBucketAssignment30: Unable to set PVs: $errorCode"
    }
    puts stderr "[exec date] ping runcontrol..."
    if [catch {APSRunControlPing} result] {
        return -code error "SRTopupBucketAssignment31:  APSRunControlPing \#7, Run control denied: $result"
    }
    if $stuffBucketZero {
        puts stderr "[exec date] read LI:pulsesAO,LI:P0pulsesAO ..."
        if [catch {APScavget -list=LI:pulsesAO,LI:P0pulsesAO} result ] {
            return -code error "SRTopupBucketAssignment32: $result"
        }
        set defaultLinacBunches [lindex $result 0]
        set linacBunchesForP0 [lindex $result 1]
        puts stderr "[exec date] SetLinacBunches"
        if [catch {SetLinacBunches -number $defaultLinacBunches} result] {
            return -code error "SRTopupBucketAssignment33: $result"
        } 
    }
    if $turnOnOffParBunchCleaning {
        #turn off par bunch cleaning through setting the delay to 1000 us
        puts stderr "[exec date] turn off par bunch cleaning through setting the delay to 1000 us"
        set parBunchCleaningDelay 1000
        if [pv putw parBunchCleaningDelay] {
            return -code error "SRTopupBucketAssignment26: unable to turn off par bunch cleaning: $errorCode"
        }
    }
    puts stderr "[exec date]  wait for the calculation warning time to return to a high value before starting the loop gain."
    # wait for the calculation warning time to return to a high value
    # before starting the loop again.
    set first 1
    while 1 {
        if $first {
            puts stderr "[exec date] read topup state, topuptime2warn before starting the loop again..."
        }
        if [pv getw {apsTopupEnabled apsTopupTime2WarnCalc}] {
            return -code error "SRTopupBucketAssignment34: Unable to read PVs: $errorCode"
        }
        if ![string match $apsTopupEnabled Enable] {
            return
        }
        # wait for the calculation warning time.
        if {$apsTopupTime2WarnCalc != 0} break
        if $first {
            puts stderr "[exec date] ping runcontrol before starting the loop again..."
        }
        if [catch {APSRunControlPing} result] {
            return -code error "SRTopupBucketAssignment35: Run control denied: $result"
        }
        set first 0
        after 1000
    }
    puts stderr "[exec date] ping runcontrol before starting the loop..."
    if [catch {APSRunControlPing} result] {
        return -code error "SRTopupBucketAssignment35: Run control denied: $result"
    }
    puts stderr "[exec date] start next loop..."
}

puts stderr "Topup injection terminated externally."
dp_atexit append APSRunControlExit 
if {[info exists allowPARcleaning] && $allowPARcleaning} {
    dp_atexit append "APSPARCleaning -state 1"
}
