#!/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

# wrote for chunxi

set CVSRevisionAuthor "\$Revision: 1.11 $ \$Author: shang $"

proc SetStatus {text} {
    global fpgaBPMConfigStatus
    set fpgaBPMConfigStatus "[clock format [clock seconds] -format %H:%M:%S]  $text"
    update
}


set TmpRoot /tmp/[APSTmpString]
set fileIndex 0
set first 1

set timeout 3
proc CollectTurnHistory {args} {
    set type ""
    APSParseArguments {type}
    
    global outputDir X Y TmpRoot status processData triggerValue IOCList FPGABpmTurnHistory trigger RAMscrFile waittime loadRAM
    global triggerSetup showPlots fileIndex first shortLong configuration trigger plane xGain yGain ramDesc timeout allBPMList RAMscrFile RAMdesc
    
    if !$triggerSetup {
        SetStatus "setup trigger..."
        SetupTrigger
    }
    if {$type=="phase"} {
        set RAMscrFile SBPMWaveform-singleX.gz
        set RAMdesc "Single bunch x only with no commutation"
    }
    #load RAM
    SetStatus "load control RAM ..."
    if [catch {LoadRAM} result] {
        SetStatus $result
        return
    }
    SetStatus "Reading plane mode for each bpm..."
    if [catch {exec cavget -list=[join $allBPMList ,] -list=:PlaneMode -pend=60} planeList] {
        return -code $allPlaneList
    }
    
    set monFile ${type}-[format %03d $fileIndex].wmon 
    if [catch {exec sddsmakedataset -col=name,type=string -data=[join $allBPMList ,] \
                 -col=plane,type=string -data=[join [string toupper $planeList] ,] \
                 -pipe=out \
                 | sddsprocess -pipe=in $outputDir/$monFile \
                 -print=col,WaveformPV,%s:turnHistory:%sposition,name,plane -print=col,BPMName,%s%s,name,plane \
                 -define=par,WaveformLength,262144,type=long } result] {
        return -code error $result
    }
    SetStatus "Set Post trigger..."
    SetPostTrigger
    SetStatus "Checking arm status..."
    if [catch {APScavget -list=[join $IOCList ,] -list=:TurnHistoryTrigTimeSI -pend=30 } prevTrigList] {
        return -code error $prevTrigList
    }
    if [catch {exec cavget -list=A014-IETS:BTC:SRSetFreqM -floatformat=%.8e -pend=30 -printErrors} origFreq] {
        return -code error $origFreq
    }
    
    if [catch {exec cavget -list=SRF:K4:PS1:Ch0 -pend=30 -printErrors} origPhase] {
        reeturn -code error $origPhase
    }
    switch $type {
        P0Feedback {
            set valList 1
            set deltaList 1
        }
        freq {
            set valList {-100 50 50 50 50}
            set deltaList {-100 -50 0 50 100}
        }
        phase {
            set valList {-15}
            set deltaList {-15}
        }

    }
    cd $outputDir
    foreach val $valList delta $deltaList {
        #SetStatus "disable 2 Hz injection trigger..."
        #if [catch {exec cavput -list=Mt:EG1:eg.ETE7=NO -pend=20} result] {
        #    return -code error "Error in disabling 2Hz injection trigger: $result"
        #}
        switch $type {
            freq {
                SetStatus "change RF freq by $delta..."
                if [catch {exec cavput -list=A014-IETS:BTC:SRSetFreqM=$val -delta -pend=30 } result] {
                    if [catch {exec cavput -list=Mt:EG1:eg.ETE7=YES -pend=20} result] {
                        return -code error "Error in enabling 2Hz injection trigger: $result"
                    }
                    return -code error "Error in changing RF freq: $result"
                }
                after 2000
                SetStatus "arm bpms ..."
                if [catch {exec cavput -list=[join $IOCList ,] -list=:turn:gtr:arm=1 -pend=30 } result] {
                    if [catch {exec cavput -list=Mt:EG1:eg.ETE7=YES -pend=20} result] {
                        return -code error "Error in enabling 2Hz injection trigger: $result"
                    }
                    return -code error $result
                }
                after 1000
            }
            phase {
                #if [catch {exec cavput -list=Mt:EG1:eg.ETE7=YES -pend=20} result] {
                #    return -code error "Error in enabling 2Hz injection trigger: $result"
                #}
                SetStatus "Arm bpms ..."
                if [catch {exec cavput -list=[join $IOCList ,] -list=:turn:gtr:arm=1 -pend=60 } result] {
                    #if [catch {exec cavput -list=Mt:EG1:eg.ETE7=YES -pend=20} result1] {
                    #    return -code error "Error in enabling 2Hz injection trigger: $result1"
                    #}
                    return -code error "Error in arming bpms: $result"
                }
                after [expr int($waittime * 1000)]
                SetStatus "change RF phase by $delta ..."
                if [catch {exec cavput -list=SRF:K4:PS1:Ch0=$val -delta -pend=60} result] {
                    #if [catch {exec cavput -list=Mt:EG1:eg.ETE7=YES -pend=20} result1] {
                    #    return -code error "Error in enabling 2Hz injection trigger: $result1"
                    #}
                    return -code error "Error in change phase to $val: $result"
                }
                after [expr int($waittime * 1000)]
                after 1000
            }
            P0Feedback {
                SetStatus "setup P0 Feedback gain..."
                SetP0FeedbackGain -xGain $xGain -yGain $yGain
                after 2000
                SetStatus "arm bpms ..."
                if [catch {exec cavput -list=[join $IOCList ,] -list=:turn:gtr:arm=1 -pend=20 } result] {
                    #if [catch {exec cavput -list=Mt:EG1:eg.ETE7=YES -pend=20} result] {
                    #    return -code error "Error in enabling 2Hz injection trigger: $result"
                    #}
                    return -code error $result
                }
                after 2000
            }
        }
        
        #check if all bpms are armed
        if {$type!="phase"} {
            SetStatus "Wait $timeout (at most) seconds for bpms to be armed..."
            set timeout1 [expr $timeout + [clock seconds]]
            while {[clock seconds]<$timeout1} {
                if [catch {APScavget -list=[join $IOCList ,] -list=:TurnHistoryIsArmed -num -pend=30 } armList] {
                   # if [catch {exec cavput -list=Mt:EG1:eg.ETE7=YES -pend=20} result] {
                   #     return -code error "Error in enabling 2Hz injection trigger: $result"
                   # }
                    return -code error $armList
                }
                set armed 1
                foreach val $armList {
                if !$val {
                    set armed 0
                    break
                }
                }
                if $armed {
                break
                } else {
                    after 1000
                    update
                    #check again until all bpms are being updated.
                }
            }
            #enable 2hz trigger
           # SetStatus "enabled 2 hz trigger ..."
            #if [catch {exec cavput -list=Mt:EG1:eg.ETE7=YES -pend=20} result] {
            #    return -code error "Error in enabling 2Hz injection trigger: $result"
            #}
        }
        SetStatus "wait for all bpms are disarmed..."
        while {1} {
            if [catch {APScavget -list=[join $IOCList ,] -list=:TurnHistoryIsArmed -num -pend=30 } armList] {
                return -code error $armList
            }
            set armed 0
            foreach val $armList ioc $IOCList {
                if $val {
                    set armed 1
                    SetStatus "$ioc is not disarmed ..."
                    break
                } else {
                }
            }
            if !$armed {
                break
            } else {
                after 1000
                update
                #check again until all bpms are being updated.
            }
        }
        SetStatus "All bpms are disarmed."
        if {$type=="P0Feedback"} {
            SetStatus "Set P0Feedback gain to 0."
            SetP0FeedbackGain -xGain 0 -yGain 0
        }
        set fileList ""
        
        SetStatus "collecting data..."
        set file ${outputDir}/scalars-[format %03d $fileIndex].sdds
        if [catch {exec sddscasr -save /home/helios/oagData/sr/FPGAbpm/inputFiles/FPGAbpmTurnHistory.mon $file } result] {
            return -code error "Error in reading scalars: $result"
        }
        if [catch {exec sddswgetdata $monFile -inputStyle=wmon $outputDir/${type}-[format %03d $fileIndex].dat -pend=60} result] {
            return -code error "Error in reading FPGA waveform pvs: $result"
        }
        SetStatus "data collecting done."
        incr fileIndex
    }
    switch $type {
        freq {
            SetStatus "data collecting done. restore RF frequency..."
            if [catch {exec cavput -list=A014-IETS:BTC:SRSetFreqM=-100 -delta  -pend=30 } result] {
                return -code error "Error in changing RF freq: $result"
            }        
        }
        phase {
            SetStatus "data collecting done. restore RF phase..."
            if [catch {exec cavput -list=SRF:K4:PS1:Ch0=$origPhase  -pend=30} result] {
                return -code error $result
            }
        }
    }
    SetStatus "done."
}

set showPlots 0
proc ProcessTurnHistory {args} {
    global outputDir status X Y IOCList fileSelection showPlots fileIndex

    GetSelectedIOCList
    set oldDir [pwd]
    cd $outputDir
    foreach ioc $IOCList {
        foreach bpm [set ${ioc}(bpmList)] {
	    global fpgaBPM$bpm
            if [set fpgaBPM$bpm] {
                set BPM $bpm
                foreach plane {X Y} {
                    if [set $plane] {
                        set file [glob -nocomplain ${BPM}${plane}-[format %03d $fileIndex].sdds]
                        if ![llength $file] {
                            continue
                        }
                        SetStatus "Processing $BPM $plane ..."
                        if [catch {ProcessBPMHistory -filename $file -bpm $BPM -plane $plane -showPlots 1} result] {
                            SetStatus "Error in processing $BPM $plane data: $result"
                        }
                    }
                        
                }
            }
        }
    }
    cd $oldDir
    SetStatus "done."
}



set showPlots 0
proc ProcessTurnHistory {args} {
    global outputDir status X Y IOCList fileSelection showPlots fileIndex

    GetSelectedIOCList
    set oldDir [pwd]
    cd $outputDir
    foreach ioc $IOCList {
        foreach bpm [set ${ioc}(bpmList)] {
	    global fpgaBPM$bpm
            if [set fpgaBPM$bpm] {
                set BPM $bpm
                foreach plane {X Y} {
                    if [set $plane] {
                        set file [glob -nocomplain ${BPM}${plane}-[format %03d $fileIndex].sdds]
                        if ![llength $file] {
                            continue
                        }
                        SetStatus "Processing $BPM $plane ..."
                        if [catch {ProcessBPMHistory -filename $file -bpm $BPM -plane $plane -showPlots 1} result] {
                            SetStatus "Error in processing $BPM $plane data: $result"
                        }
                    }
                        
                }
            }
        }
    }
    cd $oldDir
    SetStatus "done."
}

proc ProcessBPMHistory {args} {
    set bpm ""
    set plane ""
    set filename ""
    set showPlots 0
    APSParseArguments {bpm plane filename showPlots }
    
    set fileRoot [file root $filename]
    set ioc [lindex [split $bpm :] 0]
    set cols [exec sddsquery -col $filename]
    if [regexp {turnHistorySmall} $cols] {
	set pv  ${bpm}:turnHistorySmall:${plane}position
	set sumpv ${bpm}:turnHistorySmall:${plane}sum
    } else {
	set pv ${bpm}:turnHistory:${plane}position
	set sumpv ${bpm}:turnHistory:${plane}sum
    }
    if ![file exist $fileRoot.fft] {
       
        if [catch {exec sddsprocess $filename $fileRoot.sdds1 \
                     "-redefine=col,Time,Index 3.682547610987599e-06 *,units=s"
            exec sddsfft $fileRoot.sdds1 $fileRoot.fft \
                     -col=Time,${pv} -suppressAverage -psdOutput,integrated } result] {
            return -code error "Error1: unable to process  $bpm history data: $result"
        }
        exec mv $fileRoot.sdds1 $filename
    }
    if $showPlots {
        PlotBPMHistory -bpm $bpm -plane $plane -filename $filename
    }
}


set outputDir [APSGoToDailyDirectory -subdirectory fpgaMIA]
set X 1
set Y 0

set fpgaBPMConfigStatus ""
APSApplication . -name "collectFPGAdata" \
  -version $CVSRevisionAuthor \
  -overview "FPGA bpm turn history collection and reviewer."
APSScrolledStatus .status -parent .userFrame -textVariable fpgaBPMConfigStatus -width 70 \
    -height 8 -packOption "-fill both -expand true"
#always collect long waveform
set postTrigger 131072


set waittime 0.5
set plane X
set xGain 16
set yGain 12
set loadRAM 1
set Trigger 2Hz
proc MakeCollectionWidget {args} {
    set parent ""
    APSParseArguments {parent}
    global X Y showPlots fileIndex postTrigger shortLong xGain yGain plane waittime swap RAMscrFile RAMdesc Trigger
    global descList scrList
    APSLabeledEntry .dir -parent $parent -label "Output directory:" -textVariable outputDir -width 70 \
        -contextHelp "directory for writing files to or processing, viewing files from." \
        -fileSelectDirectory 1 -fileSelectButton 1 
    APSFrameGrid .grid1 -parent $parent -xList {x1 x2}
    set w1 $parent.grid1.x1
    set w2 $parent.grid1.x2
    set width 25
    APSLabeledEntry .xgain -parent $w1 -label "P0 feedback x gain:" -textVariable xGain -width $width
    APSLabeledEntry .ygain -parent $w2 -label "P0 feedback y gain:" -textVariable yGain -width $width
    
    APSLabeledEntry .index -parent $w1 -label "File index:" -textVariable fileIndex -width $width  \
	-contextHelp "the filename will be named by file index, and it increases by 1 after each data collection"
    
    APSLabeledEntry .wait -parent $w2 -label "waittime between arm and change rf phase (seconds):" -textVariable waittime -width $width
   
    APSRadioButtonFrame .trigger -parent $w2 -label "Trigger:" -buttonList {"2Hz continuous" "injection"} -valueList {2Hz Injection} \
      -variable Trigger -orientation horizonal
    APSComboboxFrame .scr -parent $parent -label "Select control bits RAM:" \
      -packOption "-fill x" \
      -textVariable RAMdesc \
      -itemList $descList \
      -width 80 -editable 0 \
      -callback "SetRAMSCR -index" \
      -contextHelp "select control RAM file for FPGA data acquisition control."
    
    APSFrame .f -parent $parent -packOption "-side top"
    $parent.f.frame configure -bd 0
    set parent $parent.f.frame
    APSButton .col0 -parent $parent -text "Collect with P0 Feedback" -command "CollectTurnHistory -type P0Feedback"
    APSButton .col1 -parent $parent -text "Collect with RF Phase Scan" -command "CollectTurnHistory -type phase"
    APSButton .col -parent $parent -text "Collect All" -command "CollectTurnHistoryAll"
    APSButton .set0 -parent $parent -text "Set P0Gain to 0" -command "SetP0FeedbackGain -xGain 0 -yGain 0"
    APSButton .restore -parent $parent -text "Restore Single Cogging" -command "RestoreSystem -type single" \
      -contextHelp "restore FPGAs to single bunch."
    APSButton .restore1 -parent $parent -text "Restore 24-singlets Cogging" -command "RestoreSystem -type 24singlets" \
      -contextHelp "restore FPGAs to 24 singlets."
    #APSButton .proc -parent $parent -text "Process turn history" -command "ProcessTurnHistory"
    #APSButton .view -parent $parent -text "Plot turn history" -command "PlotTurnHistory"
    #APSButton .plot1 -parent $parent -text "Plot Raw Data" -command "PlotRawData"
}

proc CollectTurnHistoryAll {args} {
    global RAMscrFile scrList RAMdesc descList

    foreach file  $scrList desc $descList {
        set RAMscrFile $file
        set RAMdesc $desc
        CollectTurnHistory -type P0Feedback
    }
    CollectTurnHistory -type phase
}

proc SetP0FeedbackGain {args} {
    set xGain ""
    set yGain ""
    APSParseArguments {xGain yGain}
    set tmpRoot /tmp/[APSTmpString]
    
    foreach plane {x y} {
        if [catch {exec sddsmakedataset -pipe=out \
                     -col=Waveform,type=double -data=[join [APSReplicateItem -item [set ${plane}Gain] -number 432] ,] \
                     | sddsprocess -pipe=in $tmpRoot.$plane \
                     -print=par,WaveformPV,S:P0FB:AcqGain[string toupper $plane]_SetWF \
                     -define=col,Index,i_row,type=long } result] {
            return -code error "SetGain(1): $result"
        }
        if [catch {exec sddswput $tmpRoot.$plane -pendio=30} result] {
            return -code error "SetGain(2): error in setting $plane plane gain: $result"
        }
    }
}

set SCRdir /home/helios/oagData/SCR/snapshots/SBPMWaveform

proc LoadRAM {args} {
    global SCRdir configuration postTrigger IOCList FPGABpmTurnHistory plane RAMdesc RAMscrFile
    
    if ![string length $RAMscrFile] {
        return -code error "RAM control bits file was not selected."
    }
    
    SetStatus "loading $RAMdesc ..."
    if [catch {APSSCRLogAction -file $RAMscrFile -action restore-start} result] {
        SetStatus "$result"
    }
    set logFile /tmp/[APSTmpString]
    set filename $SCRdir/$RAMscrFile
    
    set restoreError 0
    if [catch {exec sddscasr $filename -restore -logFile=$logFile -pendIOTime=100 \
                 -waveform=directory=$SCRdir,onefile,rootname=[file rootname [file tail [file readlink $filename]]],extension=.waveform.gz } result] {
        SetStatus "Error in loading $RAMscrFile to iocs: $result"
        set restoreError 1
    }
   
    set fd [open $logFile "r"]
    while {![eof $fd]} {
        set text [gets $fd]
        if {[string match -nocase "*error*" $text]} {
            set restoreError 1
            break
        }
    }
    close $fd
    if $restoreError {
        APSFileDisplayWindow [APSUniqueName .fileDisp] -fileName $logFile \
          -comment "Error output from burtwb" -deleteOnClose 1 \
          -printCommand "enscript -r"
    } else {
        SetStatus "done."
    }
}



set triggerChoice "inject continuous (2 hz)"
set triggerValueList continuous
set trigger $triggerChoice
proc RestoreTrigger {args} {
    global IOCList
    set reference /home/helios/oagData/SCR/snapshots/SBPMs/SBPMs-Preferred.gz
    set option ""
    foreach ioc $IOCList {
        if [string length $option] {
            append option ,ControlName=${ioc}:clientEvent*,|
        } else {
            set option -match=col,ControlName=${ioc}:clientEvent*
        }
    }
    set tmpFile /tmp/[APSTmpString]
    if [catch {exec sddsprocess $reference $option $tmpFile.restore} result] {
        return -code error $result
    }
    if [catch {exec sddscasr -restore $tmpFile.restore -pend=60} result] {
        return -code error $result
    }
}

proc ReArmAll {args} {
    global IOCList
    if [catch {exec cavput -list=[join $IOCList ,] \
                 -list=:turn:gtr:trigger=event,:turn:gtr:arm=1 -pend=30} result] {
        return -code error "ReArmAll: $result"    
    }
}

set triggerSetup 0
proc SetupTrigger {args} {
    global IOCList triggerValue triggerSetup IOCList postTrigger  Trigger
    
    #first put trigger to event
    SetStatus "Setup trigger for [join $IOCList ,] ..."
    if [catch {exec cavput -list=[join $IOCList ,] \
                 -list=:turn:gtr:trigger=event,:turn:gtr:arm=1 -pend=30} result] {
        return -code error "SetupTrigger(error1): $result"    
    }
    if [catch {exec cavput -list=[join $IOCList ,] -list=:clientEvent2d.OUT4=Disabled,:clientEvent2d.OUT5=Disabled,:clientEvent33.OUT4=Disabled -pend=30} result] {
        return -code error "SetupTrigger(error1a): $result"
    }
    
    switch $Trigger {
        2Hz {
            set suffix :clientEvent2d.OUT4
        }
        Injection {
            set suffix :clientEvent2d.OUT5
        }
    }
    
    if [catch {exec cavput -list=[join $IOCList ,] \
                 -list=$suffix=1 -pend=30 } result] {
        return -code error "SetupTrigger(error2): $result" 
    }
    SetStatus "set post-trigger ..."
    if [catch {exec cavput -list=[join $IOCList ,] -list=:turn:gtr:numberPTS=$postTrigger -pend=30} result] {
	return -code error "SetupTrigger(error3): $result" 
    }
    set triggerSetup 1
    SetStatus "done."
}

proc SetPostTrigger {args} {
    global postTrigger  IOCList 
    
    if ![llength $IOCList] {
	SetStatus "No bpms selected."
	return
    }
    if [catch {exec cavput -list=[join $IOCList ,] -list=:turn:gtr:numberPTS=$postTrigger -pend=30} result] {
	return -code error "SetPostTrigger: $result" 
    }
}

proc RestoreSystem {type} {
    set type single
    APSParseArguments {type}
    
    global SCRdir
    switch $type {
        single {
            SetStatus "Restore FPGAs to single bunch ..."
            set reference SBPMWaveform-singleBunch.gz
        }
        24singlets {
            SetStatus "Restore FPGAs to 24 singlets ..."
            set reference SBPMWaveform-24singlets.gz
        }
    }
    set logFile /tmp/[APSTmpString]
    set restoreError 0
    set timingFile [file readlink $SCRdir/$reference]
    if [catch {exec sddscasr $timingFile -restore -logFile=$logFile -pendIOTime=100 \
                 -waveform=directory=$SCRdir,onefile,rootname=[file root [file tail $timingFile]],extension=.waveform.gz } result] {
        SetStatus "Error in loading $timingFile to iocs: $result"
        set restoreError 1
    }
    
    set fd [open $logFile "r"]
    while {![eof $fd]} {
        set text [gets $fd]
        if {[string match -nocase "*error*" $text]} {
            set restoreError 1
            break
        }
    }
    close $fd
    if $restoreError {
        APSFileDisplayWindow [APSUniqueName .fileDisp] -fileName $logFile \
          -comment "Error output from burtwb" -deleteOnClose 1 \
          -printCommand "enscript -r"
    } else {
        SetStatus "done."
    }
}

set RAMscrFile ""
set RAMdesc ""
proc SetRAMSCR {args} {
    set index ""
    APSParseArguments {index}

    global descList scrList RAMscrFile RAMdesc
    set RAMscrFile [lindex $scrList $index]
}
set IOCList ""
set allBPMList ""
for {set sector 1} {$sector<=40} {incr sector} {
    lappend IOCList S${sector}A
    lappend allBPMList S${sector}A:P2 S${sector}A:P3 S${sector}A:P4
    lappend IOCList S${sector}B
    lappend allBPMList S${sector}B:P5 S${sector}B:P4 S${sector}B:P3 S${sector}B:P2
}
set xGain 16
set yGain 12

set env(EPICS_CA_MAX_ARRAY_BYTES)  "3000000"
set descList {"Single bunch x or y with no commutation" "Single bunch x only with no commutation" "Single bunch y only with no commutation" }
set scrList {SBPMWaveform-SingleXYonly.gz SBPMWaveform-singleX.gz SBPMWaveform-singleY.gz}

MakeCollectionWidget -parent .userFrame

