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

# First version of script by N. Sereno.
#

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

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

APSApplication . -name "CPU Control and Measurement" \
  -version $CVSRevisionAuthor \
  -overview "CPU Waveform Measurement and Correction"

bind all <Double-Button-3> { 
    APSInfoWindow .contextHelp -name "Context Help" \
      -infoMessage [APSNearestContextHelp %W] \
      -width 15
}

set ControlStatus "Ready"
set CPUMainRelAmplitude 0.1
set Title {1A = 0.008 mrad}
set Delay 0
set plotDirectory ./

proc MakeCPUStatus {} {
    global ControlStatus
    
    APSScrolledStatus .status -parent .userFrame -textVariable ControlStatus -width 75 -packOption {-side top}
}

proc MakeCPUMeasureWidget {widget args} {
    set parent ""
    APSParseArguments {parent}
    
    APSFrame $widget -parent $parent \
      -height 30 -relief flat \
      -packOption {-side top -fill x} 
    set w $parent$widget.frame
# I don't remember why we have this feature, so I commented it out. LEm
#    MakeCPUToggleWidget .cpuAmpFrame -parent $w
    MakeDSPFileSetupWidget .file -parent $w
    MakeCPUCollectDataWidget .collectData -parent $w
}

proc MakeCPUToggleWidget {widget args} {
    
    set parent ""
    APSParseArguments {parent}
    
    APSFrame $widget -parent $parent \
      -height 30 \
      -packOption {-side top -fill x} 
    
    set w $parent$widget.frame
    APSLabeledEntry .cpuMainRelAmp -parent $w -width 7 \
      -textVariable CPUMainRelAmplitude \
      -packOption {-side left} \
      -label "CPU Main Toggle Amplitude." \
      -contextHelp "Amplitude for toggling the CPU in order to re-read the waveforms."
    
    APSButton .toggleCPUAmplitude -parent $w \
      -text "Toggle" \
      -command {toggleCPURelAmplitude $CPUMainRelAmplitude -statusCallback SetStatus} \
      -packOption {-side left} \
      -contextHelp "This button toggles the CPU amplitude in order to re-read the waveforms."
}

proc MakeDSPFileSetupWidget {widget args} {
    global outputDir root index comment abort

    set parent ""
    APSParseArguments {parent}
    
    APSFrame $widget -parent $parent \
      -height 30 \
      -packOption {-side top -fill x} 
    
    set w $parent$widget.frame

    APSLabeledEntry .outputDir -parent $w \
      -label "Output directory:" -textVariable outputDir \
      -contextHelp "Enter a name for the output file directory." -width 55

    APSButton .daily -parent $w.outputDir -packOption "-anchor e" \
      -text "daily" -size small \
      -command {set outputDir [APSGoToDailyDirectory -subdirectory CPU]}

    APSLabeledEntry .root -parent $w -label "Root name of file: " \
      -textVariable root \
      -contextHelp "Enter the root name of the file for the corrector error output <root>-nnn."

    APSLabeledEntry .index -parent $w -label "Index (incremented just before execution): " -textVariable index \
      -contextHelp "Enter the index (minus 1) to be part of the name of the output file. The index is incremented by 1 before execution."

    APSButton .reset -parent $w.index -packOption "-anchor e" \
      -text "reset" -size small \
      -command {set index -1}

    APSLabeledEntry .comment -parent $w -label "Comment: " -textVariable comment \
      -width 50 \
      -contextHelp "Enter a comment."
    APSLabeledEntry .average -parent $w -label "Number of acquisitions to average: " -textVariable average \
      -contextHelp "Enter the number to average."

    APSLabeledEntry .smoothPoints -parent $w -label "Smoothing points for averaging: " -textVariable smoothPoints \
      -contextHelp "Enter the number of smoothing points for averaging. Must be odd integer."
    APSLabeledEntry .smoothPasses -parent $w -label "Smoothing passes for averaging: " -textVariable smoothPasses \
      -contextHelp "Enter the number of smoothing passes for averaging. If no smoothing is desired set avlue to zero."


}

proc MakeCPUCollectDataWidget  {widget args} {

    set parent ""
    APSParseArguments {parent}
    
    APSFrame $widget -parent $parent \
      -height 30 -relief flat \
      -packOption {-side top -fill x } 
    
    APSFrame .meas -parent $parent$widget.frame \
      -height 30 -relief flat \
      -packOption {-side top -fill x } 
    
    APSFrame .plot  -parent $parent$widget.frame \
      -height 30 -relief flat \
      -packOption {-side top -fill x } 
    
    set w $parent$widget.frame.meas.frame

    APSButton .dspScopeSetup -parent $w \
      -text "DSP Setup" \
      -command {DSPScopeSetup -statusCallback SetStatus} \
      -packOption {-side left} \
      -contextHelp "This button sets up the DSP scope for data collection."

    APSButton .collectData -parent $w \
      -text "Collect Data" \
      -command {incr index; \
                  CollectData -output $outputDir/$root-[format %03ld $index] -comment $comment -statusCallback SetStatus} \
      -packOption {-side left} \
      -contextHelp "This button collect DSP scope data."

    APSButton .abortbutton -parent $w -text "Abort" \
      -packOption "-side left" \
      -command {set abort 1} \
      -contextHelp "Abort data collection."

    set w $parent$widget.frame.plot.frame

    APSButton .plotData -parent $w \
      -text "Plot Data" \
      -command {PlotData -file $outputDir/$root-[format %03ld $index]} \
      -packOption {-side left} \
      -contextHelp "This button plots the DSP scope data."

    APSButton .plotAvgData -parent $w \
      -text "Plot Averaged Data" \
      -command {PlotData -file $outputDir/$root-[format %03ld $index].ave} \
      -packOption {-side left} \
      -contextHelp "This button plots the averaged DSP scope data along with the original data."

    APSButton .plotDataZ -parent $w \
      -text "Plot Zoomed Data" \
      -command {PlotData -zoomed 1 \
                  -file $outputDir/$root-[format %03ld $index]} \
      -packOption {-side left} \
      -contextHelp "This button plots the zoomed-in DSP scope data."

    APSButton .plotDataFamily -parent $w \
      -text "Plot Family of Root Name" \
      -command {PlotData -family 1 \
                  -file $outputDir/$root} \
      -packOption {-side left} \
      -contextHelp "This button plots the family of averaged data from the root name of file."

     APSButton .doAverage -parent $w \
      -text "Re-do Average" \
      -command {AverageCorrectorErrorData -inputFile $outputDir/$root-[format %03ld $index]} \
      -packOption {-side left} \
      -contextHelp "This button re-does the average of the DSP scope data."
   return
}

proc PlotData {args} {
    set file ""
    set zoomed 0
    set family 0
    APSParseArguments {file zoomed family}

    if !$family {
        set fileArgument $file
        if {![file exists $file]} {
            return -code error "PlotData: File $file doesn't exist"
        }
    } else {
        set fileArgument [lsort [glob $file-???.ave]]
        if ![llength $fileArgument] {
            return -code error "PlotData: No match for $file-???.ave."
        }
    }
    if $zoomed {
        set options "-layout=1,2 -filter=col,t,0,0.5"
    } else {
        set options "-layout=1,2"
    }
    if [catch {eval exec sddsplot $options -axes=x \
                   -grap=line,vary -leg=file,edit=10Z/ -topline=@Comment \
                   -sep=nameindex -group=nameindex \
                   -col=t,(S*H*Error,S*V*Error) $fileArgument \
                   &} \
            result] {
        return -code error $result
    }
    return
}

proc MakeCPUProcessWidget {widget args} {
    global outputDir root index comment abort firstWaveform startTime period tauH tauV

    set parent ""
    APSParseArguments {parent}
    
    APSFrame $widget -parent $parent \
      -height 30 \
      -packOption {-side top -fill x} 
    
    set w $parent$widget.frame

    APSRadioButtonFrame .firstWaveform -parent $w -orientation horizontal \
      -label "First waveform: " -variable firstWaveform \
      -buttonList {Pos Neg} \
      -valueList {Pos Neg} -contextHelp \
      "Choose the waveform type which occurs first in the RTFB dsp scope signal."

    APSLabeledEntry .start -parent $w -label "Start time (s): " -textVariable startTime \
      -width 40 \
      -contextHelp "Start time of first waveform as it appears on the RTFB corrector error signal triggered on P0."

    APSLabeledEntry .tauH -parent $w -label "Time constant in h-plane (s):" \
      -textVariable tauH \
      -width 40 \
      -contextHelp "Time constant for deconvolving in h-plane." 

    APSLabeledEntry .tauV -parent $w -label "Time constant in v-plane (s):" \
      -textVariable tauV \
      -width 40 \
      -contextHelp "Time constant for deconvolving in v-plane. Usually much smaller than in h-plane" 

    APSLabeledEntry .period -parent $w -label "Full period (s): " \
      -textVariable period \
      -width 40 \
      -contextHelp "Period of CPU cycle. Usually 0.5 s if triggering exteranlly from P0."

    APSLabeledEntry .triggerTime -parent $w -label "Duration of first waveform/state (s): " \
      -textVariable hperiod1 \
      -width 40 \
      -contextHelp "Time duration of first waveform. Not necessarily equal to one half of full period."

    APSLabeledEntry .aveTime -parent $w -label "Duration of the impulse part (s): " \
      -textVariable transientSection \
      -width 40 \
      -contextHelp "Time duration of the impulse part. Used for separate waveform smoothing between impulse (transient) and tail."

    APSRadioButtonFrame .equalTransient -parent $w -orientation horizontal \
      -label "Make transient correction equal and opposite" -variable equalTransients \
      -buttonList {yes no} -valueList {1 0} \
      -contextHelp "Forces the processing of transients to make the solutions for Negative and Positive pulse equal and opposite, i.e. average the two transients before calculating the solution."

    APSRadioButtonFrame .averageChannels -parent $w -orientation horizontal \
      -label "Make channel corrections equal" -variable averageChannels \
      -buttonList {yes no} -valueList {1 0} \
      -contextHelp "Makes the solutions for the CPU correctors equal, i.e. only first integral correction, ignore second intergral, if any."

    APSRadioButtonFrame .matrix -parent $w -orientation horizontal \
      -label "Use mapping matrix below:" -variable useMapping \
      -buttonList {no first last} -valueList {no first last} \
      -contextHelp "Use mapping matrix to convert S4A:H/V3 and S5A:H/V3 to CPU correctors."

    APSLabeledEntryFrame .hmap1  -parent $w -label [format %-35s "H-mapping matrix:"] \
      -variableList [list hmap(corr1.S4) hmap(corr1.S5)] \
      -orientation horizontal -type real \
      -contextHelp "The matrix elements are used to convert the S4A:H3 S5A:H3 waveform into a cpu corrector waveform.\n\n | hcorr1 |   | X   X |  | S4A:H3 |\n |        | = |       |  |        |\n | hcorr2 |   | X   X |  | S5A:H3 |\n"
    APSLabeledEntryFrame .hmap2  -parent $w -label [format %-35s ""] \
      -variableList [list hmap(corr2.S4) hmap(corr2.S5)] \
      -orientation horizontal -type real \
      -contextHelp "The matrix elements are used to convert the S4A:H3 S5A:H3 waveform into a cpu corrector waveform.\n\n | hcorr1 |   | X   X |  | S4A:H3 |\n |        | = |       |  |        |\n | hcorr2 |   | X   X |  | S5A:H3 |\n"
    APSLabeledEntryFrame .vmap1  -parent $w -label [format %-35s "V-mapping matrix:"] \
      -variableList [list vmap(corr1.S4) vmap(corr1.S5)] \
      -orientation horizontal -type real \
      -contextHelp "The matrix elements are used to convert the S4A:V3 S5A:V3 waveform into a cpu corrector waveform.\n\n | vcorr1 |   | X   X |  | S4A:V3 |\n |        | = |       |  |        |\n | vcorr2 |   | X   X |  | S5A:V3 |\n"
    APSLabeledEntryFrame .vmap2  -parent $w -label [format %-35s ""] \
      -variableList [list vmap(corr2.S4) vmap(corr2.S5)] \
      -orientation horizontal -type real \
      -contextHelp "The matrix elements are used to convert the S4A:V3 S5A:V3 waveform into a cpu corrector waveform.\n\n | vcorr1 |   | X   X |  | S4A:V3 | \n |        | = |       |  |        | \n | vcorr2 |   | X   X |  | S5A:V3 | \n"

    APSRadioButtonFrame .plotDebugging -parent $w -orientation horizontal \
      -label "Debug plots verbosity level: " -variable debugPlotLevel \
      -buttonList {None Some Lots} \
      -valueList {0 1 2} -contextHelp \
      "Choose the verbosity level of waveform plots that will be plotting with \"Process Data\" button."

    APSButton .processDataDC -parent $w \
      -text "Process Data - DC part" \
      -command {ProcessDataDC -input $outputDir/$root-[format %03ld $index].ave \
                  -outputRoot $outputDir/$root-[format %03ld $index] \
                  -startTime $startTime \
                  -period $period \
                  -hperiod1 $hperiod1 \
                  -tauH $tauH \
                  -tauV $tauV \
                  -gain $gain \
                  -useMapping $useMapping \
                  -equalTransients $equalTransients \
                  -averageChannels $averageChannels \
                  -debugPlotLevel $debugPlotLevel \
                  -statusCallback SetStatus} \
      -packOption {-side left} \
      -contextHelp "This button processes the DSP scope data and creates 4 corrector waveform files for DC correction."
    APSButton .processDataAC -parent $w \
      -text "Process Data - AC part" \
      -command {ProcessDataAC -input $outputDir/$root-[format %03ld $index].ave \
                  -outputRoot $outputDir/$root-[format %03ld $index] \
                  -startTime $startTime \
                  -period $period \
                  -hperiod1 $hperiod1 \
                  -tauH $tauH \
                  -tauV $tauV \
                  -gain $gain \
                  -useMapping $useMapping \
                  -equalTransients $equalTransients \
                  -averageChannels $averageChannels \
                  -debugPlotLevel $debugPlotLevel \
                  -statusCallback SetStatus} \
      -packOption {-side left} \
      -contextHelp "This button processes the DSP scope data and creates 4 corrector waveform files for AC correction."

    APSButton .plotAdjustment -parent $w \
      -text "Plot Adjustment Data" \
      -command {PlotAdjustmentData -inputRoot $outputDir/$root-[format %03ld $index] \
                  -statusCallback1 SetStatus} \
      -packOption {-side left} \
      -contextHelp "This button plots the adjustment waveform calculated."

}

proc MakeCPUModWaveformWidget {widget args} {
    global outputDir root index comment abort firstWaveform startTime period

    set parent ""
    APSParseArguments {parent}
    
    APSFrame $widget -parent $parent \
      -height 30 \
      -packOption {-side top -fill x} 
    
    set w $parent$widget.frame
    APSLabeledEntry .gain -parent $w -label "Gain:" \
      -textVariable gain \
      -width 40 \
      -contextHelp "Gain to apply to correction." 
    
    APSLabeledEntry .outputRoot -parent $w -label "Output root:" \
      -textVariable outputRoot \
      -width 40 \
      -contextHelp "Output root for data file for uploading."
    
    APSLabeledEntry .outputVersion -parent $w -label "Index (incremented after creating new file):" \
      -textVariable outputVersion \
      -width 40 \
      -contextHelp "Index for output root for data file for uploading."
    
    APSRadioButtonFrame .page -parent $w -orientation horizontal \
      -label "Propagate correction to next page:" -variable propagate \
      -buttonList {no yes} -valueList {0 1} \
      -contextHelp "If yes, use same corrector settings for next-highest current correction (next page in correction file)."

    APSButton .calculate -parent $w \
      -text "Create New Files" \
      -command {incr outputVersion; Apply -root $outputDir/$root-[format %03ld $index] \
                  -outputRoot $outputRoot -outputVersion $outputVersion \
                  -mode calculate \
                  -gain $gain \
                  -statusCallback SetStatus} \
      -packOption {-side left} \
      -contextHelp "This button calculates new files based on original uploaded files and new correction files."
    
    APSButton .plot -parent $w \
      -text "Plot Data Files" \
      -command {Apply -root $outputDir/$root-[format %03ld $index] \
                  -outputRoot $outputRoot -outputVersion $outputVersion \
                  -mode plot \
                  -statusCallback SetStatus} \
      -packOption {-side left} \
      -contextHelp "This button plots the new files to be uploaded."

    APSButton .upload -parent $w \
      -text "Upload Data Files" \
      -command {Apply -root $outputDir/$root-[format %03ld $index] \
                  -outputRoot $outputRoot -outputVersion $outputVersion \
                  -mode load \
                  -statusCallback SetStatus} \
      -packOption {-side left} \
      -contextHelp "This button uploads to new corrector files."
     APSButton .uploadx1 -parent $w \
      -text "Upload H1" \
      -command {Apply -root $outputDir/$root-[format %03ld $index] \
                  -outputRoot $outputRoot -outputVersion $outputVersion \
                  -mode loadx1 \
                  -statusCallback SetStatus} \
      -packOption {-side left} \
      -contextHelp "This button uploads to new corrector files for hcorr1."
     APSButton .uploadx2 -parent $w \
      -text "Upload H2" \
      -command {Apply -root $outputDir/$root-[format %03ld $index] \
                  -outputRoot $outputRoot -outputVersion $outputVersion \
                  -mode loadx2 \
                  -statusCallback SetStatus} \
      -packOption {-side left} \
      -contextHelp "This button uploads to new corrector files for hcorr2."
     APSButton .uploady1 -parent $w \
      -text "Upload V1" \
      -command {Apply -root $outputDir/$root-[format %03ld $index] \
                  -outputRoot $outputRoot -outputVersion $outputVersion \
                  -mode loady1 \
                  -statusCallback SetStatus} \
      -packOption {-side left} \
      -contextHelp "This button uploads to new corrector files for vcorr1."
     APSButton .uploady2 -parent $w \
      -text "Upload V2" \
      -command {Apply -root $outputDir/$root-[format %03ld $index] \
                  -outputRoot $outputRoot -outputVersion $outputVersion \
                  -mode loady2 \
                  -statusCallback SetStatus} \
      -packOption {-side left} \
      -contextHelp "This button uploads to new corrector files for vcorr2."
}

proc MakeCPUUndoWaveformWidget {widget args} {
    global outputDir root index comment abort firstWaveform startTime period

    set parent ""
    APSParseArguments {parent}
    
    APSFrame $widget -parent $parent \
      -height 30 \
      -packOption {-side top -fill x} 
    set w $parent$widget.frame

    APSButton .undoy2 -parent $w \
      -text "Undo V2  " \
      -command {Apply -root $outputDir/$root-[format %03ld $index] \
                  -outputRoot $outputRoot -outputVersion $outputVersion \
                  -mode undoy2 \
                  -statusCallback SetStatus} \
      -packOption {-side right} \
      -contextHelp "This button undo last vcorr2 uploads."

    APSButton .undoy1 -parent $w \
      -text "Undo V1  " \
      -command {Apply -root $outputDir/$root-[format %03ld $index] \
                  -outputRoot $outputRoot -outputVersion $outputVersion \
                  -mode undoy1 \
                  -statusCallback SetStatus} \
      -packOption {-side right} \
      -contextHelp "This button undo last vcorr1 uploads."

    APSButton .undox2 -parent $w \
      -text "Undo H2  " \
      -command {Apply -root $outputDir/$root-[format %03ld $index] \
                  -outputRoot $outputRoot -outputVersion $outputVersion \
                  -mode undox2 \
                  -statusCallback SetStatus} \
      -packOption {-side right} \
      -contextHelp "This button undo last xcorr2 uploads."

    APSButton .undox1 -parent $w \
      -text "Undo H1  " \
      -command {Apply -root $outputDir/$root-[format %03ld $index] \
                  -outputRoot $outputRoot -outputVersion $outputVersion \
                  -mode undox1 \
                  -statusCallback SetStatus} \
      -packOption {-side right} \
      -contextHelp "This button undo last xcorr1 uploads."

    APSButton .undo -parent $w \
      -text "Undo All Corr.   " \
      -command {Apply -root $outputDir/$root-[format %03ld $index] \
                  -outputRoot $outputRoot -outputVersion $outputVersion \
                  -mode undo \
                  -statusCallback SetStatus} \
      -packOption {-side right} \
      -contextHelp "This button undo all uploads from last time."
}

proc Apply {args} {
    global loadedFile
    set root ""
    set gain 1.0
    set statusCallback ""
    set mode calculate
    set outputRoot ""
    set outputVersion ""
    APSParseArguments {root gain mode statusCallback \
                         outputRoot outputVersion}

    if {![string length $outputRoot] || \
          ![string length $outputVersion]} {
        return -code error "Apply: invalid syntax"
    }
    set tmpfile /tmp/[APSTmpString]
    set baseDir /home/helios/oagData
    
    set newFile(hcorr1) /sr/IDs/CPU/ACmodes/$outputRoot.hcorr1.[format %03ld $outputVersion]
    set newFile(hcorr2) /sr/IDs/CPU/ACmodes/$outputRoot.hcorr2.[format %03ld $outputVersion]
    set newFile(vcorr1) /sr/IDs/CPU/ACmodes/$outputRoot.vcorr1.[format %03ld $outputVersion]
    set newFile(vcorr2) /sr/IDs/CPU/ACmodes/$outputRoot.vcorr2.[format %03ld $outputVersion]

    set corrList {vcorr2 hcorr2 hcorr1 vcorr1}

    switch $mode {
        calculate {
            if [string length $statusCallback] {
                $statusCallback "Calculating upload files..."
            }
            if [catch {exec cavget -list=ID04b:corrFile_ -list=1,2,3,4} loadedFiles] {
                    return -code error "Apply: $loadedFile"
            }
            set loadedFile(vcorr2) [lindex $loadedFiles 0]
            set loadedFile(hcorr2) [lindex $loadedFiles 1]
            set loadedFile(hcorr1) [lindex $loadedFiles 2]
            set loadedFile(vcorr1) [lindex $loadedFiles 3]
            
            foreach corr $corrList {
                # input adjustment file is $root.$corr.adj
                # original data file (to modify) $baseDir$loadedFile($corr)
                # output file is $baseDir/$newFile($corr)
                if [catch {CalculateNewFile -input $root.$corr.adj \
                             -original $baseDir$loadedFile($corr) \
                             -output $baseDir/$newFile($corr) \
                             -gain $gain \
                         } result ] {
                    return -code error "Apply: $result"
                }
            }
            if [string length $statusCallback] {
                $statusCallback "Correction files calculated."
            }
        }
        plot {
            exec sddsplot -layout=2,2 \
              -split=pages -sep=pages,request -group=pages \
              -same -topline=@CurrentString -grap=line,vary \
              -leg=edit=%/Current// \
              -col=TimeIndex,Current??? $baseDir/$newFile(hcorr1) \
              -ylabel=hcorr1  \
              -col=TimeIndex,Current??? $baseDir/$newFile(hcorr2) \
              -ylabel=hcorr2  \
              -col=TimeIndex,Current??? $baseDir/$newFile(vcorr1) \
              -ylabel=vcorr1  \
              -col=TimeIndex,Current??? $baseDir/$newFile(vcorr2) \
              -ylabel=vcorr2   \
              &
        }
        load {
            #load in the files
            if [catch {exec cavget -list=ID04b:corrFile_ -list=1,2,3,4} loadedFiles] {
                    return -code error "Apply: $loadedFile"
            }
            set loadedFile(vcorr2) [lindex $loadedFiles 0]
            set loadedFile(hcorr2) [lindex $loadedFiles 1]
            set loadedFile(hcorr1) [lindex $loadedFiles 2]
            set loadedFile(vcorr1) [lindex $loadedFiles 3]
            if [catch {exec cavput -list=ID04b:corrFile_ -list=1=$newFile(vcorr2),2=$newFile(hcorr2),3=$newFile(hcorr1),4=$newFile(vcorr1)} results] {
                return -code error $results
            }
            if [catch {exec cavput -list=ID04b:loadCorr_=1 -list=1,2,3,4 \
                     } results] {
                return -code error $results
            } 
            if [string length $statusCallback] {
                $statusCallback "Correction files uploaded."
            }
        }
        undo {
            #undo last load files
            if [catch {exec cavput -list=ID04b:corrFile_ -list=1=$loadedFile(vcorr2),2=$loadedFile(hcorr2),3=$loadedFile(hcorr1),4=$loadedFile(vcorr1)} results] {
                return -code error $results
            }
            if [catch {exec cavput -list=ID04b:loadCorr_=1 -list=1,2,3,4 \
                     } results] {
                return -code error $results
            } 
            if [string length $statusCallback] {
                $statusCallback "Correction files uploaded."
            }
        }
        loadx1 {
            #load in the file for hcorr1 only
            if [catch {exec cavget -list=ID04b:corrFile_ -list=3} loadedFile(hcorr1)] {
                    return -code error "Apply: $loadedFile"
            }
            if [catch {exec cavput -list=ID04b:corrFile_ -list=3=$newFile(hcorr1)} results] {
                return -code error $results
            }
            if [catch {exec cavput -list=ID04b:loadCorr_=1 -list=3 \
                     } results] {
                return -code error $results
            } 
            if [string length $statusCallback] {
                $statusCallback "Correction files in hcorr1 uploaded."
            }
        }
        undox1 {
            #undo hcorr1 only
            if [catch {exec cavput -list=ID04b:corrFile_ -list=3=$loadedFile(hcorr1)} results] {
                return -code error $results
            }
            if [catch {exec cavput -list=ID04b:loadCorr_=1 -list=3 \
                     } results] {
                return -code error $results
            } 
            if [string length $statusCallback] {
                $statusCallback "Correction files in hcorr1 uploaded."
            }
        }
        loadx2 {
            #load in the file for hcorr2 only
            if [catch {exec cavget -list=ID04b:corrFile_ -list=2} loadedFile(hcorr2)] {
                    return -code error "Apply: $loadedFile"
            }
            if [catch {exec cavput -list=ID04b:corrFile_ -list=2=$newFile(hcorr2)} results] {
                return -code error $results
            }
            if [catch {exec cavput -list=ID04b:loadCorr_=1 -list=2 \
                     } results] {
                return -code error $results
            } 
            if [string length $statusCallback] {
                $statusCallback "Correction files in hcorr2 uploaded."
            }
        }
        undox2 {
            #undo hcorr2 only
            if [catch {exec cavput -list=ID04b:corrFile_ -list=2=$loadedFile(hcorr2)} results] {
                return -code error $results
            }
            if [catch {exec cavput -list=ID04b:loadCorr_=1 -list=2 \
                     } results] {
                return -code error $results
            } 
            if [string length $statusCallback] {
                $statusCallback "Correction files in hcorr1 uploaded."
            }
        }
        loady1 {
            #load in the file for vcorr1 only
            if [catch {exec cavget -list=ID04b:corrFile_ -list=4} loadedFile(vcorr1)] {
                    return -code error "Apply: $loadedFile"
            }
            if [catch {exec cavput -list=ID04b:corrFile_ -list=4=$newFile(vcorr1)} results] {
                return -code error $results
            }
            if [catch {exec cavput -list=ID04b:loadCorr_=1 -list=4 \
                     } results] {
                return -code error $results
            } 
            if [string length $statusCallback] {
                $statusCallback "Correction files in vcorr1 uploaded."
            }
        }
        undoy1 {
            #undo vcorr1 only
            if [catch {exec cavput -list=ID04b:corrFile_ -list=4=$loadedFile(vcorr1)} results] {
                return -code error $results
            }
            if [catch {exec cavput -list=ID04b:loadCorr_=1 -list=4 \
                     } results] {
                return -code error $results
            } 
            if [string length $statusCallback] {
                $statusCallback "Correction files in hcorr1 uploaded."
            }
        }
        loady2 {
            #load in the file for vcorr2 only
            if [catch {exec cavget -list=ID04b:corrFile_ -list=1} loadedFile(vcorr2)] {
                    return -code error "Apply: $loadedFile"
            }
            if [catch {exec cavput -list=ID04b:corrFile_ -list=1=$newFile(vcorr2)} results] {
                return -code error $results
            }
            if [catch {exec cavput -list=ID04b:loadCorr_=1 -list=1 \
                     } results] {
                return -code error $results
            } 
            if [string length $statusCallback] {
                $statusCallback "Correction files in vcorr2 uploaded."
            }
        }
        undoy2 {
            #undo vcorr2 only
            if [catch {exec cavput -list=ID04b:corrFile_ -list=1=$loadedFile(vcorr2)} results] {
                return -code error $results
            }
            if [catch {exec cavput -list=ID04b:loadCorr_=1 -list=1 \
                     } results] {
                return -code error $results
            } 
            if [string length $statusCallback] {
                $statusCallback "Correction files in hcorr1 uploaded."
            }
        }
        default {
            return -code error "Apply: mode $mode unknown"
        }
    }
}

proc CalculateNewFile {args} {
    set input ""
    set original ""
    set output ""
    set gain 1
    APSParseArguments {input original output gain}
    set tmpfile /tmp/[APSTmpString]
    global propagate
    
    # maximum allowable absolute-value setting for coils
    set maxH 10
    set maxV 10
    if [regexp hcorr $input] {
        set max $maxH
        set maxI2 [expr $maxH*$maxH]
    } else {
        set max $maxV
        set maxI2 [expr $maxV*$maxV]
    }

# Assume that the input file has only one page, and has at least 70 time index points.
# As of 2/9/2009 it is possible to run CPU with one page now.

#    set pages [exec sdds2stream -npages=bare $original]
#    if {$pages > 1} {
#        return -code error "CalculateNewFile: Cannot handle multi-page file for -original (file $original"
#    }
    
    exec sddssort $original  $tmpfile.old -para=MainCurrent,inc -noWarning
    exec sddsprocess $tmpfile.old -redef=para,ipage,i_page -noWarning
    set current [exec sdds2stream -para=MainCurrent $input]
    set current0 [expr $current-1]
    set current1 [expr $current+1]
    exec sddsprocess $tmpfile.old $tmpfile.01 -filt=para,MainCurrent,$current0,$current1
    set page0 [exec sdds2stream -para=ipage $tmpfile.01]
    if {!$page0} {
        return -code error "CPU maincurrent $current is not in existing correction table"
    }
    set page1 [expr $page0+$propagate]
    exec sddsprocess $tmpfile.old $tmpfile.02 -filt=para,ipage,$page0,$page1,!

    if [catch {exec sddsconvert $input $tmpfile.adj \
                 -rename=col,CurrentPos=CurrentPosAdj \
                 -rename=col,CurrentNeg=CurrentNegAdj \
             } result ] {
        return -code error "CalculateNewFile: Problem with file $input: $result"
    }

    # file $tmpfile.adj is the file that we need to add to waveform file.
    # assume that the time index points line up.
#    exec sddsconvert $original -pipe=out \
#      -dele=para,MainCurrent \
#      | sddsxref -pipe $tmpfile.adj -pipe \
#      -take=CurrentPosAdj,CurrentNegAdj \
#      -transfer=para,MainCurrent \
#      | sddsprocess -pipe -noWarning \
#      "-redef=col,CurrentPos,CurrentPos CurrentPosAdj $gain * + $max min2 -$max max2" \
#      "-redef=col,CurrentNeg,CurrentNeg CurrentNegAdj $gain * + $max min2 -$max max2" \
#      | sddsconvert -pipe=in $output \
#      -noWar \
#      -retain=para,MainCurrent,CurrentString \
#      -retain=col,TimeIndex,CurrentNeg,CurrentPos

# new examination <I^2><$max^2>
    exec sddsxref $tmpfile.01 $tmpfile.adj -pipe=out \
      -take=CurrentPosAdj,CurrentNegAdj -reuse=page \
      | sddsprocess -pipe -noWarning \
      "-redef=col,CurrentPos,CurrentPos CurrentPosAdj $gain * + $max min2 -$max max2" \
      "-redef=col,CurrentNeg,CurrentNeg CurrentNegAdj $gain * + $max min2 -$max max2" \
      -del=para,PosPower,NegPower \
      | sddsprocess -pipe \
      -proc=CurrentPos,rms,PosPower -proc=CurrentNeg,rms,NegPower \
      | sddsconvert -pipe=in $tmpfile.out \
      -noWarning \
      -retain=para,MainCurrent,CurrentString,PosPower,NegPower \
      -retain=col,TimeIndex,CurrentNeg,CurrentPos

    if {$propagate} {
        exec sddsprocess $tmpfile.old -pipe=out -filt=para,ipage,$page1,$page1 \
            | sddsxref -pipe $tmpfile.out -pipe  \
            -take=Cur* -edit=col,Cur*,ei/1/ -transfer=para,MaxPosPower,MaxNegPower \
            | sddsprocess -pipe -redef=col,CurrentNeg,CurrentNeg1 -redef=col,CurrentPos,CurrentPos1 \
            | sddsprocess -pipe=in $tmpfile.03 -del=col,Curr*1
        eval exec sddscombine  $tmpfile.03 $tmpfile.out $tmpfile.04
        exec cp $tmpfile.04 $tmpfile.out
    }
    set value [exec sdds2stream -para=PosPower $tmpfile.out]
    if {[lindex $value 0] > $maxI2} {
        set output $original
        return -code error "Pos - Power supply reaches its limit. Please reduce gain"
    }
    set value [exec sdds2stream -para=NegPower $tmpfile.out]
    if {[lindex $value 0] > $maxI2} {
        set output $original
        return -code error "Neg - Power supply reaches its limit. Please reduce gain"
    }
    exec sddscombine $tmpfile.out $tmpfile.02 -pipe=out \
        | sddssort -pipe=in -para=MainCurrent,inc $output
    return
}

proc SetStatus {text} {
    global ControlStatus
    set ControlStatus $text
    update
}

# Sets the relative CPU amplitude factor and toggles the cpu main supply current.

proc toggleCPURelAmplitude {relAmpfactor args} {
    
    global ControlStatus

    APSParseArguments {statusCallback}

    if {$relAmpfactor > 1 || $relAmpfactor < 0} {
        if {$statusCallback!=""} {
            $statusCallback "CPU relative amplitude factor must be in the range 0 <= amplitude <= 1."
        }
        APSAlertBox .alert -errorMessage "CPU relative amplitude factor must be in the range 0 <= amplitude <= 1."
        return 0
    } else {
        catch {exec cavput -list=ID04b:set_V_coil=0.1 -delta=factor=1}
        catch {exec cavput -list=ID04b:set_V_coil=0.1 -delta=factor=-1}
        if {$statusCallback!=""} {
            $statusCallback "CPU main coil toggled with relative factor of $relAmpfactor."
        }
    }
}

proc DSPScopeSetup {args} {

    global ControlStatus configFile
    
    APSParseArguments {statusCallback}

    APSRestoreSRFBDspScope -filename $configFile -timing 1 \
      -channels 1 -clearMode 1 
    
    if {$statusCallback!=""} {
        $statusCallback "DSP scope setup complete."
    }
}

proc CollectData {args} {
    global configFile scalarsFile abort average

    APSParseArguments {statusCallback output comment}

    if ![string length $output] {
        return -code error "CollectData: No output file specified."
    }
    if [file exists $output] {
        return -code error "CollectData: File $output already exists!"
    }
    if {$statusCallback!=""} {
            $statusCallback "Collecting $average acquisition(s) from DSPscope...[exec date +%H:%M:%S]"
        }
    for {set i 0} {$i < $average} {incr i} {
        if {[exec cavget -pend=15 -list=SRFB:DS:SampleBO] == "Off"} {
            armDSPscope -statusCallback $statusCallback
        }
        set abort 0
        
        # Triggers from external trigger, which is the 2 Hz injection trigger.
        waitForTrigger -statusCallback $statusCallback
        if {$statusCallback!=""} {
            $statusCallback "Collecting data from DSPscope...[exec date +%H:%M:%S]"
        }
        update
        if [catch {exec sddswmonitor $configFile $output-[format %02ld $i] \
                     -comment=Comment,[APSMakeSafeQualifierString $comment] \
                     -pend=15 -scalars=$scalarsFile \
             } result] {
            if {$statusCallback!=""} {
                $statusCallback "CollectData: Error with sddswmonitor: $result"
                $statusCallback "Continuing anyway..."
            }
        }
        lappend fileList $output-[format %02ld $i]
    }

    if [catch {exec cavget -list=ID04b:set_V_coil.VAL  \
             } mainCurrent ] {
        return -code error "CollectData: Problem with getting main current (V current) for CPU"
    }
    
    if [catch {eval exec sddscombine $fileList -pipe=out \
                 | sddsenvelope -pipe \
                 -mean=S*H*,S*V* -copy=Index \
                 | sddsxref -pipe [lindex $fileList 0] \
                 -leave=* -transfer=para,* \
                 | sddsconvert -pipe=in $output \
                 -edit=col,*Mean*,%/Mean// \
             } result] {
        return -code error "CollectData: $result"
    }
    if [catch {exec sddsprocess $output -nowarn \
                 "-def=para,TickTime,SRFB:fsAO rec,units=sec" \
                 "-redef=col,t,Index TickTime *,units=sec" \
                 -define=para,MainCurrent,$mainCurrent \
             } result] {
        return -code error "CollectData: $result"
    }

    if [catch {AverageCorrectorErrorData -inputFile $output} result] {
        return -code error "CollectData: Error with AverageCorrectorErrorData: $result"
    }

    file delete -force ${output}~ $fileList
    if {$statusCallback!=""} {
        $statusCallback "Collecting done."
    }
}

proc armDSPscope {args} {
    global abort
    
    APSParseArguments {statusCallback}
    set dum 1
    while {[exec cavget -pend=15 -list=SRFB:GBL:FeedbackBlockedBI] == "Blocked"} {
        if {$dum == 1} {
            set status "Waiting for feedback block to clear... [exec date +%H:%M:%S]"
            set dum 0
        }
        APSWaitWithUpdate -waitSeconds 1 -updateInterval 0.5
    }
    
    set dum 1
    while {(([exec cavget -pend=15 -list=SRFB:GBL:HorzTripBI] == "Trip") || \
              ([exec cavget -pend=15 -list=SRFB:GBL:VertTripBI] == "Trip")) && \
             ($abort == 0) } {
        if {$dum == 1} {
            if {$statusCallback!=""} {
                $statusCallback "Waiting for trips to be reset... [exec date +%H:%M:%S]"
            }
            set dum 0
        }
        APSWaitWithUpdate -waitSeconds 1 -updateInterval 0.5
    }

    if {$abort == 0} {
        if {$statusCallback!=""} {
            $statusCallback "Arming DSPscope... [exec date +%H:%M:%S]"; update
        }
        exec cavput -pend=15 -list=SRFB:DS:SampleBO=1
        while {[exec cavget -pend=15 -list=SRFB:DS:SampleBO] == "Off"} {
            APSWaitWithUpdate -waitSeconds 1 -updateInterval 0.5
        }
    }
}

proc waitForTrigger {args} {
    global abort

    APSParseArguments {statusCallback}

    if {$abort == 0} {
        set triggered 0
        if {$statusCallback!=""} {
            $statusCallback "Waiting for dspscope to trigger... [exec date +%H:%M:%S]"; update
        }
        while {($triggered == 0) && ($abort == 0)} {
            if {[exec cavget -pend=15 -list=SRFB:DS:SampleBO] == "Off" } {
                set triggered 1
            }
            APSWaitWithUpdate -waitSeconds 1 -updateInterval 1
        }
        
        if {$triggered == 1} {
            if {$statusCallback!=""} {
            $statusCallback "Triggered [exec date +%H:%M:%S]"
            }
            update
        } else {
            if {$statusCallback!=""} {
                $statusCallback "Aborted... [exec date +%H:%M:%S]"
            }
            update
            set triggered 0
        }
    }
}

proc PlotAdjustmentData {args} {
    set inputRoot ""
    set statusCallback ""

    APSParseArguments {inputRoot statusCallback}


    if ![file exists $inputRoot.ave] {
        return -code error "ProcessData: Can't find file $inputRoot.ave. Perhaps data not taken yet."
    }
    if [string length $statusCallback] {
        $statusCallback "Plotting adjustment files..."
    }
    
    exec sddsplot -grap=line,vary -axes=x \
      -col=TimeIndex,Current??? -leg $inputRoot.hcorr1.adj -file -end \
      -col=TimeIndex,Current??? -leg $inputRoot.hcorr2.adj -file -end \
      -col=TimeIndex,Current??? -leg $inputRoot.vcorr1.adj -file -end \
      -col=TimeIndex,Current??? -leg $inputRoot.vcorr2.adj -file -end \
      &

    return
}

proc ProcessDataAC {args} {
    global hmap vmap transientSection
    set outputRoot ""
    set startTime 0.012
    set period 0.5000
    set firstWaveform Pos
    set hperiod1 0.2
    set tauH 0.007
    set tauV 0.001
    set useMapping first
    set equalTransients 0
    set averageChannels 0
    set debugPlotLevel 0
    APSParseArguments {input outputRoot startTime period hperiod1 firstWaveform tauH tauV useMapping equalTransients averageChannels debugPlotLevel}

    if ![file exists $input] {
        return -code error "ProcessData: Can't find file $input"
    }

# maps the correction of the S4 and S5 correctors to the CPU correctors

    set tmpfile /tmp/[APSTmpString]
    if [string match $useMapping "first"] {
        exec sddsprocess $input -pipe=out \
          "-def=col,hcorr1,S4A:H3:Error  $hmap(corr1.S4) * S5A:H3:Error  $hmap(corr1.S5) * +" \
          "-def=col,hcorr2,S4A:H3:Error  $hmap(corr2.S4) * S5A:H3:Error  $hmap(corr2.S5) * +" \
          "-def=col,vcorr1,S4A:V3:Error  $vmap(corr1.S4) * S5A:V3:Error  $vmap(corr1.S5) * +" \
          "-def=col,vcorr2,S4A:V3:Error  $vmap(corr2.S4) * S5A:V3:Error  $vmap(corr2.S5) * +" \
          | sddsprocess -pipe \
          "-redef=col,S4A:H3:Error,hcorr1" \
          "-redef=col,S5A:H3:Error,hcorr2" \
          "-redef=col,S4A:V3:Error,vcorr1" \
          "-redef=col,S5A:V3:Error,vcorr2" \
          | sddsprocess -pipe=in  $tmpfile.1 \
          -del=col,\[hv\]corr\[12\]
        # I don't think we should be overwriting an input file. So I comment this
        # and make some later code more complicated.
        #        exec mv $tmpfile.1 $input
    }

    APSSetVarAndUpdate ControlStatus "Processing data..."


    # 127 ms is the limit for correction waveforms but we can
    # analyze more than that (variable timeLimit). We keep the first 127 ms of the 
    # deconvolved waveform anyway for interpolation of the afg waveform.
    set timeLimit 0.170

    # create a response file for deconvolution at the end
    set tickTime [lindex [exec sdds2stream -para=TickTime $input] 0]
    set number [expr int($timeLimit/$tickTime) + 1]
    if {$tauH > 0 && $tauV > 0} {
        exec sddssequence -pipe=out \
          -define=t -sequence=begin=0,number=$number,delta=$tickTime  \
          | sddsprocess -pipe=in response \
          -def=para,tauH,$tauH \
          -def=para,tauV,$tauV \
          "-def=col,responseH,t tauH / chs exp tauH /" \
          "-def=col,responseV,t tauV / chs exp tauV /" 
    } else {
        return -code error "ProcessData: One of the time constants is negative!"
    }
    
    switch $firstWaveform {
        Pos {
            set rpnExpr ""
        }
        Neg {
            set rpnExpr "chs"
        }
        default {
            return -code error "ProcessData: Invalid firstWaveform: $firstWaveform"
        }
    }
    set num1 [expr $number - 1]
    if [string match $useMapping "first"] {
        if [catch {exec sddsprocess $tmpfile.1 -pipe=out \
                     "-redef=col,t,t $startTime -" \
                     | sddsprocess -pipe \
                     "-test=col,t 0 >" \
                     "-define=col,Sign,t $period 1.0 * mod $hperiod1 - sign $rpnExpr" \
                     | sddsbreak -pipe \
                     -changeOf=Sign \
                     | sddsprocess -pip=in $tmpfile.2 \
                     -proc=Sign,first,Sign \
                     -proc=t,first,tOffset \
                     "-redef=col,t,t tOffset -" \
                     "-redef=col,Index,i_row" \
                     -filter=col,Index,0,$num1 \
                 } result ] {
            return -code error "ProcessData(0): $result" 
        }
    } else {
        if [catch {exec sddsprocess $input -pipe=out \
                     "-redef=col,t,t $startTime -" \
                     | sddsprocess -pipe \
                     "-test=col,t 0 >" \
                     "-define=col,Sign,t $period 1.0 * mod $hperiod1 - sign $rpnExpr" \
                     | sddsbreak -pipe \
                     -changeOf=Sign \
                     | sddsprocess -pip=in $tmpfile.2 \
                     -proc=Sign,first,Sign \
                     -proc=t,first,tOffset \
                     "-redef=col,t,t tOffset -" \
                     "-redef=col,Index,i_row" \
                     -filter=col,Index,0,$num1 \
                 } result ] {
            return -code error "ProcessData(0): $result" 
        }
    }

    if {$debugPlotLevel > 0} {
        exec sddsplot -col=t,S*:*Error $tmpfile.2 -file -axes=x "-topline=Raw Data Channels" \
          -grap=sym,conn=sub,vary=sub  -leg=para=Sign,format=%.0f \
          -sep=nameindex -group=nameindex -split=pages &
    }

    foreach type {Neg Pos} sign {-1 1} {
        if [catch {exec sddsprocess $tmpfile.2 -pipe=out \
                     -filter=para,Sign,$sign,$sign \
                     | sddsenvelope -pipe \
                     -copy=t \
                     -mean=S?A:H3:Error \
                     -mean=S?A:V3:Error \
                     | sddsconvert -pipe=in $tmpfile.$type.2 \
                     -edit=col,*Mean,%/Mean// \
                 } result ] {
            return -code error "ProcessData(1): $result" 
        }
        
        #  $tmpfile.$type.2.proc is transient part (zero-value tail)
        if [catch {exec sddssmooth $tmpfile.$type.2 -pipe=out \
                     -col=S?A:?3:Error -passes=1 \
                     -SavitzkyGolay=5,5,2 \
                     | sddsprocess -pipe=in $tmpfile.$type.2.proc \
                     -process=S?A:?3:Error,average,%sBase1,tail=50 \
                     -process=S?A:?3:Error,average,%sBase2,head=5 \
                     "-redef=col,%s,%s %sBase1 -,select=S?A:?3:Error" \
                     -process=S?A:?3:Error,ave,%sAve \
                     -process=S?A:?3:Error,min,%sMin \
                     -process=S?A:?3:Error,max,%sMax \
                 } result ] {
            return -code error "ProcessData(2): $result" 
        }   
    }

    # for debugging
    if {$debugPlotLevel > 1} {
        exec sddsplot -file -grap=sym,conn=sub,vary=sub \
          -sep=nameindex -group=nameindex -split=pages -axes=x \
          -col=t,S*Error $tmpfile.Pos.2 -leg=spec=Pos \
          -col=t,S*Error $tmpfile.Neg.2 -leg=spec=Neg &
        exec sddsplot -file -grap=sym,conn=sub,vary=sub \
          -sep=nameindex -group=nameindex -split=pages -axes=x \
          -col=t,S*Error $tmpfile.Pos.2.proc -leg=spec=Pos \
          -col=t,S*Error $tmpfile.Neg.2.proc -leg=spec=Neg &
        exec sddsplot -file -grap=sym,conn=sub,vary=sub \
          -sep=group=2 -axes=x \
          -ylabel=edit=4%/Mean\[//4%/\]// \
          -col=t,S*Error $tmpfile.Pos.2.proc -leg \
          -col=t,S*Error $tmpfile.Neg.2.proc -leg &
    }

    if $equalTransients {
        # [Pos + (-Neg)]/2 -> Pos 
        # [(-Pos) + Neg]/2 -> Neg
        exec sddsxref $tmpfile.Pos.2.proc $tmpfile.Neg.2.proc -pipe=out \
          -take=S*:* \
          -edit=col,S*:*,ei/Neg \
          | sddsprocess -pipe \
          "-redef=col,%s,%s %sNeg - 2 /,sel=S*:*Error" \
          | sddsconvert -pipe=in $tmpfile.Pos.2.proc.new \
          -retain=col,t,S*:*Error
        
        exec sddsxref $tmpfile.Neg.2.proc $tmpfile.Pos.2.proc -pipe=out \
          -take=S*:* \
          -edit=col,S*:*,ei/Pos \
          | sddsprocess -pipe \
          "-redef=col,%s,%s %sPos - 2 /,sel=S*:*Error" \
          | sddsconvert -pipe=in $tmpfile.Neg.2.proc.new \
          -retain=col,t,S*:*Error
        exec mv $tmpfile.Neg.2.proc.new $tmpfile.Neg.2.proc 
        exec mv $tmpfile.Pos.2.proc.new $tmpfile.Pos.2.proc
    }

    if $averageChannels {
        # [S4AH3 + S5AH3]/2 -> S4AH3
        # [S4AH3 + S5AH3]/2 -> S5AH3
        foreach type {Neg Pos} {
            exec sddsprocess $tmpfile.$type.2.proc -pipe=out \
              "-redef=col,HChannelAve,S4A:H3:Error S5A:H3:Error + 2 /" \
              "-redef=col,VChannelAve,S4A:V3:Error S5A:V3:Error + 2 /" \
              | sddsprocess -pipe \
              -redef=col,S4A:H3:Error,HChannelAve \
              -redef=col,S5A:H3:Error,HChannelAve \
              -redef=col,S4A:V3:Error,VChannelAve \
              -redef=col,S5A:V3:Error,VChannelAve \
              | sddsconvert -pipe=in $tmpfile.$type.2.proc.new \
              -retain=col,t,S*:*Error
            exec mv $tmpfile.$type.2.proc.new $tmpfile.$type.2.proc
        }
    }

    if {$averageChannels || $equalTransients} {
        if {$debugPlotLevel > 1} {
            exec sddsplot -file -grap=sym,conn=sub,vary=sub \
              -sep=nameindex -group=nameindex -split=pages \
              -col=t,S*Error $tmpfile.Pos.2.proc -leg=spec=Pos \
              -col=t,S*Error $tmpfile.Neg.2.proc -leg=spec=Neg &
        }
    }
    
    set plotRequests ""
    foreach type {Neg Pos} {
        # At this point we have the transient signal with 
        # zero values for the end point.

        set corrList {S4A:H3 S5A:H3 S4A:V3 S5A:V3}
        foreach corr $corrList {

            exec sddsconvert $tmpfile.$type.2.proc $tmpfile.$type.2.$corr.final \
              -retain=col,t,${corr}:Error

            lappend plotRequests  -axe=x -grap=line,vary \
              -col=t,${corr}:Error "-topline=$corr before deconvolution" \
              $tmpfile.$type.2 "-leg=spec=$type Original" \
              -col=t,${corr}:Error \
              $tmpfile.$type.2.$corr.final "-leg=spec=$type Final" -end
        }

        set CPUcorrList {hcorr1 hcorr2 vcorr1 vcorr2}
        set responseList {responseH responseH responseV responseV }
        foreach corr $corrList CPUcorr $CPUcorrList response $responseList {
            if [catch {exec sddsconvolve $tmpfile.$type.2.$corr.final \
                         response \
                         $tmpfile.$type.${corr} \
                         -deconvolve \
                         -signalColumns=t,${corr}:Error \
                         -responseColumns=t,$response \
                         -outputColumns=t,Adjustment\
                     } result ] {
                return -code error "ProcessData: $result" 
            }
            if [catch {exec sddssmooth $tmpfile.$type.${corr} -pipe=out \
                         -passes=2 -col=Adjustment -nowarnings \
                         | sddsinterp -pipe \
                         -col=t,Adjustment \
                         -sequence=128,0,127e-3 \
                         -aboverange=value=0 \
                         | sddsprocess -pipe "-def=col,TimeIndex,t 1e3 *" \
                         "-redef=col,Adjustment,TimeIndex $transientSection 1000 * > ? 0 : Adjustment \$" \
                         | sddsprocess -pipe -clip=[expr $transientSection * 1000],1,invert \
                         | sddsinterp -pipe=in $tmpfile.$type.${corr}.interp \
                         -col=TimeIndex,Adjustment -fillIn
                     } result ] {
                return -code error "ProcessData: $result" 
            }
        }
    }

    # create file for reading into CPU ioc
    foreach corr $corrList CPUcorr $CPUcorrList {
        if [catch {exec sddsconvert $tmpfile.Pos.${corr}.interp -noWarning \
                     -rename=col,Adjustment=CurrentPos
            exec sddsconvert $tmpfile.Neg.${corr}.interp -noWarning \
                     -rename=col,Adjustment=CurrentNeg
            exec sddsxref $tmpfile.Pos.${corr}.interp $tmpfile.Neg.${corr}.interp -pipe=out \
                     -take=CurrentNeg \
                     | sddsxref -pipe=in $input $outputRoot.$CPUcorr.adj \
                     -transfer=para,MainCurrent \
                 } result ] {
            return -code error "ProcessData: $result" 
        }
    }
    
    if {$debugPlotLevel > 1} {
        eval exec sddsplot $plotRequests &
        exec sddsplot -grap=line,vary -axes=x \
          -col=t,S5A:H3:Error $tmpfile.Neg.2 "-topline=S5A:H3 Neg" -leg=spec=Original \
          -col=t,CurrentNeg $tmpfile.Neg.S5A:H3.interp "-leg=spec=Transient Correction" \
          -end \
          -col=t,S5A:H3:Error $tmpfile.Pos.2 "-topline=S5A:H3 Pos" -leg=spec=Original \
          -col=t,CurrentPos $tmpfile.Pos.S5A:H3.interp "-leg=spec=Transient Correction" \
          -end \
          -col=TimeIndex,Current??? -leg "-topline=Transient Correction" $outputRoot.hcorr1.adj -file -end \
          -col=TimeIndex,Current??? -leg "-topline=Transient Correction" $outputRoot.hcorr2.adj -file -end \
          \
          -col=t,S5A:V3:Error $tmpfile.Neg.2 "-topline=S5A:V3 Neg" -leg=spec=Original \
          -col=t,CurrentNeg $tmpfile.Neg.S5A:V3.interp "-leg=spec=Transient Correction" \
          -end \
          -col=t,S5A:V3:Error $tmpfile.Pos.2 "-topline=S5A:V3 Pos" -leg=spec=Original \
          -col=t,CurrentPos $tmpfile.Pos.S5A:V3.interp "-leg=spec=Transient Correction" \
          -end \
          -col=TimeIndex,Current??? -leg "-topline=Transient Correction" $outputRoot.vcorr1.adj -file -end \
          -col=TimeIndex,Current??? -leg "-topline=Transient Correction" $outputRoot.vcorr2.adj -file -end \
          &
    }

    APSSetVarAndUpdate ControlStatus "Processing done."
    return
}

proc ProcessDataDC {args} {
    global hmap vmap transientSection
    set outputRoot ""
    set startTime 0.012
    set period 0.5000
    set firstWaveform Pos
    set hperiod1 0.2
    set tauH 0.0065
    set tauV 0.0005
    set useMapping first
    set equalTransients 0
    set averageChannels 0
    set debugPlotLevel 0

    APSParseArguments {input outputRoot startTime period hperiod1 firstWaveform tauH tauV useMapping equalTransients averageChannels debugPlotLevel}

    if ![file exists $input] {
        return -code error "ProcessData: Can't find file $input for input in [pwd]"
    }

    APSSetVarAndUpdate ControlStatus "Processing data..."
    set tmpfile /tmp/[APSTmpString]

# maps the correction of the S4 and S5 correctors to the CPU correctors
    if [string match $useMapping "first"] {
        exec sddsprocess $input $tmpfile.1 -noWarning \
          "-def=col,hcorr1,$hmap(corr1.S4) S4A:H3:Error  *  $hmap(corr1.S5) S5A:H3:Error * +" \
          "-def=col,hcorr2,$hmap(corr2.S4) S4A:H3:Error  *  $hmap(corr2.S5) S5A:H3:Error * +" \
          "-def=col,vcorr1,$vmap(corr1.S4) S4A:V3:Error  *  $vmap(corr1.S5) S5A:V3:Error * +" \
          "-def=col,vcorr2,$vmap(corr2.S4) S4A:V3:Error  *  $vmap(corr2.S5) S5A:V3:Error * +" 
    }
    if [string match $useMapping "no" ] {
        exec sddsprocess $input $tmpfile.1 -noWarning \
          -def=col,hcorr1,S4A:H3:Error \
          -def=col,hcorr2,S5A:H3:Error \
          -def=col,vcorr1,S4A:V3:Error \
          -def=col,vcorr2,S5A:V3:Error 
    }

    exec sddsconvert $tmpfile.1 -noWarning \
      -delete=col,S4A:H3:Error*,S5A:H3:Error*,S4A:V3:Error*,S5A:V3:Error* 
    
    exec sddsplot -lay=2,2 -split=page -sep=pages -sep=nameindex  \
      "-topline=After matrix transformation (or after none)" \
      -col=t,(hcorr?,vcorr?) $tmpfile.1 \
      &

    
# create files with parameters of corrector offsets (DC levels) to apply to 
# CPU tables. The DC averaging is done over a section that follows the
# transient section. 10 ms is used as padding for the Neg section.
    foreach type {Neg Pos} tFirst "$transientSection [expr $hperiod1 + $transientSection]" tLast "[expr $hperiod1 - 10e-3] $period" {
        #  Split data into two pieces
        if [catch {exec sddsprocess $tmpfile.1 $outputRoot.$type \
                     -filter=col,t,$tFirst,$tLast \
                     -proc=?corr?,ave,%sAve \
                 } result ] {
            return -code error "ProcessData(2): $result" 
        }
    }

    # we should use 127 points to avoid any confusion.
    set corrList {vcorr2 hcorr2 hcorr1 vcorr1}
    foreach corr $corrList {
        exec sddssequence -pipe=out -def=TimeIndex \
          -sequence=beg=0,number=128,delta=1 \
          | sddsxref -pipe $outputRoot.Neg \
          -transfer=para,${corr}Ave -leave=* \
          -rename=para,${corr}Ave=${corr}Neg \
          | sddsxref -pipe $outputRoot.Pos \
          -transfer=para,${corr}Ave -leave=* \
          -rename=para,${corr}Ave=${corr}Pos \
          | sddsxref -pipe $input \
          -transfer=para,MainCurrent -leave=* \
          | sddsprocess -pipe=in $outputRoot.${corr}.adj \
          -def=col,CurrentPos,${corr}Pos \
          -def=col,CurrentNeg,${corr}Neg
        
    }


    if {$debugPlotLevel > 1} {
        eval exec sddsplot $plotRequests &
        exec sddsplot -grap=line,vary -axes=x \
          -col=t,S5A:H3:Error $tmpfile.Neg.2 "-topline=S5A:H3 Neg" -leg=spec=Original \
          -col=t,CurrentNeg $tmpfile.Neg.S5A:H3.interp "-leg=spec=Transient Correction" \
          -end \
          -col=t,S5A:H3:Error $tmpfile.Pos.2 "-topline=S5A:H3 Pos" -leg=spec=Original \
          -col=t,CurrentPos $tmpfile.Pos.S5A:H3.interp "-leg=spec=Transient Correction" \
          -end \
          -col=TimeIndex,Current??? -leg "-topline=Transient Correction" $outputRoot.hcorr1.adj -file -end \
          -col=TimeIndex,Current??? -leg "-topline=Transient Correction" $outputRoot.hcorr2.adj -file -end \
          \
          -col=t,S5A:V3:Error $tmpfile.Neg.2 "-topline=S5A:V3 Neg" -leg=spec=Original \
          -col=t,CurrentNeg $tmpfile.Neg.S5A:V3.interp "-leg=spec=Transient Correction" \
          -end \
          -col=t,S5A:V3:Error $tmpfile.Pos.2 "-topline=S5A:V3 Pos" -leg=spec=Original \
          -col=t,CurrentPos $tmpfile.Pos.S5A:V3.interp "-leg=spec=Transient Correction" \
          -end \
          -col=TimeIndex,Current??? -leg "-topline=Transient Correction" $outputRoot.vcorr1.adj -file -end \
          -col=TimeIndex,Current??? -leg "-topline=Transient Correction" $outputRoot.vcorr2.adj -file -end \
          &
    }

    APSSetVarAndUpdate ControlStatus "Processing done."
    return
}

proc AverageCorrectorErrorData {args} {
    global period hperiod1 transientSection smoothPoints smoothPasses
    set inputFile ""
    APSStrictParseArguments {inputFile}
    set tmpfile /tmp/[APSTmpString]

    if [catch {exec sddsprocess $inputFile  -pipe=out \
                 "-def=col,Period,t $period / int,type=long" \
                 | sddsfdfilter -pipe \
                 -col=t,*Error -notch=center=60,flat=8 -cascade -notch=center=120,flat=8 \
                 | sddsbreak -pipe \
                 -increaseof=Period \
                 | sddsconvert -pipe \
                 -keeppages=5 \
                 | sddsenvelope -pipe \
                 -mean=S*\[HV\]*Error -copy=Index,t \
                 | sddsprocess -pipe \
                 -process=t,first,tFirst \
                 -process=Index,first,IndexFirst \
                 "-redef=col,Index,Index IndexFirst -" \
                 "-redef=col,t,t tFirst -" \
                 | sddsxref -pipe $inputFile \
                 -transfer=para,Comment,TickTime,MainCurrent \
                 -leave=* \
                 | sddsconvert -pipe=in $tmpfile \
                 -edit=col,*Mean*,%/Mean// \
             } result ] {
        return -code error "AverageCorrectorErrorData: $result"
    }
    if [catch {exec sddsprocess $tmpfile -pipe=out -filt=col,t,0,$transientSection \
                 | sddssmooth -pipe=in $tmpfile.out1 -col=S*
               exec sddsprocess $tmpfile -pipe=out -filt=col,t,0,$transientSection,! \
                 | sddsprocess -pipe -filt=col,t,$transientSection,$hperiod1 \
                 | sddssmooth -pipe=in $tmpfile.out2 -col=S* -points=$smoothPoints -pass=$smoothPasses -noWarnings
               set t1 [expr $hperiod1 + $transientSection]  
               exec sddsprocess $tmpfile -pipe=out -filt=col,t,0,$hperiod1,! \
                 | sddsprocess -pipe -filt=col,t,$hperiod1,$t1 \
                 | sddssmooth -pipe=in $tmpfile.out3 -col=S* 
               exec sddsprocess $tmpfile -pipe=out -filt=col,t,0,$t1,! \
                 | sddsprocess $tmpfile -pipe=out -filt=col,t,$t1,$period \
                 | sddssmooth -pipe=in $tmpfile.out4 -col=S* -points=$smoothPoints -pass=$smoothPasses -noWarnings
               exec sddscombine $tmpfile.out1 $tmpfile.out2 $tmpfile.out3 $tmpfile.out4 \
                 -merge -over $inputFile.ave
              } result ] {
        return -code error "AverageCorrectorErrorData: $result"
    }
    return
}

# Procedure to plot the most recent cpu data.

proc PlotMostRecentCPUData {args} {

    global ControlStatus Title Delay

    APSStrictParseArguments {statusCallback}
    set mostRecentFile [lindex [lsort [glob ??????-s*s*-*s.sdds]] end]
    
    catch {regexp {(......)-s.*s.*-.*s.sdds} $mostRecentFile {} root}

    if ![string length $root] {
        if {$statusCallback!=""} {
            $statusCallback "You must give a valid rootname."
        }
        APSAlertBox .alert -errorMessage "You must give a valid rootname."
        return 0
    }

    catch {exec sddsplot -lay=2,2 -title= \
             -limit=xmin=[expr 0.0 + $Delay],xmax=[expr 0.4 + $Delay]\
             -topline=$root \
             -col=t,(S*H*Error,S*V*Error) -sep -mode=y=offset \
             -same $root-s4s5-2.4s.sdds \
             -title=[APSMakeSafeQualifier $Title] -end \
             -col=t,(S*H3,S*V3) -sep -mode=y=offset \
             -same $root-s4s5-2.4s.sdds \
             "-title=$Title" -end &}
}

proc PlotCPUData {args} {

    global ControlStatus Title Delay plotDirectory
    
    APSParseArguments {title delay statusCallback}
    
    set fileList [glob ??????-s*s*-*s.sdds]
    set itemList ""
    foreach file $fileList {
        catch {regexp {(......)-s.*s.*-.*s.sdds} $file {} root}
        lappend itemList $root
    }

    set selectFile [APSChooseItemFromList \
                      -name "Raw Data Selection" \
                      -itemList $itemList \
                      -returnList $fileList \
                      -returnIndices 0 \
                      -multiItem 0 \
                      -contextHelp "Select a CPU data file to plot"]

    catch {regexp {(......)-s.*s.*-.*s.sdds} $selectFile {} root}

    exec sddsplot -lay=2,2 -title= \
      -limit=xmin=[expr 0.0 + $Delay],xmax=[expr 0.4 + $Delay]\
      -topline=$root \
      -col=t,(S*H*Error,S*V*Error) -sep -mode=y=offset \
      -same ${selectFile} \
      -title=$Title -end \
      -col=t,(S*H3,S*V3) -sep -mode=y=offset \
      -same ${selectFile} \
      "-title=$Title" -end \
      &
}

proc FindBracketingPageIndices {args} {
    set baseFile ""
    set inputfile ""
    APSStrictParseArguments {baseFile inputFile}

    if ![file exists $baseFile] {
        return -code error "FindBracketingPageIndices: File $baseFile does not exist!"
    }
    if ![file exists $inputFile] {
        return -code error "FindBracketingPageIndices: File $inputFile does not exist!"
    }

    set valueList [exec sdds2stream -param=MainCurrent $baseFile]
    set targetValue [exec sdds2stream -param=MainCurrent $inputFile]
    if {[llength $targetValue] > 1} {
        return -code error "FindBracketingPageIndices: Found more than on page in $inputFile"
    }
    if {$targetValue < [lindex $valueList 0]} {
        # value is lower than the first page value
        return [list 0 1]
    }
    for {set i 0} {$i < [llength $valueList]} {incr i} {
        if {[lindex $valueList $i] == $targetValue } {
            # page numbers are numbered starting with 1
            incr i
            return [list $i $i]
        }
        if {[lindex $valueList $i] < $targetValue && \
              $targetValue < [lindex $valueList [expr $i + 1]]} {
            incr i
            return [list $i [expr $i + 1]]
        }
    }
    if {$targetValue > [lindex $valueList end]} {
        # value is higher than the last page value
        # then return the last page.
        return [list [llength $valueList] [llength $valueList]]
    }
    return -code error "FindBracketingPageIndices: Target value of $targetValue was not found in list $valueList."
}

# Build Application

MakeCPUStatus
MakeCPUMeasureWidget .setup -parent .userFrame
MakeCPUProcessWidget .proc -parent .userFrame
MakeCPUModWaveformWidget .mod -parent .userFrame
MakeCPUUndoWaveformWidget .udw -parent .userFrame

set configFile /home/helios/oagData/sr/RTFB/monitorFiles/S4S5CorrError.dspscope
set scalarsFile /home/helios/oagData/sr/RTFB/monitorFiles/SRFBTrigReadStatus.monitor

set index -1
set root corrError
set comment test
set outputVersion 0
set outputRoot [clock format [clock seconds] -format "%y%m%d"]

set startTime 0.000
set firstWaveform Neg
set period 0.5000
set hperiod1 0.202
set tauH 0.004
set tauV 0.0005
set outputDir .
set abort 0
set gain 1.0
set debugPlotLevel 0
set average 4

# mapping from RTFB to CPU corrector. Normally we don't use this.
set hmap(corr1.S4) 4.51
set hmap(corr1.S5) 3.06
set hmap(corr2.S4) -2.58
set hmap(corr2.S5) -0.32

set vmap(corr1.S4) 1.265
set vmap(corr1.S5) 0.14
set vmap(corr2.S4) -0.28
set vmap(corr2.S5) 1.58
set useMapping first

set equalTransients 0
set averageChannels 0

set smoothPoints 3
set smoothPasses 1
set propagate 0
#For some reason, these are the new timing values.
set startTime 0.000
set hperiod1 0.193
set transientSection 0.050
#For undo loadedFile
if [catch {exec cavget -list=ID04b:corrFile_ -list=1,2,3,4} loadedFiles] {
    return -code error "Apply: $loadedFile"
}
set loadedFile(vcorr2) [lindex $loadedFiles 0]
set loadedFile(hcorr2) [lindex $loadedFiles 1]
set loadedFile(hcorr1) [lindex $loadedFiles 2]
set loadedFile(vcorr1) [lindex $loadedFiles 3]

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