
#
# $Log: not supported by cvs2svn $
# Revision 1.61  2012/02/24 20:04:05  shang
# added centerFre0 argument to change the NASA center frequency after tune measurement, this can avoid the NASA leftover trace through moving the frequency.
#
# Revision 1.60  2012/02/14 19:42:25  shang
# split the P0ReducedGain into xP0ReducedGain for x tune and yP0ReducedGain for y tune so that x/y tune can have different P0 feedback gains.
#
# Revision 1.59  2011/12/13 19:26:26  shang
# improved APSSetupStriplineDrive to setup SR:TUNE:HP_1366A_C2P1_MBBO to X/Y automatically if the tune mux is VSA.
#
# Revision 1.58  2011/10/18 19:33:07  shang
# update stripline mux setup due to hardware changes again.
#
# Revision 1.57  2011/10/17 20:30:45  shang
# changed stripline (mux) setup due to hardware changes.
#
# Revision 1.56  2011/10/03 20:57:29  shangS
# changed stripline setup due to hardware change, and changed the reduced P0 feedback gain to 2.0 per CY's request.
#
# Revision 1.55  2011/09/30 22:04:10  shang
# changed to set SR:TUNE:HP_1366A_C2P1_MBBO to X/Y only for VSA.
#
# Revision 1.54  2011/09/30 20:29:46  shang
# now sets NASA phase shift only if it is provided.
#
# Revision 1.53  2011/09/30 20:04:49  shang
# changed the default y plane phase shift to 0 degree.
#
# Revision 1.52  2011/09/29 20:42:44  shang
# updated due to mux pv names change.
#
# Revision 1.51  2011/09/29 16:40:42  shang
# added pendIOTime to cavput/cavget commands to allow slow CA connection.
#
# Revision 1.50  2011/09/29 14:49:07  shang
# added xPhase and yPhase arguments to APSSetupStriplineDrive to be able to change the x/y plane phase shift for tune measurement.
#
# Revision 1.49  2011/09/27 17:50:07  shang
# added "-mode=y=offset" to plot option to be able to plot x/y tunes in the same scale.
#
# Revision 1.48  2011/09/27 17:39:16  shang
# added turn off stripline input mux at the end of tune measurement.
#
# Revision 1.47  2011/09/27 17:34:45  shang
# changed the Y plane stripline setup, set SR:TUNE:Mux4Sw2BO and SR:TUNE:HP_1366A_C1P0_MBBO to Y-1800 for y tune measurement.
#
# Revision 1.46  2011/09/22 21:57:31  shang
# updated APSSetupStriplineDrive due to hardware change.
#
# Revision 1.45  2011/05/27 11:37:00  lemery
# Modified some formatting while I was reading some parts of this.
#
# Revision 1.44  2011/05/27 11:10:21  lemery
# Added APSMpMeasureTunes: to error massges in APSMpMeasureTunes.
#
# Revision 1.43  2011/05/27 11:05:42  lemery
# Untabified and indented for sanity (mine).
#
# Revision 1.42  2011/05/12 16:26:28  shang
# Now the P0 feedback gain is changable instead of fixed value of 5.0 because sometimes gain with 5.0 is not low enough to get a good data.
#
# Revision 1.41  2010/11/03 18:07:38  shang
# it now does not reduced the P0Feedback gain in hybrid bunch pattern.
#
# Revision 1.40  2010/10/19 18:43:57  shang
# modified tune measurements to work with P0 feedback loop closed.
#
# Revision 1.39  2010/06/01 20:15:12  shang
# added putting the network analyzer sweep mode to "Hold" after measurement.
#
# Revision 1.38  2010/03/12 15:22:17  shang
# swapped the stripline input mux pv with the drive mux pv due to the hardare changes.
#
# Revision 1.37  2009/07/17 20:56:06  shang
# added xFreq, yFreq, xSpan, ySpan, xPower and yPower arguments to setup NASA parameters for measuring x/y tunes.
#
# Revision 1.36  2009/05/28 17:15:20  shang
# added option of using dividing line for measuring x/y tune separately, the default is use dividing line as before.
#
# Revision 1.35  2009/05/22 19:25:20  borland
# Fixed a bug in processing the x tune data.
#
# Revision 1.34  2009/05/21 16:23:41  shang
# removed debug statements
#
# Revision 1.33  2009/05/20 16:32:07  shang
# added setting SR:TUNE:HP_1366A_P0_MBBO to X (1) or Y (2) when the stripline is chosen as X or Y.
#
# Revision 1.32  2009/03/27 19:32:40  shang
# added waiting 10 seconds for sweeping the rf frequencies to measure the tune.
#
# Revision 1.31  2009/03/27 19:09:44  shang
# fixed a typo
#
# Revision 1.30  2009/03/27 15:35:11  shang
# added APSSetupStriplineDrive to turn on/off stripline, added turn on stripline before tune measurement and off after tune measurement to  APSMpMeasureTunes
#
# Revision 1.29  2008/03/25 22:31:17  shang
# modified the tune processing since it did not work properly before.
#
# Revision 1.28  2007/07/11 15:41:44  shang
# added the ability to measure x/y tunes separately and set the invalid tunes to zero.
#
# Revision 1.27  2004/11/30 16:38:59  shang
# removed the plot of channel 2 data in APSMpMeasureTunes proc since its data
# is useless
#
# Revision 1.26  2001/12/17 20:56:04  emery
# Removed some offending -def=para,<...> commands in processing
# the tune waveforms.
#
# Revision 1.25  2001/12/06 15:40:13  sereno
# Added processing commands to define parameters CenterFreq, Span, rfDrivePower
# etc. from cryptic PV names.  This effectively undo's the last four changes
# to this script.  N. Sereno.
#
# Revision 1.24  2001/12/05 23:46:11  sereno
# Changed P1P1.sum to P1P1:sum due to typo error.  N. Sereno
#
# Revision 1.23  2001/12/05 23:44:21  sereno
# Replaced P1P1sum with P1P1:sum and rfDrivePower with P:TUNE:NASA:rfPowerAI
# per previous two changes.  N. Sereno
#
# Revision 1.22  2001/12/05 23:40:40  sereno
# Changed variable rfFreq to SY:Hp8657RefFreq per the last change.  N. Sereno
#
# Revision 1.21  2001/12/05 23:32:06  sereno
# Changed CenterFreq and Span variables to the PV variable names for the
# PAR NASA.  Removed obsolete columns in
# /home/oxygen/OAG/oagData/par/tuneArchive/inputFiles/spectAnalScalars.mon
# to fix the sddswmonitor error.  N. Sereno
#
# Revision 1.20  2000/04/26 16:40:36  soliday
# Added APSMpStep proc options.
#
# Revision 1.19  1999/03/20 03:01:28  borland
# Added BeamParamLabel to output file.
#
# Revision 1.18  1998/10/14 21:59:13  borland
# Added some indices to a series of identical error messages.
#
# Revision 1.17  1998/05/15 23:47:11  borland
# Added computation of normalized peak height of tune peaks.
#
# Revision 1.16  1998/01/10 17:10:10  borland
# Fixed an unintentional behavior in APSMpMeasureTunes. Now, when averagingSeconds
# is 0, return without stopping the averaging.
#
# Revision 1.15  1997/08/04 13:10:44  borland
# Added -nowarning to sddsprocess after peakfind.  Hope it will avoid
# some unnecessary error returns.
#
# Revision 1.14  1997/07/25 19:55:43  borland
# Input data is now taken from special directories, rather than the general
# sddsmonitorFiles directory.  This allowed changing some input fileswithout
# risk of screwing something else up.
#
# Revision 1.13  1997/07/17 21:43:03  borland
# Now more robust against errors processing tune data.
#
# Revision 1.12  1997/07/11 16:16:20  borland
# Removed use of APSAddToTempFileList because dp_atexit isn't available to
# every app that uses this routine.  Yuck.  Need a better solution.
#
# Revision 1.11  1997/05/29 15:30:05  borland
# Temporary files are added to the temp file list for automatic deletion.
#
# Revision 1.10  1997/05/28 16:29:21  borland
# Added processing of tune to pick out picks.
#
# Revision 1.9  1997/04/21 14:55:14  borland
# APSMpMeasureTunes now uses APSMakeSafeQualifierString on comment string
# before giving it to sddsprocess.
#
# Revision 1.8  1997/03/10 16:59:08  borland
# Now wraps tune range from [0.5, 1.0] to [0.5, 0].
#
# Revision 1.7  1997/01/24 17:02:04  borland
# Now restarts N/A sweep in certain modes.
#
# Revision 1.6  1997/01/21 20:28:39  borland
# Fixed argument passing from SR and PAR routines.
#
# Revision 1.5  1996/12/07 23:04:49  borland
# Changed sddswmonitor command so that it takes data in double precision.
#
# Revision 1.4  1996/10/18 22:29:57  borland
# Put in kludge to detect lack of "after" command when invoked from tclsh.
#
# Revision 1.3  1996/10/18 19:21:42  borland
# Removed use of APSMpInterface around APSMpStep init.
#
# Revision 1.2  1996/10/18 18:22:22  borland
# Now put hold on trace even if analyzer sweep is not triggered.
#
# Revision 1.1  1996/10/07 20:30:37  borland
# Added -pend options to cavput and cavget commands.
#
#

proc APSMpMeasureTunesInitDialog {frame} {
    global APSMpMeasureTunes 

    APSRadioButtonFrame .rb1 -parent $frame \
      -label "Analyzer: " -orientation horizontal \
      -variable APSMpMeasureTunes(analyzer) \
      -buttonList {Network Spectrum VectorSignal} \
      -valueList {NA SA VSA} -contextHelp \
      "Select the analyzer you want to use for tune measurement."

    APSRadioButtonFrame .rb2 -parent $frame \
      -label "Do setup: " -orientation horizontal \
      -variable APSMpMeasureTunes(doSetup) \
      -buttonList {Yes No} -valueList {1 0} \
      -contextHelp "Select whether to set up the instrument before taking data."

    APSLabeledEntry .le1 -parent $frame \
      -label "Setup file: " \
      -textVariable APSMpMeasureTunes(setupFile) \
      -contextHelp "Enter the name of a SCR file from which to take instrument configuration data." \
      -width 40

    APSRadioButtonFrame .rb3 -parent $frame \
      -label "Use data in analyzer: " -orientation horizontal \
      -variable APSMpMeasureTunes(useExistingData) \
      -buttonList {Yes No} -valueList {1 0} \
      -contextHelp "Select whether to use data already collected by the instrument, or to collect new data."
    
    APSRadioButtonFrame .rb4 -parent $frame \
      -label "Plot data: " -orientation horizontal \
      -variable APSMpMeasureTunes(plotData) \
      -buttonList {Yes No} -valueList {1 0} \
      -contextHelp "Select whether to plot the data or not."

    APSLabeledEntry .le2 -parent $frame \
      -label "Averaging time (sec): " \
      -textVariable APSMpMeasureTunes(averagingSeconds) \
      -contextHelp "Enter the number of seconds to wait for averaging if new data is collected."

    APSLabeledEntry .le3 -parent $frame \
      -label "Output filename (include path): " \
      -textVariable APSMpMeasureTunes(outputFile) \
      -contextHelp "Enter the name of the file to which to save the data.  Include the path in the filename." \
      -width 80

    APSLabeledEntry .le4 -parent $frame \
      -label "Comment: " \
      -textVariable APSMpMeasureTunes(comment) \
      -contextHelp "Enter a comment for the data." \
      -width 80
}

proc APSMpPARMeasureTunes {args} {
    if [catch {eval APSMpMeasureTunes -ring PAR $args} result] {
        APSMpReturn error $result
    }
    APSMpReturn ok
}

proc APSMpSRMeasureTunes {args} {
    if [catch {eval APSMpMeasureTunes -ring SR $args} result] {
        APSMpReturn error $result
    }
    APSMpReturn ok
}

proc APSSetupStriplineDrive {args} {
    set plane ""
    set stripline 1
    set rf 1
    set xPhase X-0
    set yPhase Y-0
    set VSA 0
    APSStrictParseArguments {plane stripline rf xPhase yPhase VSA}

    if ![string length $plane] {
        return -code error " APSSetupStriplineDrive1: plane not provided."
    }
    set plane [string toupper $plane]
    switch $plane {
        X {
            if [catch {exec cavput -list=SR:TUNE:HP_1366A_C0P1_MBBO=X,SR:TUNE:Mux4Sw1BO=0,SR:TUNE:Mux4Sw2BO=1 -pend=30} result] {
                return -code error "APSSetupStriplineDrive1a: unable to set stripline mux to x plane: $result"
            }
        }
        Y {
            if [catch {exec cavput -list=SR:TUNE:HP_1366A_C0P1_MBBO=Y,SR:TUNE:Mux4Sw1BO=1,SR:TUNE:Mux4Sw2BO=1 -pend=30} result] {
                return -code error "APSSetupStriplineDrive1b: unable to set stripline mux to y plane: $result"
            }
        }
        X/Y {
	    if [catch {exec cavput -list=SR:TUNE:Mux4Sw2BO=0 -pend=30} result] {
                return -code error "APSSetupStriplineDrive1b: unable to set stripline mux to y plane: $result"
            }

        }
        BOTH -
        XY {
	    if [catch {exec cavput -list=SR:TUNE:Mux4Sw2BO=0 -pend=30} result] {
                return -code error "APSSetupStriplineDrive1b: unable to set stripline mux to y plane: $result"
            }
            set plane X/Y
        }
        default {
            return -code error " APSSetupStriplineDrive1: invalid plane -- $plane provided."  
        }
    }
    if [catch {exec cavget -list=SR:TUNE:Mux4Sw0BO -pend=10} mode] {
	return -code error "APSSetupStriplineDrive1: can not read  SR:TUNE:Mux4Sw0BO: $mode"
    }
    if {$VSA || $mode=="VSA"} {
	#for NASA, C1P1 do not care, but for VSA, x tune/ y tune, needs C1P1 to be X/Y
	if [catch {exec cavput -list=SR:TUNE:HP_1366A_C2P1_MBBO=X/Y -pend=30} result] {
	    return -code error "APSSetupStriplineDrive1a: unable to setup striplines: $result"
	}
    }
    if [catch {exec cavput -list=SR:TUNE:stripSELmbbo=$plane -pend=30 } result ] {
        return -code error "APSSetupStriplineDrive2: unable to setup striplines: $result"
    }
    if [catch {exec cavput -list=SR:TUNE:NASA:rfPowerBO=$rf -pend=30} result ] {
        return -code error "APSSetupStriplineDrive3: unable to turn on/off NASA rf power: $result"
    }      
    if {!$stripline} {
        #turn off the stripline
        if [catch {exec cavput -list=SR:TUNE:sig -list=5,6,7,8 -list=bo=Gnd -pend=30} result] {
            return -code error "APSSetupStriplineDrive4: unable to turn off stripline: $result"
        }
    }
}

proc APSMpMeasureTunes {args} {
    global status
    set ring PAR
    set analyzer NA
    set doSetup 0
    set setupFile ""
    set useExistingData 0
    set averagingSeconds 30
    set outputFile ""
    set comment "None"
    set plotData 1
    set lowerTune x
    set upperTune y
    set dividingLine 0.20
    set measureXYtuneTogether 1
    set useDividingLine 1
    set xPower ""
    set yPower ""
    set xFreq ""
    set yFreq ""
    set span ""
    set xP0ReducedGain 2.0
    set yP0ReducedGain 2.0
    set xDimtelReducedGain 2
    set yDimtelReducedGain 2
    set xPhase X-0
    set yPhase Y-0
    set xDelay ""
    set yDelay ""
    APSStrictParseArguments {analyzer doSetup setupFile useExistingData averagingSeconds useDividingLine \
                         outputFile comment plotData ring lowerTune upperTune dividingLine measureXYtuneTogether \
                         xPower yPower xFreq yFreq span xP0ReducedGain yP0ReducedGain \
                         xDimtelReducedGain yDimtelReducedGain \
                         xPhase yPhase xDelay yDelay}

    set ring [string toupper $ring]
    switch $ring {
        SR { 
            set prefix SR
            set harmonic 1296
            set beamInten S35DCCT
            set beamIntenUnits mA
            set beamParamOpt \
              "-print=parameter,BeamParamLabel,%.2lf mA   %.0lf bunches   %s,S35DCCT,BucketsFilled,TimeStamp"
        }
        PAR {
            set prefix P
            set harmonic 1
            set beamInten P1P1:sum
            set beamIntenUnits V
            set beamParamOpt "-print=parameter,BeamParamLabel,%.2lf V  %s,P1P1:sum,TimeStamp"
        }
        default {
            APSMpReturn error "APSMpMeasureTunes: No such ring for tune measurement: $ring"
        }
    }

    set inputDir /home/helios/oagData/[string tolower ${ring}]/tuneArchive/inputFiles
    
    APSMpStep init -promptDialog APSMpMeasureTunesInitDialog \
      -vars {analyzer doSetup setupFile useExistingData averagingSeconds \
               outputFile comment plotData}

    if [string compare $analyzer NA] {
        APSMpReturn error "APSMpMeasureTunes: Unknown/unsupported analyzer: $analyzer"
    }
    
    if {$doSetup && [string length $setupFile]} {
        APSMpStep SettingUp -proc "APSSetupNetworkAnalyzer"
        if [catch {APSSetupNetworkAnalyzer -setupFile $setupFile -ring $ring} result] {
            APSMpReturn error "APSMpMeasureTunes: Error trying to set up $ring network analyzer: $result"
        }
    }

    if [catch {exec cavput -pend=10 -list=${prefix}:TUNE:NASA:sweepHoldBO.PROC=1} result] {
        APSMpReturn error "APSMpMeasureTunes: Error trying to stop sweep on network analyzer: $result"
    }
    if !$useExistingData {
        APSMpStep TriggeringAnalyzer
        if {[catch {exec cavput -pend=10 -list=${prefix}:TUNE:NA \
                      -list=SA:sweepContBO.PROC=1,:CH1:averageBO=0,:CH2:averageBO=0} result]} {
            APSMpReturn error "APSMpMeasureTunes: Error trying to stop averaging on network analyzer: $result"
        }
        if [llength [info commands after]] {
            after 1000
        } else {
            exec sleep 1
        }
        if [catch {exec cavput -pend=10 -list=${prefix}:TUNE:NA \
                     -list=:CH1:averageBO=1,:CH2:averageBO=1} result] {
            APSMpReturn error "APSMpMeasureTunes: Error trying to start averaging on network analyzer: $result"
        }
        if $averagingSeconds>0 {
            APSMpStep WaitingForAnalyzer
            APSWaitWithUpdate -waitSeconds $averagingSeconds -updateInterval 1
            if {[catch {exec cavput -pend=10 -list=${prefix}:TUNE:NASA:sweepHoldBO.PROC=1} result]} {
                APSMpReturn error "APSMpMeasureTunes: Error trying to stop sweep on network analyzer: $result"
            }
        }
    }
    if ![string length $outputFile] {
        APSMpReturn ok
    }
    APSMpStep AcquiringData
    set xTune 0
    set yTune 0
    if [string length $xDelay] {
        if [catch {exec cavput -list=SR:tune:hpdl:x:SetDelay=$xDelay -pend=10} result] {
            APSMpReturn error "APSMpMeasureTunes: Error setting xdelay: $result"
        }
    }
    if [string length $yDelay] {
        if [catch {exec cavput -list=SR:tune:hpdl:y:SetDelay=$yDelay -pend=10} result] {
            APSMpReturn error "APSMpMeasureTunes: Error setting ydelay: $result"
        }
    }
    if $measureXYtuneTogether {
        # these are string PVs which return an integer if they
        # were included in the scalars options of sddswmonitor.
        # So we have to collect the values through a cavget command.
        if [catch {APSSetupStriplineDrive -plane X/Y} result] {
            APSMpReturn error "APSMpMeasureTunes: Error in setup the stripline drive to X/Y plane: $result"
        }
        APSMpStep "Waiting for waveform to be updated."
        if {[catch {exec cavput -pend=10 -list=${prefix}:TUNE:NASA:sweepContBO.PROC=1} result]} {
            APSMpReturn error "APSMpMeasureTunes: Error trying to start sweep on network analyzer: $result"
        }
        after 10000
        if {[catch {exec cavput -pend=10 -list=${prefix}:TUNE:NASA:sweepContBO.PROC=1} result]} {
            APSMpReturn error "APSMpMeasureTunes: Error trying to start sweep on network analyzer: $result"
        }
        lappend PVlist ${prefix}:TUNE:NASA:analyzerModeBI ${prefix}:TUNE:NA:CH1:measureMI \
          ${prefix}:TUNE:NA:CH2:measureMI ${prefix}:TUNE:NASA:ifBwMI \
          ${prefix}:TUNE:NA:CH1:formatMI ${prefix}:TUNE:NA:CH2:formatMI \
          ${prefix}:TUNE:NASA:ptsSampledAI \
          SR:tune:hpdl:x:SetDelay SR:tune:hpdl:y:SetDelay 
        lappend varList mode meas1 meas2 IFBW format1 format2 ptsSampled xshift yshift
        if [catch {exec cavget -pend=10 -list=[join $PVlist ,] -pend=30} result] {
            APSMpReturn error "APSMpMeasureTunes: Error trying to read parameters from network analyzer: $result"
        }
        set index 0
        foreach elem $varList {
            set $elem [lindex $result $index]
            incr index
        }
        for {set ch 1} {$ch<3} {incr ch} {
            set units$ch ?
            switch [subst \$format$ch] {
                Linear { set units$ch V}
                Log    { set units$ch dB}
            }
        }
        set ptsSampled [expr $ptsSampled-1]
        set tmpInput /tmp/[APSTmpString]
        set tmpOutput /tmp/[APSTmpString]
        exec sddsprocess $inputDir/networkAnalyzer.wmon \
          $tmpInput -redefine=param,WaveformLength,$ptsSampled,type=long 
        
        if [catch {exec sddswmonitor $tmpInput -steps=1 $tmpOutput -precision=double \
                     -scalar=$inputDir/spectAnalScalars.mon} result] {
            APSMpReturn error "APSMpMeasureTunes: Problem with sddswmonitor: $result"
        }
        if {[catch {exec cavput -pend=10 -list=${prefix}:TUNE:NASA:sweepContBO.PROC=1} result]} {
            APSMpReturn error "APSMpMeasureTunes: Error trying to start sweep on network analyzer: $result"
        }
        if {[catch \
               {exec sddsprocess $tmpOutput $tmpOutput.1 \
                  -define=para,coblyPhaseShiftDelayX,$xshift \
                  -define=para,colbyPhaseShiftDelayY,$yshift \
                  -print=param,MeasurementCh1,$meas1 \
                  "-print=param,Comment,[APSMakeSafeQualifierString $comment]" \
                  -print=param,MeasurementCh2,$meas2 \
                  "-define=param,StartFreq,CenterFreq Span 2 / -,units=Hz,type=float" \
                  "-define=param,DeltaFreq,Span $ptsSampled 1 - /,units=Hz,type=float" \
                  "-define=param,Harmonic,$harmonic,type=long" \
                  -print=param,FormatCh1,$format1 -print=param,FormatCh2,$format2 \
                  -print=param,IFBW,$IFBW \
                  "-define=param,rotationFreq,rfFreq Harmonic /" \
                  "-define=col,Frequency,Index DeltaFreq * StartFreq + 1e6 /,units=MHz,type=float" \
                  "-define=column,Tune,Frequency 1e6 * rotationFreq / = int - 0.5 > ? pop 1 swap - : pop \$ " \
                  -redefine=col,${prefix}:TUNE1,${prefix}:TUNE1,units=$units1 \
                  -redefine=col,${prefix}:TUNE2,${prefix}:TUNE2,units=$units2} result]} {
            if [catch {exec sddsprocess $tmpOutput $outputFile \
                         -define=parameter,${lowerTune}Tune,0 \
                         -define=parameter,${upperTune}Tune,0 \
                         "-print=parameter,TuneLabel,\$gn\$r\$bx\$n = ?  \$gn\$r\$by\$n = ?"} result1] {
                APSMpReturn error "APSMpMeasureTunes: Error processing tune data (1): $result\n$result1"
            }
            catch {file delete -force $tmpOutput $tmpOutput.1}
            APSMpReturn error "APSMpMeasureTunes: Error processing tune data (2): $result"
        }
        if [catch {exec sddsprocess $tmpOutput.1 -pipe=out \
                     -process=${prefix}:TUNE1,max,${prefix}:TUNE1Max \
                     "-define=col,NormalizedTrace,${prefix}:TUNE1 ${prefix}:TUNE1Max /" \
                     | sddspeakfind -pipe=in $tmpOutput.1a -column=NormalizedTrace -threshold=0.1 \
                     -exclusion=0.2 } result] {
            catch {file delete -force $tmpOutput $tmpOutput.1 $tmpOutput.1a}
            APSMpReturn error "APSMpMeasureTunes: Error processing tune data (3): $result"
        }
        set tunes [exec sdds2stream -col=Tune $tmpOutput.1a]
        foreach tune $tunes {
            if {$tune>0 && $tune<$dividingLine} {
                set xTune $tune
            }
            if {$tune>$dividingLine && $tune<0.5} {
                set yTune $tune
            } 
        }
        if [catch {exec sddsprocess $tmpOutput.1a  $tmpOutput.2 -nowarning \
                     -define=par,xTune,$xTune \
                     -define=par,yTune,$yTune \
                     -process=${prefix}:TUNE1,max,${lowerTune}Amplitude,func=Tune,lower=0,upper=$dividingLine \
                     -process=${prefix}:TUNE1,max,${upperTune}Amplitude,func=Tune,lower=$dividingLine,upper=0.5 \
                     "-define=parameter,${lowerTune}NormAmplitude,${lowerTune}Amplitude $beamInten / 10 rfDrivePower 10 / pow /,units=V/$beamIntenUnits/mW" \
                     "-define=parameter,${upperTune}NormAmplitude,${upperTune}Amplitude $beamInten / 10 rfDrivePower 10 / pow /,units=V/$beamIntenUnits/mW" \
                     "-print=parameter,TuneLabel,\$gn\$r\$bx\$n = %.4f  \$gn\$r\$by\$n = %.4f,xTune,yTune" 
            exec sddsxref $tmpOutput.1 $tmpOutput.2 -pipe=out -leave=* \
                     -transfer=parameter,TuneLabel,xTune,yTune,*NormAmplitude \
                     | sddsprocess -pipe=in $outputFile $beamParamOpt \
                 } result] {
            APSMpReturn error "APSMpMeasureTunes: Error processing tune data (3): $result\n$result"
        }
        catch {file delete -force $tmpOutput $tmpOutput.1 $tmpOutput.1a $tmpOutput.2 $tmpInput} 
        if $plotData {
            exec sddsplot -column=Tune,${prefix}:TUNE1  $outputFile -split=page -sep=page \
              -graph=line,vary -topline=@TuneLabel -title=@BeamParamLabel &
        }
    } else {
        if [catch {exec cavget -list=Mt:TopUpAutoEnableC.VAL -pend=30 -numerical} topupRunning] {
            APSMpReturn error "APSMpMeasureTunes: Error in getting topup state: $topupRunning."
        }
        if $topupRunning {
            if [catch {exec cavget -list=Mt:TopUpIntervalP.VAL -pend=20} topupInterval] {
                APSMpReturn error "APSMpMeasureTunes: Error in reading topup interval: $topupInterval"
            }
            if {$topupInterval<120} {
                if [catch {exec cavput -list=Mt:TopUpIntervalP.VAL=120 -pend=20} result] {
                    APSMpReturn error "APSMpMeasureTunes: Error in increasing topup interval to 240 seconds:"
                }
            }
            APSMpStep "Waiting for topup shot:"
            set status  "Waiting for topup shot:"
            while {1} {
                if [catch {APScavget -list=Mt:TopUpTime2Inject.VAL -pend=30} injTime] {
                    APSMpReturn error "APSMpMeasureTunes: Error in reading injection time: $injTime"
                }
                if {$injTime>100} {
                    break
                }
                after 500
            }
        }
        set tmpRoot /tmp/[APSTmpString]
        if [catch {exec sddswget -pv=Mt:S:FillPatternWF.VAL $tmpRoot.pattern} result] {
            APSMpReturn -code error "APSMpMeasureTunes: Unable to read bunch pattern WF: $result"
        }
        if [catch {exec sddsdiff -col=Index,Waveform $tmpRoot.pattern  \
                     /home/helios/oagData/sr/bunchPatterns/bunchPatternFillRef.hybrid561} result] {
            set reduceGain 1
        } else {
            #do not reduce P0Feedback gain for hybrid pattern
            set reduceGain 0
        }
        foreach plane {x y} value {0 1} lower [list 0.05 $dividingLine] upper [list $dividingLine 0.5] power [list $xPower $yPower] \
          freq [list $xFreq $yFreq] {
              switch $plane {
                  x {
                      set dimtelPV IGPF:Z:SHIFTGAIN
                      set dimtelReducedGain $xDimtelReducedGain 
                  }
                  y {
                      set dimtelPV IGPF:Y:SHIFTGAIN
                      set dimtelReducedGain $yDimtelReducedGain 
                  }
              }
              if [catch {exec cavget -list=$dimtelPV -pend=10} dimtelGain] {
                  #return -code error "Error reading dimetl gain: $dimtelGain"
              }
              if {$dimtelGain<$dimtelReducedGain} {
                  #do nothing
              } else {
                  if [catch {exec cavput -list=$dimtelPV=$dimtelReducedGain -pend=10} result] {
                      #return -code error "Error reduce dimtel gain: $result"
                  }
              }
              if $reduceGain {
                  foreach system {TFB P0} prefix1 {S:P0FB S:TFB:M} {
                      APSMpStep "Save current $system FB gain"
                      set status "Save current $system  gain"
                      set gainPV ${prefix1}:AcqGain[string toupper $plane]_SetWF
                      if [catch {exec sddswget -pv=$gainPV $tmpRoot.$plane.$system.gain -pend=30} result] {
                          APSMpReturn error "APSMpMeasureTunes: Error in saving $gainPV."
                      }
                      if [catch {exec sddsprocess $tmpRoot.$plane.$system.gain -pipe=out \
                                   -process=Waveform,first,Gain \
                                   | sdds2stream -pipe -par=Gain } currentGain] {
                          APSMpReturn error "APSMpMeasureTunes: Error getting curreng gain: $currentGain"
                      }
                      set rGain [set ${plane}P0ReducedGain]
                      if {[expr abs($currentGain)]<=[expr abs($rGain)]} {
                          #do not change the gain if current gain is less than
                          APSMpStep "$system $plane gain ($currentGain) is less than the reduced gain ($rGain), skip."
                          set status "$system $plane gain ($currentGain) is less than the reduced gain ($rGain), skip."
                          continue
                      }
                      APSMpStep "Reduce $system feedback $plane gain."
                      set status "Reduce $system feedback $plane gain."
                      if [catch {exec sddsprocess $tmpRoot.$plane.$system.gain $tmpRoot.$plane.$system.gain1 \
                                   "-redefine=col,Waveform,[set ${plane}P0ReducedGain]" \
                               } result] {
                          APSMpReturn error "APSMpMeasureTunes: Error in process P0 feedback gain: $result"
                      }
                      if [catch {exec sddswput $tmpRoot.$plane.$system.gain1 -pend=30} result] {
                          APSMpReturn error "APSMpMeasureTunes: Error in reducing P0 feedback gain: $result"
                      }
                  }
                  APSAddToTmpFileList -ID measuretunes -fileList "$tmpRoot.$plane.$system.gain $tmpRoot.$plane.$system.gain1"
              }
             
              APSMpStep "Measure $plane tune..."
              set status "Measure $plane tune..."
              if [catch {APSSetupStriplineDrive -plane $plane -xPhase $xPhase -yPhase $yPhase } result] {
                  APSMpReturn error "APSMpMeasureTunes: Error in setup the stripline drive to $plane plane: $result"
              }
              if [string length $power] {
                  if [catch {exec cavput -list=SR:TUNE:NASA:rfPowerAO=$power -pend=30} result] {
                      APSMpReturn error "APSMpMeasureTunes: Error in setup rf power: $result"
                  }
              }
              if {[string length $freq]} {
                  if [catch {exec cavput -list=SR:TUNE:NASA:centerFreqAO=$freq -pend=30} result] {
                      APSMpReturn error "APSMpMeasureTunes: Error in setup rf center frequency and span: $result"
                  }
              } 
              if [string length $span] {
                  if [catch {exec cavput -lis=SR:TUNE:NASA:freqSpanAO=$span -pend=30 } result] {
                      APSMpReturn error "APSMpMeasureTunes: Error in setup rf center frequency and span: $result"
                  }
              }
              
              #if [catch {exec cavput -list=SR:TUNE:stripSELmbbo=$value} result] {
              #    APSMpReturn error "APSMpMeasureTunes: Error in switching planes: $result"
              #}
              APSMpStep "Waiting for waveform to be updated."
              set status "Waiting for waveform to be update."
              if {[catch {exec cavput -pend=10 -list=${prefix}:TUNE:NASA:sweepContBO.PROC=1} result]} {
                  APSMpReturn error "APSMpMeasureTunes: Error trying to start sweep on network analyzer: $result"
              }
              after 10000
              
              # these are string PVs which return an integer if they
              # were included in the scalars options of sddswmonitor.
              # So we have to collect the values through a cavget command.
              lappend PVlist ${prefix}:TUNE:NASA:analyzerModeBI ${prefix}:TUNE:NA:CH1:measureMI \
                ${prefix}:TUNE:NA:CH2:measureMI ${prefix}:TUNE:NASA:ifBwMI \
                ${prefix}:TUNE:NA:CH1:formatMI ${prefix}:TUNE:NA:CH2:formatMI \
                ${prefix}:TUNE:NASA:ptsSampledAI \
                SR:tune:hpdl:x:SetDelay SR:tune:hpdl:y:SetDelay 
              lappend varList mode meas1 meas2 IFBW format1 format2 ptsSampled xshift yshift
              if [catch {exec cavget -pend=10 -list=[join $PVlist ,] -pend=30} result] {
                  APSMpReturn error "APSMpMeasureTunes: Error trying to read parameters from network analyzer: $result"
              }
              set index 0
              foreach elem $varList {
                  set $elem [lindex $result $index]
                  incr index
              }
              for {set ch 1} {$ch<3} {incr ch} {
                  set units$ch ?
                  switch [subst \$format$ch] {
                      Linear { set units$ch V}
                      Log    { set units$ch dB}
                  }
              }
              set ptsSampled [expr $ptsSampled-1]
              set tmpInput /tmp/[APSTmpString]
              set tmpOutput /tmp/[APSTmpString]
              exec sddsprocess $inputDir/networkAnalyzer.wmon \
                $tmpInput -redefine=param,WaveformLength,$ptsSampled,type=long 
              if [catch {exec sddswmonitor $tmpInput -steps=1 $tmpOutput -precision=double \
                           -scalar=$inputDir/spectAnalScalars.mon} result] {
                  APSMpReturn error "APSMpMeasureTunes: Problem with sddswmonitor: $result"
              }
              if {[catch {exec cavput -pend=10 -list=${prefix}:TUNE:NASA:sweepContBO.PROC=1} result]} {
                  APSMpReturn error "APSMpMeasureTunes: Error trying to start sweep on network analyzer: $result"
              }
              if $reduceGain {
                  foreach system {P0 TFB} {
                      if [file exist $tmpRoot.$plane.$system.gain1] {
                          APSMpStep "Restore $system feedback $plane gain..."
                          set status "Restore $system feedback $plane gain..."
                          if [catch {exec sddswput $tmpRoot.$plane.$system.gain -pend=30} result] {
                              APSMpReturn error "APSMpMeasureTunes: Error in restoring P0 feedback $plane gain: $result"
                          }
                      }
                  }
              }
              if {$dimtelGain<$dimtelReducedGain} {
                  #do nothing
              } else {
                  if [catch {exec cavput -list=$dimtelPV=$dimtelGain -pend=10} result] {
                      #return -code error "Error restore dimtel gain: $result"
                  }
              }
              if {[catch \
                     {exec sddsprocess $tmpOutput $tmpOutput.1 \
                        -define=para,coblyPhaseShiftDelayX,$xshift \
                        -define=para,colbyPhaseShiftDelayY,$yshift \
                        -print=param,MeasurementCh1,$meas1 \
                        "-print=param,Comment,[APSMakeSafeQualifierString $comment]" \
                        -print=param,MeasurementCh2,$meas2 \
                        "-define=param,StartFreq,CenterFreq Span 2 / -,units=Hz,type=float" \
                        "-define=param,DeltaFreq,Span $ptsSampled 1 - /,units=Hz,type=float" \
                        "-define=param,Harmonic,$harmonic,type=long" \
                        -print=param,FormatCh1,$format1 -print=param,FormatCh2,$format2 \
                        -print=param,IFBW,$IFBW \
                        "-define=param,rotationFreq,rfFreq Harmonic /" \
                        "-define=col,Frequency,Index DeltaFreq * StartFreq + 1e6 /,units=MHz,type=float" \
                        "-define=column,Tune,Frequency 1e6 * rotationFreq / = int - 0.5 > ? pop 1 swap - : pop \$ " \
                        -redefine=col,${prefix}:TUNE1,${prefix}:TUNE1,units=$units1 \
                        -redefine=col,${prefix}:TUNE2,${prefix}:TUNE2,units=$units2 \
                    } result]} {
                  if [catch {exec sddsprocess $tmpOutput $outputFile.$plane \
                               -define=parameter,${plane}Tune,0 \
                               "-print=parameter,TuneLabel,\$gn\$r\$bx\$n = ?  \$gn\$r\$by\$n = ?"} result1] {
                      APSMpReturn error "APSMpMeasureTunes: Error processing tune data (1): $result\n$result1"
                  }
                  catch {file delete -force $tmpOutput $tmpOutput.1}
                  APSMpReturn error "APSMpMeasureTunes: Error processing tune data (2): $result"
              }
              if $useDividingLine {
                  set extraOpt "-filter=col,Tune,$lower,$upper"
                  set extraOpt1 ",lower=$lower,upper=$upper"
              } else {
                  set extraOpt ""
                  set extraOpt1 ""
              }
              if [catch {eval exec sddsprocess $tmpOutput.1 -pipe=out \
                           -process=${prefix}:TUNE1,max,${prefix}:TUNE1Max \
                           $extraOpt \
                           \"-define=col,NormalizedTrace,${prefix}:TUNE1 ${prefix}:TUNE1Max /\" \
                           | sddspeakfind -pipe -column=NormalizedTrace -threshold=0.5 \
                           -exclusion=0.2 \
                           | sddssort -pipe=in $tmpOutput.1a -column=NormalizedTrace,decr} result] {
                  APSMpReturn error "APSMpMeasureTunes: Error processing tune data (2a): $result"
                  
              }
              set tune [lindex [exec sdds2stream -col=Tune $tmpOutput.1a] 0]
              if $useDividingLine {
                  if {$tune<$upper && $tune>$lower} {
                      set ${plane}Tune $tune
                  }
              } else {
                  set ${plane}Tune $tune
              }
              
              if [catch {eval exec sddsprocess $tmpOutput.1a $tmpOutput.2 -nowarning \
                           -define=par,${plane}Tune,[set ${plane}Tune]  \
                           -process=${prefix}:TUNE1,max,${plane}Amplitude,func=Tune$extraOpt1  \
                           \"-define=parameter,${plane}NormAmplitude,${plane}Amplitude $beamInten / 10 rfDrivePower 10 / pow /,units=V/$beamIntenUnits/mW\" \
                           \"-print=parameter,TuneLabel,\\\$gn\\\$r\\\$b${plane}\\\$n = %.4f,${plane}Tune\"
                  exec sddsxref $tmpOutput.1 $tmpOutput.2 -pipe=out -leave=* \
                           -transfer=parameter,TuneLabel,${plane}Tune,*NormAmplitude \
                           | sddsprocess -pipe=in $outputFile.$plane $beamParamOpt \
                           "-print=par,plane,$plane" } result] {
                  APSMpReturn error "APSMpMeasureTunes: Error processing tune data (4): $result"
              }
              catch {file delete -force $tmpOutput $tmpOutput.1 $tmpOutput.1a $tmpOutput.2 $tmpInput}
          }
        set xamp [exec sdds2stream -par=xNormAmplitude $outputFile.x]
        set yamp [exec sdds2stream -par=yNormAmplitude $outputFile.y]
        if [catch {exec sddscombine $outputFile.x $outputFile.y -pipe=out \
                     | sddsprocess -pipe \
                     -redefine=par,xTune,$xTune \
                     "-redefine=par,yTune,$yTune" \
                     "-redefine=par,xNormAmplitude,$xamp" \
                     "-redefine=par,yNormAmplitude,$yamp" \
                     | sddsprocess -pipe=in $outputFile \
                     "-reprint=parameter,TuneLabel,\$gn\$r\$bx\$n = %.4f  \$gn\$r\$by\$n = %.4f,xTune,yTune" \
                 } result] {
            APSMpReturn error "APSMpMeasureTunes: Error processing tune data (5): $result"
        }
        file delete -force $outputFile.x $outputFile.y
        if $plotData {
            exec sddsplot $outputFile -split=page -col=Tune,${prefix}:TUNE1 -grap=line,vary -mode=y=offset \
              -topline=@TuneLabel $outputFile &
            # exec sddsplot $outputFile.x $outputFile.y -layout=1,2 -sep -column=Tune,${prefix}:TUNE1 \
              #     -graph=line,vary -topline=@TuneLabel -title=@BeamParamLabel &
        }
        if $topupRunning {
            APSMpStep "Restore topup interval to $topupInterval."
            APSMpStep "Restore topup interval to $topupInterval."
            if [catch {exec cavput -list=Mt:TopUpIntervalP.VAL=$topupInterval -pend=20} result] {
                APSMpReturn error "APSMpMeasureTunes: Error in restoring topup interval: $result"
            }
        }
    }   
    
    if [catch {APSSetupStriplineDrive -plane X/Y -rf 0 -stripline 0} result] {
        APSMpReturn error "APSMpMeasureTunes: Error in setup the stripline drive to X/Y plane: $result"
    }
    #put the sweep to hold
    if [catch {exec cavput -list=SR:TUNE:NASA:sweepSelectMBBO=0,SR:TUNE:HP_1366A_C0P1_MBBO=0 -pend=10} result] {
        APSMpReturn error "APSMpMeasureTunes: Error in put the sweep mode to hold: $result"
    }
    APSMpReturn ok
}

proc APSMpMeasureP0FBTune {args} {
    set outputFile ""
    set plot 0
    set update 0
    set steps 20
    set statusCallback ""
    set archive 0
    set interval 1
    set tuneRangeLow 0.10
    set system P0
    APSStrictParseArguments {outputFile plot update steps statusCallback archive interval tuneRangeLow system} 

    if [catch {exec cavget -pend=10 -list=Mt:TopUpAutoEnableC.VAL -num } topup] {
        return -code error "APSMpMeasureP0FBTune1: Unable to read topup state: $topup"
    }
    
    if [catch {exec cavget -list=SR:bunchPatternSO -pend=10} bunchPattern] {
        return -code error "APSMpMeasureP0FBTune2:  Error in reading bunchPattern: $bunchPattern."
    }
    set topupWait 20
    if [regexp {8x7} $bunchPattern] {
        set num 8
    } elseif [regexp {324} $bunchPattern] {
        set num 12
        if {$system=="TFB"} {
            set num 27
            #TFB 324 pattern use 27 bunches
        }
    } elseif [regexp {24} $bunchPattern] {
        set num 24
    } else {
        set num 12
        if {$system=="TFB"} {
            if [regexp {48} $bunchPattern] {
                set num 24
            } else {
                set num 27
            }
            #for TFB system, treat 
        }
            
        #treat 432 as 324
        #do not do anything if the pattern does not match
        #return
        #return -code error "APSMpMeasureP0FBTune3: invalid bunchPattern - $bunchPattern."
    }
    switch $system {
        P0 {
            set dir P0Feedback
        }
        TFB {
            set dir TFB
        }
    }
    if $topup {
        if [string length $statusCallback] {
            eval $statusCallback  {"[clock format [clock seconds] -format %H:%M:%S]: Waiting for topup shot:"}
        }
        while {1} {
            if [catch {exec cavget -list=Mt:TopUpTime2Inject.VAL -pend=30} injTime] {
                return -code error "APSMpMeasureP0FBTune3a: Error in reading injection time: $injTime"
                exit 1
            }
            if {$injTime>$topupWait} {
                break
            }
            after 1000
        }
    }
    if $archive {
        set outputFile /home/helios/oagData/sr/$dir/tuneArchive/data/[clock format [clock seconds] -format %Y-%j-%m%d.%H%M%S]
    } elseif ![string length $outputFile] {
        set outputFile /home/helios/oagData/sr/$dir/tuneArchive/loggedData/[clock format [clock seconds] -format %Y-%j-%m%d.%H%M%S]
    }
    
    if [string length $statusCallback] {
        eval $statusCallback {"[clock format [clock seconds] -format %H:%M:%S]: Taking data..."}
    }
    switch $system {
        P0 {
            set prefix S:P0FB
            set respOptx "-redefine=col,xResponse,1 FFT2xMean / sqrt"
            set respOpty "-redefine=col,yResponse,1 FFT2yMean / sqrt"
        }
        TFB {
            set prefix S:TFB:M
            #4/1/2019 do not know why FTB do not to have inverse .....
            set respOptx "-redefine=col,xResponse,FFT2xMean sqrt"
            set respOpty "-redefine=col,yResponse,FFT2yMean sqrt"
        }
        default {
            set prefix S:P0FB
        }
    }
            
    set tmpRoot /tmp/[APSTmpString]getP0FBTune
    if [catch {exec sddswmonitor -erase $tmpRoot.1 -pend=30 -interval=$interval \
                 -scalars=/home/helios/oagData/sr/P0Feedback/tuneArchive/inputFiles/tuneScalars.mon \
                 -pvnames=${prefix}:scope:gtr:waveform0,${prefix}:scope:gtr:waveform1,${prefix}:scope:gtr:waveform2,${prefix}:scope:gtr:waveform3\
                 -step=$steps
        exec sddswmonitor -erase $tmpRoot.2 -pend=30 \
                 -pvnames=${prefix}:AcqGainX_GetWF,${prefix}:AcqGainY_GetWF 
    } result] {
        return -code error "APSMpMeasureP0FBTune4: Error in reading P0 feedback waveforms: $result"
    }
    APSAddToTempFileList $tmpRoot.1 $tmpRoot.2
    if [catch {exec sddsprocess $tmpRoot.1 -pipe=out \
                 -process=${prefix}:scope:gtr:waveform0,ave,waveform0Ave \
                 -process=${prefix}:scope:gtr:waveform1,ave,waveform1Ave \
                 -process=${prefix}:scope:gtr:waveform0,rms,waveform0RMS \
                 -process=${prefix}:scope:gtr:waveform1,rms,waveform1RMS \
                 -process=${prefix}:scope:gtr:waveform0,spread,waveform0Spread \
                 -process=${prefix}:scope:gtr:waveform1,spread,waveform1Spread \
                 -process=${prefix}:scope:gtr:waveform2,spread,waveform2Spread \
                 -process=${prefix}:scope:gtr:waveform3,spread,waveform3Spread \
                 | sddscollapse -pipe \
                 | sddsprocess -pipe=in $tmpRoot.1a \
                 -process=waveform0Spread,spread,waveform0Spread \
                 -process=waveform1Spread,spread,waveform1Spread \
                 -process=waveform2Spread,spread,waveform2Spread \
                 -process=waveform3Spread,spread,waveform3Spread \
                 -process=waveform0Ave,ave,waveform0Ave \
                 -process=waveform1Ave,ave,waveform1Ave  \
                 -process=waveform0RMS,rms,waveform0RMS \
                 -process=waveform1RMS,ave,waveform1RMS  } result] {
        return -code error "APSMpMeasureP0FBTune5: Error in processing waveform average: $result"
    }
    
    APSAddToTempFileList $tmpRoot.1a
    set w0ave [exec sdds2stream -par=waveform0Ave $tmpRoot.1a]
    set w1ave [exec sdds2stream -par=waveform1Ave $tmpRoot.1a]
    set w0rms [exec sdds2stream -par=waveform0RMS $tmpRoot.1a]
    set w1rms [exec sdds2stream -par=waveform1RMS $tmpRoot.1a]
    set w0spread [exec sdds2stream -par=waveform0Spread  $tmpRoot.1a]
    set w1spread [exec sdds2stream -par=waveform1Spread  $tmpRoot.1a]
    set w2spread [exec sdds2stream -par=waveform2Spread  $tmpRoot.1a]
    set w3spread [exec sdds2stream -par=waveform3Spread  $tmpRoot.1a]
    if [catch {exec cavget -list=S-DCCT:CurrentM -pend=10} DCCT] {
        return -code error "APSMpMeasureP0FBTune6: error in reading DCCT current."
    }
    
    if [catch {exec sddsprocess $tmpRoot.2 $tmpRoot.2a \
                 -process=${prefix}:AcqGainX_GetWF,average,xGain \
                 -process=${prefix}:AcqGainY_GetWF,average,yGain -now } result] {
        return -code error "APSMpMeasureP0FBTune7: Error in obtaining P0 gains: $result"
    }
    APSAddToTempFileList $tmpRoot.2a
    set xGain [exec sdds2stream -para=xGain $tmpRoot.2a]
    set yGain [exec sdds2stream -para=yGain $tmpRoot.2a]
    if {$num == 24} {
        if [catch {exec sddsprocess $tmpRoot.1 -pipe=out \
                     -filter=col,Index,0,16367 \
                     | sddsprocess "-redefine=col,IndexM,Index $num mod" -pipe \
                     | sddssort -col=IndexM -pipe \
                     | sddsbreak -changeOf=IndexM  -pipe \
                     | sddsprocess -pipe -redefine=col,Index,i_row \
                     -filter=col,Index,0,681 \
                     | tee $tmpRoot.input \
                     | sddsfft -pipe=in $tmpRoot.fft.1 -window \
                     -col=Index,${prefix}:scope:gtr:waveform? \
                     -padwithzeroes=2 -suppressAverage} result] {
            return -code error "APSMpMeasureP0FBTune8: error in processing data: $result"
        }
    } elseif { $num == 8 } {
        if [catch {exec sddsprocess $tmpRoot.1 -pipe=out \
                     -filter=col,Index,0,16383 \
                     | sddsbreak -rowLimits=2048  -pipe \
                     | sddsprocess -pipe -redefine=col,Index,i_row \
                     | tee $tmpRoot.input \
                     | sddsfft -pipe=in $tmpRoot.fft.1 -window \
                     -col=Index,${prefix}:scope:gtr:waveform? \
                     -suppressAverage } result] {
            return -code error "APSMpMeasureP0FBTune9: error in processing data: $result"
        }
    } elseif { $num == 12 } {
        if [catch {exec sddsprocess $tmpRoot.1 -pipe=out \
                     -filter=col,Index,0,12287 \
                     | sddsprocess "-redefine=col,IndexM,Index $num mod" -pipe \
                     | sddssort -col=IndexM -pipe \
                     | sddsbreak -changeOf=IndexM  -pipe \
                     | sddsprocess -pipe -redefine=col,Index,i_row \
                     -filter=col,Index,0,1023 \
                     | tee $tmpRoot.input \
                     | sddsfft -pipe=in $tmpRoot.fft.1 -window \
                     -col=Index,${prefix}:scope:gtr:waveform? \
                     -padwithzeroes -suppressAverage } result] {
            return -code error "APSMpMeasureP0FBTune10: error in processing data: $result"
        }
    } elseif { $num==27} {
         if [catch {exec sddsprocess $tmpRoot.1 -pipe=out \
                     -filter=col,Index,0,16361 \
                     | sddsprocess "-redefine=col,IndexM,Index $num mod" -pipe \
                     | sddssort -col=IndexM -pipe \
                     | sddsbreak -changeOf=IndexM  -pipe \
                     | sddsprocess -pipe -redefine=col,Index,i_row \
                     -filter=col,Index,0,605 \
                     | tee $tmpRoot.input \
                     | sddsfft -pipe=in $tmpRoot.fft.1 -window \
                     -col=Index,${prefix}:scope:gtr:waveform? \
                     -padwithzeroes=2 -suppressAverage} result] {
            return -code error "APSMpMeasureP0FBTune8: error in processing data: $result"
        }
    }
    if [catch {exec sddsprocess $tmpRoot.input -process=${prefix}:scope:gtr:waveform0,spread,xInputSpread \
                 -process=${prefix}:scope:gtr:waveform1,spread,yInputSpread \
                 -pipe=out \
                 | sddscollapse -pipe \
                 | sddsprocess -pipe=in $tmpRoot.input.1 \
                 -process=xInputSpread,spread,xInSpread \
                 -process=yInputSpread,spread,yInSpread } result] {
        return -code error "APSMpMeasureP0FBTune10: error processing input waveform spread: $result"
    }
    set w0spread [exec sdds2stream -par=xInSpread $tmpRoot.input.1]
    set w1spread [exec sdds2stream -par=yInSpread $tmpRoot.input.1]
    APSAddToTempFileList $tmpRoot.input.1
    APSAddToTempFileList $tmpRoot.fft.1 $tmpRoot.input
    if [catch {exec  sddsprocess $tmpRoot.fft.1 $tmpRoot.fft \
                 "-redefine=col,FFT2x,FFT${prefix}:scope:gtr:waveform0 sqr" \
                 "-redefine=col,FFT2y,FFT${prefix}:scope:gtr:waveform1 sqr" } result] {
        return -code error "APSMpMeasureP0FBTune11: $result"
    }
    APSAddToTempFileList $tmpRoot.fft
    if [catch {exec sddsenvelope $tmpRoot.fft -pipe=out -mean=FFT2* -copy=f \
                 | sddsprocess -pipe  \
                 "$respOptx" "$respOpty" \
                 -filter=col,f,0,0.5 \
                 | tee $tmpRoot.tune.1 \
                 | sddsxref -pipe $tmpRoot.1 -leave=* -transfer=par,* \
                 | sddsprocess -pipe "-define=par,P0FeedbackXGain,$xGain" "-define=par,P0FeedbackYGain,$yGain" \
                 "-redefine=par,waveform0Ave,$w0ave" "-redefine=par,waveform1Ave,$w1ave" \
                 | sddsprocess -pipe=in $tmpRoot.tune.2 \
                 -process=xResponse,max,xTunePeak,functionOf=f,lowerLimit=$tuneRangeLow,upperLimit=0.4 \
                 -process=yResponse,max,yTunePeak,functionOf=f,lowerLimit=$tuneRangeLow,upperLimit=0.4 \
                 -process=xResponse,max,xTune,position,functionOf=f,lowerLimit=$tuneRangeLow,upperLimit=0.4 \
                 -process=yResponse,max,yTune,position,functionOf=f,lowerLimit=$tuneRangeLow,upperLimit=0.4 \
                 "-print=par,TuneLabel,\$gn\$r\$bx\$n = %.4f  \$gn\$r\$by\$n = %.4f,xTune,yTune" \
                 "-reprint=par,BeamParamLabel,%.2lf mA   %.0lf bunches P0Xgain=%.1lf P0Ygain=%.1lf  %s,S35DCCT,BucketsFilled,P0FeedbackXGain,P0FeedbackYGain,TimeStamp" \
} result] {
        return -code error "APSMpMeasureP0FBTune12: $result"
    }
    if [catch {exec sddsxref $tmpRoot.tune.1 $tmpRoot.tune.2 $tmpRoot.tune -leave=* -transfer=par,* } result] {
        return -code error "APSMpMeasureP0FBTune12a: $result"
    }
    #re-process the file to have the same format as NASA tune output file
    foreach plane {x y} {
        if [catch {exec sddsconvert $tmpRoot.tune -pipe=out \
                     -retain=col,f,${plane}Response,FFT2${plane}Mean \
                     -rename=col,f=Frequency,${plane}Response=SR:TUNE1,FFT2${plane}Mean=FFT2Mean  \
                     | sddsprocess -pipe "-redefine=col,SR:TUNE1,Frequency 0.05 < ? 0 : SR:TUNE1 $ " \
                     | sddsprocess -pipe=in $tmpRoot.$plane \
                     "-redefine=col,SR:TUNE1,Frequency 0.45 > ? 0 : SR:TUNE1 $ " \
                     -redefine=col,Tune,Frequency -redefine=col,Index,i_row,type=long \
                     -print=par,plane,$plane \
                 } result] {
            return -code error "APSMpMeasureP0FBTune13: $result"
        }
        APSAddToTempFileList $tmpRoot.$plane
    }
    APSAddToTempFileList $tmpRoot.tune.1 
    APSAddToTempFileList $tmpRoot.tune.2
    
    catch {exec rm $tmpRoot.tune}
    if [catch {exec sddscombine $tmpRoot.x $tmpRoot.y -over $tmpRoot.tune} result] {
        return -code error "APSMpMeasureP0FBTune14: $result"
    }
    if [string length $outputFile] {
        if [catch {exec sddscombine $tmpRoot.x $tmpRoot.y -over $outputFile} result] {
            return -code error "APSMpMeasureP0FBTune15: $result"
        }
    }
   
    #APSAddToTempFileList $tmpRoot.tune
    set xTune [lindex [exec sdds2stream -par=xTune $tmpRoot.tune] 0]
    set yTune [lindex [exec sdds2stream -par=yTune $tmpRoot.tune] 0]
    set xPeak [lindex [exec sdds2stream -par=xTunePeak $tmpRoot.tune] 0]
    set yPeak [lindex [exec sdds2stream -par=yTunePeak $tmpRoot.tune] 0]
    
    if $plot {
        exec sddsplot -grap=line,vary -split=page  -col=Tune,SR:TUNE1 -filter=col,Tune,$tuneRangeLow,0.4 -topline=@TuneLabel -title=@BeamParamLabel $tmpRoot.tune &
        after 2000
    }
    if {$system=="P0"} {
        if {$DCCT<50 || $xGain<5 || $yGain<5} {
            set xTune 0
            set yTune 0
        }
    }
    if $update {
        #for TFB system still use P0FB pv holders for logging
        switch $system {
            P0 {
                set prefix0 S:P0FB
                set tunePrefix FB
            } 
            TFB {
                set prefix0 S:TFB:M
                set tunePrefix TFB
            }
        }
        if [catch {exec cavput -pend=20 -list=SR:TUNE:${tunePrefix}:XtuneAI=$xTune,SR:TUNE:${tunePrefix}:YtuneAI=$yTune,SR:TUNE:${tunePrefix}:XtunePeakAI=$xPeak,SR:TUNE:${tunePrefix}:YtunePeakAI=$yPeak,${prefix0}:WFAveX=$w0ave,${prefix0}:WFAveY=$w1ave,${prefix0}:gainAveX=$xGain,${prefix0}:gainAveY=$yGain,${prefix0}:InputWFSpreadX=$w0spread,${prefix0}:InputWFSpreadY=$w1spread,${prefix0}:OutputWFSpreadX=$w2spread,${prefix0}:OutputWFSpreadY=$w3spread} result] {
            return -code error "APSMpMeasureP0FBTune16: error in set x/y tune: $result"
        }
        #add P0 first bucket location
        if [catch {APSGetFBbunchPatternParameters -system $system} startBucket] {
            # return -code error "APSMpMeasureP0FBTune17a: error getting the start bucket: $startBucket"q
            #ignore the error
        } else {
            if [catch {exec cavput -list=${prefix0}:StartBucketLO=$startBucket -pend=10} result] {
                return -code error "APSMpMeasureP0FBTune17: error setting P0 first bucket location: $result"
            }
        }
    }
    if [string length $statusCallback] {
        eval $statusCallback {"[clock format [clock seconds] -format %H:%M:%S]: done."}
    }
    return 0
}

proc APSGetFBbunchPatternParameters {args} {
    #return start bucket
    set system TFB
    set filename ""
    APSStrictParseArguments {system filename}
    switch $system {
        P0 {
            set prefix S:P0FB:
        }
        TFB {
            set prefix S:TFB:M:
        }
        default {
            return -code error "Invalid system - $system provided"
        }
    }
    set tmpRoot /tmp/[APSTmpString]
    if ![string length $filename] {
        set tmpRoot /tmp/[APSTmpString]
        set filename $tmpRoot.1
        if [catch {exec sddswget -pv=${prefix}AcqControlGetWF $filename } result] {
            return -code error "Error reading ${prefix}AcqControlGetWF : $result"
        }
    }
    if [catch {exec sddsprocess $filename -pipe=out "-redefine=col,Waveform,Waveform,type=long" \
                 -nowarnings \
                 | sddsbinarystring -pipe -col=Waveform \
                 | sddsprocess -pipe -edit=col,Bits,WaveformBinaryString,27d -nowarnings \
                 -edit=col,HPBit,Bits,1f4d \
                 -edit=col,IPBit,Bits,1d1f3d \
                 -edit=col,Bit2,Bits,2d1f2d \
                 -edit=col,Bit1,Bits,3d1f1d \
                 -edit=col,Bit0,Bits,4d \
                 | sddsprocess -pipe \
                 -scan=col,IBit2,Bit2,%ld,type=long \
                 -scan=col,IBit1,Bit1,%ld,type=long \
                 -scan=col,IBit0,Bit0,%ld,type=long \
                 -scan=col,HighPassFilter,HPBit,%ld,type=long \
                 -scan=col,InputProcess,IPBit,%ld,type=long \
                 "-define=col,OutputMode,IBit0 IBit1 2 * + IBit2 4 * +,type=long" -nowarnings\
                 | tee $filename.proc \
                 | sddsprocess -pipe -filter=col,Index,1050,1296" \
                 | sddsprocess -pipe "-define=col,PosDiff,Index 1050 -,type=long" \
                 | sddsprocess -pipe=in $tmpRoot.$system -filter=col,InputProcess,0.5,1.5 \
                 -process=PosDiff,min,StartPos,functionOf=Index,pos -nowarnings \
                 -process=Index,first,Offset \
                 -process=Index,last,lastSample \
                 -nowarnings \
                 -define=par,Counts,n_rows,type=long } result] {
      #    puts "Error in reading and processing P0 waveform: $result"
	return -code error "Error in reading and processing P0 waveform: $result"
    }
    APSAddToTmpFileList -ID p0feedback -fileList  "$tmpRoot.$system $tmpRoot.1 $tmpRoot.2"
    
    global multiplets multipletSpacing multipletStart multipletOffset special324
    set counts [exec sdds2stream -par=Counts $tmpRoot.$system]
    if $counts==0 {
        #no input signal found.
        set multipletOffset 1050
        set multipletStart 1050 
        set lastSample 1296
    } else {
        set multipletOffset [format %.0f [exec sdds2stream -par=Offset $tmpRoot.$system]]
        set multipletStart [format %.0f [exec sdds2stream -par=StartPos $tmpRoot.$system]]
        set lastSample [format %.0f [exec sdds2stream -par=lastSample $tmpRoot.$system]]
    }
    #lower 3 bits, 001, 010 -- is the sample pattern
    if [catch {exec sddsprocess $filename.proc -filter=col,OutputMode,1,2 -pipe=out -nowarnings \
                 | sddsprocess -pipe=in $tmpRoot.2 -define=par,Counts,n_rows,type=long} result] {
        return -code error "Error processing sample patterns: $result"
    }
    set multiplets [exec sdds2stream -par=Counts $tmpRoot.2]
    if $multiplets==0 {
        set multiplets 24
    } 
    set multipletSpacing  [expr 1296/$multiplets]
    if {$multiplets==48} {
        set spacing 54
    } elseif {$multiplets>27} {
        set spacing 27
    } else {
        set spacing $multipletSpacing
    }
    if {$multiplets==324 && [expr $lastSample-$multipletStart]<=[expr 27*4]} {
        set special324 1
    }
    #puts "$multipletOffset offset"
    
    # puts "offset $multipletOffset; spacing: $spacing; start: $multipletStart"
    return $multipletStart
}
