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



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

set setupDir /home/helios/oagData/monitorFiles/sr
set archiveDir /home/helios/oagData/sr/slowBHArchive

set outputDir [pwd]
set outputDir [exec editstring $outputDir -edit=S/helios/z/i/helios/]
set outputFilename ""
set outputRoot slowBH
set lastOutputRoot ""
set userComment ""
set outputIndex -1
set historyBufferSize 4080
set acquisitionPlane *
set latestXValue ?
set latestYValue ?
set latestUpdateTime ?

set lastOutputFile ""
set archivalBPM B:P1

proc MakeOutputFileName {} {
    global outputDir outputFilename outputRoot lastOutputRoot outputIndex
    global applicationMode archiveDir
    set clockSecs [clock seconds]
    if [string compare $applicationMode archival]==0 {
        set parentDir $archiveDir/[clock format $clockSecs -format %Y-%m%d]
        if ![file exists $parentDir] {
            if [catch {file mkdir $parentDir 
                file attributes $parentDir -permissions 00775 } result] {
                setStatusText "Problem making data directory: $result"
                return
            }
        }
        set outputDir $parentDir/[clock format $clockSecs -format %H%M%S]
        if ![file exists $outputDir] {
            if [catch {file mkdir $outputDir} result] {
                setStatusText "Problem making data directory: $result"
                return
            }
        }
        return $outputDir/slowBH.sdds
    }
    if {![file exists $outputDir] || ![file isdirectory $outputDir]} {
        setStatusText "$outputDir is not a directory."
        return
    }
    if [string length $outputFilename] {
        return $outputDir/$outputFilename
    } else {
        if [string compare $outputRoot $lastOutputRoot]==0 {
            scan $outputIndex %ld outputIndex
            incr outputIndex
        } else {
            set outputIndex 0
        }
        set lastOutputRoot $outputRoot
        while 1 {
            # find index that isn't being used yet
            set filename $outputDir/${outputRoot}-[format %03ld $outputIndex].sdds
            if ![file exists $filename] {
                return $filename
            }
            incr outputIndex
        }
    }
}

proc MakeFileEntryFrame {widget args} {
    set parent ""
    APSStrictParseArguments {parent}
    APSFrame $widget -parent $parent -label "Output Specification"
    set w $parent$widget.frame
    global outputDir outputFilename outputRoot outputIndex lastOutputRoot userComment

    APSLabeledEntry .dir -parent $w -textVariable outputDir \
      -label "Directory: " -width 70 \
      -contextHelp "Enter the name of the directory in which data files will be written."
    APSLabeledEntry .file -parent $w -textVariable outputFilename \
      -label "Filename: " -width 70 \
      -contextHelp "Enter the name of a file to which to write data.  Used only if the rootname below is blank."
    APSLabeledEntry .root -parent $w -textVariable outputRoot \
      -label "Rootname: " -width 70 \
      -contextHelp "Enter the root name for automatic filename generation.  If blank, the filename above is used."
    APSLabeledEntry .comment -parent $w -textVariable userComment \
      -width 70 -label "Comment: " -contextHelp \
      "Enter a comment to be placed in the files with the data."

    APSFrameGrid .outSpec -parent $w -xList {x1 x2} -yList {y1}
    APSButton .daily -parent $w.outSpec.x1.y1 -packOption "-side bottom" \
	-text "Go to daily directory" \
        -command {set outputDir [APSGoToDailyDirectory -subdirectory slowBH]} \
	-contextHelp "Setting daily directory in which to put data files."

    frame $w.outSpec.x2.y1.indexfr
    pack $w.outSpec.x2.y1.indexfr -side bottom
    set wi $w.outSpec.x2.y1.indexfr
    APSLabeledEntry .index -parent $wi -textVariable outputIndex \
      -label "Index: " -width 10 -packOption "-expand 1 -side left" \
      -contextHelp "Shows the file index for automatic filename generation for the last file.  Used in conjunction with the rootname."
    APSButton .reset -parent $wi -text "RESET" -size small \
      -command "set outputIndex -1" -packOption "-side right" \
      -contextHelp "Use to reset the index counter for automatic filename generation."
    
}

proc MakeBPMEntryFrame {widget args} {
    set parent ""
    APSStrictParseArguments {parent}
    APSFrame $widget -parent $parent -label "BPM/Sector Selection" 
    set w $parent$widget.frame
    lappend gridList f1 f2 f3 f4
    APSFrameGrid .fg -parent $w -xList "$gridList"
    for {set sector 1} {$sector<41} {incr sector} {
        set gridListIndex [expr int(($sector-1)/10)]
        global S${sector}BPM 
        APSLabeledEntry .e$sector -parent $w.fg.[lindex $gridList $gridListIndex] \
          -label "S${sector}: " \
          -width 6 -textVariable S${sector}BPM -contextHelp \
          "Enter the BPM that you want to acquire data for for sector $sector.  A blank entry means no acquisition for this sector."
    }
    APSButton .clear -parent $w -text CLEAR \
      -contextHelp "Clears sector value in the entry boxes above." \
      -command {SetAllSectors ""}
    set index 0
    foreach BPM {A:P1 A:P2 A:P3 A:P4 B:P5 B:P4 B:P3 B:P2 B:P1} {
        APSButton .bpm$index -parent $w -text $BPM \
          -command "SetAllSectors $BPM" \
          -contextHelp "Press to set all sectors for $BPM acquisition."
        incr index
    }
}

proc MakeHardwareSettingsFrame {widget args} {
    set parent ""
    APSStrictParseArguments {parent}
    APSFrame $widget -parent $parent -label "BPM and History Settings"
    set w $parent$widget.frame
    APSLabeledEntry .bufsize -parent $w -label "Buffer size: " \
      -textVariable historyBufferSize -width 6 \
      -contextHelp "Enter the desired history buffer size (up to 4080)"
    
}

proc MakeAcquisitionSettingsFrame {widget args} {
    global acquisitionPlane ""
    set parent ""
    APSStrictParseArguments {parent}
    APSFrame $widget -parent $parent -label "Acquisition Settings"
    set w $parent$widget.frame
    APSRadioButtonFrame .xymode -parent $w -label "Planes" \
      -orientation vertical -variable acquisitionPlane \
      -buttonList {both "x only" "y only"} \
      -valueList {* x y} \
      -contextHelp "Select acquisition of both planes, or one plane by itself.  This is not the same as setting the toggle mode on the BPMs."
}


proc MakeAdvancedButtonsFrame {widget args} {
    set parent ""
    APSStrictParseArguments {parent}

    APSFrameGrid $widget -parent $parent -yList {y1 y2}
    set parent $parent$widget
    APSButton .target -parent $parent.y1 -text TARGET \
      -contextHelp "Targets histories to read the BPMs specified.  Done automatically by ACQUIRE." \
      -command SetHistoryTargets 
    APSButton .configure -parent $parent.y1 -text CONFIGURE \
      -contextHelp "Configures the BPMs to prepare for data acquisition.  Done automatically by ACQUIRE." \
      -command ConfigureHistorySectors
    APSButton .acquire -parent $parent.y1 -text ACQUIRE \
      -contextHelp "Targets the beam histories, configures BPMs, and acquires data." \
      -command AcquireSlowHistories

    APSButton .plot -parent $parent.y2 -text "t PLOT" \
      -contextHelp "Plots the last set of data acquired, or the data named explicitly." \
      -command "PlotLastSlowHistories -quickSDDSplot 0"
    APSButton .qplot1 -parent $parent.y2 -text "quickSDDSplot vs t" \
      -contextHelp "Launches quickSDDSplot for the time series data." \
      -command "PlotLastSlowHistories -quickSDDSplot 1"
    APSButton .fftplot -parent $parent.y2 -text FFT/PLOT \
      -contextHelp "FFTs and plots the last set of data acquired, or the data named explicitly." \
      -command "FFTPlotLastSlowHistories FFT"
    APSButton .psdplot -parent $parent.y2 -text PSD/PLOT \
      -contextHelp "PSDs and plots the last set of data acquired, or the data named explicitly." \
      -command "FFTPlotLastSlowHistories PSD"
    APSButton .qplot2 -parent $parent.y2 -text "quickSDDSplot vs f" \
      -contextHelp "Launches quickSDDSplot for the FFT of the data." \
      -command "FFTPlotLastSlowHistories QP"
}

set showArchiveContourPlot 0
set plotFrequencyMode lin
proc MakeArchivalButtonsFrame {widget args} {
    set parent ""
    APSStrictParseArguments {parent}
    global AcquireArchivalDataButton AcquireContinuousButton StopContinuousButton

    APSFrame .basic -parent $parent -label "Basic Operations"
    set w $parent.basic.frame
    APSButton .acquire -parent $w -text Acquire/Analyze \
      -contextHelp "Configures BPMs and acquires data for all sectors." \
      -command AcquireArchivalData
    set AcquireArchivalDataButton $w.acquire.button
    APSButton .analyze -parent $w -text "Analyze/Plot Last" \
      -contextHelp \
      "Analyzes the last data acquired, if needed.  Subsequently plots the results of the analysis." \
      -command {AnalyzeArchivalData -lastFile 1} 
    APSButton .continuous -parent $w -text "Continuous Run" \
      -command CollectContinuousRMSData \
      -contextHelp \
      "Continuously acquires data for selected sectors and computes RMS x and y motion. The results are written to process variables and displayed in the status area of this application."
    set AcquireContinuousButton $w.continuous.button
    APSButton .stopcontin -parent $w -text "Stop Continuous Run" \
      -command {set abortContinuousDataCollection 1; bell} -contextHelp \
      "Aborts continuous collection of slow beam history data and computation of RMS motion."
    set StopContinuousButton $w.stopcontin.button
    APSDisableButton $StopContinuousButton

    APSFrame .basic2 -parent $parent -label "History Plot" 
    set w $parent.basic2.frame
    global StartYear StartMonth StartDay StartHour EndYear EndMonth EndDay EndHour
    APSDateTimeAdjEntry .startDate -parent $w \
      -yearVariable StartYear -monthVariable StartMonth \
      -dayVariable StartDay -hourVariable StartHour \
      -label "Starting date/time (year, month, day, hour): " -defaultHour 0 
    APSDateTimeAdjEntry .endDate -parent $w \
      -yearVariable EndYear -monthVariable EndMonth \
      -dayVariable EndDay -hourVariable EndHour \
      -label "Ending date/time (year, month, day, hour):   " -defaultHour 24 
    APSIncrementDateVariables -offset -30 -unit day \
      -dayVariable StartDay -yearVariable StartYear \
      -monthVariable StartMonth
    set StartHour 0
    set EndHour 24

    APSButton .history -parent $w -text "Plot RMS History" \
      -command PlotRMSHistory -contextHelp \
      "Shows the history of the x and y RMS values."

    APSFrame .review -parent $parent -label "Review PSDs" 
    set w $parent.review.frame
    APSFrame .opt -parent $w -label "" -relief flat
    set wo $w.opt.frame
    APSRadioButtonFrame .rb -parent $wo -label "Show contour plot" -variable \
      showArchiveContourPlot -buttonList {Yes No} -valueList {1 0} -orientation \
      horizontal -packOption "-side left" -contextHelp \
      "Requests showing a color contour plot of the PSDs.  Takes a little while."
    APSRadioButtonFrame .rb2 -parent $wo -label "  Show log frequency" -variable \
      plotFrequencyMode -buttonList {Yes No} -valueList {log lin} -orientation \
      horizontal -contextHelp \
      "Requests showing the frequency axis on a logarithmic scale."
    APSDateTimeAdjEntry .dt -parent $w -dayVariable reviewDay \
      -yearVariable reviewYear -monthVariable reviewMonth 
    APSButton .search -parent $w -text "Search" -command "SearchForArchivedData .slist -parent $parent" \
      -contextHelp "Search for archived PSD data for the given date."

    APSFrame .latest -parent $parent -label "Latest Values from Continuous Mode"
    set w $parent.latest.frame
    APSLabeledOutput .time -parent $w -label "Latest Update: " \
      -textVariable latestUpdateTime  -width 30
    APSLabeledOutput .x -parent $w -label "Latest x RMS (um): " \
      -textVariable latestXValue
    APSLabeledOutput .y -parent $w -label "Latest y RMS (um): " \
      -textVariable latestYValue

}

proc doRunControlPinging {args} {
    global runControl haltRunControlPinging runControlLevel
    set once 0
    APSParseArguments {once}
    if !$runControl return
    if !$runControlLevel return
    if [catch {APSRunControlPing} result] {
        if !$haltRunControlPinging {
            APSDeleteTempFiles 
            APSAlertBox [APSUniqueName .] -errorMessage \
              "This application is being denied permission to run the slow beam histories: $result."
            catch {APSRunControlExit}
            catch {blt::bgexec dummy cavput -pendIOTime=5 -list=SR: \
                -list=x,y -list=RMS:30HzAI=0}
            exit
        }
    }
    if !$once {
        if !$haltRunControlPinging {
            after 1000 doRunControlPinging
        }
    }
}

set runControlLevel 0
proc startSlowHistoryRC {args} {
    set statusCallback APSNoOp
    APSStrictParseArguments {statusCallback}
    
    global runControl runControlPV haltRunControlPinging runControlLevel
    if {$runControl} {
        if ![catch {APSRunControlPing}] {
            incr runControlLevel
            return 1
        }
        if [catch {APSRunControlInit -pv $runControlPV -description \
                     SRAcquireSlowHistory -timeout 30000} result] {
            eval $statusCallback {"Unable to acquire RunControl permission."}
            eval $statusCallback {"Reason: $result"}
            return 0
        }
        incr runControlLevel
        set haltRunControlPinging 0
        after 1000 doRunControlPinging
    }
    return 1
}

proc stopSlowHistoryRC {} {
    global runControl runControlLevel haltRunControlPinging 
    if $runControl {
        incr runControlLevel -1
        if !$runControlLevel {
            set haltRunControlPinging 1
            catch {APSRunControlExit}
        }
    }
    catch {blt::bgexec dummy cavput -pendIOTime=5 -list=SR: \
             -list=x,y -list=RMS:30HzAI=0}
    global latestUpdateTime latestXValue latestYValue
    set latestUpdateTime ?
    set latestXValue ?
    set latestYValue ?
}

# using realtime orbit feedback system rms motion bpm enables (in y-plane) to 
# determine list of archival bpm.
set values [exec cavget -numerical \
              -list=SRFB:S -range=beg=1,end=40 -list=B:P1:y:IncludeInRmsC \
              -labeled -embrace]
set archivalBPMList ""
for {set index 0} {$index<40} {incr index} {
    if {[lindex [lindex $values $index] 1]} {
        regexp {SRFB:(S.*B:P1)} [lindex [lindex $values $index] 0] {} bpm
        lappend archivalBPMList $bpm
    }
}

proc CollectContinuousRMSData {} {
    global abortContinuousDataCollection AcquireContinuousButton StopContinuousButton
    global AcquireArchivalDataButton 
    global latestUpdateTime latestXValue latestYValue
    global archivalBPMList 
    if {![startSlowHistoryRC -statusCallback setStatusText]} {
        return
    }
    APSDisableButton $AcquireContinuousButton
    APSDisableButton $AcquireArchivalDataButton
    APSEnableButton $StopContinuousButton
    set tmpFile /tmp/[APSTmpString]
    APSAddToTempFileList $tmpFile
    set abortContinuousDataCollection 0
    setStatusText "Beginning continuous data collector for [llength $archivalBPMList] sectors"

    while {!$abortContinuousDataCollection} {
        doRunControlPinging -once 1
        if [catch {APSSRAcquireSlowHistories -excludeScalars 1 \
                     -BPMList $archivalBPMList \
                     -outputFile $tmpFile -abortVariable abortContinuousDataCollection \
                     -statusCallback setStatusText} result] {
            setStatusText "$result"
            break
        }
        doRunControlPinging -once 1
        setStatusText "Processing data."
        if [catch {APSProcessSlowHistoryData -inputFile $tmpFile \
                     -rmsOnly 1 } rmsList] {
            setStatusText "$rmsList"
            break
        }
        doRunControlPinging -once 1
        if [catch {blt::bgexec dummy cavput -pendIOTime=5 -list=SR: \
                     -list=x=[lindex $rmsList 0],y=[lindex $rmsList 1] \
                     -list=RMS:30HzAI} result] {
            setStatusText "$result"
            break
        }
        doRunControlPinging -once 1
        set latestUpdateTime [clock format [clock seconds]]
        set resultx ""
        set resulty ""
        if {[catch {set latestXValue [format %10.3f [lindex $rmsList 0]]} resultx] || \
            [catch {set latestYValue [format %10.3f [lindex $rmsList 1]]} resulty]} {
            bell
            setStatusText "Data is invalid: $resultx $resulty"
            setStatusText "Consider using another workstation."
        }
        update
        APSDeleteTempFiles
    }
    APSDeleteTempFiles
    stopSlowHistoryRC
    setStatusText "Data collection terminated."
    APSEnableButton $AcquireContinuousButton
    APSEnableButton $AcquireArchivalDataButton
    APSDisableButton $StopContinuousButton
}

proc AcquireArchivalData {} {
    global lastOutputFile archivalBPM archiveDir AcquireArchivalDataButton
    global AcquireContinuousButton StopContinuousButton

    if {![startSlowHistoryRC -statusCallback setStatusText]} {
        return
    }
    setStatusText "Setting up to acquire $archivalBPM for all sectors..."
    SetAllSectors $archivalBPM

    APSDisableButton $AcquireArchivalDataButton
    APSDisableButton $AcquireContinuousButton
    if {![AcquireSlowHistories]} {
        APSEnableButton $AcquireArchivalDataButton
        APSEnableButton $AcquireContinuousButton
        stopSlowHistoryRC
        return 0
    }
    doRunControlPinging -once 1
    if {[file exists $archiveDir/lastDataDir] && \
          [catch {file delete -force $archiveDir/lastDataDir} result]} {
        setStatusText $result
        APSEnableButton $AcquireArchivalDataButton
        APSEnableButton $AcquireContinuousButton
        stopSlowHistoryRC
        return 0
    }
    doRunControlPinging -once 1
    if [catch {blt::bgexec dummy ln -s [file dirname $lastOutputFile] $archiveDir/lastDataDir 
        file attributes [file dirname $lastOutputFile] -permissions 00775} result] {
        setStatusText $result
        APSEnableButton $AcquireContinuousButton
        APSEnableButton $AcquireArchivalDataButton
        stopSlowHistoryRC
        return 0
    }
    stopSlowHistoryRC
    if ![AnalyzeArchivalData -fileName $lastOutputFile] {
        APSEnableButton $AcquireContinuousButton
        APSEnableButton $AcquireArchivalDataButton
        stopSlowHistoryRC
        return 0
    }
    APSEnableButton $AcquireContinuousButton
    APSEnableButton $AcquireArchivalDataButton
    return 1
}

proc SearchForArchivedData {widget args} {
    set parent ""
    APSStrictParseArguments {parent}

    global reviewDay reviewYear reviewMonth archiveDir
    set dirName $archiveDir/$reviewYear-[format %02ld%02ld $reviewMonth $reviewDay]
    if ![file exists $dirName] {
        setStatusText "No data for that day ($dirName)."
        return 0
    }
    set oldDir [pwd]
    cd $dirName
    set dirList [lsort [glob -nocomplain \[0-9\]\[0-9\]\[0-9\]\[0-9\]\[0-9\]\[0-9\]]]
    cd $oldDir
    if ![llength $dirList] {
        setStatusText "No data for that day."
        return 0
    }

    set HMSList ""
    foreach elem $dirList {
        lappend HMSList [string range $elem 0 1]:[string range $elem 2 3]:[string range $elem 4 5]
    }

    if [winfo exists $parent$widget] {
        destroy $parent$widget
    }

    APSScrolledList $widget -parent $parent -packOption "-side bottom" \
      -name "PSD choices for $reviewMonth/$reviewDay/$reviewYear" \
      -itemList $HMSList -callback ReviewArchivedPSD \
      -contextHelp "List of PSD files for $reviewMonth/$reviewDay/$reviewYear.  Double-click to review a file.  The numbers give the time of the dumps in hours, minutes, and seconds."

}

proc ReviewArchivedPSD {HMSItem doubleClick} {
    global reviewDay reviewMonth reviewYear archiveDir showArchiveContourPlot plotFrequencyMode
    if !$doubleClick {
        return
    }
    setStatusText "Working on $HMSItem"
    regsub -all : $HMSItem "" HMS
    set fileName $archiveDir/$reviewYear-[format %02ld%02ld $reviewMonth $reviewDay]/$HMS/slowBH.sdds
    if ![file exists $fileName] {
        set fileName $fileName.gz
        if ![file exists $fileName] {
            setStatusText "Not found: $fileName (ReviewArchivedPSD)"
            return
        }
    }
    AnalyzeArchivalData -fileName $fileName -contourPlot $showArchiveContourPlot -frequencyMode $plotFrequencyMode
}

proc PlotRMSHistory {} {
    global archiveDir
    global StartYear StartMonth StartDay StartHour EndYear EndMonth EndDay EndHour
    set fileName $archiveDir/slowBH.history
    if ![file exists $fileName] {
        setStatusText "Not found: $fileName (PlotRMSHistory)"
        return 0
    }
    if [catch {APSConvertTimeToHours $StartHour} hour] {
        setStatusText "Invalid starting hour: $StartHour"
        return 0
    }
    set StartTime \
      [blt::bgexec dummy timeconvert \
         -breakDown=year=$StartYear,day=$StartDay,month=$StartMonth,hour=$hour]
    if [catch {APSConvertTimeToHours $EndHour} hour] {
        setStatusText "Invalid ending hour: $EndHour"
        return 0
    }
    set EndTime \
      [blt::bgexec dummy timeconvert \
         -breakDown=year=$EndYear,day=$EndDay,month=$EndMonth,hour=$hour]

    setStatusText "Plotting... [clock format [clock seconds] -format %H:%M:%S]"
    blt::bgexec dummy sddsplot -column=StartTime,(xRMS,yRMS) -graph=sym,vary=subtype \
      -filter=column,Time,$StartTime,$EndTime \
      -legend=edit=%/RMS//,scale=2 \
      -limit=ymax=0.10 \
      -ticks=xtime $fileName -unsuppress=y -labelsize=0.03 -title= \
      "-ylabel=edit=z\\\(i/RMS Beam Motion /" &
}

proc AnalyzeArchivalData {args} {
    set fileName ""
    set lastFile ""
    set contourPlot 0
    set frequencyMode lin
    APSStrictParseArguments {fileName lastFile contourPlot frequencyMode} 
    global archiveDir
    if [string length $lastFile] {
        set fileName $archiveDir/lastDataDir/slowBH.sdds.gz
    }
    if {[string length $fileName]==0 || ![file exists $fileName]} {
        setStatusText "Not found: >$fileName< (AnalyzeArchivalData)"
        return 0
    }
    set psdFile [file rootname $fileName].psd
    if ![file exists $psdFile] {
        setStatusText "Analyzing...[clock format [clock seconds] -format %H:%M:%S]"
        if [catch {blt::bgexec dummy sddsfft $fileName -pipe=out -column=t,*:* -psd \
                     -suppressaverage \
                     | sddsconvert -pipe -delete=column,FFT* \
                     | sddsxref -pipe $fileName -leave=* -transfer=parameter,* \
                     | sddsrowstats -pipe -mean=xPSD,PSD*x -mean=yPSD,PSD*y \
                     | sddsconvert -pipe -delete=column,PSD* \
                     | sddsprocess -pipe=in $psdFile \
                     -process=*PSD,sum,%sSum \
                     "-redefine=column,xPSD,xPSD,units=mm\$a2\$n/Hz,symbol=" \
                     "-redefine=column,yPSD,yPSD,units=mm\$a2\$n/Hz,symbol=" \
                     "-define=parameter,xRMS,xPSDSum fftFrequencySpacing * sqrt,units=mm" \
                     "-define=parameter,yRMS,yPSDSum fftFrequencySpacing * sqrt,units=mm" \
                     "-define=parameter,xRMSum,xRMS 1e3 *,units=um" \
                     "-define=parameter,yRMSum,yRMS 1e3 *,units=um" \
                     "-print=parameter,xLabel,RMS x motion is %.3lfum,xRMSum" \
                     "-print=parameter,yLabel,RMS y motion is %.3lfum,yRMSum" \
                 } result] {
            setStatusText "Error processing data: $result"
            return 0
        }
        if [catch {blt::bgexec dummy sddsprocess $psdFile -noWarning \
                     -ifis=para,HLoopGlobalStatus \
                     -print=parameter,xFBStatus,%.0lf,HLoopGlobalStatus \
                     -print=parameter,yFBStatus,%.0lf,VLoopGlobalStatus \
                     -reedit=parameter,xFBStatus,%/0/Off/%/1/On/ \
                     -reedit=parameter,yFBStatus,%/0/Off/%/1/On/ \
                     "-reprint=parameter,xLabel,%s Feedback %s,xLabel,xFBStatus" \
                     "-reprint=parameter,yLabel,%s Feedback %s,yLabel,yFBStatus" \
                 } result] {
            setStatusText "Error processing data: $result"
            return 0
        }
        catch {file delete ${psdFile}~}
        if [catch {blt::bgexec dummy sdds2stream -parameter=xRMS,yRMS $psdFile} rmsResults] {
            setStatusText "Error processing data: $result"
            return 0
        }
        if {[lindex $rmsResults 0]==0 || [lindex $rmsResults 1]==0} {
            setStatusText "Error width data collection---no motion detected---data removed."
            catch {eval file delete -force $psdFile $fileName [file dirname $fileName]}
            return 0
        }
        set tmpFile /tmp/[APSTmpString]
        if [catch {blt::bgexec dummy sddscollapse $psdFile $tmpFile} result] {
            setStatusText "Error processing data: $result"
            return 0
        }
        set rmsFile $archiveDir/slowBH.history 
        if [file exists $rmsFile] {
            if [catch {blt::bgexec dummy sddscombine $rmsFile $tmpFile  -pipe=out -merge \
                         | sddssort -pipe=in $tmpFile.1 \
                         -col=StartTime -unique
                file delete $rmsFile 
                file copy $tmpFile.1 $rmsFile} result] {
                setStatusText "Error processing data: $result"
                return 0
            }
        } else {
            if [catch {file copy $tmpFile $rmsFile} result] {
                setStatusText "Error processing data: $result"
                return 0
            }
        }
        catch {file attributes $rmsFile -permissions 00664}
        catch {file delete $tmpFile $tmpFile.1}
    }
    setStatusText "Plotting...[clock format [clock seconds] -format %H:%M:%S]"
    blt::bgexec dummy sddsplot -layout=1,2 -mode=y=log,y=special,x=${frequencyMode},x=special -labelsize=0.035 \
      -title= -topline= -graph=line,type=1 \
      -column=f,xPSD $psdFile -topline=@TimeStamp \
      -string=@xLabel,p=.95,q=.95,just=rc -end \
      -column=f,yPSD $psdFile -string=@yLabel,p=.95,q=.95,just=rc  &

    if $contourPlot  {
        set timeStamp [blt::bgexec dummy sdds2stream -parameter=TimeStamp $psdFile -noquotes]
        setStatusText "FFTing data..."
        set fftFile /tmp/[APSTmpString]
        APSAddToTempFileList $fftFile
        blt::bgexec dummy sddsfft $fileName -pipe=out -column=t,*:*  -psd -suppressaverage \
        | sddsxref $fileName -pipe=in $fftFile -transfer=param,* -leave=*
        setStatusText "Plotting..."
        set floor 1e-6
        blt::bgexec dummy sddscontour -shade=16 -column=f,PSD*:*x -log=$floor $fftFile \
          -ystrings=edit=%/PSD// "-topline=Data from $timeStamp" &
        blt::bgexec dummy sddscontour -shade=16 -column=f,PSD*:*y -log=$floor $fftFile \
          -ystrings=edit=%/PSD// "-topline=Data from $timeStamp" &
    }

    return 1
}

proc SetAllSectors {BPM} {
    for {set sector 1} {$sector<41} {incr sector} {
        global S${sector}BPM 
        set S${sector}BPM $BPM
    }
}

proc SetHistoryTargets {} {
    if {![startSlowHistoryRC -statusCallback setStatusText]} {
        return
    }
    global FPGAsectorList
    set BPMList {}
    doRunControlPinging -once 1
    for {set sector 1} {$sector<41} {incr sector} {
        global S${sector}BPM 
        if [lsearch -exact $FPGAsectorList $sector]<0 {
            if [string length [subst \$S${sector}BPM]] {
                lappend BPMList S:bpm${sector}=S${sector}[subst \$S${sector}BPM]
            }
        }
    }
    doRunControlPinging -once 1
    if ![llength $BPMList] {
        setStatusText "No BPM names given."
        stopSlowHistoryRC
        return 0
    } else {
        eval blt::bgexec dummy cavput -list=[join $BPMList ,] -list=:SlowBh:MI.VAL \
          -pendIoTime=30
        stopSlowHistoryRC
        return [llength $BPMList]
    }
}

proc ConfigureHistorySectors {} {
    if {![startSlowHistoryRC -statusCallback setStatusText]} {
        return
    }
    global historyBufferSize FPGAbpmList FPGAsectorList
    set BPMList {}
    set sectorList {}
    for {set sector 1} {$sector<41} {incr sector} {
        global S${sector}BPM 
        if [string length [subst \$S${sector}BPM]] {
            set bpm S${sector}[subst \$S${sector}BPM]
            if [lsearch -exact $FPGAbpmList $bpm]<0 {
                if [lsearch -exact $FPGAsectorList $sector]<0 {
                    lappend sectorList S:bpm$sector
                }
                lappend BPMList $bpm
            }
        }
    }
    doRunControlPinging -once 1
    if ![llength $BPMList] {
        setStatusText "No BPM names given."
        stopSlowHistoryRC
        return 0
    } else {
        if {[catch {blt::bgexec dummy cavput -list=S:bpm:memscan_wt_ao=11 \
                      -pendIoTime=30} result] || \
              [catch {doRunControlPinging -once 1} ] || \
              [catch {blt::bgexec dummy cavput -list=[join $BPMList ,] -list=:lock_bo=0 -pendIoTime=30} result] || \
              [catch {doRunControlPinging -once 1} ] || \
              [catch {blt::bgexec dummy cavput -list=[join $BPMList ,] -list=:disablex_bo=0,:disabley_bo=0 \
                        -pendIoTime=30} result]} {
            setStatusText "Error: $result"
            stopSlowHistoryRC
            return 0
        }
        doRunControlPinging -once 1
        if $historyBufferSize>4080 {
            set historyBufferSize 4080
        }
        if {[catch {blt::bgexec dummy cavput -list=[join $sectorList ,] \
                      -list=:SlowBh: -list=modeBO=1,enableBO=1,sizeAO=$historyBufferSize \
                      -pendIoTime=30} result] } {
            setStatusText "Error: $result"
            stopSlowHistoryRC
            return 0
        }
        stopSlowHistoryRC
        return [llength $BPMList]
    }
}

proc updateWaitingMessage {} {
    # setStatusText "Waiting for histories to fill...[clock format [clock seconds] -format %H:%M:%S]"
}

proc AcquireSlowHistories {args} {
    if {![startSlowHistoryRC -statusCallback setStatusText]} {
        return 0
    }
    global setupDir historyBufferSize userComment acquisitionPlane lastOutputFile
    global applicationMode RTFBScalars FPGAbpmList FPGAsectorList
    doRunControlPinging -once 1
    
    set outputFile [MakeOutputFileName]
    if ![string length $outputFile] {
        stopSlowHistoryRC
        return 0
    }
    if [file exists $outputFile] {
        setStatusText "Error: file exists:  [file rootname $outputFile]"
        stopSlowHistoryRC
        return 0
    }
    setStatusText "Output will go to $outputFile"
    setStatusText "Setting up BPM selection....[clock format [clock seconds] -format %H:%M:%S]"

    set BPMList {}
    set sectorList {}
    set selectionFile /tmp/[APSTmpString].1 

    set sFID [open $selectionFile w]
    puts $sFID "SDDS1\n&column name=BPMName type=string &end\n&data mode=ascii no_row_counts=1 &end"
    for {set sector 1} {$sector<41} {incr sector} {
        doRunControlPinging -once 1
        global S${sector}BPM 
        if [lsearch -exact $sectorList $sector]!=-1 {
            set S${sector}BPM ""
        } elseif [string length [subst \$S${sector}BPM]] {
            set bpm S${sector}[subst \$S${sector}BPM]
            if [lsearch -exact $FPGAbpmList $bpm]<0 {
                if [lsearch -exact $FPGAsectorList $sector]<0 {
                    lappend sectorList S:bpm$sector
                }
                lappend BPMList $bpm
                # output twice to get x and y plane 
                puts $sFID "S${sector}[subst \$S${sector}BPM]"
                puts $sFID "S${sector}[subst \$S${sector}BPM]"
            }
        }
    }
    close $sFID
    set inputFile /tmp/[APSTmpString].2
    if [catch {blt::bgexec dummy sddsxref $selectionFile $setupDir/SRAcquireSlowHistory.xref -pipe=out \
                 -match=BPMName \
                 | sddsprocess -pipe=in $inputFile \
                 -match=column,Plane=$acquisitionPlane \
                 -define=param,WaveformLength,$historyBufferSize,type=long} result] {
        setStatusText "Problem making input file: $result"
        stopSlowHistoryRC
        return 0
    }

    setStatusText "Configuring....[clock format [clock seconds] -format %H:%M:%S]"
    if {![SetHistoryTargets] || ![ConfigureHistorySectors]} {
        setStatusText "Problem configuring."
        stopSlowHistoryRC
        return 0
    }

    setStatusText "Triggering histories....[clock format [clock seconds] -format %H:%M:%S]"
    set Rate [blt::bgexec dummy cavget -list=S:bpm1:SlowBh:SampleRateAI,S:bpm1:SlowBh:SampleRateAI.EGU -delim=:]
    set RateUnits [lindex [split $Rate :] 1]
    set Rate [lindex [split $Rate :] 0]
    
    if [catch {blt::bgexec dummy cavput -list=[join $sectorList ,] -list=:SlowBh:ArmResetBO=1 -pend=30} result] {
        setStatusText "Problem arming histories: $result"
        stopSlowHistoryRC
        return 0
    }

    global historyBufferSize
    set waitTime [expr $historyBufferSize/(1.0*$Rate)+1]
    APSWaitWithUpdate -waitSeconds $waitTime -updateInterval 5 \
      -updateCommand "doRunControlPinging -once 1; updateWaitingMessage"

    set cawaitOption ""
    set first 1
    foreach element $sectorList {
        set cawaitOption "$cawaitOption -waitFor=$element:SlowBh:xBF.BFUL,equalTo=1"
        if !$first {
            set cawaitOption "$cawaitOption -and"
        }
        set first 0
    }

    set tryLimit 30
    for {set try 0} {$try<$tryLimit} {incr try} {
        # setStatusText "Waiting for histories to fill...[clock format [clock seconds] -format %H:%M:%S]"
        doRunControlPinging -once 1
        if [catch {eval blt::bgexec dummy cawait $cawaitOption -interval=1 -timeLimit=1} result] {
            puts stderr "$result"
            continue
        } else {
            break
        }
    }
    if $try==$tryLimit {
        setStatusText "Timeout waiting for histories to fill."
        stopSlowHistoryRC
        return 0
    }

    setStatusText "Acquiring data...[clock format [clock seconds] -format %H:%M:%S]"
    set tmpFile /tmp/[APSTmpString]
    if [catch {blt::bgexec dummy sddswmonitor $inputFile $tmpFile -step=1 \
                -ezcaTiming=0.01,10000 -scalar=$RTFBScalars \
                 "-comment=Comment,[APSMakeSafeQualifierString $userComment]"} result] {
        setStatusText "Problem acquiring: $result"
        stopSlowHistoryRC
        return 0
    }
    doRunControlPinging -once 1

    setStatusText "Postprocessing...[clock format [clock seconds] -format %H:%M:%S]"
    if [string compare $RateUnits Hz]==0 {
        set inverseRateUnits s
    } else {
        set inverseRateUnits 1/$RateUnits
    }
    set timeAcq [expr int([blt::bgexec dummy timeconvert -breakdown=now])]
    if [catch {blt::bgexec dummy sddsprocess $tmpFile $outputFile \
                 "-define=param,Rate,$Rate,units=$RateUnits" \
                 "-define=column,t,Index Rate /,units=$inverseRateUnits,type=float" \
                 -nowarning} result] {
        setStatusText "Problem postprocessing: $result"
        stopSlowHistoryRC
        return 0
    }
    doRunControlPinging -once 1

    if {[string compare $applicationMode archival]==0} {
        if [catch {blt::bgexec dummy gzip $outputFile} result] {
            setStatusText "Problem postprocessing: $result"
            stopSlowHistoryRC
            return 0
        }
        set outputFile $outputFile.gz
    }
    doRunControlPinging -once 1
    set lastOutputFile $outputFile
    setStatusText "Done."
    bell
    stopSlowHistoryRC
    return 1
}

proc setStatusText {text} {
    global statusText 
    set statusText $text
    update
    doRunControlPinging -once 1
}

proc PlotLastSlowHistories {args} {
    set quickSDDSplot 0
    APSStrictParseArguments {quickSDDSplot}
    global outputDir outputFilename lastOutputFile
    if [string length $outputFilename] {
        set fileToPlot $outputDir/$outputFilename
    } else {
        set fileToPlot $lastOutputFile
    }
    if {![string length $fileToPlot] || ![file exists $fileToPlot]} {
        setStatusText "Nothing found to plot."
        return
    }

    if $quickSDDSplot {
        blt::bgexec dummy quickSDDSplot -dataFileList $fileToPlot &
    } else {
        setStatusText "Plotting $fileToPlot..."
        blt::bgexec dummy sddsplot -column=t,*:* -separate $fileToPlot -title=@Comment &
    }
}

proc FFTPlotLastSlowHistories {mode} {
    global outputDir outputFilename lastOutputFile
    if [string length $outputFilename] {
        set fileToPlot $outputDir/$outputFilename
    } else {
        set fileToPlot $lastOutputFile
    }
    if {![string length $fileToPlot] || ![file exists $fileToPlot]} {
        setStatusText "Nothing found to plot."
        return
    }
    set fftFile $fileToPlot.fft
    if ![file exists $fftFile] {
        setStatusText "FFTing $fileToPlot..."
        blt::bgexec dummy sddsfft $fileToPlot -pipe=out -column=t,*:*  -psd -suppressaverage \
          | sddsxref $fileToPlot -pipe=in $fftFile -transfer=param,* -leave=*
    } else {
        setStatusText "Using existing file $fftFile"
    }
    if [string compare $mode QP]==0 {
        blt::bgexec dummy quickSDDSplot -dataFileList $fftFile &
    } else {
        setStatusText "Plotting..."
        blt::bgexec dummy sddsplot -column=f,${mode}*:* -separate $fftFile -clip=1,0 -mode=y=log,y=special -title=@Comment \
          "-topline=@TimeStamp,edit=i/Data taken /" &
#        if [string compare $mode FFT] {
#            set floor 1e-6
#        } else {
#            set floor 1e-8
#        }
#        blt::bgexec dummy sddscontour -shade=16 -column=f,${mode}*:*x -log=$floor $fftFile &
#        blt::bgexec dummy sddscontour -shade=16 -column=f,${mode}*:*y -log=$floor $fftFile & 
    }
}

set statusText Working.
set args $argv
set applicationMode expert
set runControl 1
set RTFBScalars /home/helios/oagData/monitoring/RTFBStatus/RTFBStatus.mon
set FPGAbpmList [exec sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out \
                   -match=column,ElectronicsType=FPGA -nowarnings \
                   | sdds2stream -pipe -column=DeviceName]
set FPGAsectorList ""
foreach bpm $FPGAbpmList {
    set sector [scan $bpm S%ld]
    if [lsearch -exact $FPGAsectorList $sector]<0 {
        lappend FPGAsectorList $sector
    }
}
APSStrictParseArguments {applicationMode runControl}

APSApplication . -name "SRAcquireSlowHistory:$applicationMode" -version $CVSRevisionAuthor \
  -overview {This application does configuration and acquisition for the storage ring slow history facility.}

package require BLT

APSScrolledStatus .status -parent .userFrame -textVariable statusText \
        -width 70 -height 5 -withButtons 1 -lineLimit 500 

if $runControl {
    set haltRunControlPinging 0
    set runControlPV S:SlowBeamHistoryRC
    blt::bgexec dummy medm -attach -x -macro RCPV=$runControlPV ./sr/psApp/APSRunControlSingle.adl &
    dp_atexit append APSRunControlExit 
}

if [string compare $applicationMode archival] {
    MakeFileEntryFrame .output -parent .userFrame
    MakeBPMEntryFrame .bpm -parent .userFrame
    APSFrameGrid .setting -parent .userFrame -xList {left right}
    MakeHardwareSettingsFrame .hwsettings -parent .userFrame.setting.left
    MakeAcquisitionSettingsFrame .acqsettings -parent .userFrame.setting.right
    MakeAdvancedButtonsFrame .advanced -parent .userFrame
} else {
    MakeArchivalButtonsFrame .archival -parent .userFrame 
    after 1000
    update
    APSInfoWindow .info -name "RMS beam motion measurement update"  -infoMessage "The archival slow history is no longer required or used for collecting RMS orbit motion data. The RT feedback system is now being used as the primary source of orbit motion data. However there is no harm in running the SRAcquireSlowHistory application any time." -modal 1

}
APSSetVarAndUpdate statusText "Ready."
update idletasks
