#
# $Log: not supported by cvs2svn $
# Revision 1.31  2008/02/07 21:26:38  emery
# Changed /tmp to /local because /tmp gets periodically cleaned.
#
# Revision 1.30  2008/02/07 18:13:11  emery
# Make copy of input files of SRBunchCurrent.tcl to a /tmp/sddsmonitorFiles
# directory, which is created if needed.
#
# Revision 1.29  2006/09/08 16:39:52  soliday
# Added missing close quotes to line 336
#
# Revision 1.28  2006/02/28 20:59:01  emery
# Added hint in error message of <prefix>DataReadSQ.SCAN readback value.
#
# Revision 1.27  2006/02/06 15:45:27  emery
# Changed a comment which explains the data type of the ADC file.
#
# Revision 1.26  2005/12/21 23:28:08  emery
# Corrected a parameter mixup in sddsprocess in last version
#
# Revision 1.25  2005/12/21 23:19:20  emery
# Added option baselineCorrection to APSSRReadBunchCM for not
# trying to determine the baseline from the data
# and use a hard-coded -27. This is necessary for
# 1296 bunch pattern, and probably for 324 bunch
# pattern as well.
#
# Revision 1.24  2003/08/26 18:31:25  emery
# Corrected PV prefix for ADC #2 (Should be A750:2, not ADC750:2)
#
# Revision 1.23  2003/08/26 17:45:56  emery
# Added option of selecting ADC750 #2 for bunch by bunch monitor.
#
# Revision 1.22  2002/03/06 05:34:21  emery
# Aded numbers for each error message in APSSRMakeTargetFillPattern
#
# Revision 1.21  2001/11/15 22:28:47  borland
# Added -noScalars and -S35DCCT options so that caller may pass the beam current.
# This saves making connections to the S35DCCT:currentCC PV, which is sometimes
# a cause of problems.
#
# Revision 1.20  2001/11/14 22:06:09  borland
# *** empty log message ***
#
# Revision 1.19  2001/07/06 21:43:01  borland
# APSSRReadBunchCM now keeps all the parameter data that is in the sddswmonitor
# scalars file.
#
# Revision 1.18  2001/07/06 21:21:03  borland
# APSSRReadBunchCM now timestamps the data file.
#
# Revision 1.17  2001/07/06 19:41:15  borland
# APSSRReadBunchCM now reads the bucket number that was just injected into.
#
# Revision 1.16  2001/03/16 21:45:10  emery
# Added distinctive diagnostic message to possible place where
# CA errors occur.
#
# Revision 1.15  2001/02/13 23:33:46  borland
# Fixed problems with previous changes.
#
# Revision 1.14  2001/02/13 23:26:31  borland
# Added useFillPattern option to APSSRReadBunchCM.  If set, then the BBCM waveform
# is multiplied by the fill pattern waveform to provide a more accurate record
# of the bnuch pattern.
#
# Revision 1.13  2001/02/12 22:36:19  borland
# APSSRReadBunchCM no longer bombs on divide-by-zero if there is no beam.
#
# Revision 1.12  2001/02/06 19:44:26  soliday
# Fixed some tcl warning messages found with procheck
#
# Revision 1.11  2000/02/15 05:46:17  emery
# Added APSSRReadBunchCMTurnByTurn procedure.
#
# Revision 1.10  1999/11/30 21:05:48  emery
# Added argument BPMGroupMode to APSSRMakeTargetFillPattern.
# Allows target pattern for simple bunch train that uses buckets 0 to 5.
#
# Revision 1.9  1998/11/17 02:12:25  emery
# commented out the cawait command in APSSRReadBunchCM which
# waited for the "Fine Tune" status result.
#
# Revision 1.8  1998/08/25 03:55:03  emery
# Removing the bunch 0 scan (BNCHI:SetTimingBO)
# on the advice of F. Lenkszuz.
#
# Revision 1.7  1998/08/02 16:35:54  borland
# Increased cavput/cavget timeouts.
#
# Revision 1.6  1998/08/01 21:48:45  borland
# Now does a bunch 0 scan and waits for it to complete.
#
# Revision 1.5  1998/03/24 12:01:16  emery
# changed PV Mt:S:FillPatternWF.VAL to Mt:S:FillPatternWF
# because sddswmonitor was appending .NORD to the original
# name which gave an error.
#
# Revision 1.4  1998/03/21 20:16:28  borland
# Modified APSSRReadBunchCM to accept the name of a file containing the
# target pattern.  If given, it computes the deficit per bucket and also
# finds the bucket with the maximum deficit.
#
# Revision 1.3  1998/03/21 20:08:12  borland
# Modified APSSRMakeTargetFillPattern so that it gives 1296 rows, with zeros
# where there is not beam wanted.
#
# Revision 1.2  1998/03/21 19:47:46  borland
# Modified APSSRGetTargetFillPattern so that it gives a pattern that maintains
# the defined level in the BPM group.  The remainder of the target current is
# put in the multiplets.
#
# Revision 1.1  1998/03/21 19:19:05  borland
# First version.
#
# 

proc APSSRReadBunchCM {args} {
    # Reads the bunch-by-bunch current monitor and produces a file
    # giving the calibrated current in each bunch.  Optionally averages
    # several waveforms.  Does its own baseline subtraction and
    # calibration vs the DCCT.
    # Doesn't do any setup of the BBB current monitor.

    set output ""
    set average 1
    set targetFile ""
    set timeLimit 20
    set noScalars 0
    set useFillPattern 1
    set S35DCCT ""
    set ADCunit 1
    set baselineCorrection 1

    set monitorFilesDir /home/helios/oagData/sr/sddsmonitorFiles
    # To avoid using network file system, one can use the directory below
    # with files copied from above directory
    set monitorFilesDir /local/sddsmonitorFiles
    if ![file exists /local/sddsmonitorFiles] {
        exec mkdir /local/sddsmonitorFiles
        exec chmod a+rwx /local/sddsmonitorFiles
        set fileList {BunchCM.scalars}
        foreach file $fileList {
            exec cp /home/helios/oagData/sr/sddsmonitorFiles/$file /local/sddsmonitorFiles/$file
        }
    }
    set clockSecs [clock seconds]
    if {[APSStrictParseArguments {output average targetFile useFillPattern \
                                    noScalars S35DCCT ADCunit baselineCorrection}] || \
          ![string length $output] || $average<=0} {
        return -code error "APSSRReadBunchCM: bad arguments"
    }
    switch $ADCunit {
        1 { 
            set PVPrefix BNCHI:
            set WaveformPV ADC750:DataWF
        }
        2 {
            set PVPrefix ADC:2:
            set WaveformPV ADC750:2:DataWF
        }
        default {return -code error "APSSRReadBunchCMTurnByTurn: bad ADCunit value"}
    }
    
    if {$noScalars && (![string length $S35DCCT] || $S35DCCT<=0)} {
        return -code error "APSSRReadBunchCM: you must supply S35DCCT argument if you specify no scalars"
    }
    #    if [catch {exec cavput -list=${PVPrefix}SetTimingBO=1 -pend=10} result] {
    #        return -code error "APSSRReadBunchCM: $result"
    #    }
    if [catch {APScavget -list=${PVPrefix}DataReadSQ.SCAN -pend=10 } intervalData] {
        return -code error "APSSRReadBunchCM: $intervalData"
    }
    if [scan [string trim $intervalData \"] "%lf" interval]==0 {
        return -code error "APSSRReadBunchCM: scan rate not understood: $intervalData.\nCheck value of BNCHI:waveFormScanMO"
    }
    set tmpFile /tmp/[APSTmpString]
    #    if [catch {exec cawait -waitfor=${PVPrefix}StatusMI.VAL,equal=7 -timeLimit=$timeLimit } result] {
    #        return -code error "APSSRReadBunchCM: $result"
    #    }
    set scalarsArg ""
    if !$noScalars {
        # that is, with scalars
        set scalarsArg -scalars=$monitorFilesDir/BunchCM.scalars 
    }
    
    if [catch {eval exec sddswmonitor -PVnames=$WaveformPV,Mt:S:FillPatternWF \
                 $scalarsArg -step=$average -interval=$interval $tmpFile} result] {
        return -code error "APSSRReadBunchCM: (sddswmonitor) $result"
    }
    if [string length $targetFile] {
        set output1 $tmpFile.1
    } else {
        set output1 $output
    }
    if $useFillPattern {
        set factorName Mt:S:FillPatternWFMean
    } else {
        set factorName 1
    }
    if !$noScalars {
        # with scalars
        set paramList [APSGetSDDSColumn -column ReadbackName -fileName \
                         $monitorFilesDir/BunchCM.scalars]
        set unitsList [APSGetSDDSColumn -column ReadbackUnits -fileName \
                         $monitorFilesDir/BunchCM.scalars]
        foreach param $paramList units $unitsList {
            lappend opt1List -define=column,${param}1,$param,units=$units
            lappend opt2List -process=${param}1Mean,first,${param}Mean
            lappend joinList ${param}1
        }
    } else {
        # no scalars
        set opt1List -define=column,S35DCCT1,$S35DCCT,units=mA
        set opt2List -process=S35DCCT1Mean,first,S35DCCTMean
        set joinList S35DCCT1
    }
    if $baselineCorrection {
        if !$useFillPattern {
            # removes data that is within +5 units from baseline
            # perhaps we need to determine the double band baseline and
            # subtract it.
            if [catch \
                  {eval exec sddsprocess $tmpFile -pipe=out $opt1List \
                     | sddsenvelope -pipe -copy=Index -nowarning \
                     -mean=[join [concat $joinList [list $WaveformPV Mt:S:FillPatternWF]] ,] \
                     | sddsprocess -pipe $opt2List \
                     -process=${WaveformPV}Mean,base,%sBase \
                     \"-define=column,AdjustedWF,${WaveformPV}Mean ${WaveformPV}MeanBase - 5 > ? pop : 0 $ $factorName * \" \
                     -process=AdjustedWF,sum,%sSum \
                     \"-define=parameter,BCMCalibration,AdjustedWFSum 0 == ? 0 : S35DCCTMean AdjustedWFSum / $ \" \
                     \"-define=column,BunchCurrent,AdjustedWF BCMCalibration *,units=mA\" \
                     -define=parameter,FillPatternApplied,$useFillPattern,type=long \
                     \"-define=parameter,Time,$clockSecs,units=s\" \
                     \"-print=parameter,TimeStamp,[clock format $clockSecs]\" \
                     | sddsconvert -pipe=in $output1 \
                     -rename=column,Index=Bucket \
                     -delete=column,*1Mean,AdjustedWF,${WaveformPV}Mean } result] {
                return -code error "APSSRReadBunchCM: $result"
            }
        } else {
            # use fill pattern
            if [catch \
                  {eval exec sddsprocess $tmpFile -pipe=out $opt1List \
                     | sddsenvelope -pipe -copy=Index -nowarning  \
                     -mean=[join [concat $joinList [list $WaveformPV Mt:S:FillPatternWF]] ,] \
                     | sddsprocess -pipe=in $tmpFile.env  $opt2List 

                      exec sddsprocess $tmpFile.env -pipe=out \
                     "-redef=col,WaveformShifted,i_row 1 - 0 < pop ? 1295 : \$ &Mt:S:FillPatternWFMean \[,type=long" \
                     | sddsprocess -pipe=in $tmpFile.proc \
                     "-redef=col,NewWaveform,Mt:S:FillPatternWFMean WaveformShifted +,type=long"


                      eval exec sddsprocess  $tmpFile.proc $tmpFile.empty \
                     -filter=col,NewWaveform,0,0 \
                     \"-def=col,IsOdd,Index 2 mod \" \
                     \"-def=col,IsEven,Index 1 + 2 mod \" \
                     \"-def=col,BaselineOddBucketsWF,${WaveformPV}Mean IsOdd * \" \
                     \"-def=col,BaselineEvenBucketsWF,${WaveformPV}Mean IsEven * \" \
                     -proc=BaselineOddBucketsWF,sum,BaselineOddBucketsWF \
                     -proc=BaselineEvenBucketsWF,sum,BaselineEvenBucketsWF \
                     -proc=IsOdd,sum,OddEmptyBuckets \
                     -proc=IsEven,sum,EvenEmptyBuckets \
                     \"-def=para,${WaveformPV}OddBase,BaselineOddBucketsWF OddEmptyBuckets  / \" \
                     \"-def=para,${WaveformPV}EvenBase,BaselineEvenBucketsWF EvenEmptyBuckets  / \" 

                      set results [exec sdds2stream -para=${WaveformPV}OddBase,${WaveformPV}EvenBase $tmpFile.empty]
                      foreach {oddBase evenBase} $results {}              

                      exec sddsprocess $tmpFile.env -pipe=out \
                     "-def=col,IsOdd,Index 2 mod " \
                     "-def=col,IsEven,Index 1 + 2 mod "  \
                     "-def=col,Baseline,IsOdd 1 == pop pop ? $oddBase : $evenBase \$" \
                     "-def=col,AdjustedWF,${WaveformPV}Mean Baseline -" \
                      -process=AdjustedWF,sum,%sSum,weight=Mt:S:FillPatternWFMean \
                     "-define=parameter,BCMCalibration,AdjustedWFSum 0 == ? 0 : S35DCCTMean AdjustedWFSum / \$ " \
                     "-redefine=column,AdjustedWF,AdjustedWF Mt:S:FillPatternWFMean * " \
                     "-define=column,BunchCurrent,AdjustedWF BCMCalibration *,units=mA" \
                     -define=parameter,FillPatternApplied,$useFillPattern,type=long \
                     "-define=parameter,Time,$clockSecs,units=s" \
                     "-print=parameter,TimeStamp,[clock format $clockSecs]" \
                     | sddsconvert -pipe=in $tmpFile.adj \
                     -rename=column,Index=Bucket 

                      exec sddsmakedataset /tmp/response.part1 \
                     -col=Waveform,type=double -data=1,-0.07 \
                     -col=Bucket,type=long -data=0,1
                      #exec chmod 666 /tmp/response.part1
                      exec sddssequence /tmp/response.part2 \
                     -def=Bucket,type=long \
                     -sequence=beg=2,end=1295,delta=1
                      #exec chmod 666 /tmp/response.part2

                      exec sddscombine /tmp/response.part1 /tmp/response.part2 /tmp/response -merge -overWrite 
                      file delete -force /tmp/response.part1 /tmp/response.part2
                      #exec chmod 666 /tmp/response

                      exec sddsconvolve $tmpFile.adj  /tmp/response $tmpFile.adj2 \
                     -signal=Bucket,AdjustedWF \
                     -response=Bucket,Waveform \
                     -output=Bucket,Waveform \
                     -deconvolve
                      file delete -force /tmp/response
                      # do some normalizin'
                      exec sddsprocess $tmpFile.adj2 -pipe=out \
                     | sddsxref -pipe $tmpFile.env \
                     -take=Mt:S:FillPatternWFMean \
                     | sddsprocess -pipe=in $output1 \
                     -process=Waveform,sum,%sSum,weight=Mt:S:FillPatternWFMean \
                     "-redefine=parameter,BCMCalibration,WaveformSum 0 == ? 0 : S35DCCTMean WaveformSum / \$ " \
                     "-redefine=column,Waveform,Waveform Mt:S:FillPatternWFMean * " \
                     "-redefine=column,BunchCurrent,Waveform BCMCalibration *,units=mA" \
                     -redefine=parameter,FillPatternApplied,$useFillPattern,type=long \
                     "-redefine=parameter,Time,$clockSecs,units=s" \
                     "-reprint=parameter,TimeStamp,[clock format $clockSecs]" 
                  } result] {
                return -code error "APSSRReadBunchCM: $result"
            }
        }
    } else {
        # this would be used for 1296 fills
        # assume -27 as baseline, and no removal of bucket data
        if [catch \
              {eval exec sddsprocess $tmpFile -pipe=out $opt1List \
                 | sddsenvelope -pipe -copy=Index -nowarning \
                 -mean=[join [concat $joinList [list $WaveformPV Mt:S:FillPatternWF]] ,] \
                 | sddsprocess -pipe $opt2List \
                 -define=para,${WaveformPV}MeanBase,-27 \
                 \"-define=column,AdjustedWF,${WaveformPV}Mean ${WaveformPV}MeanBase - $factorName * \" \
                 -process=AdjustedWF,sum,%sSum \
                 {"-define=parameter,BCMCalibration,AdjustedWFSum 0 == ? 0 : S35DCCTMean AdjustedWFSum / $ "} \
                 {"-define=column,BunchCurrent,AdjustedWF BCMCalibration *,units=mA"} \
                 -define=parameter,FillPatternApplied,$useFillPattern,type=long \
                 {"-define=parameter,Time,$clockSecs,units=s"} \
                 {"-print=parameter,TimeStamp,[clock format $clockSecs]"} \
                 | sddsconvert -pipe=in $output1 \
                 -rename=column,Index=Bucket \
                 -delete=column,*1Mean,AdjustedWF,${WaveformPV}Mean } result] {
            return -code error "APSSRReadBunchCM: $result"
        }
    }
    if [string length $targetFile] {
        if [catch {exec sddsxref $output1 $targetFile -pipe=out \
                     -take=TargetCurrent \
                     | sddsprocess -pipe=in $output \
                     "-define=column,CurrentDeficit,TargetCurrent BunchCurrent -,units=mA" \
                     "-process=CurrentDeficit,max,CurrentDeficitMax" \
                     "-process=CurrentDeficit,max,CurrentDeficitMaxBucket,position,func=Bucket" \
                 } result] {
            return -code error "APSSRReadBunchCM: $result"
        }
       # catch {eval file delete $tmpFile $tmpFile.1}
    } 
    set files [glob ${tmpFile}*]
    catch {eval file delete -force $files}
}


proc APSSRMakeTargetFillPattern {args} {
    # Reads the fill pattern current in the machine and produces a file
    # giving the target fill pattern.  The target fill pattern is based on
    # maintaining the same current as presently in the machine (or a
    # defined level) plus a defined current in the BPM group.

    set output ""
    # These variables define the *intended* bunch pattern, including the
    # ratio of current in the BPM group to the current in the other bunches.
    set BPMGroupLength 6
    set BPMGroupCurrent 10
    set BPMGroupMode First
    # Optionally define how much current to define as the target.
    # By default, uses what's in the machine now.
    set targetCurrent 0

    if {[APSStrictParseArguments {output BPMGroupMode BPMGroupLength \
                                    BPMGroupCurrent targetCurrent}] || \
          ![string length $BPMGroupMode] || ![string length $output] || \
          $BPMGroupLength<1 || $BPMGroupCurrent<=0 || \
          $targetCurrent<0} {
        return -code error "APSSRMakeTargetFillPattern(0): bad arguments"
    }
    if {$targetCurrent<=0} {
        # read the DCCT 10 times to get a stable averaged value
        if [catch {exec cavget -list=S-DCCT:CurrentM -repeat=number=10,pause=0.5,average} \
              targetCurrent] {
            return -code error "APSSRMakeTargetFillPattern(1): $targetCurrent"
        }
    }
    set tmpFile /tmp/[APSTmpString]
    if [catch {exec sddswmonitor -PVnames=Mt:S:FillPatternWF -step=1 \
                 $tmpFile} result] {
        return -code error "APSSRMakeTargetFillPattern(2): $result"
    }
    if ![string compare $BPMGroupMode None] {
        # make bunch pattern for pure multiplet pattern.
        # all bunches should have the same charge.
        if [catch \
              {exec sddsprocess $tmpFile -pipe=out \
                 "-define=parameter,targetCurrent,$targetCurrent,units=mA" \
                 "-process=Mt:S:FillPatternWF,sum,BunchCount" \
                 "-define=parameter,MLevel,targetCurrent BunchCount /,units=mA" \
                 "-define=column,TargetCurrent,MLevel Mt:S:FillPatternWF *,units=mA" \
                 | sddsconvert -pipe=in $output \
                 -rename=column,Index=Bucket \
                 -retain=column,Bucket,TargetCurrent,Index} result] {
            return -code error "APSSRMakeTargetFillPattern(3): $result"
        }
    } else {
        # BG means bunch group. InBG has value 1 if the bucket in is the bunch group.
        if [catch \
              {exec sddsprocess $tmpFile -pipe=out \
                 "-define=column,InBG,Index $BPMGroupLength < ? 1 : 0 $ ,type=short" \
                 "-define=parameter,targetCurrent,$targetCurrent,units=mA" \
                 "-process=Mt:S:FillPatternWF,sum,BunchCount" \
                 "-define=parameter,BGLevel,$BPMGroupCurrent $BPMGroupLength /,units=mA" \
                 "-define=parameter,MLevel,targetCurrent $BPMGroupCurrent - BunchCount $BPMGroupLength - /,units=mA" \
                 "-define=column,TargetCurrent,InBG 1 == ? BGLevel : MLevel $ Mt:S:FillPatternWF *,units=mA" \
                 | sddsconvert -pipe=in $output \
                 -rename=column,Index=Bucket \
                 -retain=column,Bucket,TargetCurrent,Index} result] {
            return -code error "APSSRMakeTargetFillPattern(4): $result"
        }
    }
    catch {file delete $tmpFile}
}

proc APSSRReadBunchCMTurnByTurn {args} {
    # Reads the bunch-by-bunch current monitor in a turn-by-turn mode
    # and produces a file with 64k raw data points of type char.
    # The data is not calibrated.
    # Doesn't do any setup of the BBB current monitor.

    set output ""
    set ADCunit 1

    if {[APSStrictParseArguments {output ADCunit}] || ![string length $output]} {
        return -code error "APSSRReadBunchCMTurnByTurn: bad arguments"
    }
    switch $ADCunit {
        1 {set PVPrefix BNCHI:}
        2 {set PVPrefix A750:2:}
        default {return -code error "APSSRReadBunchCMTurnByTurn: bad ADCunit value"}
    }

    set file turnData[clock format [clock seconds] -format "%Y-%m%d-%H%M%S"].raw
    if [catch {exec cavput -list=$PVPrefix -list=GetTurnByTurnBO=1,TurnByTurnFilePathSI=/home/helios4/scopetmp,TurnByTurnFileNameSI=$file \
             } result] {
        return -code error "APSSRReadBunchCMTurnByTurn:$result"
    }
    # give a chance for the PV to update.
    after 1000
    if [catch {exec cavput -list=$PVPrefix -list=TurnByTurnWriteFileBO=1  \
             } result] {
        return -code error "APSSRReadBunchCMTurnByTurn:$result"
    }
    # give a chance for the file system to update.
    after 2000
    if [catch {file copy [file join /home helios4 scopetmp $file] $output \
             } result] {
        return -code error "APSSRReadBunchCMTurnByTurn:$result"
    }
}
