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


set auto_path [linsert $auto_path 0 /usr/local/oag/apps/lib/$env(HOST_ARCH)]
set auto_path [linsert $auto_path 0 /usr/local/oag/lib_patch/$env(HOST_ARCH)]
APSStandardSetup


set CVSRevisionAuthor "\$Revision: 1.3 $ \$Author: soliday $"

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

proc StartScan {args} {
    global outputDir rootname steps pauseAfterChange readbackPause numToAve scanType
    global mixerDelay1Start  mixerDelay1End mixerDelay2Start mixerDelay2End sampleDelayXStart \
	sampleDelayXEnd sampleDelayYStart sampleDelayYEnd
    global scanResult
    
    set timestr [clock format [clock seconds] -format %Y-%m%d:%H%M%S]
 
    set inputDir /home/helios/oagData/par/P0feedback/inputFiles

    set tmpRoot /tmp/[APSTmpString]
    set patternFile ""
    switch $scanType {
	attenuator {
	    set patternFile /home/helios/oagData/par/P0feedback/patternFiles/all-432-buckets
	    set valueFile $inputDir/attenuatorScan.sdds
	    foreach type {attenuator0 attenuator1} pv {C0:P0FB:SumAttSet.A C1:P0FB:SumAttSet.A} {
		if [catch {exec replaceText $inputDir/P0FeedbackScanVar1.template $tmpRoot.exp.$type \
			       -orig=<control_name>,<column_name>,<values_file> \
			       -repl=$pv,$type,$valueFile } result] {
		    return -code error "Error in generate attenuator scan file: $result"
		}
		if ![file exist $tmpRoot.exp] {
		    exec cp $tmpRoot.exp.$type $tmpRoot.exp
		} else {
		    if [catch {exec cat $tmpRoot.exp $tmpRoot.exp.$type > $tmpRoot.expa} result] {
			return -code error $result
		    }
		    exec mv $tmpRoot.expa $tmpRoot.exp	
		}
	    }
	}
	mixerDelay {
	    set patternFile [generate_singlepattern_file]
	    set typeList {mixerDelay1 mixerDelay2}
	    set pvList {S:tune:hpdl:z:SetDelay1 S:tune:hpdl:z:SetDelay2}
	}
	sampleDelay {
	    set patternFile [generate_singlepattern_file]
	    set typeList {sampleDelayX sampleDelayY}
	    set pvList {S:tune:hpdl:x:SetDelay S:tune:hpdl:y:SetDelay}
	}
	default {
	    return -code error "scan type was not selected."
	}
    }
    if {$scanType!="attenuator"} {
	foreach type $typeList pv $pvList {
	    set start [set ${type}Start]
	    set end [set ${type}End]
	    if [catch {exec replaceText $inputDir/P0FeedbackScanVar.template $tmpRoot.exp.$type \
			   -orig=<control_name>,<column_name>,<points>,<limit1>,<limit2> \
			   -repl=$pv,$type,$steps,$start,$end } result] {
		return -code error "Error in generate delay scan file: $result"
	    }
	    if ![file exist $tmpRoot.exp] {
		exec cp $tmpRoot.exp.$type $tmpRoot.exp
	    } else {
		if [catch {exec cat $tmpRoot.exp $tmpRoot.exp.$type > $tmpRoot.expa} result] {
		    return -code error $result
		}
		exec mv $tmpRoot.expa $tmpRoot.exp	
	    }
	}
    }
    set outputFile $outputDir/${scanType}-${timestr}.sdds
    if [catch {exec replaceText $inputDir/P0FeedbackScan.template.exp $tmpRoot.exp1 \
		   -orig=<post_pause>,<outputFile>,<numToAve>,<steps> -repl=$pauseAfterChange,$outputFile.waveform,$numToAve,$steps} result] {
	return -code error "Error in generate exp file: $result"
    }
    
    if [catch {exec cat $tmpRoot.exp $tmpRoot.exp1 > $tmpRoot.exp2} result] {
	return -code error $result
    }
    set expFile $outputDir/${scanType}-${timestr}.exp
    exec cp $tmpRoot.exp2 $expFile
    SetStatus "loading bucket control pattern $patternFile..."
    if [catch {exec sddswput $patternFile} result] {
	return -code error "Error in loading pattern file $patternFile: $result"
    }
    SetStatus "start scan..."
    APSExecLog .ik$scanType -name "$scanType scan" -width 100 \
	-unixCommand "sddsexperiment $expFile $outputFile -verbose" \
	-callback "PostProcessScan -filename $outputFile -type $scanType" \
	-abortCallback "set scanResult$type aborted" -cancelCallback "set scanResult$type canceled"
}

proc PostProcess {args} {
    global outputDir scanType selectFile
     
    set files [glob -nocomplain $outputDir/${scanType}*.sdds]
    if ![llength $files] {
	return -code error "No files found for $scanType."
    }
    APSScrolledListWindow .select -name "Select File" -label "Select File" \
	-itemList $files -selectionVar selectFile
    tkwait variable selectFile
    if [catch {PostProcessScan -filename $selectFile -type $scanType} result] {
	return -code error $result
    }
}


proc ProcessAttenuator {args} {
    set filename ""
    APSParseArguments {filename}
    set tmpRoot /tmp/[APSTmpString]
    set col1 C0:P0FB:SumAttSet.A
    set col2 C1:P0FB:SumAttSet.A
    
    if [catch {exec sddsprocess $filename.waveform -pipe=out \
		   -process=*waveform?,maximum,%sMax \
		   -process=*waveform?,minimum,%sMin \
		   -process=*waveform?,average,%sAve \
		   | sddscollapse -pipe \
		   | sddsprocess -pipe \
		   "-define=col,wf0Max,S:P0FB:scope:gtr:waveform0Max abs" \
		   "-define=col,wf0Min,S:P0FB:scope:gtr:waveform0Min abs" \
		   "-define=col,wf1Max,S:P0FB:scope:gtr:waveform1Max abs" \
		   "-define=col,wf1Min,S:P0FB:scope:gtr:waveform1Min abs" \
		   | sddsprocess -pipe  \
		   "-define=col,wf0Peak,wf0Max wf0Min > ? S:P0FB:scope:gtr:waveform0Max : S:P0FB:scope:gtr:waveform0Min $ " \
		   "-define=col,wf1Peak,wf1Max wf1Min > ? S:P0FB:scope:gtr:waveform1Max : S:P0FB:scope:gtr:waveform1Min $ " \
		   "-redefine=col,wf0MaxOffset,S:P0FB:scope:gtr:waveform0Max S:P0FB:scope:gtr:waveform0Ave - abs" \
		   "-redefine=col,wf1MaxOffset,S:P0FB:scope:gtr:waveform1Max S:P0FB:scope:gtr:waveform1Ave - abs" \
		   "-redefine=col,wf0MinOffset,S:P0FB:scope:gtr:waveform0Min S:P0FB:scope:gtr:waveform0Ave - abs" \
		   "-redefine=col,wf1MinOffset,S:P0FB:scope:gtr:waveform1Min S:P0FB:scope:gtr:waveform1Ave - abs" \
		   "-redefine=col,Step,i_row,type=long" \
		   | sddsprocess -pipe "-process=wf0Peak,min,wf0" "-process=wf1Peak,min,wf1" \
		   | sddsxref -pipe=in $filename -take=$col1,$col2 \
		   $tmpRoot.proc} result] {
	return -code error "ProcessAttenuator1: $result"
    }
    if [catch {exec sddsprocess  $tmpRoot.proc -filter=col,Step,63,64  -pipe=out \
		   | sddsprocess -process=wf0Peak,average,wf0Pos -pipe \
		   | sdds2stream -para=wf0Pos -pipe } xPosition] {
	return -code error "ProcessAttenuator2: $xPosition"
    }

    if [catch {exec sddsprocess \
		   -filter=col,Step,63,64 $tmpRoot.proc -pipe=out | \
		   sddsprocess -process=wf1Peak,average,wf1Pos -pipe \
		   | sdds2stream -para=wf1Pos -pipe } yPosition] {
	return -code error "$yPosition"
    }
    SetStatus "$xPosition $yPosition"
    
    if {$xPosition > 0 } {
	set value1 1600
    } else {
	set value1 -1600
    }
    if {$yPosition>0} {
	set value2 1600
    } else {
	set value2 -1600
    }
    set wf0 [exec sdds2stream -par=wf0 $tmpRoot.proc]
    set wf1 [exec sdds2stream -par=wf1 $tmpRoot.proc]
    if {$wf0>=0} {
	set xOps 0
	set xOption -define=par,xOps,0
    } else {
	set xOption -process=wf0Peak,zerocrossing,xOps,functionof=$col1
    }

    if {$wf1>=0} {
	set yOps 0
	set yOption -define=par,yOps,0
    } else {
	set yOption -process=wf1Peak,zerocrossing,yOps,functionof=$col2
    }
    if [catch {exec sddsprocess $tmpRoot.proc -pipe=out \
		   "-redefine=col,wf0PeakDiff,wf0Peak $value1 -" \
		   "-redefine=col,wf1PeakDiff,wf1Peak $value2 -" \
		   | sddsprocess -pipe=in $filename.proc \
		   $xOption \
		   -process=wf0PeakDiff,zerocrossing,xScan,functionof=$col1 \
		   $yOption \
		   -process=wf1PeakDiff,zerocrossing,yScan,functionof=$col2 -nowarnings } result] {
	return -code error "ProcessAttenuator3: $result"
    }
    
    exec sddsplot -grap=line,vary -col=$col1,wf0Peak -col=$col1,wf0PeakDiff $filename.proc &
    exec sddsplot -grap=line,vary -col=$col2,wf1Peak -col=$col2,wf1PeakDiff $filename.proc &
    
    foreach name {xOps yOps xScan yScan} {
	set $name [format %.4f [exec sdds2stream -par=$name $filename.proc]]
    }
    SetStatus "attenuator for operation: x=$xOps, y=$yOps"
    SetStatus "attenuator for delay scan: x=$xScan, y=$yScan"
    if ![APSYesNoPopUp "Do you want to install the obtained attunator: for operation, x=$xOps, y=$yOps; and for scan: x=$xScan, y=$yScan."] {
	return
    }
    if [catch {exec cavget -list=$col1,$col2 -cavputForm -pend=30 -printErrors} cavputForm] {
	return -code error "Error in reading attenuator values; $cavputForm"
    }

    if [catch {exec cavput -list=$col1=$xOps,$col2=$yOps -pend=30} result] {
	return -code error "Error in setting attenuator to operational values: $result"
    }
    after 1000
    if [catch {APSSaveMachine -machine P0Feedback -description "Attenuator reference for operation obtained by timing scan" } result] {
	return -code error "ProcessAttenuator4: $result"
    }
    set snapshot [lindex $result 0]
    if [catch {APSSCRInstallPreferredFile -system P0Feedback -choice "Attenuator for operation" -filename \
		   $snapshot} result] {
	return -code error "ProcessAttenuator4a -- error install attenuator reference: $result"
    }
    
    if [catch {exec cavput -list=$col1=$xScan,$col2=$yScan -pend=30} result] {
	return -code error "Error in setting attenuator to delay scan values: $result"
    }
    after 1000
    if [catch {APSSaveMachine -machine P0Feedback \
		   -description "Attenuator reference for delay scan obtained by timing scan" } result] {
	return -code error "ProcessAttenuator4: $result"
    }
    set snapshot [lindex $result 0]
    if [catch {APSSCRInstallPreferredFile -system P0Feedback -choice "Attenuator for delay scan" -filename \
		   $snapshot} result] {
	return -code error "ProcessAttenuator4a -- error install attenuator reference: $result"
    }
    SetStatus "restore attenuator values."
    if [catch {exec cavput $cavputForm -pend=10} result] {
	return -code error "Error in restore attenuator values: $result"
    }
}

proc PostProcessScan {args} {
    set filename ""
    set type ""
    set steps 1
    APSParseArguments {filename type steps}
    
    set rows [exec sdds2stream -rows=bar $filename]
    if {$rows==0} {
	SetStatus "$filename is empty."
	return
    }
    if ![file exist $filename.waveform] {
	SetStatus "waveform data was not taken, unable to process data."
	return
    }
    switch $type {
	attenuator {
	    if [catch {ProcessAttenuator -filename $filename} result] {
		return -code error $result
	    }
	    return
	}
	mixerDelay {
	    set col1 S:tune:hpdl:z:GetDelay1
	    set col2 S:tune:hpdl:z:GetDelay2
	    set pv1 S:tune:hpdl:z:SetDelay1
	    set pv2 S:tune:hpdl:z:SetDelay2
	    #not implemented yet
	}
	sampleDelay {
	    set col1 S:tune:hpdl:x:GetDelay
	    set col2 S:tune:hpdl:y:GetDelay
	    set pv1 S:tune:hpdl:x:SetDelay
	    set pv2 S:tune:hpdl:y:SetDelay
	    #not implemented yet
	}
    }
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec cavget -list=$col1 -pend=30} value1] {
	return -code error "Error reading delayx: $value1"
    }
    if [catch {exec cavget -list=$col2 -pend=30} value2] {
	return -code error "Error reading delayy: $value2"
    }
    if [catch {exec sddsprocess $filename.waveform -pipe=out -process=S:P0FB:scope:gtr:waveform\[01\],ave,%sAve \
		   | sddscollapse -pipe \
		   | sddsprocess -pipe "-redefine=col,Step,i_row,type=long" \
		   "-define=col,wf0,S:P0FB:scope:gtr:waveform0Ave abs" \
		   "-define=col,wf1,S:P0FB:scope:gtr:waveform1Ave abs" \
		   "-define=par,xCurrDelay,$value1" "-define=par,yCurrDelay,$value2" \
		   | sddsxref -pipe $filename -take=$col1,$col2 \
		   | tee $filename.proc \
		   | sddspeakfind -pipe -col=wf0 -col=wf1 \
		   | sddsprocess -pipe "-define=col,detal0,$col1 xCurrDelay - abs" \
		    "-define=col,delta1,$col2 yCurrDelay - abs" \
		   |  sddsprocess -pipe=in \
		   -process=detal0,min,xDelay,functionof=$col1,position \
		   -process=delta1,min,yDelay,functionof=$col2,position \
		   $filename.peak \
	       } result] {
	return -code error "Postprocess scan1: $result"
    }
    exec sddsplot -col=$col1,S:P0FB:scope:gtr:waveform0Ave -col=$col2,S:P0FB:scope:gtr:waveform1Ave $filename.proc \
	-grap=line,vary &
    set xDelay [format %.4f [exec sdds2stream -par=xDelay $filename.peak]]
    set yDelay [format %.4f [exec sdds2stream -par=yDelay $filename.peak]]
    SetStatus "$type scan result: xDelay=$xDelay, yDelay=$yDelay"
    if [APSYesNoPopUp "$type scan result: xDelay=$xDelay, yDelay=$yDelay; do you want to install them to $type?"] {
	if [catch {exec cavput -list=$pv1=$xDelay,$pv2=$yDelay -pend=30} result] {
	    return -code error "error in setting $type delay: $result"
	}
    }	
}


proc generate_singlepattern_file {args} {
    global startBucket
    if {$startBucket==1059} {
	return  /home/helios/oagData/par/P0feedback/patternFiles/SingleBunchStart1059-Toggle2Clock
    } else {
	#generate new pattern file
	set tmpRoot /tmp/[APSTmpString]
	set patternFile $tmpRoot.bunchpattern
	set multiplets 1
	set multipleStart $startBucket
	set multipletSpacing 1296
	set totalBuckets 1296
	set bpmGroupMode None
	if {$bpmGroupMode=="First"} {
	    set first 1
	} else {
	    set first 0
	}
	
	if { [expr int (fmod ($multipletStart, 3)+0.001)] > 0 } {
	    return -code error "multipleStart must be multiple of 3!"
	}
	if { [expr int (fmod ($multipletSpacing, 18)+0.001)] > 0 } {
	    return -code error "multipleSpacing must be multiple of 18!"
	}

	set count 0
	#    set multipletStartMod [expr int (fmod ($multipletStart, $multipletSpacing) +0.001 )] 
	for {set index $multipletStart } {$index< [expr $multipletStart+$totalBuckets ] } {incr index } {
	    set indexMod [expr int (fmod ($index-$multipletStart, $multipletSpacing) + 0.001)]
	    set indexMod1 [expr int (fmod ($index, $totalBuckets)+0.01)]
	    if {$indexMod1 > [expr $totalBuckets / 2]} {
		set indexMod1 [expr $totalBuckets - $indexMod1]
	    }
	    if {$indexMod1==0 } {
		if { $first==1} {
		    lappend valList 1
		} elseif {$indexMod==0 && $count<$multiplets} {
		    lappend valList 1
		    incr count
		} else { lappend valList 0 }
	    } elseif {$indexMod==0 && $count < $multiplets } {
		if {$first==1 && $indexMod1<$multipletSpacing} { 
		    lappend valList 0
		} else {
		    lappend valList 1
		    incr count
		}
	    } else {
		lappend valList 0
	    }
	}
	set start1 [expr $totalBuckets - $multipletStart]    
	set end1 [expr $totalBuckets - 1]
	set start2 0
	set end2 [expr $totalBuckets -$multipletStart -1]
	set valList [concat [lrange $valList $start1 $end1] [lrange $valList $start2 $end2]]
	if [catch {exec sddsmakedataset -pipe=out -col=TargetCurrent,type=double -data=[join $valList ,]\
		       | sddsprocess -pipe=in $patternFile -define=col,Bucket,i_row,type=long } result] {
	    return -code error $result
	}
	return $patternFile
    }
}

proc CheckScanSelection {args} {
    set type ""
    APSParseArguments {type}
    global timingList steps attenuator mixerDelay sampleDelay
    eval global $timingList 
    switch $type {
	attenuator {
	    set steps 128
	    set otherList {mixerDelay1 mixerDelay2 sampleDelayX sampleDelayY}
	}
	mixerDelay {
	    set steps 61
	    set otherList {attenuator0 attenuator1 sampleDelayX sampleDelayY}
	}
	sampleDelay {
	    set steps 61
	    set otherList {attenuator0 attenuator1 mixerDelay1 mixerDelay2}
	}
    }
    set $type 1
    foreach nm $otherList {
	set $nm 0
	set type [string range $nm 0 end-1]
	set $type 0
    }
}

set outputDir [APSGoToDailyDirectory -subdirectory P0FeedbackTimingScan]
APSApplication . -name "P0FeedbackTimingScan" -version $CVSRevisionAuthor \
  -overview "scan par kickers and setup par kicker timing."

set status "Ready."
set rootname P0Feedback
set steps 61
set pauseAfterChange 2.0
set readbackPause 0.5
set numToAve 5
set mixerDelay1Start -3.0
set mixerDelay1End 3.0
set mixerDelay2Start -3.0
set mixerDelay2End 3.0
set sampleDelayXStart -6.0
set sampleDelayXEnd 6.0
set sampleDelayYStart -6.0
set sampleDelayYEnd 6.0
set startBucket 1059
set scanType ""

APSScrolledStatus .status -parent .userFrame -textVariable status \
    -width 70 -height 8


APSLabeledEntry .dir -parent .userFrame -width 70 \
  -label "Output dir: " -textVariable outputDir \
  -contextHelp \
  "Enter a directory in which the output files will be written."
APSButton .dialy -parent .userFrame.dir -text "daily" -size small \
  -command {set outputDir [APSGoToDailyDirectory -subdirectory parKickerScan]} \
  -packOption "-side right" \
  -contextHelp "Set the output dir to APS daily directory"
APSLabeledEntry .rootname -parent .userFrame -width 70 \
  -label "Output rootname: " -textVariable rootname \
  -contextHelp \
  "Enter a rootname for generation of the output filenames."
APSFrameGrid .grid -parent .userFrame -xList {x1 x2}
set w1 .userFrame.grid.x1
set w2 .userFrame.grid.x2

set width 21

APSLabeledEntry .steps -parent $w2 -width $width -label "Experiment Steps:" -textVariable steps
APSLabeledEntry .pause -parent $w1 -width $width -label "Pause (s) after change control:" -textVariable pauseAfterChange \
  -contextHelp "The waiting time after each control pv change"
APSLabeledEntry .read -parent $w2 -width $width -label "Pause (s) between two readings:" -textVariable readbackPause \
  -contextHelp "The waiting time between two readbacks for reading the monitoring PVs in each experiment (scan) step."
APSLabeledEntry .ave -parent $w1 -width $width -textVariable numToAve -label "Average number:" \
  -contextHelp "The average number of reading the monitor pvs at each experiment (scan) step"

APSLabeledEntryFrame .ik1 -parent $w1 -label "Mixer delay1(start/end):" -width 10 -orientation horizontal \
    -variableList {mixerDelay1Start mixerDelay1End} -contextHelp "provide the scan range of mixer delay1 -- BR:Ttune:hpdl:z:SetDelay1"
APSLabeledEntryFrame .ik2 -parent $w2 -label "Mixer delay2(start/end):" -width 10 -orientation horizontal \
    -variableList {mixerDelay2Start mixerDelay1End} -contextHelp "provide the scan range of BR:Ttune:hpdl:z:SetDelay2"
APSLabeledEntryFrame .ik -parent $w1 -label "Sample delay X(start/end):" -width 10 -orientation horizontal \
    -variableList {sampleDelayXStart sampleDelayXEnd} -contextHelp "provide the scan range of S:tune:hpdl:x:SetDelay"
APSLabeledEntryFrame .ek4 -parent $w2 -label "Sample delay Y(start/end)" -width 10 -orientation horizontal \
    -variableList {sampleDelayYStart sampleDelayYEnd} -contextHelp "provide the scan range of S:tune:hpdl:y:SetDelay"
APSLabeledEntry .startb -parent $w2 -label "Start bucket" -width 10 -textVariable startBucket \
    -contextHelp "the start bucket number in the bunch pattern."

set timingList {attenuator0 attenuator1 mixerDelay1 mixerDelay2 sampleDelayX sampleDelayY}
set pvList {C0:P0FB:SumAttSet.A C1:P0FB:SumAttSet.A S:tune:hpdl:z:SetDelay1 S:tune:hpdl:z:SetDelay2 S:tune:hpdl:x:SetDelay S:tune:hpdl:y:SetDelay}
APSRadioButtonFrame .scan -parent $w1 -label "Scan type" -buttonList {attenuator mixerDelay sampleDelay} \
    -variable scanType \
    -valueList {attenuator mixerDelay sampleDelay} -orientation horizontal \
    -commandList {"set steps 128" "set steps 61" "set steps 61"}



APSButton .start -parent .userFrame -text "Start Timing Scan" -command "StartScan"
APSButton .post -parent .userFrame -text "Post Process" -command "PostProcess"



