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

# $Log: not supported by cvs2svn $
# Revision 1.40  2010/04/21 22:14:11  shang
# added checking bunch pattern and returning an alert box if the bunch pattern is not 24 siglets or hybrid because the bunch purity script only works for
# 24 siglets and hybrid fill.
#
# Revision 1.39  2009/10/08 14:52:33  soliday
# Updated to fix an issue when plotting data from a file that has a space
# in the name.
#
# Revision 1.38  2008/02/06 16:03:40  soliday
# Removed calls to setfacl because it is no longer needed.
#
# Revision 1.37  2007/10/12 17:24:12  shang
# changed FPGA waveform collecting and plotting.
#
# Revision 1.36  2007/06/01 17:20:39  shang
# fixed a typo
#
# Revision 1.35  2007/04/05 15:48:10  shang
# modified the plot labels for FPGA buckets data per CY's request.
#
# Revision 1.34  2007/04/04 18:40:25  shang
# modified processing FPGA data to work with one main bucket case.
#
# Revision 1.33  2007/03/29 19:59:54  shang
# fixed a bug in deleting FPGA files.
#
# Revision 1.32  2007/03/22 17:58:22  shang
# enhanced FPGA plots per CY's request.
#
# Revision 1.31  2007/03/13 20:16:56  shang
# added ability to change the calibration factor, bucket width and option of peak or integration to calculate the bunch purity.
#
# Revision 1.30  2007/03/09 21:21:14  shang
# changed the calibration factor to 55.769
#
# Revision 1.29  2006/10/06 21:45:35  shang
# changed the x/y Dector position for "Move APD in" button
#
# Revision 1.28  2006/09/08 16:17:47  soliday
# Changed exec BunchPurityAutoScan.tcl to exec BunchPurityAutoScan
#
# Revision 1.27  2006/03/31 21:56:05  shang
# modified to show the data related directories only for plot/review
#
# Revision 1.26  2006/03/24 21:59:11  shang
# comment out APSDebugPath and APSDefineSCRVariables since they seem useless and
# may cause delay in startup.
#
# Revision 1.25  2006/03/15 21:45:32  shang
# changed pixel per bucket to 58.333 and fixed the plot of the bucket position.
#
# Revision 1.24  2006/02/08 20:09:16  shang
# removed the integral purity, but added peak purities of buckets +-3 and +-1.
#
# Revision 1.23  2006/01/24 20:59:13  shang
# removed codes for setup ADC since those PVs no longer exist
#
# Revision 1.22  2005/12/02 22:57:50  shang
# fixed the problem with peakPosition existence
#
# Revision 1.21  2005/12/01 21:30:53  shang
# plots lines for +-3, +-2, and +-1 buckets
#
# Revision 1.20  2005/02/23 19:00:36  shang
# added reading MCA live time and real time and added them to the parameter of data file.
#
# Revision 1.19  2005/01/31 16:06:14  shang
# it now uses exponential format for plotting the bunch purity
#
# Revision 1.18  2004/12/08 22:39:23  shang
# replaced all "upstream" and "downstream" messages by "left" and "right"
#
# Revision 1.17  2004/12/08 22:37:22  shang
# changed message: upstream to left, downstream to right to avoid missleading
#
# Revision 1.16  2004/11/05 16:38:32  shang
# changed the plot legend to the date and time of the original file for temporary
# ploting.
#
# Revision 1.15  2004/11/05 16:24:49  shang
# added initialization of plotFile
#
# Revision 1.14  2004/11/04 21:32:09  shang
# added lumpkin to allowed users
#
# Revision 1.13  2004/11/04 20:25:29  shang
# separates the upstream and downstream integrated purity and avoids writing to
# the archive directory if user does not have permission.
#
# Revision 1.12  2004/11/04 16:17:17  shang
# added button for calculating bunch purity
#
# Revision 1.11  2004/10/07 19:20:20  shang
# made the user plot option overwrites hard-code plot option
#
# Revision 1.10  2004/08/17 16:51:57  shang
# added auto-scan feature
#
# Revision 1.9  2004/07/21 17:27:07  shang
# sorted the files by date and made the specified plot range work
#
# Revision 1.8  2004/07/08 20:41:28  shang
# added normalized S36AM:BP:mca.VAL column (S36AM:BP:mca.VALNorm) to output file and
# added it to the plots with logrithom plot option; simplied the plotting codes
#
# Revision 1.7  2003/12/04 01:31:27  borland
# Fixed problem with composition of plot commands that resulted in plotting of
# same data twice with no visible scales.
#
# Revision 1.6  2003/12/02 17:26:18  shang
# the legend for multiple files plot only shows the time-stamps
#
# Revision 1.5  2003/12/02 16:44:57  shang
# it is now able to plot multiple files and the accept button works properly
#
# Revision 1.4  2003/11/19 22:31:09  shang
# changes the rootname back to sr-bPurity when emptry bucket number (for all buckets)
# enters,
#
# Revision 1.3  2003/11/19 21:59:50  shang
# added setting Bucket number feature. The existing review window will be destroyed
# when plot/review button is pressed and the list window is automatically updated
# if an item is deleted. (tested with Lampkin in control room)
#
# Revision 1.2  2003/11/07 22:36:56  shang
# added asdops user to new created directory
#
# Revision 1.1  2003/11/05 17:35:05  shang
# converted from s35BPDSetup wrote by Bingxin Yang.
#
# rewrite from s35BPDSetup, H. Shang
# original script is written by Bingxin Yang

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
APSStandardSetup
#APSSCRDefineVariables
# Process command line arguments
set PowerUser 0
set args $argv
APSParseArguments {PowerUser}

# Authorization setting: everyone can run it
set authorizedUser 1

# Menu 
set CVSRevisionAuthor "\$Revision: 1.41 $ \$Author: shang $"

if {$PowerUser} {
   set appName "SRBPDSetup: Bunch Purity Setup"
   set PowerUser 1
} else {
   set appName "SRBPDSetup: Bunch Purity Operation"
   set PowerUser 0
}
APSApplication . -name $appName -version $CVSRevisionAuthor \
  -overview "Setup motors for the S35 bunch purity detector"
update
# message window output "stdout"
set mainStatus "To set up bunch purity monitor motors from MCR, use \[Motor setup\]."
APSScrolledStatus .status -parent .userFrame -width 82 -height 10 -textVariable mainStatus 

proc SetMainStatus {text args} {     
    global mainStatus 
    set code ""
    APSParseArguments {code}
    set mainStatus "[clock format [clock seconds] -format %H:%M:%S] $text"
    switch $code {
        error -
        warning {
            bell
        }
        default {}
    }
    update      
}    

# Widgets design: Setup
proc SetupFrame {widget args} {
    APSStrictParseArguments {parent}

    set w $parent$widget.frame
    APSFrame $widget -parent $parent \
      -label "Restore settings for the Bunch Purity Monitor" 
    
    # executable command
    APSButton .motorSetup -parent $w \
      -text "Setup motor driver" \
      -packOption "-side left" \
      -command {setupMotors} \
      -contextHelp "Load stepper motor driver setup parameters"

    # executable command
    APSButton .motorInit -parent $w \
      -text "Init motor limits" \
      -packOption "-side left" \
      -command {initMotors} \
      -contextHelp "Initialize the stepper motor position counter"

    APSButton .timeSetup -parent $w \
      -text "Load bunch pattern" \
      -packOption "-side right" \
      -command {setupTiming} \
      -contextHelp "Setup timing for bunch purity detector."

    return
}


# Widgets design: Detector
proc DetectorFrame {widget args} {
    global abortRun
    APSStrictParseArguments {parent}

    set w $parent$widget.frame
    APSFrame $widget -parent $parent \
      -label "Set location for the Bunch Purity Detector" 
    
    APSButton .openShutter -parent $w \
      -text "Open shutters" \
      -packOption "-side left" \
      -command {openShutters} \
      -contextHelp "Open 35-ID photon shutter PS2 and safety shutters."

    APSButton .motorIn -parent $w \
      -text "Move APD IN" \
      -packOption "-side left" \
      -command {sendMotorsIn} \
      -contextHelp "Move the Bunch Purity Detector into the beam"

    APSButton .motorOut -parent $w \
      -text "Move APD OUT" \
      -packOption "-side left" \
      -command {sendMotorsOut} \
      -contextHelp "Move the Bunch Purity Detector out of the beam"

    APSButton .abort -parent $w \
      -text "STOP MOTORS" \
      -packOption "-side left" \
      -command {set abortRun 1} \
      -contextHelp "Stop moving motors / abort proc"

    APSButton .closeShutter -parent $w \
      -text "Close shutters" \
      -packOption "-side left" \
      -command {closeShutters} \
      -contextHelp "Close 35-ID photon shutter PS2 and safety shutters."

    return
}


# Widgets design: APDStatus
proc StatusFrame {widget args} {
    global abortRun xMotorPos yMotorPos APDCounts

    APSStrictParseArguments {parent}    

    # text input   
    set w $parent$widget.frame
    APSFrame $widget -parent $parent -label "CURRENT APD STATUS"

    APSLabeledEntryFrame .motorPosition -parent $w \
      -label "xDetector / yDetector / Count Rate : " \
      -variableList { xMotorPos yMotorPos APDCounts } \
      -contextHelp "Display the position of the motors and countrate." \
      -orientation horizontal -width 8 -packOption "-side left" 

    # executable commands
    APSButton .move -parent $w \
      -text "Update"  \
      -packOption "-side right" \
      -command { updateStatusDisplay } \
      -contextHelp "Update the status displays."

    return
}

set BucketList ""
for {set i 0} {$i<24} {incr i} {
    lappend BucketList [expr $i*54]
}

proc SetBucketNumber {args} {
    global BucketNumber outputRootname BucketList FPGARootname
    
    set BucketNumber [string trim $BucketNumber]
    if ![string length $BucketNumber] {
        set outputRootname sr-bPurity-50ns-newTac
        set FPGARootname sr-bPurityFPGA
        #turn on the autoload
        if [catch {exec cavput -list=S35IDBnchClkGenAutoLoadBO.VAL=On -pend=30} result] {
            return -code error "1.$result"
        }
        return
    }
    if [lsearch $BucketList $BucketNumber]<0 {
        return -code error "Invalid bucket number entered."
    }
    set outputRootname sr-bPurity-b${BucketNumber}
    set FPGARootname sr-bPurityFPGA-b${BucketNumber}
    #1. turn off the autoload
    if [catch {exec cavput -list=S35IDBnchClkGenAutoLoadBO.VAL=Off -pend=30} result] {
        return -code error $result
    }
    #2. clear the bunch patterns
    if [catch {exec cavput -list=S35IDBnchClkGenClearPatBO.VAL=Clear -pend=30} result] {
	return -code error $result
    }
    #set the bucket number
    if [catch {exec cavput -list=S35IDBnchClkGenSetBucketAO.VAL=$BucketNumber -pend=30} result] {
	return -code error $result
    }
}

set bucketPreset ""
proc SetPresetBuckets {args} {
    global bucketPreset
    
    if ![string length $bucketPreset] {
        return -code error "The bucket preset pattern is not chosen!"
    }
    if {$bucketPreset== "24"} {
        #turn on the autoload
	if [catch {exec cavput -list=S35IDBnchClkGenAutoLoadBO.VAL=On -pend=30} result] {
	    return -code error "1.$result"
	}
	return  
    }
    switch $bucketPreset {
        10 {
            set bucketList {0 54 108 162 216 270 540 594 1080 1134}
        }
        12even {
            set bucketList {0 108 216 324 432 540 648 756 864 972 1080 1188}
        }
        12odd {
            set bucketList {54 162 270 378 486 594 702 810 918 1026 1134 1242}
        }
        default {
            return -code error "Unknown bucket preset given!"
        }
    }
    set length [llength $bucketList]
    for {set i 0} {$i<$length} {incr i} {
        lappend valueList 1
    }
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTmpFileList -ID bunchPurity -fileList "$tmpRoot.1 $tmpRoot.2 $tmpRoot.3"
    if [catch {exec sddswget -pvname=S35IDBnchClkGenPatternWF.VAL $tmpRoot.1} result] {
        return -code error $result
    }
    if [catch {exec sddsmakedataset $tmpRoot.2 -col=Index,type=long -data=[join $bucketList ,] \
                 -col=Waveform,type=short -data=[join $valueList ,] } result] {
        return -code error $result
    }
    if [catch {exec sddsxref $tmpRoot.1 $tmpRoot.2 -equate=Index -rename=col,Waveform=Waveform1 \
                 -fillIn -nowarnings -pipe=out \
                 | sddsconvert -pipe=in $tmpRoot.3 \
                 -dele=col,Waveform -rename=col,Waveform1=Waveform } result] {
        return -code error $result
    }
}

set BucketNumber ""
# Widgets design: Waveform
proc WaveformFrame {widget args} {
    global abortRun BucketNumber separate samescale layoutOption legends bucketPreset
    global calFactor method AutoScanInterval upperLimit lowerLimit satelliteWidth bucketWidth
    APSStrictParseArguments {parent}
    
    set fieldWidth 64
    set calFactor 211.20
    set method Integration
    set bucketWidth 100
    
    set w $parent$widget.frame
    APSFrame $widget -parent $parent \
        -label "Acquire Bunch Purity Waveform" 
    # APSRadioButtonFrame .preset -parent $w -label "Bucket preset pattern:" \
        #   -variable bucketPreset -buttonList {10 "12 even" "12 odd" 24} \
        #   -valueList {10 12even 12odd 24} -orientation horizontal \
        #   -contextHelp "choose and set the bucket preset pattern, each set contains buckets as following:\n\n10: 0,54,108,162,216,270,540,1080,1134\n\n12 even: 0, 108, 216, 324, 432, 540, 648, 756, 864, 972, 1080,1188\n\n12 odd: 54, 162, 270, 378, 486, 594, 702, 810, 918, 1026, 1134, 1242\n\n24: all 24 buckets" \
        #  -commandList {SetPresetBuckets SetPresetBuckets SetPresetBuckets SetPresetBuckets}
    APSLabeledEntry .bucket -parent $w -width $fieldWidth \
        -label "Bucket number:" -textVariable BucketNumber \
        -contextHelp "Enter the bucket number to acquire waveform or empty string for all buckets"
    bind $w.bucket.entry <Return> SetBucketNumber
    APSButton .set -parent $w.bucket -packOption "-side right" -size small \
        -text "set" -command SetBucketNumber \
        -contextHelp "Press to set the bucket number."
    APSLabeledEntry .outputdirectory -parent $w \
        -label "Main dir:" -textVariable mainDir \
        -contextHelp "Enter the directory for output data file." \
        -width $fieldWidth
 
    
    APSLabeledEntry .plotOption -parent $w \
        -label "Plot option:" -textVariable userPlotOption \
        -contextHelp "Enter options for the plot." \
        -width $fieldWidth

    APSFrameGrid .grid -parent $w -xList {x1 x2} -packOption "-side top -fill x"
    set w1 $w.grid.x1
    set w2 $w.grid.x2
    APSLabeledEntry .plotstart -parent $w1 \
        -label "Plot start:" -textVariable plotStart \
        -contextHelp "Enter starting channel # for plot." \
        -width 10 -packOption "-side top -fill x"
    APSButton .defaultstart -parent $w1.plotstart -packOption "-side right" \
        -text "default" -size small \
        -command {set plotStart 1000}
    
    APSLabeledEntry .plotstop -parent $w1 \
        -label "Plot stop:" -textVariable plotStop \
        -contextHelp "Enter ending channel # for plot." \
        -width 10 -packOption "-side top -fill x"
    APSButton .defaultstart -parent $w1.plotstop -packOption "-side right" \
        -text "default" -size small \
        -command {set plotStop 3600}
    
   
    APSLabeledEntry .autointerval -parent $w1 -textVariable AutoScanInterval \
        -label "Auto-scan interval (hours):" -width 10 \
        -contextHelp "the interval of automatical scan."
    APSLabeledEntry .factor -parent $w1 -label "Calibration factor:" \
        -textVariable calFactor -width 10 \
        -contextHelp "calibration factor is the index difference between main bucket and the first satellite bucket."
    APSLabeledEntry .width -parent $w1 -label "Bucket width:" \
        -textVariable bucketWidth -width 10 \
        -contextHelp "the width (index) of bucket, which defines the range of obtaining bucket intensity."
    # radio button for plotType selection
    set plotTypeList {LOG LINEAR}
    APSRadioButtonFrame .plotChoiceFrame -parent $w2 \
        -orientation  horizontal \
        -packOption {-side top -fill x} \
        -label "   Plot Type:" \
        -variable plotType \
        -buttonList $plotTypeList \
        -valueList  $plotTypeList \
        -contextHelp "This radio button is used to select a plot type."
    
    APSCheckButtonFrame .group -parent $w2 \
        -orientation  horizontal \
        -packOption {-side top -fill x} \
        -label "   Grouping:" \
        -buttonList {separate "same scale"}  \
        -variableList  {separate samescale}  \
        -contextHelp "select grouping option for plotting multiple files."
    
    APSRadioButtonFrame .layout -parent $w2 \
        -orientation  horizontal \
        -variable layoutOption \
        -label "   Layout:" \
        -buttonList {1x1 2x2 3x3 4x4 5x5}  \
        -valueList  {-layout=1,1 -layout=2,2 -layout=3,3 -layout=4,4 -layout=5,5} \
        -contextHelp "Chooses how plot panels are layed out on a plot page.  If you choose to separate data on panels using the Grouping choices, you may also want a Layout other than the default 1x1."
     
     
    APSRadioButtonFrame .method -parent $w2 -label "   Method for purity calculation:" \
        -buttonList {Peak Integration} -valueList {Peak Integration} \
        -variable method -orientation horizontal
  
}

set frameIndex -1
proc ExecutionFrame {widget args} {
    set parent ""
    APSParseArguments {parent}
    global outputRootname FPGARootname frameIndex
    APSFrame $widget -parent $parent -label "Execution"
    APSFrame .acq1 -parent $parent$widget.frame
    APSButton .acq -parent $parent$widget.frame.acq1.frame -text "Acquire MCA Data" \
        -command "acqWaveform" -contextHelp "acquire bunch purity into MCA"
    APSButton .abort -parent $parent$widget.frame.acq1.frame -text "Abort"  -command {set abortRun 1}
    set tabFrameList [APSTabFrame .tab -parent $parent.exec.frame -label "Save/Process/View Data" \
                          -labelList {"Camera AIM MCA" "FPGA MCA"} -width 750 -height 150 \
                          -packOption "-expand true" -frameIndexVariable frameIndex ]
    set w1 [lindex $tabFrameList 0]
    set w2 [lindex $tabFrameList 1]
    # executable commands 
    APSLabeledEntry .outputfilename -parent $w1 \
        -label "File rootname:" -textVariable outputRootname \
        -contextHelp "Enter the root name of the output file." \
        -width 70
    
    APSFrameGrid .grid -parent $w1 -yList {y1 y2}
    
    APSButton .getwave -parent $w1.grid.y1 \
        -text "Save Data File"  \
        -command {getWaveform} \
        -contextHelp "Save bunch purity MCA waveform to file."
    APSButton .calc -parent $w1.grid.y1 \
        -text "Calculate Bunch Purity"  \
        -command {CalculateBunchPurityFrom} \
        -contextHelp "calcualte bunch purity for selected files."
    APSButton .plot -parent $w1.grid.y1 \
        -text "Plot/Review data"  \
        -command {plotData -userPlotOption $userPlotOption } \
        -contextHelp "Plot MCA waveform data."
    
    APSButton .auto -parent $w1.grid.y2 -text "Start Auto-Scan" -command StartAutoScan \
        -contextHelp "call BunchPurityAutoScan to start automatic scan with given auto scan interval."
    APSButton .abortauto -parent $w1.grid.y2 -text "Abort Auto-Scan" -command AbortAutoScan \
        -contextHelp "abort automatic scan if it is running."
    APSButton .autoinfo -parent $w1.grid.y2 -text "Auto-Scan Info" -command AutoScanInfo \
      -contextHelp "bring up the medm screan of auto-scan"
    
    #FPGA buttons.
    global bucketFactor  
    set bucketFactor 0.85 
    APSLabeledEntry .outputfilename -parent $w2 \
        -label "File rootname:" -textVariable FPGARootname \
        -contextHelp "Enter the root name of the output file." \
        -width 70
    APSFrameGrid .grid -parent $w2 -xList {x1 x2}
    APSLabeledEntry .factor -parent $w2.grid.x1 \
        -label "Main bucket factor:" -textVariable bucketFactor \
        -width 20 -contextHelp "the factor defines the main buckects, i.e, if the bucket intensity relative to the peak intensity is greater than this factor, then it is main bucket."
    APSButton .save -parent $w2 -text "Save Data File"  \
        -command "getFPGAWaveform" \
        -contextHelp "save FPGA waveform data into files."
    APSButton .process -parent $w2 -text "Re-process" \
        -command "PlotFPGAData -reprocess 1"
    APSButton .plot0a -parent $w2 -text "PlotData" \
        -command "PlotFPGAData -plotSum 1"
    APSButton .plot0 -parent $w2 -text "PlotAllBuckets" \
        -command "PlotFPGAData -plotBucket 1"
    APSButton .plot1 -parent $w2 -text "Plot Raw" \
        -command "PlotFPGAData -plotRaw 1" 
}


proc setupMotors {args} {
    global abortRun VERBOSE xMotor yMotor

    SetMainStatus "Setting up stepper motor parameters..."

    # Set up stepper motor parameters	
    #exec /home/helios/PHOTODIA/operations/s35apps/Setup/s35BPDMotorSetup
    if [catch {S35BPDMotorSetup} result] {
        SetMainStatus "S35BPDMotorSetup: $result" -code error
        return
    }
    SetMainStatus "Done." 
    return
}

proc S35BPDMotorSetup {args} {
    SetMainStatus "Setup 35-ID-A Bunch Purity Detector stepper motors" 
   # if [catch {exec /home/helios/PHOTODIA/operations/s35apps/Setup/s35BM_BPDmcaSetup } result] {
   #     return -code error "Error in setup 35-ID-A Bunch Purity Detector stepper motors: $result"
   # }

    return
    
    #following code are obselete due to hardware changes.
    
    # Set up screen names
    if [catch {exec cavput \
                 "-list=S36AM:BP:APDxMT.DESC=BP detector X,S36AM:BP:APDyMT.DESC=BP detector Y" \
                 -pend=30} result] {
        return -code error "Set up screen names: $result"
    }
    
    # Set up motor resolution
    if [catch {exec cavput -list=S36AM:BP:APDxMT.MRES=0.0035,S36AM:BP:APDyMT.MRES=0.005 -pend=30} result] {
        return -code error "Set up motor resolution: $result"
    }
    
    # Set up motor retry deadband: twice of the step size
    if [catch {exec cavput -list=S36AM:BP:APDxMT.RDBD=0.01,S36AM:BP:APDyMT.RDBD=0.01 -pend=30} result] {
        return -code error "Set up motor retry deadband: $result"
    }

    # Set up motor # of retries: 10
    if [catch {exec cavput -list=S36AM:BP:APDxMT.RTRY=10,S36AM:BP:APDyMT.RTRY=10 -pend=30} result] {
        return -code error "Set up motor # of retries: $result"
    }

    # Set up motor direction: 0 = POS, 1 = NEG
    if [catch {exec cavput -list=S36AM:BP:APDxMT.DIR=0,S36AM:BP:APDyMT.DIR=0 -pend=30} result] {
        return -code error "Set up motor direction: $result"
    }

    # Set up motor speed
    if [catch {exec cavput -list=S36AM:BP:APDxMT.VELO=1,S36AM:BP:APDyMT.VELO=1 -pend=30} result] {
        return -code error "Set up motor speed: $result"
    }
    # Set up motor backlash speed
    if [catch {exec cavput -list=S36AM:BP:APDxMT.BVEL=0.5,S36AM:BP:APDyMT.BVEL=0.5 -pend=30} result] {
        return -code error "Set up motor backlash speed: $result"
    }

    # Set up acceleration:
    if [catch {exec cavput -list=S36AM:BP:APDxMT.ACCL=0.25,S36AM:BP:APDyMT.ACCL=0.25 -pend=30} result] {
        return -code error "Set up acceleration: $result"
    }
    # Set up backlash acceleration
    if [catch {exec cavput -list=S36AM:BP:APDxMT.BACC=0.1,S36AM:BP:APDyMT.BACC=0.1 -pend=30} result] {
        return -code error "Set up backlash acceleration: $result"
    }
    # Set up lower limit
    if [catch {exec cavput -list=S36AM:BP:APDxMT.LLM=-100,S36AM:BP:APDyMT.LLM=-100 -pend=30} result] {
        return -code error "Set up lower limit: $result"
    }
    
    # Set up upper limit
    if [catch {exec cvaput -list=S36AM:BP:APDxMT.HLM=100,S36AM:BP:APDyMT.HLM=100 -pend=30} result] {
        return -code error "Set up upper limit: $result"
    }
    
    # Use encoder? 0 = NO, 1 = YES
    if [catch {exec cvaput -list=S36AM:BP:APDxMT.UEIP=0,S36AM:BP:APDyMT.UEIP=0 -pend=30} result] {
        return -code error "Set up encoder: $result"
    }
    
    # Use readback? 0 = NO,  1 = YES
    if [catch {exec cvaput -list=S36AM:BP:APDxMT.URIP=0,S36AM:BP:APDyMT.URIP=0 -pend=30} result] {
        return -code error "Set up readback: $result"
    }
}

proc setupTiming { } {
    APSSetVarAndUpdate BPD_Status "Load bunch pattern."
    
    set pvList {S35IDBnchClkGenDisableBO.VAL S35IDBnchClkGenAutoLoadBO.VAL \
                  S35IDBnchClkGenClearPatBO.VAL S35IDBnchClkGenLoadPatBO.VAL \
                  S35IDBnchClkGenAutoLoadBO.VAL}        
    set valList {0 0 1 1 1}
    set putcomm ""
    foreach pv $pvList val $valList {
        lappend putcomm $pv=$val
    }
    if [catch {exec cavput -list=[join $putcomm ,] -pend=30 } result] {
        return -code error "setupTiming: $result"
    }
    
    SetMainStatus "Set up MCA/ADC." 
   # exec /home/helios/PHOTODIA/operations/s35apps/Setup/s35BPDmcaSetup
    if [catch {S35BPDmcaSetup} result] {
        SetMainStatus "S35BPDmcaSetup: $result" -code error
    }
    SetMainStatus "Done." 
    return
}

proc S35BPDmcaSetup {args} {
    SetMainStatus "Setup 35-ID-A Bunch Purity Detector MCA/ADC"
    SetMainStatus "Setup 35-ID-A Bunch Purity Detector stepper motors" 
    if [catch {exec /home/helios/PHOTODIA/operations/s35apps/Setup/s35BM_BPDmcaSetup } result] {
        return -code error "Error in setup 35-ID-A Bunch Purity Detector stepper motors: $result"
    }

    return

    #following code are obselete due to hardware changes.
    
    # Set up ADC (remove these, since these PV no longer exists)
    #if [catch {exec cavput -list=S36AM:icbAdc1SU. \
    #             -list=A=4096,B=0,C=0,D=4096,E=5,F=95,G=0,I=1,J=0,K=0 -pend=30} result] {
    #    return -code error "Set up ADC: $result"
    #}

    # Set up MCA operating parameters
    if [catch {exec cavput -list=S36AM:BP:mca \
                 -list=.PLTM=300,.PRTM=0,.MODE=0,ReadSeq.SCAN=5,Check.SCAN=5 -pend=30} result] {
        return -code error "Set up MCA operationg parameters: $result"
    }

    # Set up MCA ROI low-limit
    if [catch {exec cavput -list=S36AM:BP:mca. \
                 -list=R0LO=2270,R1LO=2160,R2LO=2050,R3LO=1940,R4LO=2400,R5LO=2510,R6LO=2620 -pend=30} result] {
        return -code error "Set up MCA ROI low-limit: $result"
    }
    # Set up MCA ROI low-limit (1 bucket = 113 chan)
    if [catch {exec cavput -list=S36AM:BP:mca. \
                 -list=R0HI=2400,R1HI=2270,R2HI=2160,R3HI=2050,R4HI=2510,R5HI=2620,R6HI=2730 -pend=30} result] {
        return -code error "Set up MCA ROI low-limit (1 bucket = 113 chan): $result"
    }
    # Set ROI background 
    if [catch {exec cavput -list=S36AM:BP:mca. \
                 -list=R0BG=0,R1BG=0,R2BG=0,R3BG=0,R4BG=0 -pend=30} result] {
        return -code error "Set up ROI background: $result"
    }

    # Set ROI background preset flag (0=No, 1 = Yes)
    if [catch {exec cavput -list=S36AM:BP:mca. \
                 -list=R0IP=0,R1IP=0,R2IP=0,R3IP=0,R4IP=0 -pend=30} result] {
        return -code error "Set up ROI background preset flag : $result"
    }
    
    # Set ROI background preset
    if [catch {exec cavput -list=S36AM:BP:mca. \
                 -list=R0P=0,R1P=0,R2P=0,R3P=0,R4P=0,R5P=0 -pend=30} result] {
        return -code error "Set up ROI background preset: $result"
    }
}


proc openShutters {args} {
    global abortRun VERBOSE
 
    if [catch {exec cavput -list=S35ID:PS2OpenC.VAL=1 -pend=30} result] {
        return -code error $result
    }
    # Watch shutter status
    set abortRun 0
    for {set istep 1} {$istep <= 6} {incr istep} {
        after 1000
        if [catch {exec cavget -list=EPS:35:ID:PS2:POSITION -pend=10} ps2Status] {
            return -code error $ps2Status
        }
    	if {$ps2Status == "Open"} {
            SetMainStatus "Shutters (PS2/SS) are open."
            return 0
    	}
        if {$abortRun} {return 1}
    }
    SetMainStatus "Shutters (PS2/SS) are closed."
    return
}


proc closeShutters {args} {
    global abortRun VERBOSE
    
    if [catch {exec cavput -list=S35ID:PS2CloseC.VAL=1 -pend=30} result] {
        return -code error $result
    }
    set abortRun 0
    for {set istep 1} {$istep <= 6} {incr istep} {
        after 1000
        if [catch {exec cavget -list=EPS:35:ID:PS2:POSITION -pend=10} ps2Status] {
            return -code error $ps2Status
        }
    	if {$ps2Status == "Closed"} {
            SetMainStatus "Shutters (PS2/SS) are closed."
            return 0
    	}
        if {$abortRun} {return 1}
    }

    SetMainStatus "Shutters (PS2/SS) are open."
    return
}



proc sendMotorsIn {args} {
    global abortRun VERBOSE xMotor yMotor
    
#   ********************************************************
# 	DETECTOR POSITION FOR BUNCH PURITY MEASUREMENTS
#   ********************************************************
    set xDetector 38
    set yDetector 4

    # Move the detector into beam
    set abortRun 0
    SetMainStatus "Moving the detector IN (x = $xDetector mm, y= $yDetector mm) ..."
    if [catch {exec cavput -list=${xMotor}.VAL=$xDetector -pend=30} result] {
        return -code error $result
    }
    after 500
    if [catch {exec cavput -list=${yMotor}.VAL=$yDetector -pend=30} result] {
        return -code error $result
    }
        
    # Wait while checking whether the motor stopped or reach limits
    watchMotorsMove -watchTime 99
    if {$abortRun} {
       abortMotorScan
       return
    }
    # Start autoCount
    startMCA

    SetMainStatus "Done"
    return
}


proc startMCA {args} {
    # start Multi-Channel Analyzer
    #S36AM:BP:scaler.CONT--> S35BMBL2:scaler.CONT however the new pv does not exist either, leave it there
   # if [catch {exec cavput -list=S36AM:BP:scaler.CONT=1,S36AM:BP:mcaStart.VAL=0,S36AM:BP:mca.ERAS=1,S36AM:BP:mca.STRT=1 -pend=30} result] {
   #     return -code error $result
   # }
    if [catch {exec cavput -list=S36AM:BP:scaler.CONT=1,S35BM:BP:mcaStart.VAL=0,S35BM:BP:mca.ERAS=1,S35BM:BP:mca.STRT=1 -pend=30} result] {
        return -code error $result
    }
}


proc sendMotorsOut {args} {
    global abortRun VERBOSE xMotor yMotor

    # Move the detector OUT OF beam
    set abortRun 0
    SetMainStatus "Moving the detector OUT...."
    if [catch {exec cavput -list=${xMotor}.VAL=0,${yMotor}.VAL=0 -pend=30} result] {
        return -code error $result
    }

    # Wait while checking whether the motor stopped or reach limits
    watchMotorsMove -watchTime 99
    if {$abortRun} {
        abortMotorScan
    } else {
        SetMainStatus "Done"
    }
}


proc stopMotors {args} {
    global VERBOSE xMotor yMotor

    # Stop the motors first and then re-enable
    SetMainStatus "Stop moving motors"
    if [catch {exec cavput -list=${xMotor}.SPMG=0,${yMotor}.SPMG=0 -pend=30} result] {
        return -code error $result
    }
    if [catch {exec cavput -list=${xMotor}.SPMG=3,${yMotor}.SPMG=3 -pend=30} result] {
        return -code error $result
    }
    return
}


proc sendMotorsLimits {args} {
    global abortRun VERBOSE xMotor yMotor

    # Stop the motors and then send them to limit
    stopMotors
    if [catch {exec cavput -list=${xMotor}.VAL=-99 -pend=30 } resutl] {
        return -code error $result
    }
    after 500
    if [catch {exec cavput -list=${yMotor}.VAL=-99 -pend-30} result] {
        return -code error $result
    }

    # Wait to reach the limits and then back off 0.25 mm
    watchMotorsMove -watchTime 99
    if $abortRun abortMotorScan
    
    return
}


proc initOneMotor {args} {
    global abortRun VERBOSE

    # Get motor name
    APSParseArguments {theMotor}
    set abortRun 0

    # Backoff first 
    SetMainStatus "$theMotor is backing off."
    if [catch {exe cavget -list=${theMotor}MT.RBV -pend=10} value] {
        return -code error $value
    }
    set motorVal [format "%.3f" [expr $value + 0.28]]
    if [catch {exec cavput -list=${theMotor}MT.VAL=$motorVal -pend=30} result] {
        return -code error $result
    }
   # if {[watchMotorsMove -watchTime 2] != 0} { break } binxing has it here, I have question about it
    # Initialize motors 
    SetMainStatus "Initialize stepper motor: $theMotor"
    for {set iteratn 1} {$iteratn <= 10} {incr iteratn} {
        if [catch {exec cavput -list=${theMotor}:resetBO.VAL=1 -pend=30} result] {
            return -code error $result
        }
        after 1000
        if {[watchMotorsMove -watchTime 5] != 0} { break }
        after 1000
        # Check whether the motor initialized correctly
        if [catch {exec cavget -list=${theMotor}:initStatMI.VAL -pend=10} theStatus] {
            return -code error $theStatus
        }
        #SetMainStatus "theMotor = $theMotor, theStatus = $theStatus"
        if {[string match "*Ok*" $theStatus]} {
            SetMainStatus "Done."
            break     	    
        } else {
           SetMainStatus "Failed $iteratn times. Initialize again ..."
           if {$theStatus == "\{Motion Error\}"} {
               # After motor error, the motor need to be backed off o.5 mm before retry
               if [catch {exec cavget -list=${theMotor}MT.RBV -pend=10} value] {
                   return -code error $value
               }
               set val [ormat "%.3f" [expr $value + 0.50]]
               if [catch {exec cavput -list=${theMotor}MT.VAL=$val -pend=30} result] {
                   return -code error $result
               }
               if {[watchAbort -watchTime 1] != 0} { break }
           } 
        }
    }
    return
}


proc initMotors {args} {
    global abortRun VERBOSE xMotor yMotor

    # Send motors to limits
    sendMotorsLimits
    if {$abortRun} { return 1 }
    SetMainStatus "Both motors are at their limits."

    # Init motors one by one
    initOneMotor -theMotor $xMotor
    initOneMotor -theMotor $yMotor

    return
}


proc abortMotorScan {args} {
    global abortRun VERBOSE

    stopMotors
    set abortRun 0
    SetMainStatus "abort motor run"
    return
}


proc watchAbort {args} {
    global abortRun VERBOSE

    # watch time in seconds
    APSParseArguments {watchTime}
    SetMainStatus "watchTime = $watchTime"
    
    #Set to check twice a second
    set waitSteps     [format "%.0f" [expr 2 * $watchTime]]
    for {set istep 1} {$istep <= $waitSteps} {incr istep} {
        after 1000
        if {$abortRun} {
            abortMotorScan
            return 1
        }
    }
    return 0
}

proc watchMotorsMove {args} {
    global abortRun VERBOSE xMotor yMotor

	# watch time in seconds
    APSParseArguments {watchTime}
    
    #Set to check twice a second
    set waitSteps     [format "%.0f" [expr 2 * $watchTime]]
    for {set istep 1} {$istep <= $waitSteps} {incr istep} {
        after 1000
        if [catch {exec cavget -list=${xMotor}.DMOV -pend=10} xStatus] {
            return -code error $xStatus
        }
        if [catch {exec cavget -list=${yMotor}.DMOV -pend=10} yStatus] {
            return -code error $yStatus
        }
        #SetMainStatus "watchMotorMove: xStatus = $xStatus, yStatus = $yStatus"
        
    	if {($xStatus == 1) && ($yStatus == 1)} {break}
        if {$abortRun} { 
            abortMotorScan
            return 1
        }
    	updateStatusDisplay
    }
    return 0
}


proc acqWaveform {args} {
    global VERBOSE abortRun    
    case 
    SetMainStatus "Start MCA to take data"
    if [catch {startMCA} result] {
        SetMainStatus "Error in Starting MCA: $result" -code error
    }
    if [catch {exec cavget -list=S35BM:BP:mca.PLTM -pend=10} livetimeSet] {
	return -code error $livetimeSet
    }
    SetMainStatus "taking data (wait for $livetimeSet seconds)..."
    set abortRun 0
    while { 1 } {
	if [catch {exec cavget -list=S35BM:BP:mca.ELTM -pend=10} livetime] {
	    return -code error $livetime
	}
	if {$livetime==$livetimeSet} {break}
        if $abortRun break
        update
        after 1000
    }
    
    SetMainStatus "Done(acqWaveform)"
    return
}

proc updateStatusDisplay {args} {
    global abortRun xMotor yMotor APDCounter xMotorPos yMotorPos APDCounts
    
    if [catch {exec cavget -list=${xMotor}.RBV -pend=10} xMotorPos] {
        return -code error $xMotorPos
    }
    if [catch {exec cavget -list=${yMotor}.RBV -pend=10} yMotorPos] {
        return -code error $yMotorPos
    }
    if [catch {exec cavget -list=$APDCounter -pend=10} APDCounts] {
        return -code error $APDCounts
    }
    update
    return
}


proc getWaveform {args} {
    global VERBOSE mainDir outputRootname 
    
    APSParseArguments {directory rootname plotOption}

    set directory $mainDir/[clock format [clock seconds] -format "%Y-%m%d"]
    if ![file exist $directory] {
        exec mkdir $directory
        #catch {exec setfacl -m mask:rwx $directory}
       # exec /home/helios/OAG/bin/setFACL-oagPlus \
       #   emery,borland,shang,oag,bxyang,sr,asdops,sereno,cyao,lumpkin,par $directory
    }
    set file ${outputRootname}-[clock format [clock seconds] -format %Y-%m%d.%H:%M:%S]
    
    if [file exists $directory/$file] {
        return -code error "getWaveform: file $directory/$file exists."
    }

    #####   Take data   #####
    SetMainStatus "Saving S35BM:MCA waveform to $file"
    set tmpfile /tmp/[APSTmpString]
    APSAddToTmpFileList -ID 1 -fileList $tmpfile
    exec sddswmonitor $tmpfile -pv=S35BM:BP:mca.VAL
    
    APSAddToTmpFileList -ID 1 -fileList "$tmpfile $tmpfile.1"
    if [catch {exec cavget -list=S35BM:BP:mca.ELTM -pend=10} LiveTime] {
        return -code error $LiveTime
    }
    if [catch {exec cavget -list=S35BM:BP:mca.ERTM -pend=10} RealTime] {
        return -code error $RealTime
    }
    if [catch {exec sddsprocess $tmpfile $tmpfile.1 \
                 "-define=par,MCALiveTime,$LiveTime" "-define=par,MCARealTime,$RealTime" \
                 -process=S35BM:BP:mca.VAL,max,S35BM:BP:mca.VAL_Max \
                 "-define=col,S35BM:BP:mca.VALNorm,S35BM:BP:mca.VAL S35BM:BP:mca.VAL_Max 1e-6 + /" } result] {
        return -code error $result
    }
    #check bunch pattern, bunch purity calculation only works for 24 singlets and hybrid
    if [catch {exec cavget -list=SR:bunchPatternSO -pend=30 -printErrors} bunchPattern] {
        return -code error "Unable to read bunch pattern: $bunchPattern"
    }
    if {[regexp {0\+24} $bunchPattern] || [regexp {8x7} $bunchPattern]} {
        if [catch {CalculateBunchPurity -inputfile $tmpfile.1 -outputfile $directory/$file} result] {
            return -code error $result
        }
        exec chmod a+w $directory/$file
        
        SetMainStatus "Done"
    } else {
        APSAlertBox  [APSUniqueName .] -type warning \
          -errorMessage "Bunch purity scripts only works for 24 siglets and hybrid pattern, it does not work for current fill pattern ($bunchPattern)."
    }
    return
}

proc getFPGAWaveform {args} {
    global  mainDir FPGARootname 
    set directory $mainDir/FPGA/[clock format [clock seconds] -format "%Y-%m%d"]
    if ![file exist $directory] {
        exec mkdir $directory
        #catch {exec setfacl -m mask:rwx $directory}
        #exec /home/helios/OAG/bin/setFACL-oagPlus \
        #    emery,borland,shang,oag,bxyang,sr,asdops,sereno,cyao,lumpkin,par $directory
    }
    
    set file ${FPGARootname}-[clock format [clock seconds] -format %Y-%m%d.%H:%M:%S] 
    if [file exists $directory/$file] {
        return -code error "getFPGAWaveform: file $directory/$file exists."
    }
    
    #####   Take data   #####
    SetMainStatus "Saving FPGA waveform to $file"
    set tmpfile /tmp/[APSTmpString]
    APSAddToTmpFileList -ID 1 -fileList $tmpfile
    
    if [catch {exec sddswmonitor $tmpfile -pv=SR:bpure:MCAstatisticsGS.VALG -step=1 \
                   -scalars=/home/helios/oagData/sr/bunchPurity/inputFiles/FPGA.scalars} result] {
        return -code error $result
    } 
    APSAddToTmpFileList -ID 1 -fileList "$tmpfile $tmpfile.1" 
    if [catch {exec sddsprocess $tmpfile -pipe=out \
                   -define=col,Waveform,SR:bpure:MCAstatisticsGS.VALG \
                   | sddsconvert -pipe -delete=col,SR:bpure:MCAstatisticsGS.VALG \
                   | sddsprocess -pipe=in $directory/$file.sdds \
                   -print=par,WaveformPV,SR:bpure:MCAstatisticsGS.VALG \
                   -process=Waveform,max,MaxCount \
                   "-define=col,WaveformNorm,Waveform MaxCount 1.0-6 + /" } result] {
        return -code error "GetFPGAWaveform1: $result"
    }
    
    if [catch {ProcessFPGAData -inputfile $directory/$file.sdds} result] {
        return -code error $result
    } 
    
    SetMainStatus "Done"
    return
}


proc MakeListOfArchives {args} {
    set matchstring *
    set directory ""
    set FPGA 0
    APSParseArguments {matchstring directory FPGA}
    global mainDir
    if ![string length $directory] {
        set directory $mainDir
    }
    set allFiles [glob $directory/*]
    set dirList ""
    foreach dir $allFiles {
        set name [file tail $dir]
        set year [scan $name %ld]
        if {[file isdirectory $dir] && [string length $name]==9 && [string length $year]==4} {
            lappend dirList [file tail $dir]
        }
    }
    set fileList ""
    foreach dir $dirList {
        if [regexp {\-} $dir] {
            set files [glob -nocomplain $directory/$dir/$matchstring]
            if {[llength $files]!=0} { 
                lappend fileList $files 
            }
        }
    }
    set fileList [join $fileList]
    set newList ""
    foreach file $fileList {
        if {$FPGA || ![string match *FPGA* $file]} {
            set itemList [file split $file]
            set listLength [llength $itemList]
            set item [eval file join [lrange $itemList [expr $listLength - 2] end] ]
            lappend newList $item
        }
    }
    set newList [lsort -decreasing $newList]
    return $newList
}

proc plotData {args} {
    global VERBOSE  plotStart plotStop plotType outputRootname mainDir
    set userPlotOption " "
    APSParseArguments {userPlotOption}

    global Fileselection fileList
    
    set files [MakeListOfArchives]
    if ![llength $files] {return -code error "No files found in $mainDir!"}
    global Fileselection fileList
    set Fileselection ""
    set fileList $files
    
    if [winfo exist .review] {
        destroy .review
    }
    APSScrolledListWindow .review -name "" \
        -label "Select a scan data file" \
        -itemList $files -selectionVar Fileselection
    APSDialogBoxAddButton .delete -parent .review -text "Delete" -command "ListCommand -action delete"
    while {1} {
        tkwait variable Fileselection
        PlotFile -file $Fileselection -userPlotOption $userPlotOption
    }
}
proc ListCommand {args} {
    global fileList mainDir frameIndex
    set action ""
    APSParseArguments {action}
    set chosenList [.review.userFrame.sl.listbox curselection]
    if ![llength $chosenList] {
        return -code error "No files are chosen!"
    }
    set viewList ""
    if $frameIndex==1 {
        set directory $mainDir/FPGA
    } else {
        set directory $mainDir
    }
    
    foreach index $chosenList {
        set file [lindex $fileList $index]
        switch $action {
            delete {
                if [APSYesNoPopUp "Are you sure to delete $file?"] {
                    catch {file delete -force $directory/$file}
                    set fileList [lreplace $fileList $index $index]
                    update
                    .review.userFrame.sl.listbox delete $index
                }
            }
        }
    }
}

proc PlotFile {args} {
    global plotType plotStart plotStop mainDir calcPurity plotFile
    set file ""
    set userPlotOption " "
    APSParseArguments {file userPlotOption}
    if ![string length $file] {
        SetMainStatus "No file selected!" -code error
        return 
    }
    set tmpfile /tmp/[APSTmpString]
    APSAddToTmpFileList -ID 1 -fileList $tmpfile
    set fileList ""
    set plotString 1
    foreach fl $file {
        if ![file exist $mainDir/$fl] {
            SetMainStatus "$mainDir/$fl does not exist!"
            return
        }
        set columns [exec sddsquery $mainDir/$fl -col]
        if [lsearch $columns S35BM:BP:mca.VALNorm]<0 {
            if [catch {exec sddsprocess $mainDir/$fl $tmpfile -nowarnings \
                         -process=S35BM:BP:mca.VAL,max,S35BM:BP:mca.VAL_Max \
                         "-define=col,S35BM:BP:mca.VALNorm,S35BM:BP:mca.VAL S35BM:BP:mca.VAL_Max 1e-6 + /" } result] {
                SetMainStatus $result -code error
                return 
            }
            file copy -force $tmpfile $mainDir/$fl
        }
        
        set parameters [exec sddsquery -par $mainDir/$fl]
        
        if {[lsearch $parameters MainPeakPos]<0} {
            if [catch {CalculateBunchPurity -inputfile $mainDir/$fl \
                           -outputfile $mainDir/${fl} } result] {
                return -code error $result
            }
        }
        if [string length $plotFile] {
            set stringFile $plotFile
        } else {
            set stringFile $mainDir/$fl
        }
        lappend fileList $mainDir/${fl}
    }
    global layoutOption separate samescale legends
    if {[llength $fileList]==1} {
        set pars [exec sddsquery -par [lindex $fileList 0]]
        if {[lsearch $pars "CalibrationFactor"]>=0 && [lsearch $pars "BucketWidth"]>=0} {
            set calFactor [exec sdds2stream -par=CalibrationFactor [lindex $fileList 0]]
            set bucketWidth [exec sdds2stream -par=BucketWidth [lindex $fileList 0]]
            append plotOption " \"-topline=calibration factor\\\\=[format %.2f $calFactor]\\\\, bucket width\\\\=$bucketWidth\""
        }
        foreach bucket {+3 +2 +1 -1 -2 -3} pos {0.9 0 0.8 0.7 0 0.6} {
            set bucket${bucket}Pos [exec sdds2stream $stringFile -par=bucket${bucket}Pos]
            if {$bucket!=2 && $bucket!=-2} {
                set bucket${bucket}Purity [format %.2e [exec sdds2stream $stringFile -par=bucket${bucket}Purity]]
                append plotOption " \"-string=bucket $bucket purity: [set bucket${bucket}Purity],p=0.02,q=$pos\""
            }
            append plotOption  " -drawline=x0v=[set bucket${bucket}Pos],x1v=[set bucket${bucket}Pos],q0v=0,q1v=0.5,line=2"
        }
    }
    if $separate {
        append plotOption " -separate"
    }
    if $samescale {
        append plotOption " -samescale=y"
    }
    if [llength $fileList]==1 {
        append plotOption " -graph=bar"
    } else {
        append plotOption " -graph=line,vary"
    }
    append plotOption " $userPlotOption"
    append plotOption " -legend=rootname,edit=a5Z\- -scale=$plotStart,$plotStop,0,0"
    if {$plotType=="LOG"} {
        append plotOption " -col=Index,S35BM:BP:mca.VAL $fileList -mode=y=logarithmic,y=special -tickSettings=ylogarithmic -endp -col=Index,S35BM:BP:mca.VALNorm -mode=y=logarithmic $fileList -ylabel=edit=i/Log\\\$b10\\\$n/ -endp "
        
    } else {
        append plotOption " $fileList -col=Index,S35BM:BP:mca.VAL -topTitle -scale=$plotStart,$plotStop,0,0"   
    }
    eval exec sddsplot $layoutOption $plotOption &
}

proc deleteDataFile {args} {
    global VERBOSE    
    set directory ""
    set file ""
    APSParseArguments {directory file}
    if ![file exists $directory/$file] {
        return -code error "Can't find file $file in $directory to delete."
    }
    if [APSYesNoPopUp "Are you sure to delete file $directory/$file?"] {
        exec rm -f "$directory/$file"
        SetMainStatus "$directory/$file was deleted"
    }
    return
}

proc StartAutoScan {args} {
    global mainDir autoScanRunControlPV outputRootname AutoScanInterval AutoScanID AutoScanInput AutoScanDone
  #  set mainDir /home/oxygen/SHANG/test/oagapp
 #   set AutoScanInterval 0.01
    set AutoScanDone 0
    set logList [APSExecLog .autoScan -height 30 -lineLimit 2048 -width 95 \
                   -name "Bunch Purity Automatic Scan" \
                   -unixCommand "BunchPurityAutoScan -mainDir $mainDir -rootname $outputRootname -runControlPV $autoScanRunControlPV -interval $AutoScanInterval" \
                   -cancelCallback "set AutoScanDone 1" \
                   -callback "set AutoScanDone 1" \
                   -abortCallback "set AutoScanDone 1" \
                  ]
    set AutoScanID [lindex $logList 2]
    set AutoScanInput [lindex $logList 0]
}

proc AbortAutoScan {args} {
    global autoScanRunControlPV 
    if [catch {APSAbortSRControllaw -runControlPV $autoScanRunControlPV} result] {
        SetMainStatus "$result.\nAbort auto-scan failed."
        return
    }
    SetMainStatus "Waiting for $autoScanRunControlPV to clear..."
    exec cawait -waitfor=$autoScanRunControlPV.RUN,equal=0
    SetMainStatus "Auto-scan is aborted."
}
proc AutoScanInfo {args} {
    global autoScanRunControlPV
    if [catch {exec medm -x -attach -macro "RCPV=$autoScanRunControlPV" \
                 ./sr/psApp/APSRunControlSingle.adl & \
             } result ] {
        SetMainStatus  "$result"
    }
}

proc ProcessFPGAData {args} {
    set inputfile ""
    set plot 1
    APSParseArguments {inputfile plot}
    global bucketFactor
    SetMainStatus "Processing [file tail $inputfile] ..."
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddsconvert $inputfile $tmpRoot.input -from=1 -to=1 
        exec sddsprocess $tmpRoot.input -pipe=out \
                   -filter=col,WaveformNorm,$bucketFactor,10 \
                   "-print=par,BucketDesc,Main Bucket" \
                   | sddsconvert -pipe=in $tmpRoot.0 -retain=col,Index} result] {
        return -code error $result
    }
    lappend fileList $tmpRoot.0
    set bucket0List [exec sdds2stream -col=Index $tmpRoot.0] 
    foreach num {1 2 3 4 5 6 -1 -2 -3 -4 -5 -6} {
        set indexList ""
        foreach bucket $bucket0List {
            lappend indexList [expr $bucket + $num]
        }
        if [catch {exec sddsmakedataset -pipe=out -col=Index,type=long \
                       -data=[join $indexList ,] -nowarnings \
                       | sddsprocess -pipe "-define=col,factor1,Index 0 < ? 1296 : 0 $,type=long" -nowarnings \
                       "-define=col,factor2,Index 1295 > ? 1296 : 0 $,type=long" \
                       | sddsprocess -pipe "-redefine=col,Index,Index factor1 + factor2 -,type=long" \
                       -print=col,BucketStr,$num "-print=par,BucketDec,$num bucket" \
                       | sddsconvert -pipe=in -retain=col,Index,BucketStr $tmpRoot.$num} result] {
            return -code error $result
        }
        lappend fileList $tmpRoot.$num
    }
    if [catch {eval exec sddscombine $fileList -merge $tmpRoot.all -overwrite
        exec sddsselect $tmpRoot.input $tmpRoot.all -pipe=out -equate=Index -invert \
                   | sddsprocess -pipe=in -nowarnings \
                   "-reprint=par,BucketDesc,other buckets" $tmpRoot.others} result] {
        return -code error $result
    }
    
    lappend fileLit $tmpRoot.others
    set inputRoot [file root $inputfile]
    if [catch {eval exec sddscombine $fileList -pipe=out -merge \
                   | sddssort -pipe -col=Index \
                   | sddsprocess -pipe -print=col,IndexStr,%ld,Index \
                   | sddsxref -pipe=in $tmpRoot.input \
                   -equate=Index -nowarnings -reuse=page -take=WaveformNorm \
                   $inputRoot.buckets } result] {
        return -code error $result
    }
    if [llength $bucket0List]==1 {
        #wrap the index around
        if [catch {exec sddsprocess $inputRoot.buckets -pipe=out \
                       "-redefine=col,Index,Index 1289 > ? pop pop -1296 : 0 $ Index +,type=long" \
                       "-reprint=col,IndexStr,%+2.2ld,Index" \
                       | sddssort -pipe=in -col=Index $inputRoot.buckets} result] {
            return -code error $result
        }
    }
    
    set bucket0List [exec sdds2stream -col=Index $tmpRoot.0]
    APSAddToTmpFileList -ID bunchpurity -fileList $fileList
    set fileList ""
    set count 1
    
    foreach bucket $bucket0List {
        set start [expr $bucket -9]
        set end [expr $bucket + 43]
        set index1List ""
        set index2List ""
        set i0 0
        for {set i $start} {$i<=$end} {incr i} {
            lappend index2List $i0
            if {$i<0} {
                lappend index1List [expr 1296 + $i]
            } elseif {$i>=1296} {
                lappend index1List [expr $i - 1296]
            } else {
                lappend index1List $i
            }
            incr i0
        }
        if [catch {exec sddsmakedataset -pipe=out \
                       -col=Index1,type=long -data=[join $index1List ,] \
                       -col=Index,type=long -data=[join $index2List ,] \
                       | sddssort -pipe -col=Index1 \
                       | sddsxref -pipe $inputfile -equate=Index1=Index -take=WaveformNorm \
                       | sddssort -pipe -col=Index \
                       | sddsconvert -pipe=in $tmpRoot.bucket$count \
                       -rename=col,WaveformNorm=Bucket$count -del=col,Index1 } result] {
            return -code error $result
        }
        lappend fileList $tmpRoot.bucket$count
        incr count
    }
    if [llength $fileList]>1 {
        if [catch {eval exec sddsxref $fileList -equate=Index -take=Bucket* -pipe=out -nowarnings -fillIn \
                       | sddsrowstats -pipe -sum=CollateSum,Bucket* \
                       | sddsprocess -pipe -process=CollateSum,Max,MaxSum \
                       -process=CollateSum,Max,MaxPos,pos,functionof=Index \
                       | sddsprocess -pipe=in $tmpRoot.collate \
                       \"-redefine=col,Index,Index MaxPos -,type=long\"  \
                       \"-redefine=col,CollateSum,CollateSum MaxSum /\" } result] {
            return -code error $result
        }
        if [catch {exec sddsprocess $tmpRoot.collate \
                       -filter=col,Index,-1,-1,Index,1,1,||,Index,3,3,||,Index,-3,-3,|| \
                       -print=col,PurityString,%.1e,CollateSum $tmpRoot.collate.1
            exec sddsselect $tmpRoot.collate $tmpRoot.collate.1 -equate=Index -invert $tmpRoot.collate.2 
            exec sddscombine $tmpRoot.collate.1 $tmpRoot.collate.2 -merge -pipe=out \
                       | sddssort -pipe=in -col=Index $inputRoot.collate } result] {
            return -code error $result
        }
    } else {
        if [catch {eval exec sddsprocess $fileList -pipe=out \
                       -define=col,CollateSum,Bucket1 \
                       -process=CollateSum,Max,MaxPos,pos,functionof=Index \
                       | sddsprocess -pipe=in $tmpRoot.collate \
                       \"-redefine=col,Index,Index MaxPos -,type=long\" } result] {
            return -code error $result
        }
        if [catch {exec sddsprocess $tmpRoot.collate \
                       -filter=col,Index,-6,1 \
                       -print=col,PurityString,%.3e,CollateSum $tmpRoot.collate.1
            exec sddsselect $tmpRoot.collate $tmpRoot.collate.1 -equate=Index -invert $tmpRoot.collate.2 
            exec sddscombine $tmpRoot.collate.1 $tmpRoot.collate.2 -merge -pipe=out \
                       | sddssort -pipe=in -col=Index $inputRoot.collate } result] {
            return -code error $result
        }
    }
    
    if $plot {
        exec sddsplot -grap=bar -mode=y=logarithmic,y=special -tickSettings=ylogarithmic \
            -pointLabel=PurityString,line=1,thickness=2 -topline=[file tail $inputfile] \
            -col=Index,CollateSum $inputRoot.collate "-title=Overall bunch purity result" & 
    }
    set indexList [exec sdds2stream -col=Index $inputRoot.collate]
    set purityList [exec sdds2stream -col=PurityString $inputRoot.collate]
    foreach index $indexList purity $purityList {
        if [string length [string trim $purity]] {
            SetMainStatus "Indext=$index, purity=$purity"
        }
    }
    SetMainStatus "done."
}

proc PlotFPGAData {args} {
    set plotRaw 0
    set plotBucket 0
    set plotSum 0
    set reprocess 0
    APSParseArguments {plotRaw plotBucket plotSum reprocess}
    
    global Fileselection1 mainDir fileList
    set Fileselection1 ""
    set files [MakeListOfArchives -matchstring *FPGA*.sdds -directory $mainDir/FPGA -FPGA 1] 
    set fileList $files
    if ![llength $files] {return -code error "No FPGA files found in $mainDir!"}
    if [winfo exist .review] {
        destroy .review
    }
     
    APSScrolledListWindow .review -name "" \
        -label "Select a FPGA data file" \
        -itemList $files -selectionVar Fileselection1
    APSDialogBoxAddButton .delete -parent .review -text "Delete" -command "ListCommand -action delete"
     
    tkwait variable Fileselection1
    if ![string length $Fileselection1] {
        SetMainStatus "No file was chosen."
        return
    }
    if $reprocess {
        foreach file $Fileselection1 {
            if [catch {ProcessFPGAData -inputfile $mainDir/FPGA/$file} result] {
                return -code error $result
            }
        }
    } else {
        foreach file $Fileselection1 {
            PlotFPGAFile -file $file -plotRaw $plotRaw \
                -plotBucket $plotBucket -plotSum $plotSum
        }
    }
}

proc PlotFPGAFile {args} {
    set file "" 
    set plotRaw 0
    set plotBucket 0
    set plotSum 0
    APSParseArguments {file plotRaw plotBucket plotSum}

    global plotType plotStart plotStop mainDir calcPurity plotFile samescale separate layoutOption
    global userPlotOption
    if ![string length $file] {
        SetMainStatus "No file selected!" -code error
        return 
    }
    
    append plotOption " $userPlotOption"
    append plotOption " \"-topline=[file root [file tail $file]]\""
    
    if {$plotType=="LOG"} {
        append plotOption " -mode=y=logarithmic,y=special -tickSettings=ylogarithmic"
    }
    if $separate {
        append plotOption " -separate"
    }
    if $samescale {
        append plotOption " -samescale=y"
    }
    set rawList ""
    set bucketList ""
    set collateList ""
    foreach fl $file {
        if ![file exist $mainDir/FPGA/$fl] {
            SetMainStatus "$mainDir/FPGA/$fl does not exist!"
            continue
        }
        lappend rawList $mainDir/FPGA/$fl
        if {$plotBucket || $plotSum} {
            set bucketFile $mainDir/FPGA/[file root $fl].buckets
            set collateFile $mainDir/FPGA/[file root $fl].collate
            
            if {![file exist $bucketFile] || ![file exist $collateFile]} {
                if [catch {ProcessFPGAData -inputfile $mainDir/FPGA/$fl -plot 0} result] {
                    return -code error $result
                }
            }
            lappend bucketLit $bucketFile
            lappend collateList $collateFile
        }
        if $plotBucket {
            append plotOption " $bucketFile -topline=[file root [file tail $bucketFile]] -col=IndexStr,WaveformNorm  -filter=col,Index,-6,323 -grap=bar,thickness=3,type=1 \"-topline=Bucket 0 to 323\" -sep"
            append plotOption " -col=IndexStr,WaveformNorm -filter=col,Index,324,647 -grap=bar,thickness=2,type=2 \"-topline=Bucket 324 to 647\" -sep"
            append plotOption " -col=IndexStr,WaveformNorm -filter=col,Index,648,971 -grap=bar,thickness=2,type=3 \"-topline=Bucket 648 to 971\" -sep"
            append plotOption " -col=IndexStr,WaveformNorm -filter=col,Index,972,1295 -grap=bar,thickness=2,type=4 \"-topline=Bucket 972 to 1295\" -sep -endp"
        }
    }
    if ![llength $rawList] {
        return
    }
    if !$plotBucket {
        append plotOption " -legend=rootname,edit=a5Z-"
    }
    if $plotRaw {
        if [llength $rawList]==1 {
            append plotOption " -graph=bar"
        } else {
            append plotOption " -graph=line,vary"
        }
        append plotOption " \"-topline=[file tail $file]\""
        append plotOption " -frompage=1 -topage=1 -col=Index,Waveform $rawList"
        eval exec sddsplot $layoutOption $plotOption & 
    }
    if $plotSum {
        append plotOption " -graph=bar,thickness=10 -pointLabel=PurityString,line=1,thickness=2,just=ct" 
        append plotOption " \"-title=Overall bunch purity result\""
        append plotOption " -col=Index,CollateSum $collateList"
        
        eval exec sddsplot -scale=-5.1,5.1,0,0 -topline=[file root [file tail $file]] \
            -mode=y=logarithmic,y=special -tickSettings=ylogarithmic \
            \"-ylabel=Normalized Count\" \
            -grap=bar,thickness=10 -sep -col=Index,Buck* -legen $collateList &
        eval exec sddsplot  $layoutOption $plotOption &
    }
    if $plotBucket {
        eval exec sddsplot -pointLabel=BucketStr -layout=2,2 -filter=col,WaveformNorm,0,0,! $plotOption &
    }
}


proc CalculateBunchPurityFrom {args} {
    global Fileselection fileList mainDir plotFile
    
    set files [MakeListOfArchives]
    if ![llength $files] {return -code error "No files found in $mainDir!"}
    global Fileselection fileList
    set Fileselection ""
    set fileList $files
    if ![llength $files] {return -code error "No files found in $directory!"}
    if [winfo exist .review] {
	destroy .review
    }
    APSScrolledListWindow .review -name "" \
      -label "Select a scan data file" \
      -itemList $files -selectionVar Fileselection
    APSDialogBoxAddButton .delete -parent .review -text "Delete" -command "ListCommand -action delete"
    while {1} {
        tkwait variable Fileselection
        foreach file $Fileselection {
            set parameternames [exec sddsquery -par $mainDir/$file]
            SetMainStatus "The bunch purity for $file is:"
            set exist 1
            foreach bucket {+3 +1 -1 -3} {
                if {[lsearch $parameternames bucket${bucket}Purity]>=0 } {
                    set purity [format %.5e [exec sdds2stream -par=bucket${bucket}Purity $mainDir/$file]] 
                    SetMainStatus "Bucket $bucket purity: $purity"
                } else {
                    set exist 0
                    break
                }
            }
            if $exist {
                if ![APSYesNoPopUp "Bunch purity for $file has been calcualted, as shown in the status box, recalculated again?"] {
                    continue
                }
            }
            if [catch {CalculateBunchPurity -inputfile $mainDir/$file -outputfile $mainDir/$file } result] {
                SetMainStatus "$result"
                return
            }
            if [string length $plotFile] {
                set showFile $plotFile
            } else {
                set showFile $mainDir/$file
            }
             foreach bucket {+3 +1 -1 -3} { 
                 set purity [format %.5e [exec sdds2stream -par=bucket${bucket}Purity $mainDir/$file]] 
                 SetMainStatus "Bucket $bucket purity: $purity"
            }
        }
    }
    
}
proc CalculateBunchPurity {args} {
    set inputfile ""
    set outputfile ""
    APSParseArguments {inputfile outputfile}
    
    global calFactor method bucketWidth
    
    set tmpfile /tmp/[APSTmpString]
    if ![file exist $inputfile] {
        return -code error "$inputfile does not exist!"
    }
    
    if [catch {exec sddsconvert $inputfile -pipe=out \
                   -del=par,*Purity,*Pos,MainPeak,MainPeakPos \
                   | sddsprocess -pipe=in $tmpfile \
                   -process=S35BM:BP:mca.VAL,max,MainPeak \
                   -process=S35BM:BP:mca.VAL,max,MainPeakPos,functionOf=Index,position \
               } result] {
        return -code error $result
    }
    
    APSAddToTmpFileList -ID BPDSetup -fileList "$tmpfile"
    set MainPeakPos [exec sdds2stream -par=MainPeakPos $tmpfile]
    set MainPeak [exec sdds2stream -par=MainPeak $tmpfile]
    if {$method=="Integration"} {
        if [catch {exec sddsprocess $inputfile -pipe=out \
                       -filter=col,Index,[expr $MainPeakPos - $bucketWidth/2],[expr $MainPeakPos + $bucketWidth/2] \
                       | sddsinteg -pipe -integrate=S35BM:BP:mca.VAL -versus=Index \
                       | sddsprocess -pipe -process=S35BM:BP:mca.VALInteg,last,IntegSum \
                       | sdds2stream -pipe -par=IntegSum } MainPeak] {
            return -code error $MainPeak
        }
    }
    
    set options ""
    SetMainStatus "Mainpeak=$MainPeak"
    foreach bucket {+3 +1 -1 -3} {
        set val [expr $MainPeakPos - $bucket * $calFactor]
        APSAddToTmpFileList -ID BPDSetup -fileList "$tmpfile.$bucket"
        if {$method=="Peak"} {
            if [catch {exec sddsprocess $tmpfile -pipe=out \
                           -filter=col,Index,[expr $val - $bucketWidth/2],[expr $val + $bucketWidth/2] \
                           | sddsprocess -pipe=in $tmpfile.$bucket \
                           -process=S35BM:BP:mca.VAL,max,peak \
                           -process=S35BM:BP:mca.VAL,max,peakPos,functionOf=Index,position } result] {
                return -code error $result
            }
            set peak [exec sdds2stream $tmpfile.$bucket -par=peak]
            lappend options "-redefine=par,bucket${bucket}Purity,[expr $peak/$MainPeak]"
        } elseif {$method=="Integration"} {
            if [catch {exec sddsprocess $tmpfile -pipe=out \
                           -filter=col,Index,[expr $val - $bucketWidth/2],[expr $val + $bucketWidth/2] \
                           | sddsinteg -pipe -integrate=S35BM:BP:mca.VAL -versus=Index \
                           | sddsprocess -pipe -process=S35BM:BP:mca.VALInteg,last,IntegSum \
                           | sdds2stream -pipe -par=IntegSum } peak] {
                return -code error $peak
            }
            lappend options "-redefine=par,bucket${bucket}Purity,[expr $peak/$MainPeak]"
        }
        lappend options "-redefine=par,bucket${bucket}Pos,$val,type=long" 
    }
    if [catch {eval exec sddsprocess $inputfile $tmpfile \
                   "-redefine=par,CalibrationFactor,$calFactor" \
                   "-redefine=par,BucketWidth,$bucketWidth,type=long" \
                   -redefine=par,MainPeakPos,$MainPeakPos,type=long \
                   -redefine=par,MainPeak,$MainPeak \
                   -redefine=par,bucket+2Pos,[expr $MainPeakPos + 2 * $calFactor],type=long \
                   -redefine=par,bucket-2Pos,[expr $MainPeakPos - 2 *$calFactor],type=long \
                   $options} result] {
        return -code error "Error1: $result"
    }
    global plotFile
    set plotFile ""
    if [catch {file copy -force $tmpfile $outputfile} result] {
        global plotFile
        set plotFile $tmpfile
        SetMainStatus "You are not permitted to overwrite $outputfile."
    }
}


set plotFile ""
set autoScanRunControlPV APS:RunControlSlot3RC
set noInit   1
set abortRun 0
set VERBOSE  0
set DRYRUN   0
set xMotor     S36AM:BP:APDxMT 
set yMotor     S36AM:BP:APDyMT 
set APDCounter S36AM:BP:scaler.S2
set mainDir /home/helios/oagData/sr/bunchPurity
set outputRootname sr-bPurity-50nsFS
set FPGARootname sr-bPurityFPGA

set plotStart 1000
set plotStop  3600
set plotType  LOG
set separate 0
set samescale 0
set legends 0
set layoutOption -layout=1,1
set AutoScanInterval 1
set upperLimit 2700
set lowerLimit 2500
set satelliteWidth 200
set calcPurity 0
set userPlotOption ""
updateStatusDisplay   
if $PowerUser {
   StatusFrame   .motortatus -parent .userFrame
}
if {$PowerUser} {SetupFrame .setup -parent .userFrame}
if $PowerUser {
    DetectorFrame .detector   -parent .userFrame
}
WaveformFrame .waveform   -parent .userFrame
ExecutionFrame .exec -parent .userFrame
update

.menu.help.menu add command -label "HTML info file" -command {
    exec netscape "/home/helios/PHOTODIA/DeviceInfo/SR/Sector35/36AM/BunchPurity/BunchPurityMonitor.html" &
    # exit
}
.menu.help.menu insert 5 separator

.menu.help.menu add command -label "Toggle verbose mode" -command {
    set VERBOSE [expr 1 - $VERBOSE]
    APSSetVarAndUpdate BPD_Status "set VERBOSE = $VERBOSE"
}
.menu.help.menu add command -label "Toggle DRYRUN mode" -command {
    set DRYRUN [expr 1 - $DRYRUN]
    APSSetVarAndUpdate BPD_Status "set DRYRUN = $DRYRUN"
}
.menu.help.menu insert 7 separator





