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

#
# $Log: not supported by cvs2svn $

# First version of GUI to measure SR tune with dimtel.
#
#

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.0 $ \$Author: shang $"

set divisor 1296.0
set archiveDir /home/helios/oagData/sr/tuneArchive/Dimteldata
set prefix SR
set lowerTune x
set upperTune y
set dividingLine 0.21
set ring SR
set dimtel(procMethod) Lorentzian

set env(EPICS_CA_ADDR_LIST) "10.6.27.93 10.6.27.102 10.6.27.103"
if [catch {exec cavget -list=A014-IETS:BTC:SRSetFreqM -printErrors  -floatFormat=%21.15e} refFreq] {
    puts stderr $refFreq
    exit 1
}
set revFrequency [expr $refFreq/$divisor]

APSApplication . -name SRMeasureTunes:Dimtel -version $CVSRevisionAuthor \
  -overview {Measure SR tunes with dimtel.}

set status Working...
APSScrolledStatus .status -parent .userFrame -textVariable status \
        -width 60 -height 6
update

proc SetStatus {text} {
    global status
    set status "$text"
    update
}

proc SetupDimtel {args} {
    global dimtel
    
    switch $dimtel(plane) {
	x {
	    if $dimtel(yDriveAmplitude)>0 {
		SetStatus "Error: y drive is not zero for drive x only!"
		return
	    }
	} 
	y {
	   if $dimtel(xDriveAmplitude)>0 {
		SetStatus "Error: x drive is not zero for drive y only!"
		return
	    } 
	}
    }
    pv linkw dimtel(xPeakFreq) S-TFB:X:SB:PEAKFREQ1
    pv linkw dimtel(yPeakFreq) S-TFB:Y:SB:PEAKFREQ1
    pv linkw dimtel(xPeak) S-TFB:X:SB:PEAK1
    pv linkw dimtel(yPeak) S-TFB:Y:SB:PEAK1
    
    if [catch {APSSetupDimtelForTuneMeasurement -xDriveFreq $dimtel(xDriveFreq) -yDriveFreq $dimtel(yDriveFreq) \
		   -xDriveFreqSpan $dimtel(xDriveFreqSpan) -yDriveFreqSpan $dimtel(yDriveFreqSpan) \
		   -xDrivePeriod $dimtel(xDrivePeriod) -yDrivePeriod $dimtel(yDrivePeriod) \
		   -xDriveAmplitude $dimtel(xDriveAmplitude) -yDriveAmplitude $dimtel(yDriveAmplitude) \
		   -xMarkerLow $dimtel(xMarkerLow) -yMarkerLow $dimtel(yMarkerLow) \
		   -xMarkerHigh $dimtel(xMarkerHigh) -yMarkerHigh $dimtel(yMarkerHigh) \
		   -statusCallback SetStatus } result] {
	return -code error "Error setup dimtel: $result"
    }
    return


    SetStatus "setup dimtel done."
}

proc MakeTuneWidget {widget args} {
    set parent ""
    APSParseArguments {parent}
    global srTune dimtel dimtelPause
     
    APSFrame $widget -parent $parent -label "Dimtel parameters"
    set w1 $parent$widget.frame
    
    
    APSFrameGrid .grid -parent $w1 -xList {x1 x2}
    set f1 $w1.grid.x1
    set f2 $w1.grid.x2
    set width 15
    APSLabel .label -parent $f1 -text "                               X Plane"
    APSLabel .lable -parent $f2 -text "     Y Plane"

    set paramFile /home/helios/oagData/sr/dispChrom/dimtelParameters.sdds
    set nameList [exec sdds2stream -col=ParameterName $paramFile]
    set valList [exec sdds2stream -col=ParameterValue $paramFile]
    foreach name $nameList val $valList {
	set dimtel($name) [format %.1f $val]
    }
    
    
    APSLabeledEntry .freq -parent $f1 -label "Drive0 frequency (kHz):" -textVariable dimtel(xDriveFreq) -width $width
    APSLabeledEntry .freq -parent $f2 -label "" -textVariable dimtel(yDriveFreq) -width $width
    
    APSLabeledEntry .span -parent $f1 -label "Drive0 frequency span(kHz):" -textVariable dimtel(xDriveFreqSpan) -width $width
    APSLabeledEntry .span -parent $f2 -label "" -textVariable dimtel(yDriveFreqSpan) -width $width
    
    APSLabeledEntry .period -parent $f1 -label "Drive0 Period (us):" -textVariable dimtel(xDrivePeriod) -width $width
    APSLabeledEntry .period -parent $f2 -label "" -textVariable dimtel(yDrivePeriod) -width $width
   
    APSLabeledEntry .amp -parent $f1 -label "Drive0 Amplitude:" -textVariable dimtel(xDriveAmplitude) -width $width
    APSLabeledEntry .amp -parent $f2 -label "" -textVariable dimtel(yDriveAmplitude) -width $width

    APSLabeledEntry .mlow -parent $f1 -label "Lower Marker:" -textVariable dimtel(xMarkerLow) -width $width
    APSLabeledEntry .mlow -parent $f2 -label "" -textVariable dimtel(yMarkerLow) -width $width

    APSLabeledEntry .mhigh -parent $f1 -label "Lower Marker:" -textVariable dimtel(xMarkerHigh) -width $width
    APSLabeledEntry .mhigh -parent $f2 -label "" -textVariable dimtel(yMarkerHigh) -width $width

   
    APSLabeledOutput .peakfreq -parent $f1 -label "SB peak frequency(kHz):" -textVariable dimtel(xPeakFreq) -width $width
    APSLabeledOutput .peakfreq -parent $f2 -label "" -textVariable dimtel(yPeakFreq) -width $width

    APSLabeledOutput .peak -parent $f1 -label "SB waveform peak:" -textVariable dimtel(xPeak) -width $width
    APSLabeledOutput .peak -parent $f2 -label "" -textVariable dimtel(yPeak) -width $width

    set dimtel(plane) x
    set dimtel(xDriveAmplitude) 0.1
    set dimtel(yDriveAmplitude) 0
    set dimtelPause 5
    set dimtel(average) 2
    APSLabeledEntry .average -parent $w1 -label "Number of average:" -textVariable dimtel(average) -width $width
    APSLabeledEntry .pause  -parent $w1 -label "Pause for dimtel averaging" -textVariable dimtelPause -width $width
    APSRadioButtonFrame .plane  -parent $w1  -label "Measure tune plane:    " -buttonList {x y both} -valueList {x y both} \
			-orientation horizontal -variable dimtel(plane) -commandList {UpdateDriveParameter UpdateDriveParameter UpdateDriveParameter}
    
    APSRadioButtonFrame .proc -parent $w1 -label "Tune processing method:" -buttonList {DIMTEL Lorentzian} -variable dimtel(procMethod) -valueList {Dimtel Lorentzian} -orientation horizontal
    
    APSButton .setup -parent $w1 -text "Setup Dimtel" -command "SetupDimtel"
   # APSButton .xdim -parent $w1 -text "X Dimtel Medm" -command "exec /home/helios/SR/dimtel/iGp12/bin/iGp_display2 X &"
   # APSButton .ydim -parent $w1 -text "Y Dimtel Medm" -command "exec /home/helios/SR/dimtel/iGp12/bin/iGp_display2 Y &"
    APSButton .xdim -parent $w1 -text "X Dimtel Medm" -command "exec /home/helios/SR/dimtel/iGp12/bin/iGp_display_APSU_TFB &"
    APSButton .ydim -parent $w1 -text "Y Dimtel Medm" -command "exec /home/helios/SR/dimtel/iGp12/bin/iGp_display_APSU_TFB Y &"

   
}

proc UpdateDriveParameter {args} {
    global dimtel
    switch $dimtel(plane) {
	x {
	    set dimtel(xDriveAmplitude) 0.1
	    set dimtel(yDriveAmplitude) 0
	}
	y {
	    set dimtel(xDriveAmplitude) 0
	    set dimtel(yDriveAmplitude) 0.1
	}
	both {
	    set dimtel(xDriveAmplitude) 0.1
	    set dimtel(yDriveAmplitude) 0.1
	}
    }
}
set dataDirectory "."
set dataRootname tunes
set dataIndex 0
set measureXYtuneTogether 0
set recenterRange 0
set archiveMXATune 1
set xDimtelReducedGain 2
set yDimtelReducedGain 2
proc MakeSaveWidget {widget args} {
    set parent ""
    APSStrictParseArguments {parent}
    global dataDirectory dataRootname dataIndex dimtel
    
    APSFrame $widget -parent $parent \
	-label "Save data" -contextHelp \
      "Provides for saving the tune spectrum to a file."
    set parent $parent$widget.frame
    
    APSLabeledEntry .directory -parent $parent -label "Directory: " \
      -textVariable dataDirectory -width 70
    APSButton .daily -parent $parent.directory -packOption "-anchor e" \
      -text "daily" -size small \
	-command {set dataDirectory [APSGoToDailyDirectory -subdirectory ${ring}Tune-Dimtel]}
    APSLabeledEntry .comment -parent $parent -label "Comment: " \
      -textVariable dataComment -width 70
    
    APSFrameGrid .grid -parent $parent -xList {x1 x2} -height 20
    set w1 $parent.grid.x1
    set w2 $parent.grid.x2
    
    set width 30
    APSLabeledEntry .rootname -parent $w1 -label "Rootname:" \
      -textVariable dataRootname -width $width
    APSLabeledEntry .index -parent $w2 -label "Index: " \
      -textVariable dataIndex -width $width
    
    #APSLabeledEntry .dividingLine -parent $w1 -label "x/y boundary:" \
     \# -textVariable dividingLine -width $width -contextHelp \
     \# "Enter the tune value to divide x from y peaks."
   
    set dimtel(setup) 1
    APSRadioButtonFrame .setup -parent $w1 -label "Setup dimtel before measuring tune?" -buttonList {Yes No} \
	-valueList {1 0} -variable dimtel(setup) -orientation horizontal
   
    APSButton .save -parent $parent -text "Acquire, View, and Save" -command \
      saveData -contextHelp \
      "Saves tune data to the directory and file you've chosen."
    APSButton .view -parent $parent -text "Acquire and View Only" -command \
      "saveData -viewOnly 1" -contextHelp \
      "Acquires tune data and displays it."
   APSButton .proc -parent $parent -text "Reprocess" -command \
	ReprocessTuneData
   
}

proc ProcessTune {args} {
    set file ""
    APSParseArguments {file}
    global dimtel
   
    set rootname [file root $file]
    if [catch {APSSRProcessDimtelTunes -rootname $rootname -plot 1 -procMethod $dimtel(procMethod) } result] {
	return -code error "Error processing tuen for $rootname: $result"
    }
}

proc ReprocessTuneData {args} {
    global dataDirectory selectFile ring dataRootname
    set oldDir [pwd]
    cd $dataDirectory
    set fileList [lsort -decreasing [glob -nocomplain ${dataRootname}*.raw]]
    if ![llength $fileList] {
	APSSetVarAndUpdate status "No files found."
	cd $oldDir
        return
    }
    set selectFile ""
    APSScrolledListWindow .sel -name "Select a file" \
	-label "Select a file" -itemList $fileList -selectionVar selectFile
    tkwait variable selectFile
    if ![string length $selectFile] {
	APSSetVarAndUpdate status "No file selected."
	cd $oldDir
        return
    }
    if [catch {ProcessTune -file $selectFile} result] {
	return -code error "Error reprocess tune: $result"
    }
    cd $oldDir
}

set first 1
proc saveData {args} {
    set archive 0
    set viewOnly 0
    set popup 1
    APSStrictParseArguments {archive viewOnly popup}

    global dimtel dataDirectory dataRootname dataComment first dataIndex dimtelPause
    
    if ![file exist $dataDirectory] {
	if [catch {exec mkdir $dataDirectory} result] {
	    return -code error "Error creating $dataDirectory: $result"
	}
    }
    if [catch {exec  cavget -list=S:DesiredMode -noquote} srMode] {
	APSAlertBox [APSUniqueName .] -errorMessage "Can not read S:DesiredMode: $srMode"
	return
    }
    if {$dimtel(setup)} {
	if {$srMode=="SUPLEMENTAL TIME" || $srMode=="USER OPERATIONS"} {
	    if ![APSYesNoPopUp "It is user operations now, are you sure to setup dimtel now?"] {
		SetStatus "Dimtel setup was cancelled in user operations mode."
		return
	    }
	}
    }
    global env
    if {$archive} {
        if {[string compare $env(USER) asdops]!=0 && [string compare $env(USER) sr]!=0} {
            set message "Archiving of tune data may only be done by ASDOPS or SR account.\n\Please put your studies data in a private directory."
            APSAlertBox [APSUniqueName .] -errorMessage $message 
            return
        }
        
    }
    if $viewOnly {
        set file /tmp/[APSTmpString]
    } else {
        if !$archive {
	    if $first {
		set files [lsort -decreasing [glob -nocomplain $dataDirectory/${dataRootname}*.sdds]]
		if ![llength $files] {
		    set dataIndex 0
		} else {
		    set lastFile [file tail [lindex $files 0]]
		    set dataIndex [scan $lastFile ${dataRootname}-%ld]
		    incr dataIndex
		}
		set first 0
	    }
            set file [format $dataDirectory/$dataRootname-%03ld.sdds $dataIndex]
            incr dataIndex
            APSSetVarAndUpdate status "Putting tune data in file $file"
        } else {
            set tag [APSOffsetDateInfo -today 1 -offset 0 -dateFormat Y-J-MD]
            set timeStamp [exec date +%H%M%S]
            global archiveDir
            set file $archiveDir/$tag.$timeStamp
            APSSetVarAndUpdate status "Putting tune data into archive area."
        }
    }
    global dimtel
    
    switch $dimtel(plane) {
	x {
	    set xOnly 1
	    set yOnly 0
	}
	y {
	    set xOnly 0
	    set yOnly 1
	}
	both {
	    set xOnly 0
	    set yOnly 0
	}
    }
    if {$dimtel(plane)=="both"} {
	set xDrive 0
	set yDrive 0
	set xOnly 0
	set yOnly 0
	set rootname [file root $file]
	foreach plane {x y} {
	    SetStatus "Measuring $plane tune..."
	    set ${plane}Only 1
	    set ${plane}Drive $dimtel(${plane}DriveAmplitude)
	    SetStatus "xOnly=$xOnly yOnly=$yOnly..."
	    if [catch {APSSRMeasureTunesWithDimtel -setupDimtel $dimtel(setup) \
			   -procMethod $dimtel(procMethod) \
			   -description "$dataComment" -pause $dimtelPause \
			   -statusCallback SetStatus \
			   -plot 0\
			   -average $dimtel(average) \
			   -xDriveFreq $dimtel(xDriveFreq) \
			   -yDriveFreq $dimtel(yDriveFreq) \
			   -xDriveFreqSpan $dimtel(xDriveFreqSpan) \
			   -yDriveFreqSpan $dimtel(yDriveFreqSpan) \
			   -xDrivePeriod $dimtel(xDrivePeriod) \
			   -yDrivePeriod $dimtel(yDrivePeriod) \
			   -xDriveAmplitude $xDrive \
			   -yDriveAmplitude $yDrive \
			   -xMarkerLow $dimtel(xMarkerLow) \
			   -yMarkerLow $dimtel(yMarkerLow) \
			   -xMarkerHigh $dimtel(xMarkerHigh) \
			   -yMarkerHigh $dimtel(yMarkerHigh) \
			   -xOnly $xOnly -yOnly $yOnly \
			   -rootname $rootname} result] {
		return -code error "Error save tune data: $result"
	    }
	    set xDrive 0
	    set xOnly 0
	}
	if [catch {exec sddscombine $rootname.x $rootname.y $rootname.sdds -over } result] {
	    return -code error "Error combine data: $result"
	}
	#plot raw data
	#plot raw data
	exec sddsplot  -gra=line,vary "-title=Single Bunch Raw data" -topline=$rootname \
	    "-ylabel=Spectrum (dB)" "-xLabel=Frequency(kHz)" \
	    -col=xFrequency,xSBspectrum $rootname.x -leg=spec=x \
	    "-string=@XplaneSBPeakFreq,p=0.05,q=0.95,format=xPeakFreq\=%.4f,sca=1.4" \
	    "-string=@XplaneSBPeak,p=0.05,q=0.85,format=xPeak\=%.4f,sca=1.4" \
	    -col=yFrequency,ySBspectrum $rootname.raw -leg=spec=y $rootname.y \
	    "-string=@YplaneSBPeakFreq,p=0.55,q=0.95,format=yPeakFreq\=%.4f,sca=1.4" \
	    "-string=@YplaneSBPeak,p=0.55,q=0.85,format=yPeak\=%.4f,sca=1.4" &
	#plot tune data
	exec sddsplot -gra=line,vary "-title=Single Bunch data" -topline=$rootname \
	    "-ylabel=Spectrum (dB)" "-xLabel=Tune" \
	    -col=xTune,xSBspectrum $rootname.x -leg=spec=x \
	    "-string=@XplaneSBMarkerTune,p=0.05,q=0.95,format=xTune\=%.4f,sca=1.4" \
	    -col=yTune,ySBspectrum $rootname.y -leg=spec=y \
	    "-string=@YplaneSBMarkerTune,p=0.55,q=0.95,format=yTune\=%.4f,sca=1.4" \
	    &
	exec sddsplot -dev=lpng -out=$rootname.png -thick=2 \
	    -gra=line,vary,thick=2 -title= -topline=$rootname \
	    "-ylabel=Spectrum (dB)" "-xLabel=Tune" \
	    -col=xTune,xSBspectrum $rootname.x -leg=spec=x \
	    "-string=@XplaneSBMarkerTune,p=0.05,q=0.95,format=xTune\=%.4f,sca=1.4" \
	    -col=yTune,ySBspectrum $rootname.y -leg=spec=y \
	    "-string=@YplaneSBMarkerTune,p=0.55,q=0.95,format=yTune\=%.4f,sca=1.4" \
	    &
    } else {
	if [catch {APSSRMeasureTunesWithDimtel -setupDimtel $dimtel(setup) \
		       -procMethod $dimtel(procMethod) \
		       -description "$dataComment" -pause $dimtelPause \
		       -statusCallback SetStatus \
		       -plot 1 \
		       -average $dimtel(average) \
		       -xDriveFreq $dimtel(xDriveFreq) \
		       -yDriveFreq $dimtel(yDriveFreq) \
		       -xDriveFreqSpan $dimtel(xDriveFreqSpan) \
		       -yDriveFreqSpan $dimtel(yDriveFreqSpan) \
		       -xDrivePeriod $dimtel(xDrivePeriod) \
		       -yDrivePeriod $dimtel(yDrivePeriod) \
		       -xDriveAmplitude $dimtel(xDriveAmplitude) \
		       -yDriveAmplitude $dimtel(yDriveAmplitude) \
		       -xMarkerLow $dimtel(xMarkerLow) \
		       -yMarkerLow $dimtel(yMarkerLow) \
		       -xMarkerHigh $dimtel(xMarkerHigh) \
		       -yMarkerHigh $dimtel(yMarkerHigh) \
		       -xOnly $xOnly -yOnly $yOnly \
		       -rootname [file root $file] } result] {
	    return -code error "Error save tune data: $result"
	}
    }
    #plot raw data
    SetStatus "tune measurement done."
    return
   
}


proc MakeArchiveWidget {widget args} {
    set parent ""
    APSStrictParseArguments {parent}
    APSFrame $widget -parent $parent -label "Archive" \
      -contextHelp "Controls archiving and review of archived tune data."

    set w $parent$widget.frame

    global startDay startMonth startYear
    global endDay endMonth endYear
    APSDateTimeAdjEntry .date0 -parent $w \
      -dayVariable startDay -monthVariable startMonth -yearVariable startYear \
      -label "Start Y/M/D: "
    APSDateTimeAdjEntry .date1 -parent $w \
      -dayVariable endDay -monthVariable endMonth -yearVariable endYear \
      -label "End   Y/M/D: "
    
    APSButton .archive -parent $w -text Archive -command \
      "saveData -archive 1" -contextHelp \
      "Saves tune data to the archive area."
    APSButton .review -parent $w -text "Review spectra" -command \
      "reviewArchivedData -mode spectra" -contextHelp \
      "Reviews archived tune data between the dates given above."
    APSButton .reprocess -parent $w -text "Reprocess Tune" -command \
        "reviewArchivedData -mode spectra -reprocess 1" -contextHelp \
      "Reprocess archived tune data between the dates given above."
    APSButton .history -parent $w -text "Show tune history" -command \
      "reviewArchivedData -mode history" -contextHelp \
      "Displays history of tune values between the dates given above."
    APSButton .ampHistory -parent $w -text "Show amplitude history" -command \
      "reviewArchivedData -mode ampHistory" -contextHelp \
      "Displays history of tune peak amplitude values between the dates given above."
    
}


proc reviewArchivedData {args} {
    set mode spectra
    set reprocess 0
    APSStrictParseArguments {mode reprocess}

    global startDay startMonth startYear dividingLine
    global endDay endMonth endYear
    global archiveDir ring

    set fileList \
      [APSFindFilesBetweenDates -tailsOnly 1 \
         -rootname "" -directory $archiveDir \
         -extensionList {.?????? .gz} \
         -startDateList [APSFormatDate -year $startYear \
                           -month $startMonth -day $startDay -dateFormat list] \
         -endDateList [APSFormatDate -year $endYear \
                           -month $endMonth -day $endDay -dateFormat list] \
        ]
    if [llength $fileList]==0 {
        APSSetVarAndUpdate status "No files found."
        return
    } else {
        APSSetVarAndUpdate status "[llength $fileList] files found."
    }
    set oldDir [pwd]
    cd $archiveDir
    if $reprocess {
        foreach file $fileList {
            if [catch {ProcessTune -filename $file} result] {
                return -code error "Error in reprocessing tune: $result"
            }
        }
	return
    }
    switch $mode {
        spectra {
            eval exec sddsplot -samescale=x -mode=y=normalize -split=page  -title=@TuneLabel \
              -column=Tune,*TUNE1 -graph=line,vary -groupby=filestring,namestring \
              -separate=filestring $fileList \
              {"-topline=@BeamParamLabel,edit=i/Archived tune data:  /"}   &
        }
        history {
            eval exec sddsplot -ticks=xtime -graph=symbol -labelsize=0.024 -frompage=1 -topage=1 \
              -groupby=nameindex -separate=nameindex \
              -parameter=Time,(xTune,yTune) \
              $fileList {"-topline=Tune history for $ring"} -title= &
        }
        ampHistory {
            eval exec sddsplot -ticks=xtime -graph=symbol -labelsize=0.024 -frompage=1 -topage=1 \
              -mode=y=log,y=special -limit=ymax=1e300,ymin=0 \
              -groupby=nameindex -separate=nameindex \
              -parameter=Time,(xNormAmplitude,yNormAmplitude) \
              $fileList {"-topline=Tune peak amplitude history for $ring"} -title= &
        }
    }
    
    cd $oldDir
    APSSetVarAndUpdate status "Plot launched"
}


APSFrameGrid .grid -parent .userFrame -xList {x1 x2}

MakeTuneWidget .tune -parent .userFrame
MakeSaveWidget .save -parent .userFrame
MakeArchiveWidget .review -parent .userFrame


