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



set auto_path [linsert $auto_path 0  /usr/local/oag/apps/lib/$env(HOST_ARCH)]
set auto_path [linsert $auto_path 0 /usr/local/oag/lib_patch/$env(HOST_ARCH)]
APSDebugPath
set CVSRevisionAuthor "\$Revision: 1.7 $ \$Author: soliday $"

APSApplication . -name SREnergyApertureScan -version $CVSRevisionAuthor

set status Ready.
APSScrolledStatus .status -parent .userFrame -textVariable status -width 80 -height 8

set IDNumber 1
set RunIndex 0
set LowerDeltaLimit -2000
set UpperDeltaLimit 2000
set LowerDeltaStart -500
set UpperDeltaStart 500
set tcl_precision 16
set CenterFrequency 351926761
set DeltaFrequency 100
set outputDirectory [pwd]
set TimeToWait 60
set doPlus 1
set doMinus 1
set numInGroup 6

APSLabeledEntry .dir -parent .userFrame -label "Directory: " \
    -textVariable outputDirectory -width 70 -contextHelp  \
    "Directory in which to put data files."
APSButton .daily -parent .userFrame -packOption "-side top -anchor w" \
   -text "Go to daily directory" \
   -command {set outputDirectory [APSGoToDailyDirectory -subdirectory energyAperture]} \
   -contextHelp "Setting daily directory in which to put data files."
APSLabeledEntry .index -parent .userFrame -label "Index: " -textVariable RunIndex -width 10 \
    -numberButtons 1 -contextHelp \
    "The index of the run.  The file rootname will be freqScan-<Index> ."

APSLabeledEntry .centerFreq -parent .userFrame -label "Center frequency (Hz): " \
    -textVariable CenterFrequency -width 10 -contextHelp \
    "The center frequency for the scan.  By default, set to the nominal rf frequency."
APSLabeledEntry .lowerLimit -parent .userFrame -label "Lower Delta Limit (Hz): " \
    -textVariable LowerDeltaLimit -width 10 -contextHelp \
    "Lower delta frequency value for the scan.  The lowest rf frequency used will be the center frequency plus this number."
APSLabeledEntry .upperLimit -parent .userFrame -label "Upper Delta Limit (Hz): " \
    -textVariable UpperDeltaLimit -width 10 -contextHelp \
    "Upper delta frequency value for the scan. The highest rf frequency used will be the center frequency plus this number."
APSLabeledEntry .lowerStart -parent .userFrame -label "Lower Delta Start (Hz): " \
    -textVariable LowerDeltaStart -width 10 -contextHelp \
    "Starting delta frequency value for the lower-side scan."
APSLabeledEntry .upperStart -parent .userFrame -label "Upper Delta Start (Hz): " \
    -textVariable UpperDeltaStart -width 10 -contextHelp \
    "Starting delta frequency value for the upper-side scan."
APSLabeledEntry .deltaFreq -parent .userFrame -label "Delta Frequency (Hz): " \
  -textVariable DeltaFrequency -width 10 -contextHelp \
  "Frequency step to use in moving toward the frequency limits." 
APSLabeledEntry .timeToWait -parent .userFrame -label "Time to wait (s): " \
  -textVariable TimeToWait -width 10 -contextHelp \
  "Time to wait for data collection at each frequency."
APSCheckButtonFrame .pmcheck -parent .userFrame -label "Sweeps to do: " \
    -buttonList {Upper Lower} -variableList {doPlus doMinus} \
    -orientation horizontal -allNone 1 -contextHelp \
    "Choose whether to do positive/upper and negative/lower sides of the sweep"
APSLabeledEntry .numInGroup -parent .userFrame -label "Number in group: " \
    -textVariable numInGroup -width 10 -contextHelp \
    "Number of bunches to but in the BPM group."

APSButton .run -parent .userFrame -text Run -command \
  {RunEnergyApertureScan -index $RunIndex -outputDir $outputDirectory \
     -lowerLimit $LowerDeltaLimit -upperLimit $UpperDeltaLimit \
     -lowerStart $LowerDeltaStart -upperStart $UpperDeltaStart \
     -centerFrequency $CenterFrequency -freqSpacing $DeltaFrequency \
     -timeToWait $TimeToWait -doPlus $doPlus -doMinus $doMinus \
     -numInGroup $numInGroup \
     -statusCallback "APSSetVarAndUpdate status"; bell ; bell } 
set abortEnergyApertureScan 0
APSButton .abort -parent .userFrame -text Abort -command \
  {APSSetVarAndUpdate status "Aborting..."; set abortEnergyApertureScan 1}

proc RunEnergyApertureScan {args} {
    set index 0
    set statusCallback APSNoOp
    set outputDir ""
    set lowerLimit -1500
    set upperLimit 1500
    set freqSpacing 100
    set centerFrequency 351927036
    set timeToWait 120
    set doPlus 1
    set doMinus 1
    set lowerStart 0
    set upperStart 0
    set numInGroup 6
    set abortVariable ""
    APSStrictParseArguments {index statusCallback outputDir lowerLimit upperLimit \
                               timeToWait centerFrequency freqSpacing \
                               doPlus doMinus lowerStart upperStart numInGroup \
                               abortVariable}

    if [string length $abortVariable] {
        global $abortVariable
        set $abortVariable 0
    }

    scan $index "%ld" index
    set index [format "%02ld" $index]
    set outputRoot $outputDir/freqScan-$index

    if {[catch {exec cavget -list=S:RC:OrbitControlLawXC,S:RC:OrbitControlLawYC -list=.SUSP -cavputForm} orbitControllawMode0] || \
          [catch {exec cavput -list=S:RC:OrbitControlLawXC,S:RC:OrbitControlLawYC -list=.SUSP=Suspend} result]} {
        return -code error "$orbitControllawMode$result"
    }

    if {![file exists $outputRoot.m.scalars.gz] || ![file exists $outputRoot.p.scalars.gz] || \
        ![file exists $outputRoot.m.orbit.gz] || ![file exists $outputRoot.p.orbit.gz]} {
        set tmpRoot /tmp/[APSTmpString]

        if {$doMinus && \
            (![file exists $outputRoot.m.scalars.gz] || \
                ![file exists $outputRoot.m.orbit.gz]) && \
              [catch {MakeSweep -changeLimit $lowerLimit -freqSpacing $freqSpacing \
                        -centerFrequency $centerFrequency -offset $lowerStart \
                        -timeToWait $timeToWait -numInGroup $numInGroup\
                        -abortVariable $abortVariable \
                        -outputRoot $outputRoot.m -statusCallback $statusCallback} result]} {
            eval $statusCallback {"$result"}
            catch {exec cavput -list=$orbitControllawMode0}
            return -code error $result
        }

        if [string length $abortVariable] {
            if [subst \$$abortVariable] {
                set doPlus 0
            }
        }

        if {$doPlus && \
            (![file exists $outputRoot.p.scalars.gz] || \
                ![file exists $outputRoot.p.orbit.gz]) && \
              [catch {MakeSweep -changeLimit $upperLimit -freqSpacing $freqSpacing \
                        -centerFrequency $centerFrequency -offset $upperStart \
                        -timeToWait $timeToWait -numInGroup $numInGroup \
                        -abortVariable $abortVariable \
                        -outputRoot $outputRoot.p -statusCallback $statusCallback} result]} {
            eval $statusCallback {"$result"}
            catch {exec cavput -list=$orbitControllawMode0}
            return -code error $result
        }
        eval $statusCallback {"Measurement done."}
    } else {
        eval $statusCallback {"Data already exists with that name."}
    }
    catch {exec cavput -list=$orbitControllawMode0}
}

proc MakeSweep {args} {
    set changeLimit 0
    set outputRoot ""
    set current 10
    set statusCallback APSNoOp
    set centerFrequency 351927036
    set freqSpacing 100
    set offset 0
    set timeToWait 120
    set numInGroup 6
    set abortVariable ""
    APSStrictParseArguments {changeLimit outputRoot current statusCallback centerFrequency freqSpacing timeToWait offset numInGroup abortVariable}

    set tmpRoot /tmp/[APSTmpString]

    set inputDir /home/helios/oagData/sr/energyApertureScan/monitorInputs


    APSBunchTrainConnect
    if {[catch {exec cavget -list=S-DCCT:CurrentM} currentNow] || \
          $currentNow<$current} {
        eval $statusCallback {"Filling to $current mA"}
        TogglePulsedMagnetEnables -location GuntoBoosterExt
        if [catch {DoIOCBunchTrainInjection -start 0 -interval 100 -number 1 \
                     -stopAt $current -cycles 30 -multiplet $numInGroup \
                    -callback $statusCallback} result] {
            return -code error $result
        }
        SetPulsedMagnetEnables -state 0 -location All
    }
    global S35BeamCurrent

    eval $statusCallback {"Disabling thick septum pulsing."}
    if [catch {exec cavput -list=Mt:Ddg3chan0.GATE=Disabled} result] {
        return -code error $result
    }

    eval $statusCallback {"Starting slave orbit logging process."}
    set orbFID [open "|sddsvmonitor $inputDir/orbit.vmon -scalars=$inputDir/scalars.mon $outputRoot.orbit \
-erase -single=stdout -steps=1000 " r+]
    eval $statusCallback {"Starting asynchronous scalar monitor process."}
    set smPID [exec sddsmonitor $inputDir/scalars.mon $outputRoot.scalars -erase -precision=double \
                 "-comment=Comment,Scan to $centerFrequency+$changeLimit Hz with $freqSpacing steps" \
                 -interval=1,s -time=1,h &]
    if [catch {exec kill -STOP $smPID} result] {
        return -code error $result
    }

    if {($changeLimit>0 && $offset>$changeLimit) || \
          ($changeLimit<0 && $offset<$changeLimit)} {
        return -code error "Starting offset is beyond limit."
    }

    if $changeLimit<0 {
        set freqSpacing [expr -abs($freqSpacing)]
    } else {
        set freqSpacing [expr abs($freqSpacing)]
    }

    eval $statusCallback {"Ramping frequency to start."}
    set frequency [expr $centerFrequency+$offset]
    if [catch {APScaRamp -pvList A014-IETS:BTC:SRSetFreqM -endList $frequency -steps 10 -pause 0.5 \
                 -variableList frequency} result] {
        return -code error $result
    }

    eval $statusCallback {"Changing frequency while collecting data."}
    set index 0
    if [string length $abortVariable] {
        global $abortVariable
    }
    while {1} {
        if {[string length $abortVariable] && \
              ![subst \$$abortVariable]} {
            break
        }

        # start data collection
        if [catch {exec kill -CONT $smPID} result] {
            return -code error $result
        }
        eval $statusCallback {"Centering hpvec on revolution harmonic"}
        catch {exec hpSocketSend hpvecsr.aps4.anl.gov "FREQ:SPAN 100000 HZ"}
        after 1000
        catch {exec hpSocketSend hpvecsr.aps4.anl.gov "ABOR;*WAI"} 
        APSWaitWithUpdate -waitSeconds 5 -updateInterval 1
        catch {exec hpSocketSend hpvecsr.aps4.anl.gov PAUS}
        after 1000
        catch {exec hpSocketSend hpvecsr.aps4.anl.gov CALC1:MARK:MAX}
        after 1000
        catch {exec hpSocketSend hpvecsr.aps4.anl.gov "FREQ:CENT (CALC1:MARK:X?)"} result
        after 1000
        catch {exec hpSocketSend hpvecsr.aps4.anl.gov "FREQ:SPAN 10000 HZ"}
        update
        eval $statusCallback {"Triggering hpvec"}
        if [catch {exec hpSocketSend hpvecsr.aps4.anl.gov "ABOR;*WAI"} result] {
            return -code error $result
        }

        # check for no beam left
        if [pv getw S35BeamCurrent] {
            global errorCode
            return -code error $errorCode
        }
        eval $statusCallback {"$S35BeamCurrent mA left."}
        if {[expr $S35BeamCurrent<0.1]} {
            eval $statusCallback {"Insufficient current--stopping scan."}
            break
        }

        eval $statusCallback {"Taking data and waiting for averaging."}
        if [catch {APSMpSRMeasureTunes -outputFile $outputRoot.tune-[format %03ld $index] \
                     -lowerTune x -upperTune y -dividingLine 0.25 -useExistingData 0 \
                     -averagingSeconds $timeToWait -plotData 0} result] {
            eval $statusCallback {"$result"}
        }
        eval $statusCallback {"Taking synch tune data."}
        if [catch {exec hpSocketSend hpvecsr.aps4.anl.gov PAUS 
            after 1000
            exec hpVecTrace -hpvecsr a $outputRoot.stune-[format %03ld $index]} result] {
            return -code error $result
        }
        if ![file exists $outputRoot.stune-[format %03ld $index]] {
            eval $statusCallback {"Warning: file $outputRoot.stune-[format %03ld $index] was not created."}
        }

        eval $statusCallback {"Taking orbit data."}
        puts $orbFID y
        flush $orbFID

        # halt data collection for ramping
        if [catch {exec kill -STOP $smPID} result] {
            return -code error $result
        }

        # check for no beam left
        if [pv getw S35BeamCurrent] {
            global errorCode
            return -code error $errorCode
        }
        eval $statusCallback {"$S35BeamCurrent mA left."}
        if {[expr $S35BeamCurrent<0.1]} {
            eval $statusCallback {"Insufficient current--stopping scan."}
            break
        }

        set frequency0 [expr $frequency+$freqSpacing]
        incr offset $freqSpacing
        if {[expr abs($offset)>abs($changeLimit)]} {
            # don't go beyond frequency limits
            break
        }

        eval $statusCallback {"Ramping frequency to $frequency0."}
        eval $statusCallback {"Offset is $offset"}
        if [catch {APScaRamp -pvList A014-IETS:BTC:SRSetFreqM -endList $frequency0 -steps 10 -pause 0.5 \
                     -variableList frequency} result] {
            return -code error $result
        }
        after 1000
        set frequency $frequency0

        incr index
    }
    # resume data collection process
    if [catch {exec kill -CONT $smPID} result] {
        return -code error $result
    }

    eval $statusCallback {"Killing data collection processes."}
    puts $orbFID q
    flush $orbFID
    close $orbFID
    exec kill $smPID

    eval $statusCallback {"Enabling thick septum pulsing."}
    if [catch {exec cavput -list=Mt:Ddg3chan0.GATE=Enabled} result] {
        return -code error $result
    }

    eval $statusCallback {"Returning to center frequency."}
    if [catch {APScaRamp -pvList A014-IETS:BTC:SRSetFreqM -endList $centerFrequency -steps 60 -pause 0.5 \
                 -variableList frequency} result] {
        return -code error $result
    }

    catch {eval exec gzip $outputRoot.scalars $outputRoot.orbit}
    catch {eval exec gzip [glob $outputRoot.stune*]}
    catch {eval exec gzip [glob $outputRoot.tune*]}
    eval $statusCallback {"Sweep done."}
}

