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

#
# $Log: not supported by cvs2svn $


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

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

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


proc dirSelectDialog {widget args} {
    global dirSelection
    set filter ""
    APSParseArguments {filter}
    
    global dataDir
    cd $dataDir
    
    if [string length $filter] {
        set dirList [lsort -decreasing [glob -nocomplain $filter]]
    } else {
        set dirList [lsort -decreasing [glob -nocomplain *]]
    }
    APSScrolledListWindow $widget \
      -name "Directory selection" \
      -label "Select a directory" \
      -itemList $dirList \
      -selectionVar dirSelection
    tkwait variable dirSelection
    return $dirSelection
}


proc findDir {args} {
    # General purpose directory selection
    # args is passed to APSFileSelectDialog
    set dirVariable ""
    set trim 0
    APSParseArguments {dirVariable trim}
    global $dirVariable

    set dirName [eval dirSelectDialog .findDirDialog $args]
    if [string length $dirName] {
        # Trim the current working directory from the name
        if $trim {
            set dirName [file tail $dirName]
        }
        set $dirVariable $dirName
    }
}

proc MakeOptionFrame {args} {
    global hResponseDir vResponseDir  hCorrectorType vCorrectorType hBpmType vBpmType
    global steps gain interval averages averageInterval deltaLimit 
    global verbose FFcompensation  datapool pvTest
    global hDespikeNeighbors hDespikeAverage hDespikePasses hDespikeThresholdStart hDespike
    global vDespikeNeighbors vDespikeAverage vDespikePasses vDespikeThresholdStart vDespike
    global hDespikeThresholdEnd hDespikeThresholdSteps hDespikeCountLimit
    global vDespikeThresholdEnd vDespikeThresholdSteps vDespikeCountLimit
    global dataDir
    
    APSParseArguments {parent}
    
    set width 20
    
    APSFrame .par1 -parent $parent -label "Common Parameters"
    set w $parent.par1.frame
    
    APSLabeledEntry .dir -parent $w -label "Correction Matrix directory:" -width 80 \
      -textVariable dataDir
    APSFrameGrid .grid -parent $w -xList {x1 x2}
    set w1 $w.grid.x1
    set w2 $w.grid.x2
    APSLabeledEntry .gain -parent $w1 -label "gain" \
      -textVariable gain -width $width \
      -contextHelp "Enter the gain (i.e. fraction of correction at each interval)"
    APSLabeledEntry .interval -parent $w1 -label "interval for datapool (s)" \
      -textVariable interval -width $width \
      -contextHelp "Enter the interval between correction steps for datapool orbit correction."
    
    APSLabeledEntry .deltaLimit -parent $w2 -label "corrector delta limit (A)" \
      -textVariable deltaLimit -width $width \
      -contextHelp "Enter the upper limit for corrector change. The corrector with the maximum change will be compared to this value. If necessary, all correctors will be scaled sown so that the corrector with the largest change will not exceed the limit."
    APSLabeledEntry .averages -parent $w2 -label "averages" \
      -textVariable averages -width $width \
      -contextHelp "Enter the number of averages of bpms at each iteration."
    APSLabeledEntry .averageInterval -parent $w2 -label "interval in averaging" \
      -textVariable averages -width $width \
      -contextHelp "Enter the interval between readbacks for the bpm averaging."
    APSCheckButtonFrame .checkButton -parent $w -label "" \
      -buttonList {"Use pvTest " "RTDC overlap compensation" } \
      -variableList {pvTest  FFcompensation} \
      -orientation horizontal \
      -contextHelp "Check one of the following options:\n\nVerbose output in the APS exec log window\nsddscontrollaw running in dry run mode, i.e. no change in correctors setpoints\nApply feedforwad setpoint to RT feedback syste.\nLog actuator values\nDespike H or V or both orbits."


    APSFrameGrid .grid -parent $parent -xList {h v}
    
    foreach plane {h v}  {
        set w $parent.grid.$plane
        APSLabel .label -parent $w -text "       $plane plane  options"
        APSLabeledEntry .responseDir -parent $w -label "Configuration" \
          -textVariable ${plane}ResponseDir -width $width -contextHelp \
          "Name of the directory for the response file for the $plane plane which can be used with sddscontrollaw."
        
        APSButton .dir -parent $w.responseDir \
          -text F -packOption "-side right" \
          -command "findDir -dirVariable ${plane}ResponseDir -filter ${plane}.*;GetBPMAndCorrectorType -fileVariable ${plane}ResponseDir" \
          -contextHelp "Bring up a directory selection dialog box to choose the directory."
        
        APSButton .get -parent $w.responseDir \
          -text Get  -packOption "-side right"  \
          -command "GetBPMAndCorrectorType -fileVariable ${plane}ResponseDir" \
          -contextHelp "get the bpm and corrector type from the configuration file"
        # APSFrame .type -parent $w
        APSLabeledEntry .type1 -parent $w -label "bpm type:" \
          -textVariable ${plane}BpmType -width $width -contextHelp \
          "bpm type: DP or plain." 
        APSLabeledEntry .type2 -parent $w -label "corrector type:" \
          -textVariable ${plane}CorrectorType -width $width -contextHelp \
          "corrector type: DP, plain or dynamic."
        
        
        APSLabeledEntry .passess -parent $w \
          -label "Despike passes:" -textVariable ${plane}DespikePasses -width $width \
          -contextHelp "Enter the number of passes to make through the despiker to get the smoothed orbit."
        APSLabeledEntry .despike0 -parent $w \
          -label "Spike find neighbors:" \
          -textVariable ${plane}DespikeNeighbors -width $width  \
          -contextHelp "Enter the number of neighbors to average over for the spike finder."
        APSLabeledEntry .despike1 -parent $w \
          -label "Spike smooth neighbors:" \
          -textVariable ${plane}DespikeAverage -width $width  \
          -contextHelp "Enter the number of neighbors to average over for the spike smoother.  Must be less than the number used for the spike finder."
        APSLabeledEntry .despike3 -parent $w \
          -label "Initial spike threshold in mm:" \
          -textVariable ${plane}DespikeThresholdStart -width $width  \
          -contextHelp "Enter the initial (startup) threshold below which despiking will not occur."
        APSLabeledEntry .despike4 -parent $w \
          -label "Final spike threshold in mm: " \
          -textVariable ${plane}DespikeThresholdEnd -width $width \
          -contextHelp "Enter the final (normal running) threshold below which despiking will not occur."
        APSLabeledEntry .despike5 -parent $w \
          -label "Steps in spike threshold ramp:  " \
          -textVariable ${plane}DespikeThresholdSteps -width $width  \
          -contextHelp "Enter the number of correction steps to take in ramping from the initial to the final spike threshold."
        
        APSLabeledEntry .despike6 -parent $w \
          -label "Spikes count limit:" \
          -textVariable ${plane}DespikeCountLimit -width $width  \
          -contextHelp "Enter the number of limit to avoid despiking if there are more than CountLimit readings outside the despiking threshold."
        APSCheckButtonFrame .check -parent $w \
          -label "" -buttonList {despike "reramp despike threshold"} -variableList [list ${plane}Despike ${plane}DespikeThresholdReramp] \
          -orientation horizontal \
          -contextHelp "Check one of the following options:\n\nDespike H or V or both orbits.\nRe-ramp h despike threshold or v despike threshold or both." 
        APSButton .$plane -parent $w \
          -text "Revert Despiking Defaults" -command  "setDespikeDefaults -plane [string toupper $plane]" \
          -contextHelp {Reverts to the H plane despiking defaults for the mode selected.}
	APSButton .view -parent $w  \
          -text "View" -command "ViewControllawOption -plane $plane" \
          -contextHelp "Press button to view and change the DP controllaw option."
        APSButton .update -parent $w  \
          -text "Update" -command "UpdateControllawOption -plane $plane" \
          -contextHelp "Press button to view and change the DP controllaw option."
	
    }
}

proc setDespikeDefaults {args} {
    global hDespikeNeighbors hDespikeAverage hDespikePasses hDespike
    global vDespikeNeighbors vDespikeAverage vDespikePasses vDespike
    global hDespikeThresholdStart hDespikeThresholdEnd hDespikeThresholdSteps
    global vDespikeThresholdStart vDespikeThresholdEnd vDespikeThresholdSteps 
    global hDespikeCountLimit vDespikeCountLimit
    global hDespikeThresholdRampPV vDespikeThresholdRampPV
    global hDespikeThresholdReramp vDespikeThresholdReramp 
    
    APSParseArguments {plane}
    if ![string compare $plane both] {
        set plane {H V}
    }
    foreach eachPlane $plane {
        switch $eachPlane {
            H {
                set hDespikeNeighbors 36
                set hDespikeAverage 4
                set hDespikePasses 2
                set hDespikeThresholdEnd 0.02
                set hDespikeThresholdStart 3.0
                set hDespikeThresholdSteps 30
                set hDespikeCountLimit 1000
                set hDespike 1
                set hDespikeThresholdRampPV S:OC:rampDespikeThreshX
                set hDespikeThresholdReramp 1
            }
            V {
                set vDespikeNeighbors 36
                set vDespikeAverage 4
                set vDespikePasses 2
                set vDespikeThresholdEnd 0.02
                set vDespikeThresholdStart 3.0
                set vDespikeThresholdSteps 30
                set vDespikeCountLimit 1000
                set vDespike 0
                set vDespikeThresholdRampPV S:OC:rampDespikeThreshY
                set vDespikeThresholdReramp 0
            }
        }
    }
    return
}

proc GetBPMAndCorrectorType {args} {
    set fileVariable ""
    global hCorrectorType vCorrectorType hBpmType vBpmType 
    APSParseArguments {fileVariable}
    set plane [string range $fileVariable 0 0]
    global $fileVariable dataDir
    set file $dataDir/[set $fileVariable]/config
    set names [APSGetSDDSParameter -fileName $file -parameter NameType]
    set types [APSGetSDDSParameter -fileName $file -parameter PVType]
    set i [lsearch -exact $names MonitorNames]
    set j [lsearch -exact $names CorrectorNames]
    if {$i==-1 || $j==-1} {
        SetSROrbitStatus "NameType paremeter in config file is not correct!" -code error
        return
    }
    set ${plane}BpmType [lindex $types $i]
    set ${plane}CorrectorType [lindex $types $j]
}

proc ViewControllawOption {args} {
    set plane ""
    APSParseArguments {plane}
    
    global dataDir PVSuffix
    global gain interval  averages averageInterval deltaLimit
    global FFcompensation
    global hResponseDir vResponseDir
    global hRunControlPV vRunControlPV 
    global hRunControlDesc vRunControlDesc 
    global hDespikeNeighbors hDespikeAverage hDespikePasses hDespike
    global vDespikeNeighbors vDespikeAverage vDespikePasses vDespike
    global pvTest 
    global hCorrectorType vCorrectorType hBpmType vBpmType oxygenStation
    global hDespikeThresholdStart vDespikeThresholdStart 
    global hDespikeThresholdEnd hDespikeThresholdSteps hDespikeCountLimit
    global vDespikeThresholdEnd vDespikeThresholdSteps vDespikeCountLimit
    global hDespikeThresholdRampPV vDespikeThresholdRampPV
    global hDespikeThresholdReramp vDespikeThresholdReramp
   
    switch $plane {
        h {
            set dir $dataDir/$hResponseDir
            set coord x
            set Coord X
            set Plane H
        }
        v {
            set dir $dataDir/$vResponseDir
            set coord y
            set Coord Y
            set Plane V
        }
        default {
            return -code error "plane has to be h or v!"
        }
    }
    if [catch {APScagetTextFromWaveform -pvName DP:S:OrbitControlLaw${Coord}SDDS.OPTN } currentOpt] {
        return -code error "Unable to read options: $currentOpt"
    }
    SetStatus "The current option for $plane plane is:"
    SetStatus "$currentOpt"
    
    set ${plane}ResponseDir [file tail [file dir [lindex [split $currentOpt " "] 1]]]
    
    GetBPMAndCorrectorType -fileVariable ${plane}ResponseDir
    if [catch {exec cavget -list=DP:S:OrbitControlLaw${Coord}SDDS.INTR } interval] {
	return -code error "Error reading interval: $interval"
    }
    if [catch {exec cavget -list=DP:S:OrbitControlLaw${Coord}SDDS.AVER -pend=30} averages] {
        return -code error "Error reading averages: $averages!"
    }
    if [catch {exec cavget -list=DP:S:OrbitControlLaw${Coord}SDDS.GAIN -pend=30} gain] {
        return -code error "Error reading gain: $gain"
    }
    if [catch {exec cavget -list=DP:S:OrbitControlLaw${Coord}SDDS.SPKE -pend=30} result] {
	return -code error "Error reading dispike threshold staart: $result"
    }
    set ${plane}DespikeThresholdStart $result
    
    set result [regexp "deltaLimit(.*)" $currentOpt a b c]
    set deltaLimit [lindex [split [lindex [split $a " "] 0] "="] 2]
   
    
}

proc UpdateControllawOption {args} {
    set plane ""
    APSParseArguments {plane}
    
    global dataDir PVSuffix
    global gain interval  averages averageInterval deltaLimit
    global FFcompensation
    global hResponseDir vResponseDir
    global hRunControlPV vRunControlPV 
    global hRunControlDesc vRunControlDesc 
    global hDespikeNeighbors hDespikeAverage hDespikePasses hDespike
    global vDespikeNeighbors vDespikeAverage vDespikePasses vDespike
    global pvTest 
    global hCorrectorType vCorrectorType hBpmType vBpmType oxygenStation
    global hDespikeThresholdStart vDespikeThresholdStart 
    global hDespikeThresholdEnd hDespikeThresholdSteps hDespikeCountLimit
    global vDespikeThresholdEnd vDespikeThresholdSteps vDespikeCountLimit
    global hDespikeThresholdRampPV vDespikeThresholdRampPV
    global hDespikeThresholdReramp vDespikeThresholdReramp
   
    switch $plane {
        h {
            set dir $dataDir/$hResponseDir
            set coord x
            set Coord X
            set Plane H
        }
        v {
            set dir $dataDir/$vResponseDir
            set coord y
            set Coord Y
            set Plane V
        }
        default {
            return -code error "plane has to be h or v!"
        }
    }
    if [catch {APScagetTextFromWaveform -pvName DP:S:OrbitControlLaw${Coord}SDDS.OPTN } currentOpt] {
        return -code error "Unable to read options: $currentOpt"
    }
    

    SetStatus "The current option for $plane plane is:"
    SetStatus "$currentOpt"
    if ![APSYesNoPopUp "Would you like to change the option now?"] {
        SetStatus "option is not changed."
        return
    }
    SetStatus "Preparing DP controllaw options..."
    GetBPMAndCorrectorType -fileVariable ${plane}ResponseDir
    if {[set ${plane}BpmType]!="DP" || [set ${plane}CorrectorType]!="DP"} {
        SetStatus "Error non datapool directory -- $dir  provided. "
        return
    }
    if ![file exists $dir/tests] {
        return -code error "Can't find file tests."
    }
    if ![file exists $dir/definitions.${PVSuffix}] {
        return -code error "Can't find file definitions.${PVSuffix}."
    }
    if ![file exists $dir/irm] {
        return -code error "Can't find file irm."
    }
    if ![file exists $dir/inUse] {
        return -code error "Can't find file inUse."
    }
    if ![file exists $dir/enables] {
        return -code error "Can't find file enables."
    }

    set foundBPM 0
    set foundCorr 0
    catch {exec sddsquery -col $dir/irm} irmColumns
    foreach bpm $irmColumns {
        if [regexp S..+:P. $bpm] {
            set foundBPM 1
            continue
        }
    }
    catch {exec sdds2stream -col=ControlName $dir/irm} irmCorrector
    foreach corrector $irmCorrector {
        if [regexp S..+:${Plane}. $corrector] {
            set foundCorr 1
            continue
        }
    }
    if [expr !$foundBPM || !$foundCorr] {
        APSAlertBox .alert -errorMessage "Could not find a valid bpm or corrector in file $dir/irm for correction in ${coord} plane."
        return -code error "Error!"
    }
  
    set options "-launcherpv=DP:S:OrbitControlLaw${Coord}SDDS $dir/irm"
    if {![file exist $dir/corrWaveform]} {
        return -code error "File corrWaveform does not exist, use Generate to generate it first"
    }
    append options " -waveforms=$dir/corrWaveform,actuator -proportional"
    if $FFcompensation {
        if {![file exist $dir/ffWaveform] } {
            return -code error "File ffWaveform does not exist, use Generate to generate it first"
        }
        append options " -waveforms=$dir/ffWaveform,ffSetpoint"
    }
    if {![file exist $dir/bpmWaveform]} {
        return -code error "File bpmWaveform does not exist, use Generate to generate it first"
    }
    append options " -waveforms=$dir/bpmWaveform,readback"
    if {![file exist $dir/waveformTest]} {
        return -code error "File waveformTest does not exist, use Generate to generate it first"
    }
     SetStatus "setting DP:S:OrbitControlLaw${Coord}SDDS.INTR=$interval ..."
    if [catch {exec cavput -list=DP:S:OrbitControlLaw${Coord}SDDS.INTR=$interval -pend=30} result] {
        return -code error $result
    }
   
    SetStatus "setting DP:S:OrbitControlLaw${Coord}SDDS.AVER=$averages ..."
    if [catch {exec cavput -list=DP:S:OrbitControlLaw${Coord}SDDS.AVER=$averages -pend=30} result] {
        return -code error $result
    }
   
    SetStatus "setting DP:S:OrbitControlLaw${Coord}SDDS.GAIN=$gain ..."
    if [catch {exec cavput -list=DP:S:OrbitControlLaw${Coord}SDDS.GAIN=$gain -pend=30} result] {
        return -code error $result
    }
    append options " -waveforms=$dir/waveformTest,test"
    append options " -infiniteLoop -gain=PVname=DP:S:OrbitControlLaw${Coord}SDDS.GAIN"
    append options " -interval=PVname=DP:S:OrbitControlLaw${Coord}SDDS.INTR"
    append options " -average=PVname=DP:S:OrbitControlLaw${Coord}SDDS.AVER"
    if {$deltaLimit > 0 } {
        append options " -deltaLimit=value=$deltaLimit"
    } else {
        SetStatus "Warning: negative deltaLimit ignored." 
    }
    if {$FFcompensation} {
        append options " -auxiliaryOutput=gain=1.0,matrix=$dir/rmFF,controlquantitydefinition=$dir/FFdefs,mode=proportional"
    }
    if [subst \$${plane}Despike] {
        if [file exists despike] {
            set optionExten ",file=$dir/despike"
        } else {
            set optionExten ""
        }
        if [catch {exec cavput \
                     -list=DP:S:OrbitControlLaw${Coord}SDDS.SPKE=[set ${plane}DespikeThresholdStart] \
                     -pend=30 } result] {
            return -code error $result
        }
        append options " -despike=passes=[set ${plane}DespikePasses],neighbors=[set ${plane}DespikeNeighbors],averageOf=[set ${plane}DespikeAverage],countLimit=[set ${plane}DespikeCountLimit],pvthreshold=DP:S:OrbitControlLaw${Coord}SDDS.SPKE$optionExten"
        if {[set ${plane}DespikeThresholdSteps]>2} {
            append options ",startThreshold=[set ${plane}DespikeThresholdStart],endThreshold=[set ${plane}DespikeThresholdEnd],stepsThreshold=[set ${plane}DespikeThresholdSteps]"
            if [set ${plane}DespikeThresholdReramp] {
                append options ",rampThresholdPV=[set ${plane}DespikeThresholdRampPV]"
            }
            
        }
    }
    if !$pvTest {
        set controlTest tests
    } else {
        set controlTest DP${Plane}tests
        append options " -testValues=$dir/$controlTest -actuator=ControlName -controlQuantityDefinitions=$dir/definitions.$PVSuffix"
    }
    SetStatus "$options"
    SetStatus "Set options to DP:S:OrbitControlLaw${Coord}SDDS.OPTN"
    if [catch {APScaputTextToWaveform -pvName DP:S:OrbitControlLaw${Coord}SDDS.OPTN -text $options} result] {
        return -code error "Unable to set options: $result"
    }
    SetStatus "done."
}

set homeDir [pwd]
set steps 300000
set gain 0.4
set interval 0.1
set deltaLimit 0.5
set averages 1
set averageInterval 1
set FFcompensation 1
set PVSuffix msAve
set filterCoeff 0.1
set hResponseDir h.defaultDP
set vResponseDir v.defaultDP

set dataDir /home/helios/oagData/sr/orbitControllaw/lattices/default
cd $dataDir
set pvTest 1
set tolerance 0.02
set hCorrectorType ""
set hBpmType ""
set vCorrectorType ""
set vBpmType ""
set home $env(HOME)

set status ""

setDespikeDefaults -plane both
GetBPMAndCorrectorType -fileVariable hResponseDir
GetBPMAndCorrectorType -fileVariable vResponseDir

APSApplication . -name "DPControllawOption" -version $CVSRevisionAuthor \
  -overview "DPControllawOption provides convenience controls for changing DP orbit controllaw options."
APSScrolledStatus .status -parent .userFrame -width 60 \
  -textVariable status

MakeOptionFrame -parent .userFrame

