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

# $Log: not supported by cvs2svn $
# Revision 1.13  2011/05/27 08:33:35  lemery
# Untabified and re-indented.
#
# Revision 1.12  2011/05/27 08:29:55  lemery
# Corrected more context help.
#
# Revision 1.11  2011/05/27 08:24:03  lemery
# Updated tune settings for (0.20,0.27)
#
# Revision 1.10  2011/05/27 08:21:19  lemery
# Indented code and corrected some context help.
#
# Revision 1.9  2011/05/19 20:11:44  xiaoam
# Add NASA tune measurement.
#
# Revision 1.8  2010/09/21 02:37:08  xiaoam
# Use a simple way to check CPU polarity.
#
# Revision 1.7  2010/02/12 20:00:47  xiaoam
# Modify maximum current of CPU and add cawait
#
# Revision 1.6  2010/01/27 18:26:53  soliday
# Updated because of PV name changes related to the CPU.
#
# Revision 1.5  2009/10/05 21:05:07  xiaoam
# Add read calibration co-efficient from old file
#
# Revision 1.4  2009/02/05 21:04:03  xiaoam
# Add quad calibration procession part
#
# Revision 1.3  2009/01/28 04:58:33  emery
# Added to context help of output file index.
#
# Revision 1.2  2008/06/06 14:00:08  emery
# Corrected some context help and made better default xtune limits.
#
# Revision 1.1  2008/06/06 07:30:54  emery
# First installation of tune correction for AC mode
# of CPU.
#

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)]
APSStandardSetup

set CVSRevisionAuthor "\$Revision: 1.14 $ \$Author: lemery $"

APSApplication . -name "CPUtuneCorrection - AC mode" -version \
  $CVSRevisionAuthor -overview "Collects tune readbacks at various ID4 CPU settings in AC mode. Then a quad correction configuration file is generated. Quad calibration factor also can be measured and checked."

proc MakeInputFrame {widget args} {
    set parent ""

    APSStrictParseArguments {parent}

    set outputDir .
    APSFrame $widget -parent $parent -label "Input parameters"
    set w $parent$widget.frame
    APSLabeledEntry .outputDir -parent $w \
      -label "Output directory:" -textVariable outputDir \
      -contextHelp "Enter a name for the output file directory." -width 50
    APSButton .daily -parent $w.outputDir -packOption "-anchor e" \
      -text "daily" -size small \
      -command {set outputDir [APSGoToDailyDirectory -subdirectory CPU]}
    APSLabeledEntry .comment -parent $w -label "Comment: " -textVariable comment \
      -width 55 \
      -contextHelp "Enter a comment to be written as a parameter to the output file."
    APSLabeledEntry .fileindex -parent $w -label "Output File Index: " -textVariable index \
      -contextHelp "Output file index. Increased by 1 after each measurement. Each gourp of measurement should start with a multiple of 10."
    APSRadioButtonFrame .instrument -parent $w -orientation horizontal \
      -label "Instrument for measuring tune: " -variable Instrument \
      -limitPerRow 2 \
      -buttonList {NASA VSA} \
      -valueList {NASA VSA} \
      -contextHelp \
      "Choose Instrument for measuring tune."

    APSFrame .tunewindow -parent $w -label "" -width 55
    set w0 $w.tunewindow.frame
    APSFrameGrid .fg -parent $w0 -xList {x y}
    set wx $w0.fg.x
    APSLabeledEntry .xtune -parent $wx -label "xTune: " -textVariable xTune \
      -contextHelp "Reference horizontal tune in tune measurement." 
    APSLabeledEntry .xtune0 -parent $wx -label "xTune0: " -textVariable xTune0 \
      -contextHelp "Lower limit of xtune search window"

    set wy $w0.fg.y
    APSLabeledEntry .ytune -parent $wy -label "yTune: " -textVariable yTune \
      -contextHelp "Reference vertical tune in tune measurement."
    APSLabeledEntry .xtune1 -parent $wy -label "xTune1: " -textVariable xTune1 \
      -contextHelp "Upper limit of xtune search window"

    APSLabeledEntry .halfperiod -parent $w -label "CPU half period (s): " -textVariable halfPeriod \
      -contextHelp "CPU AC-mode half-period for taking measurement."
    APSLabeledEntry .shorthalfperiod -parent $w -label "CPU short half period (s): " -textVariable shortHalfPeriod \
      -contextHelp "CPU AC-mode short half-period for ramping CPU to the next set point."
    APSLabeledEntry .oldfile -parent $w -label "Current Quad File: " -textVariable ACmodeQuadFile \
      -width 55 \
      -contextHelp "Current quad correction file."
    APSLabeledEntry .newfile -parent $w -label "New Quad File: " \
      -textVariable newFile \
      -width 55 \
      -contextHelp "New quad correction file calculated from measurement"
    APSLabeledEntry .calibration -parent $w -label "Calibration coefficient: " \
      -textVariable caliCoef \
      -width 55 \
      -contextHelp "Quad calibration coefficient"
}


proc CollectData {args} {
    APSParseArguments {ACmodeQuadFile halfPeriod shortHalfPeriod xTune yTune comment abortVar}
    global outputDir index Instrument
    global $abortVar

    incr index
    if {![string length $outputDir] } {
        APSSetVarAndUpdate status "Output directory or root not given."
        return
    }
    set dir [pwd]
    cd $outputDir

    set ACmodeDir /home/helios/oagData/sr/IDs/CPU/ACmodes
    if {$ACmodeQuadFile == ""} {
        set ACmodeQuadFile normalQuad.sdds
    }

    # set CPU in AC mode, in case it hasn't
    exec cavput -list=ID04b:DesiredMode=4

    set setpointList [exec sdds2stream -para=MainCurrent $ACmodeDir/$ACmodeQuadFile]
    exec cavput -list=ID04b:timer=$shortHalfPeriod

    # can start index at other 100's
    set indexf ${index}00
    foreach setpoint $setpointList {
        update
        if ([set $abortVar]) {
            exec cavput -list=ID04b:timer=$shortHalfPeriod
            exec cavput -list=ID04b:set_V_coil.VAL=400
            exec cawait -interval=0.5 -waitFor=ID04b:feedback.VAL,sameAs=Ready
            exec cavput -list=ID04b:set_V_coil.VAL=0
            exec cawait -interval=0.5 -waitFor=ID04b:feedback.VAL,sameAs=Ready
            set $abortVar 0
            break
        }
        set indexf [format %03ld $indexf]
        APSSetVarAndUpdate status "Doing setpoint [format %.1f $setpoint] A ..." 
        exec cavput -list=ID04b:set_V_coil.VAL=$setpoint
        while {1} {
            catch {exec cavget -list=ID04b:feedback.VAL} feedback
            if [string match $feedback "Ready"] break
            after 2000
        }

        if {$setpoint == 0} {
            APSSetVarAndUpdate status "Getting tunes for zero setpoint..."
            if [catch {collectTune -Instrument $Instrument -xTune $xTune -yTune $yTune \
                         -setpoint $setpoint -fileRoot tunes-${indexf}Neg \
                     } results] {
                APSSetVarAndUpdate status "CollectData: $results"
                return
            }
            APSSetVarAndUpdate status "just exited collectTune"
            # at 0 A Negative and Positive are the same.
            file copy -force tunes-${indexf}Neg tunes-${indexf}Pos
            incr indexf
            continue
        }

        # set half period 3s, make sure CPU stays in the same polarity when 
        # we change it to a longer halfperiod.
        # take data for negative polarity.
        exec cavput -list=ID04b:timer=3
        APSSetVarAndUpdate status "Waiting for Negative polarity..."
        exec cawait -waitFor=ID04b:V_coil,below=0
        exec cavput -list=ID04b:timer=$halfPeriod
        APSSetVarAndUpdate status "Getting tunes for Negative polarity..."
        if [catch {collectTune -Instrument $Instrument -xTune $xTune -yTune $yTune \
                     -setpoint $setpoint -fileRoot tunes-${indexf}Neg \
                 } results] {
            APSSetVarAndUpdate status "CollectData: $results"
            return
        }
        set polarityCheck [exec cavget -list=ID04b:V_coil]
        if {$polarityCheck > 0} {
            APSSetVarAndUpdate status "Something wrong: present polarity positive doesn't match the polarity before the tune measurement - negative! Increase the half-period. Blundering ahead..."
        }
        update
        if ([set $abortVar]) {
            exec cavput -list=ID04b:timer=$shortHalfPeriod
            exec cavput -list=ID04b:set_V_coil.VAL400
            exec cawait -interval=0.5 -waitFor=ID04b:feedback.VAL,sameAs=Ready
            exec cavput -list=ID04b:set_V_coil.VAL=0
            exec cawait -interval=0.5 -waitFor=ID04b:feedback.VAL,sameAs=Ready
            set $abortVar 0
            break
        }

        #take data for positive polarity.
        exec cavput -list=ID04b:timer=3
        APSSetVarAndUpdate status "Waiting for positive polarity..."
        exec cawait -waitFor=ID04b:V_coil,above=0
        exec cavput -list=ID04b:timer=$halfPeriod
        APSSetVarAndUpdate status "Getting tunes for Positive polarity..."
        if [catch {collectTune -Instrument $Instrument -xTune $xTune -yTune $yTune \
                     -setpoint $setpoint -fileRoot tunes-${indexf}Pos \
                 } results] { 
            APSSetVarAndUpdate status "CollectData: $results"
            return
        }
        set polarityCheck [exec cavget -list=ID04b:V_coil]
        if {$polarityCheck < 0} {
            APSSetVarAndUpdate status "Something wrong: present polarity negative doesn't match the polarity before the tune measurement - positive! Increase the halfPeriod."
        }
        update
        if ([set $abortVar]) {
            exec cavput -list=ID04b:timer=$shortHalfPeriod
            exec cavput -list=ID04b:set_V_coil.VAL400
            exec cawait -interval=0.5 -waitFor=ID04b:feedback.VAL,sameAs=Ready
            exec cavput -list=ID04b:set_V_coil.VAL=0
            exec cawait -interval=0.5 -waitFor=ID04b:feedback.VAL,sameAs=Ready
            set $abortVar 0
            break
        }

        exec cavput -list=ID04b:timer=$shortHalfPeriod
        incr indexf
    }

    APSSetVarAndUpdate status "collecting data finished"
    update
    cd $dir
}

proc collectTune {args} {
    APSParseArguments {Instrument xTune yTune setpoint fileRoot}
    global xTune0 xTune1 mode
    set xPower 6.0
    set yPower 0.0
    set span 40000
    set rfFrequency [exec cavget -list=A014-IETS:BTC:SRSetFreqM -floatFormat=%.1f -pendIoTime=5]
    set revFrequency [expr $rfFrequency / 1296]
    set measHarmonic 1390
    set sideband -1
    set xFreq [format %.1f [expr $revFrequency * ($measHarmonic + $xTune * $sideband)]]
    set yFreq [format %.1f [expr $revFrequency * ($measHarmonic + $yTune * $sideband)]]
    set dividingLine [format %.3f [expr ($xTune + $yTune)/2.0]]

    APSSetVarAndUpdate status "Getting tunes ..."
    if [catch {APSSetTuneMultiplexer -mode $Instrument} result] {
        SetStatus $result
        return
    }

    switch $Instrument {
        VSA {
            if [catch {exec getxytunes -root $fileRoot -only x -plotTunes 0 \
                         -description "Setpoint $setpoint" -xTune $xTune -yTune $yTune  \
                     } results] {
                APSSetVarAndUpdate status "CollectTune: $results"
                return 
            }
            if [catch {exec sddsprocess ${fileRoot}-x.sdds -pipe=out -noWarning \
                         -def=para,MainCurrent,$setpoint -print=para,Mode,$mode \
                         | sddsprocess -pipe -fil=col,Tune,$xTune0,$xTune1 \
                         | sddssmooth -pipe -col=Waveform -points=3 -pass=6 \
                         | sddsprocess -pipe=in ${fileRoot} \
                         -proc=Waveform,largest,xTune,position,functionOf=Tune
                file delete ${fileRoot}-x.sdds \
                     } results] {
                APSSetVarAndUpdate status "CollectTune: sddsprocess ${fileRoot}-x.sdds ...: $results"
            }
        }
        NASA { 
            APSMpMeasureTunes -ring SR -averagingSeconds -1
            APSMpMeasureTunes -ring SR -useExistingData 1 -averagingSeconds -1 -measureXYtuneTogether 0 \
              -plotData 0 -dividingLine $dividingLine -xPower $xPower -yPower $yPower -span $span$ \
              -xFreq $xFreq -yFreq $yFreq -outputFile $fileRoot
            if [catch {exec sddsprocess ${fileRoot} -noWarning -match=para,plane=x \
                         -def=para,MainCurrent,$setpoint -print=para,Mode,$mode \
                     } results] {
                APSSetVarAndUpdate status "CollectTune: sddsprocess ${fileRoot} ...: $results"
            }
            file delete ${fileRoot}~
        }
    }    
    update
    return
}

proc ProcessData {args} {
    APSParseArguments {xTune0 xTune1}
    #
    #Expects files tunes-<index>??Neg and tunes-<index>??Pos
    #Creates files Positive$<index>.peaks and Negative<index>.peaks."
    #
    global outputDir index

    set dir [pwd]
    cd $outputDir

    eval exec sddscombine [lsort [glob tunes-${index}??Neg]] -pipe=out \
      | sddscollapse -pipe=in Negative${index}.peaks 

    eval exec sddscombine [lsort [glob tunes-${index}??Pos]] -pipe=out \
      | sddscollapse -pipe=in Positive${index}.peaks

    APSSetVarAndUpdate status "Done."
    cd $dir
    return
} 

proc PlotData {} {
    global outputDir index

    set dir [pwd]
    cd $outputDir

    exec sddsplot -col=MainCurrent,xTune Positive${index}.peaks \
      -gra=sym,sca=3,conn=sub,sub=0 \
      -leg=spec=Positive \
      -col=MainCurrent,xTune Negative${index}.peaks \
      -gra=sym,sca=3,conn=sub,sub=1 \
      -leg=spec=Negative \
      &

    APSSetVarAndUpdate status "Done."
    cd $dir
    return
}

proc applyCPUcorrection {args} {
    #set usage "applyCPUcorrection -index <integer> -newfile <string> -help \{0|1\}\n
    #Expects files Positive$<index>.peaks and Negative<index>.peaks.\n
    #Creates files ."
    APSParseArguments {ACmodeQuadFile newFile}
    global outputDir index caliCoef 

    set dir [pwd]
    cd $outputDir

    if {$newFile==""} {
        APSSetVarAndUpdate status "No newFile given."
        return
    }

    set ACmodeDir /home/helios/oagData/sr/IDs/CPU/ACmodes
    if {$ACmodeQuadFile == ""} {
        set ACmodeQuadFile normalQuad.sdds
    }

    exec sddsprocess Positive${index}.peaks Positive${index}.peaks.correction \
      -proc=xTune,first,xTuneFirst \
      "-def=col,xTuneDiff,xTune xTuneFirst -" \
      "-def=col,QuadCorrection,xTuneDiff $caliCoef / chs,units=A"

    exec sddsprocess Negative${index}.peaks Negative${index}.peaks.correction \
      -proc=xTune,first,xTuneFirst \
      "-def=col,xTuneDiff,xTune xTuneFirst -" \
      "-def=col,QuadCorrection,xTuneDiff $caliCoef / chs,units=A"

    exec sddsplot -grap=sym,conn=sub,sca=3,vary=sub \
      "-topline=Corrections from files Positive${index}.peaks Negative${index}.peaks" \
      -col=MainCurrent,QuadCorrection Positive${index}.peaks.correction \
      -leg=spec=Positive \
      -col=MainCurrent,QuadCorrection Negative${index}.peaks.correction \
      -leg=spec=Negative \
      &

    exec sddsbreak Negative${index}.peaks.correction -pipe=out \
      -rowlimit=1 \
      | sddsexpand -pipe \
      | sddsconvert -pipe=in Negative${index}.peaks.correction.para \
      -retain=para,MainCurrent,QuadCorrection \
      -rename=para,QuadCorrection=CurrentNegCorrection
    
    exec sddsbreak Positive${index}.peaks.correction -pipe=out \
      -rowlimit=1 \
      | sddsexpand -pipe \
      | sddsconvert -pipe=in Positive${index}.peaks.correction.para \
      -retain=para,MainCurrent,QuadCorrection \
      -rename=para,QuadCorrection=CurrentPosCorrection

    exec sddsprocess -pipe=out $ACmodeDir/$ACmodeQuadFile \
      -del=para,CurrentPosCorrection,CurrentNegCorrection \
      | sddsxref -pipe  Positive${index}.peaks.correction.para \
      -transfer=para,CurrentPosCorrection -noWarning -leave=* \
      | sddsxref -pipe  Negative${index}.peaks.correction.para \
      -transfer=para,CurrentNegCorrection -noWarning -leave=* \
      | sddsprocess -pipe=in $newFile \
      "-redef=col,%s,%s %sCorrection +,select=Current???" \
      "-redef=para,CaliCoef,$caliCoef"

    APSSetVarAndUpdate status "Please copy $newFile to /home/helios/oagData/sr/IDs/CPU/ACmodes"
    APSSetVarAndUpdate status "Then load this file into the CPU control ioc."
    cd $dir
    return
}

proc QuadCalibrate {args} {
    APSParseArguments {xTune yTune}
    global outputDir caliCoef

    set dir [pwd]
    cd $outputDir
    set points 11
    set limits 5

    for {set i 0} {$i < $points} {incr i} {
        set setpoint [expr -$limits + $i * 2.0 * $limits / ($points - 1)]
        APSSetVarAndUpdate status "Doing setpoint [format %.2f $setpoint] A ..." 
        exec cavput -list=ID04b:DS_NormalQuadSetpt=$setpoint

        after 1000
        set if [format %02ld $i]

        if [catch {collectTune -Instrument $Instrument -xTune $xTune -yTune $yTune \
                     -setpoint $setpoint -fileRoot tunes-quadCalibration-${if} \
                 } results] {
            APSSetVarAndUpdate status "QuadCalibrate: $results"
            return 
        }
    }
    
    if [catch {eval exec sddscombine [lsort [glob tunes-quadCalibration-??]] -pipe=out \
                 | sddscollapse -pipe=in quadCalibration.peaks  \
             } results] {
        APSSetVarAndUpdate status "QuadCalibrate: $results"
        return 
    }

    if [catch {exec sddspfit quadCalibration.peaks quadCalibration.fit \
                 -col=MainCurrent,xTune \
                 -range=-3.5,3.5 \
                 -evaluate=quadCalibration.eval,begin=-5,end=5.number=100 \
             } results] {
        APSSetVarAndUpdate status "QuadCalibrate: $results"
        return 
    }
    
    exec sddsplot -col=MainCurrent,xTune quadCalibration.peaks \
      -gra=sym,sca=3,conn=sub,sub=0 \
      -leg=spec=Peaks \
      -col=MainCurrent,xTune quadCalibration.eval -grap=line,type=1 -leg=spec=Fit \
      &

    set caliCoef [exec sdds2stream -para=Slope quadCalibration.fit]
    set cavput -list=ID04b:set_ -list=H,V -list=_coil.VAL=0.5
    set cavput -list=ID04b:set_ -list=H,V -list=_coil.VAL=0.0
    APSSetVarAndUpdate status "Calibrate coefficient: $caliCoef" 
    APSSetVarAndUpdate status "Calibration done."
    cd $dir
    return
}

set args $argv
set outputDir .
set ACmodeQuadFile normalQuad.sdds
set halfPeriod 20
set shortHalfPeriod 1
set mode AC
set Instrument NASA
set xTune 0.20
set xTune0 0.16
set xTune1 0.24
set yTune 0.27
set index 0
set abortRun 0
set caliCoef -2.661815496630858e-03
catch {set caliCoef [lindex [exec sdds2stream -para=CaliCoef /home/helios/oagData/sr/IDs/CPU/ACmodes/normalQuad.sdds] 0]} result

APSParseArguments {outputDir index ACmodeQuadFile halfPeriod shortHalfPeriod xTune yTune comment newFile}

set status "Working..."
APSScrolledStatus .status -parent .userFrame -textVariable status -width 50
MakeInputFrame .input -parent .userFrame

APSButton .run -parent .userFrame -text Collect -command \
  { \
      catch {set abortRun 0
          CollectData -ACmodeQuadFile $ACmodeQuadFile \
               -halfPeriod $halfPeriod -shortHalfPeriod $shortHalfPeriod \
               -xTune $xTune -yTune $yTune \
               -comment $comment -abortVar abortRun} status
      update idletasks
  } \
  -contextHelp "Collects tunes at various CPU setting points"

APSButton .stop -parent .userFrame -text Stop -command \
  { \
      set abortRun 1
      APSDisableButton .userFrame.stop.button
      APSEnableButton .userFrame.run.button } \
  -contextHelp "Aborts whole run."

APSButton .process -parent .userFrame -text PROCESS -command \
  { \
      catch {ProcessData -xTune0 $xTune0 -xTune1 $xTune1} status
      update idletasks
  } \
  -contextHelp "Selects and processes the data collected today."

APSButton .plot -parent .userFrame -text "PLOT" -command \
  { \
      catch {PlotData} status
      update idletasks
  } \
  -contextHelp "Selects and plots the data collected today."

APSButton .apply -parent .userFrame -text Generate -command \
  { \
      catch {applyCPUcorrection -ACmodeQuadFile $ACmodeQuadFile\
               -newFile $newFile \
           } status
      update idletasks
  } \
  -contextHelp "Generate correction quad file."

APSButton .calibrate -parent .userFrame -text Calibration -command \
  { \
      catch {QuadCalibrate  -xTune $xTune -yTune $yTune} status
      update idletasks
  } \
  -contextHelp "Calibrate quads settings."

set status Ready.
update


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