#!/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

APSApplication . -name SREnergyApertureScan 

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

set IDNumber 1
set RunIndex 0
set LowerLimit 3600
set UpperLimit 4700
set DeltaVoltage 100
set outputDirectory [pwd]
set TimeToWait 120
# Though we no longer have an entry box for this variable, we still use it
# in calls.
set NumberInGroup 1
set TotalCurrent 0.0
set collectVSA 0

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 .lowerLimit -parent .userFrame -label "Lower Limit (kV): " \
    -textVariable LowerLimit -width 10 -contextHelp \
    "Lower voltage value for the scan."
APSLabeledEntry .upperLimit -parent .userFrame -label "Upper Limit (kV): " \
    -textVariable UpperLimit -width 10 -contextHelp \
    "Upper voltage value for the scan."
APSLabeledEntry .returnVoltage -parent .userFrame -label "Return Voltage (kV): " \
    -textVariable returnVoltage -width 10 -contextHelp \
    "Voltage value after the scan."
APSLabeledEntry .delta -parent .userFrame -label "Delta (kV): " \
  -textVariable DeltaVoltage -width 10 -contextHelp \
  "Voltage step to use in scan."
APSLabeledEntry .timeToWait -parent .userFrame -label "Time to wait (s): " \
  -textVariable TimeToWait -width 10 -contextHelp \
  "Time to wait for data collection at each voltage."

# I think we can retire this feature. The number in group for injection is always 1.
# APSLabeledEntry .numInGroup -parent .userFrame -label "Number in BPM group: " \
  -textVariable NumberInGroup -width 10 -contextHelp \
  "Number of bunches in the BPM group"
APSLabeledEntry .current -parent .userFrame -label "Current to inject to (mA): " \
  -textVariable TotalCurrent -width 10 -contextHelp \
  "Total stored current to fill to.  If zero, script will not attempt to fill."
APSRadioButtonFrame .vsaRB -parent .userFrame \
  -label "Collect nus spectrum on Dimtel LFB: " -variable collectLFB \
  -buttonList {Yes No} -valueList {1 0} \
  -orientation horizontal  \
  -contextHelp "Collect directly a waveform from Dimtel LFB at each iteration. The LFB must be previously set up to produce a nice synchrotron oscillation (nus) peak."

APSFrame .controllaw -parent .userFrame -label "Controllaw" 
set w .userFrame.controllaw.frame
set voltageToSend 4500
set returnVoltage 4500
foreach sector {36 37 40} {
    foreach c {1 2 3 4} {
        set cavityEnabled($sector,$c) 1
    }
    APSCheckButtonFrame .c$sector -parent $w -label "S$sector:   " -orientation horizontal \
        -buttonList "C1 C2 C3 C4" \
        -variableList "cavityEnabled($sector,1) cavityEnabled($sector,2) cavityEnabled($sector,3) cavityEnabled($sector,4)"
}

proc SendRFVoltage {args} {
    global cavityEnabled
    APSParseArguments {voltage}

    set totalCount 0
    foreach sector {36 37 40} {
        set cavityCount($sector) 0
        foreach cavity {1 2 3 4} {
            if $cavityEnabled($sector,$cavity) {
                incr cavityCount($sector)
                incr totalCount
            }
        }
    }

    if $totalCount==0 {
        return -code error "no cavities enabled"
    }
    set adjustedV [expr $voltage / ($totalCount*1.0) ]

    foreach sector {36 37 40} {
        if $cavityCount($sector)==0 {
            return -code error "Something odd: no cavities enabled in sector $sector"
        }
        lappend optionList $sector=[expr $adjustedV*$cavityCount($sector)]
        APSSetVarAndUpdate status "S$sector: [expr $adjustedV*$cavityCount($sector)] kV"
    }

    APSSetVarAndUpdate status "cavput -list=SRF:S -list=[join $optionList ,] -list=:cavTotalGV:SetptAO"
    exec cavput -list=SRF:S -list=[join $optionList ,] -list=:cavTotalGV:SetptAO

    return
}
    
APSLabeledEntry .vset -parent $w -label "Voltage to send" \
  -textVariable voltageToSend \
  -contextHelp "Entry the voltage that you want to send to the controllaw PVs to regulate the rf voltage." 
APSButton .vsend -parent $w -text "Send voltage" \
  -command {SendRFVoltage -voltage $voltageToSend} \
  -contextHelp "Sends the above voltage to the PVs where controllaw will see them."
APSButton .controllaw -parent $w -text "Launch controllaw windows" \
  -command {exec controllaw -controlList srrfErr &
      exec SRSetRFControllawMode & \
          } \
  -contextHelp "Launches application for starting and controlling rf controllaw for gap voltage regulation. Also launches application for setting the mode of the RF controllaw."


APSButton .setup -parent .userFrame -text "Setup VSA" \
  -command {setupVSA}  \
  -contextHelp "Sets up the hpvec VSA for synchrotron frequency measurement."

APSButton .run -parent .userFrame -text Run -command \
  {RunEnergyApertureScan -index $RunIndex -outputDir $outputDirectory \
     -lowerLimit $LowerLimit -upperLimit $UpperLimit \
     -voltageSpacing $DeltaVoltage -numInGroup $NumberInGroup \
     -current $TotalCurrent \
     -timeToWait $TimeToWait -abortVariable AbortEnergyApertureScan \
     -statusCallback "APSSetVarAndUpdate status" \
     -returnVoltage $returnVoltage -collectVSA $collectVSA; bell ; bell } 
set AbortEnergyApertureScan 0
APSButton .abort -parent .userFrame -text Abort -command \
    {APSSetVarAndUpdate status "Aborting..."; set AbortEnergyApertureScan 1}

APSButton .proc -parent .userFrame -text Process -command \
    {APSSetVarAndUpdate status "Processing data..."; processScanData -outputDir $outputDirectory -index $RunIndex}

proc processScanData {args} {
    set index 0
    set outputDir ""
    APSStrictParseArguments {index outputDir}
    scan $index "%ld" index
    set index [format "%02ld" $index]
    set outputRoot $outputDir/voltScan-$index
    set dataFile $outputRoot.scalars.gz
    if ![file exists $dataFile] {
        set dataFile $outputRoot.scalars
        if ![file exists $dataFile] {
            return -code error "Can't find file $outputRoot.scalars or $outputRoot.scalars.gz"
        }
    }
    exec sddsbreak $outputRoot.scalars.gz -pipe=out \
      -changeof=S36TotalGapVoltageSetpoint,amount=20 \
      | sddsrowstats -pipe -sum=GapVoltage,S??TotalGapVoltage \
        -sum=GapVoltageError,S??TotalGapVoltageError \
      | sddsprocess -pipe \
      -filter=column,GapVoltageError,-100,100 \
      "-define=col,LnS35DCCT,S35DCCT ln" \
      -proc=LnS35DCCT,slope,%sSlope,functionOf=TimeOfDay \
      -proc=?emittance,average,%sAverage \
      -proc=Coupling,average,%sAverage \
      -proc=SRGapVoltage,average,%sAverage \
      | sddsprocess -pipe \
      "-def=para,Rate,LnS35DCCTSlope chs" \
      "-def=para,Lifetime,Rate 1 swap /,units=hours" \
      | sddscollapse -pipe \
      | sddsconvert -pipe -edit=col,*Average,%/Average// \
      | sddsprocess -pipe=in $outputRoot.proc \
      "-def=col,NormLifetime,Lifetime Coupling sqrt /,description=Lifetime normalized to 1% coupling,units=h" \
      "-def=col,GapVoltage,SRGapVoltage 1e3 /,units=MV"

    exec sddsplot $outputRoot.proc \
      -grap=sym,conn=sub,sca=2,vary=sub -leg \
      -col=GapVoltage,Lifetime \
      -col=GapVoltage,NormLifetime -yscale=id=norm \
      &
    return
}

proc RunEnergyApertureScan {args} {
    set index 0
    set statusCallback APSNoOp
    set outputDir ""
    set lowerLimit 0
    set upperLimit 10000
    set returnVoltage 9000
    set voltageSpacing 100
    set timeToWait 120
    set abortVariable ""
    set numInGroup 1
    set current 102
    set collectVSA 0
    APSStrictParseArguments {index statusCallback outputDir lowerLimit upperLimit \
                               timeToWait voltageSpacing abortVariable numInGroup \
                               returnVoltage collectVSA current}

    scan $index "%ld" index
    set index [format "%02ld" $index]
    if ![file exists $outputDir] {
        exec mkdir -p $outputDir
    }
    set outputRoot $outputDir/voltScan-$index

    if [catch {APSBunchTrainConnect}] {
        return -code error
    }

    if {![file exists $outputRoot.scalars.gz]} {
        set tmpRoot /tmp/[APSTmpString]

        if [catch {MakeVoltageSweep -lower $lowerLimit -upper $upperLimit \
                     -voltageSpacing $voltageSpacing -numInGroup $numInGroup -current $current \
                     -timeToWait $timeToWait -abortVariable $abortVariable \
                     -outputRoot $outputRoot -statusCallback $statusCallback \
                     -collectVSA $collectVSA \
                 } result] {
            eval $statusCallback {"$result"}
            return -code error $result
        }
        if [catch {SendRFVoltage -voltage $returnVoltage} result] {
            return -code error $result
        }
        eval $statusCallback {"Measurement done."}
    } else {
        eval $statusCallback {"Data already exists with that name."}
    }
}

proc MakeVoltageSweep {args} {
    set lower 0
    set upper 10000
    set outputRoot ""
    # this is current in bunch (assuming 24 bunches)
    set current 102
    set statusCallback APSNoOp
    set voltageSpacing 100
    set timeToWait 120
    set abortVariable ""
    set numInGroup 1
    set collectVSA 0
    APSStrictParseArguments {lower upper outputRoot current \
                               statusCallback voltageSpacing timeToWait \
                               abortVariable numInGroup collectVSA}
    global S35BeamCurrent
    set tmpRoot /tmp/[APSTmpString]

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

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

    if [expr $current>0] {
        eval $statusCallback {"Filling to $current mA"}
        TogglePulsedMagnetEnables -location GuntoBoosterExt
        if [catch {DoIOCBunchTrainInjection -start 0 -interval 24 -number 1 \
                     -stopAt $current -cycles 30 -multiplet $numInGroup -callback $statusCallback} result] {
            return -code error $result
        }
        SetPulsedMagnetEnables -state 0 -location All
    }

    eval $statusCallback {"Starting asynchronous scalar monitor process."}
    set smPID [exec sddsmonitor $inputDir/scalars.mon $outputRoot.scalars -erase -precision=double \
                 -interval=1,s -time=2,h -pendIOtime=15 &]
    if [catch {exec kill -STOP $smPID} result] {
        return -code error $result
    }

    set index 0
    set voltage $upper

    # check for no beam left
    if [pv getw S35BeamCurrent] {
        return -code error $errorCode
    }
    eval $statusCallback {"$S35BeamCurrent mA left."}

    while {$voltage>=$lower} {
        if {[string length $abortVariable] && [subst \$$abortVariable]} {
            break
        }
        if [catch {SendRFVoltage -voltage $voltage} result] {
            catch {exec kill $smPID}
            return -code error $result
        }
        eval $statusCallback {"Waiting for voltage to settle."}
        APSWaitWithUpdate -waitSeconds 10 -updateInterval 1

        # start data collection
        if [catch {exec kill -CONT $smPID} result] {
            catch {exec kill $smPID}
            return -code error $result
        }
        if $collectVSA {
            if [catch {exec hpSocketSend hpvecsr.aps4.anl.gov "ABOR;*WAI"} result] {
                catch {exec kill $smPID}
                return -code error $result
            }
        }
        eval $statusCallback {"Taking data and waiting for averaging."}
        APSWaitWithUpdate -waitSeconds $timeToWait -updateInterval 1 -abortVariable $abortVariable
        if $collectVSA {
            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] {
                catch {exec kill $smPID}
                return -code error $result
            }
            if ![file exists $outputRoot.stune-[format %03ld $index]] {
                eval $statusCallback {"Warning: file $outputRoot.stune-[format %03ld $index] was not created."}
            }
        }
        
        # check for no beam left
        if [pv getw S35BeamCurrent] {
            catch {exec kill $smPID}
            global errorCode
            return -code error $errorCode
        }
        eval $statusCallback {"$S35BeamCurrent mA left."}
        if {[expr $S35BeamCurrent<0.1]} {
            eval $statusCallback {"Insufficient current--stopping scan."}
            break
        }

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

        set voltage [expr $voltage-abs($voltageSpacing)]
        incr index
    }
    # resume data collection process
    if [catch {exec kill -CONT $smPID} result] {
        catch {exec kill $smPID}
        return -code error $result
    }

    eval $statusCallback {"Killing data collection processes."}
    catch {exec kill $smPID}

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

proc setupVSA {} {
    set hpvsaSelection hpvecsr
    set streamID [APSOpenTelnetStream -IPaddress $hpvsaSelection]
    APSWriteToTelnetStream -command "MMEM:LOAD:STAT 1,'NVRAM:FSYNCH'" -streamID $streamID

    APSSetVarAndUpdate status "Wait for VSA setup..."
    update
    set operationCondition 1
    while {$operationCondition} {
        after 1000
        set operationCondition [APSWriteToTelnetStream -command "STAT:OPER:COND?" -streamID $streamID]
        update
    }
    APSCloseTelnetStream -streamID $streamID
    APSSetVarAndUpdate status "VSA setup done."
    return 1
}


# Local Variables:
# mode: tcl
# indent-tabs-mode: nil
# End:
