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

#simplified from SROrbitControllaw, there is no datapool in APSU, so only workstation based orbit correction.

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)]


if {[info exists tcl_pkgPath]} {
    set expectLib [file join [lindex $tcl_pkgPath 0] expect5.45.3 libexpect5.45.3.so]
    if {($tcl_platform(os) == "Linux") && [file exists $expectLib]} {
        load $expectLib
    } else {
        if {[catch {package require Expect} results]} {
            APSAlertBox [APSUniqueName .] -errorMessage "$results"
            exit 1
        }
    }
} else {
    if {[catch {package require Expect} results]} {
        APSAlertBox [APSUniqueName .] -errorMessage "$results"
        exit 1
    }
}

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

proc SetSROrbitStatus {text args} {
    global SROrbitStatus
    set code ""
    APSParseArguments {code}
    set SROrbitStatus "[exec date +%H:%M:%S] $text"
    update
    switch $code {
        error -
        warning {
            bell
        }
        default {
        }
    }
}

proc SetDespikeDefaults {args} {
    set plane ""
    APSParseArguments {plane}
    global OC
    set OC($plane.despikePasses) 2
    set OC($plane.despikeNeighbors) 36
    set OC($plane.despikeAverage) 4
    set OC($plane.despikeCountLimit) 1000
    set OC($plane.despikeThresholdStart) 3.0
    set OC($plane.despikeThresholdEnd) 0.02
    set OC($plane.despikeThresholdSteps) 30
    set OC($plane.despikeThresholdReramp) 0
}

proc SetDefaultPars {args} {
    global OC
    #common parameters
    set OC(timeFilter) LowPass1s
    set OC(steps) 300000
    set OC(gain) 0.4
    set OC(interval) 2
    set OC(deltaLimit) 0.2
    set OC(averages) 1
    set OC(averageInterval) 1
    set OC(verbose) 1
    set OC(dryRun) 0
    set OC(FFcompensation) 1
    set OC(BPMLimit) 10000
    set OC(XBPMLimit) 500
    set OC(hcorrLimitMargin) 0
    set OC(vcorrLimitMargin) 0
    set OC(logActuators) 1
    set OC(logStats) 1
    set OC(logGlitch) 0
    set OC(dataDir) /home/helios/oagData/sr/orbitControllaw/lattices/default
    set OC(RCTimeout) 30
    set OC(pvTest) 1
    set OC(tolerance) 0.02
    set OC(corrAOAItolerance) 2.0
    set OC(corrDacAOtolerance) 0.2
    
    
    #plane specific
    set OC(h.responseDir) h.default
    set OC(v.responseDir) v.default
    set OC(h.runControlPV) "S:RC:OrbitControlLawXC"
    set OC(h.runControlPV) "S:SlowOrbitControlLawXRC"
    set OC(h.runControlDesc) "SR x-orbit correction"
    set OC(v.runControlPV) "S:RC:OrbitControlLawYC"
    set OC(v.runControlPV) "S:SlowOrbitControlLawYRC"
    set OC(v.runControlDesc) "SR y-orbit correction"
    set OC(h.DCCTLimit) 0.5
    set OC(v.DCCTLimit) 0.5
    #despike
    set OC(h.despikePasses) 2
    set OC(v.despikePasses) 2
    set OC(h.despikeNeighbors) 36
    set OC(v.despikeNeighbors) 36
    set OC(h.despikeAverage) 4
    set OC(v.despikeAverage) 4
    set OC(h.despikeCountLimit) 1000
    set OC(v.despikeCountLimit) 1000
    set OC(h.despikeThresholdStart) 3.0
    set OC(v.despikeThresholdStart) 3.0
    set OC(h.despikeThresholdEnd) 0.02
    set OC(v.despikeThresholdEnd) 0.02
    set OC(h.despikeThresholdSteps) 30
    set OC(v.despikeThresholdSteps) 30
    set OC(h.despike) 0
    set OC(v.despike) 0
    set OC(h.despikeThresholdReramp) 0
    set OC(v.despikeThresholdReramp) 0
    
    
    #reference file
    set OC(defaultSetpointRef) /home/helios/oagData/SCR/snapshots/SR/SR-UserBeamPreferred.gz
    set OC(defaultGainRef) /home/helios/oagData/SCR/snapshots/SBPMs/SBPMs-Preferred.gz
    set OC(defaultOffsetRef) /home/helios/oagData/SCR/snapshots/SR/SR-BPMOffsetReference.gz
    set OC(defaultCorrRef) /home/helios/oagData/SCR/snapshots/SR/SR-UserBeamPreferred.gz
    
    set OC(correctorReferenceFile) $OC(defaultCorrRef)
    set OC(setpointReferenceFile)  $OC(defaultSetpointRef)
    set OC(gainReferenceFile)      $OC(defaultGainRef)
    set OC(offsetReferenceFile)    $OC(defaultOffsetRef)
}


proc MakeOptionAndParameterFrame {widget args} {
    set parent ""
    APSParseArguments {parent}

    global OC
    
    APSFrame $widget -parent $parent -label "sddscontrollaw options and test parameters" \
      -contextHelp "Frame to specify command line options for the sddscontrollaw command and test parameters."
    
    set widgetList [APSTabFrame .options -parent $parent$widget.frame -label "" \
                      -labelList {Options "Despike Parameters" "Other Parameters" References} \
                      -width 900 -height 220 -packOption "-expand yes -fill both"]
    
    pack $parent$widget.frame.options -side top
    # options frame
    set index 0
    set w0 [lindex $widgetList $index]
    incr index
    APSFrameGrid .fg -parent $w0 -xList {x1 x2}
    set w $w0.fg.x1
    APSLabeledEntry .steps -parent $w -label "steps" \
      -textVariable OC(steps) -width 10 \
      -contextHelp "Enter the number of steps to perform."
    APSLabeledEntry .gain -parent $w -label "gain" \
      -textVariable OC(gain) -width 10 \
      -contextHelp "Enter the gain (i.e. fraction of correction at each interval)"
    APSLabeledEntry .intervalDP -parent $w -label "interval (s)" \
      -textVariable OC(interval) -width 10 \
      -contextHelp "Enter the interval between correction steps."
    
    APSLabeledEntry .deltaLimit -parent $w -label "corrector delta limit (A)" \
      -textVariable OC(deltaLimit) -width 10 \
      -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."
    set w $w0.fg.x2
    APSLabeledEntry .averages -parent $w -label "averages" \
      -textVariable OC(averages) -width 10 \
      -contextHelp "Enter the number of averages of bpms at each iteration."
    APSLabeledEntry .averageInterval -parent $w -label "interval in averaging" \
      -textVariable OC(averageInterval) -width 10 \
      -contextHelp "Enter the interval between readbacks for the bpm averaging."
    APSLabeledEntry .timeout -parent $w -label "runControl timeout (s) " \
      -textVariable OC(RCTimeout) -width 10 -contextHelp \
      "Enter the run control timeout in seconds."
    APSRadioButtonFrame .bpmerror -parent $w -label "BPM Time filter:" -variable OC(timeFilter) \
	-buttonList {1-second Raw} -valueList {LowPass1s Sampled} -orientation horizontal
    
    APSCheckButtonFrame .checkButton -parent $w0 -label "" \
      -buttonList {"dry run " "log actuators " "log stats" "log glitch"} \
      -variableList {OC(dryRun) OC(logActuators) OC(logStats) OC(logGlitch)} \
      -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."
    $w0.checkButton.frame configure -relief flat


    # set w $w0.fg.x2
    set w0 [lindex $widgetList $index]
    incr index
    APSFrameGrid .fg -parent $w0 -xList {x1 x2}
    set w $w0.fg.x1
    APSLabeledEntryFrame .despike2 -parent $w \
      -label "Despike passes (H, V):         " \
      -variableList {OC(h.despikePasses) OC(v.despikePasses)} -width 5 -orientation horizontal \
      -contextHelp "Enter the number of passes to make through the despiker to get the smoothed orbit."
    APSLabeledEntryFrame .despike0 -parent $w \
      -label "Spike find neighbors (H, V):   " \
      -variableList {OC(h.despikeNeighbors)  OC(v.despikeNeighbors)} -width 5 -orientation horizontal  \
      -contextHelp "Enter the number of neighbors to average over for the spike finder."
    APSLabeledEntryFrame .despike1 -parent $w \
      -label "Spike smooth neighbors (H, V): " \
      -variableList {OC(h.despikeAverage) OC(v.despikeAverage)} -width 5 -orientation horizontal \
      -contextHelp "Enter the number of neighbors to average over for the spike smoother.  Must be less than the number used for the spike finder."
    APSLabeledEntryFrame .despike6 -parent $w \
      -label "Spikes count limit (H, V):     " \
      -variableList {OC(h.despikeCountLimit) OC(v.despikeCountLimit)} -width 5 -orientation horizontal \
      -contextHelp "Enter the number of limit to avoid despiking if there are more than CountLimit readings outside the despiking threshold."
    set w $w0.fg.x2
    APSLabeledEntryFrame .despike3 -parent $w \
      -label "Initial spike threshold in mm (H, V):  " \
      -variableList {OC(h.despikeThresholdStart) OC(v.despikeThresholdStart)} -width 5 -orientation horizontal \
      -contextHelp "Enter the initial (startup) threshold below which despiking will not occur."
    APSLabeledEntryFrame .despike4 -parent $w \
      -label "Final spike threshold in mm (H, V):    " \
      -variableList {OC(h.despikeThresholdEnd) OC(v.despikeThresholdEnd)} -width 5 -orientation horizontal \
      -contextHelp "Enter the final (normal running) threshold below which despiking will not occur."
    APSLabeledEntryFrame .despike5 -parent $w \
      -label "Steps in spike threshold ramp (H, V):  " \
      -variableList {OC(h.despikeThresholdSteps) OC(v.despikeThresholdSteps)} -width 5 -orientation horizontal \
      -contextHelp "Enter the number of correction steps to take in ramping from the initial to the final spike threshold."
    
    
    #despike frame
    APSFrame .revertDespike -parent $w
    $w.revertDespike.frame configure -relief flat
    global apsContextHelp
    label $w.revertDespike.frame.label -text "Revert despiking defaults   "
    set apsContextHelp($w.revertDespike.frame.label) "Buttons to revert to the despiking defaults for the correction mode selected."
    pack $w.revertDespike.frame.label -side left
    APSButton .h -parent $w.revertDespike.frame \
      -text "H" -packOption "-ipadx 14 -side left" \
      -command {SetDespikeDefaults -plane h} \
      -contextHelp {Reverts to the H plane despiking defaults for the mode selected.}
    APSButton .v -parent $w.revertDespike.frame \
      -text "V"  -packOption "-ipadx 14" \
      -command {SetDespikeDefaults -plane v} \
      -contextHelp {Reverts to the V plane despiking defaults for the mode selected.}
    APSCheckButtonFrame .checkButton -parent $w0 -label "" \
      -buttonList {"despike H " "despike V " "reramp despike threshold H " "reramp despike threshold V"} \
      -variableList {OC(h.despike) OC(v.despike) OC(h.despikeThresholdReramp) OC(v.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."
    $w0.checkButton.frame configure -relief flat  
    
    #parameters frame
    set w0 [lindex $widgetList $index]
    incr index
    APSFrameGrid .fg -parent $w0 -xList {x1 x2}
    set w1 $w0.fg.x1
    set w2 $w0.fg.x2
  
    APSLabeledEntry .currLimitH -parent $w1 -label "S35DCCT lower limit (mA) for H plane" \
      -textVariable OC(h.DCCTLimit) -width 10 \
      -contextHelp "Enter the lower limit of S35DCCT readback below which the sddscontrollaw correction iteration is skipped."
    APSLabeledEntry .currLimitV -parent $w1 -label "S35DCCT lower limit (mA) for V plane" \
      -textVariable OC(v.DCCTLimit) -width 10 \
      -contextHelp "Enter the lower limit of S35DCCT readback below which the sddscontrollaw correction iteration is skipped."
    APSLabeledEntry .bpmLimit -parent $w1 -label "bpm limit (mm)" \
      -textVariable OC(BPMLimit) -width 10 \
      -contextHelp "Enter the range of bpm readback outside of which the sddscontrollaw correction iteration is skipped."
    APSLabeledEntry .xbpmLimit -parent $w1 -label "Xray bpm limit (mm)" \
      -textVariable OC(XBPMLimit) -width 10 \
      -contextHelp "Enter the range of Xray bpm readback outside of which the sddscontrollaw correction iteration is skipped."
   
   
    APSLabeledEntry .corrtol -parent $w2 -label "Corr. AO-AI Tolerance (A)" \
      -textVariable OC(corrAOAItolerance) -width 20 \
      -contextHelp "The tolerance for  the difference of corrector's DacAI/CurrentAO and CurrentAI."
    APSLabeledEntry .corrtol1 -parent $w2 -label "Corr. DacAI-CurrentAO Tolerance (A)" \
      -textVariable OC(corrDacAOtolerance) -width 20 \
      -contextHelp "The tolerance for  the difference of corrector's DacAI and CurrentAO."
    APSLabeledEntry .corrlimit -parent $w2 -width 20 \
	-textVariable OC(hcorrLimitMargin) -label "H Corrector limit margin (A):" \
	-contextHelp "The h corrector limit margin, the acutal limit will be DriveLow + Margin, DriveHigh - Margin"
    APSLabeledEntry .corrlimit1 -parent $w2 -width 20  \
	-textVariable OC(vcorrLimitMargin) -label "v Corrector limit margin (A):" \
	-contextHelp "The v corrector limit margin, the acutal limit will be DriveLow + Margin, DriveHigh - Margin"
    
    set w0 [lindex $widgetList $index]
    incr index
    APSFrameGrid .grid -parent $w0 -yList {y1 y2 y3 y4}
    set w $w0.grid.y1
    APSLabeledEntry .offsetentry -parent $w -label "Offset:   " \
      -textVariable  OC(offsetReferenceFile) -width 90 -contextHelp \
      "name of the 20-term offset reference file"
   
    set w $w0.grid.y2
    APSLabeledEntry .setpointentry -parent $w -label "Setpoint: " \
      -textVariable  OC(setpointReferenceFile) -width 90 -contextHelp \
      "name of the 20-term setpoint reference file"
   
    set w $w0.grid.y3
    APSLabeledEntry .gainentry -parent $w -label "Gain:     " \
      -textVariable  OC(gainReferenceFile) -width 90 -contextHelp \
      "name of the 20-term gain reference file"
    
    set w $w0.grid.y4
    APSLabeledEntry .gainentry -parent $w -label "Corrector:" \
      -textVariable  OC(correctorReferenceFile) -width 90 -contextHelp \
      "Name of the corrector gain reference file that will be used in the \"TRANSFER CORR REFERENCE\" button. The default is the UBOP file. For special studies which require a much different steering, a new file will have to be entered here."
    
    return 0

}

proc InstallFile {args} {
    set plane ""
    APSParseArguments {plane}
    global OC
    set oldDir [pwd]
    cd $OC(dataDir)

    set file $OC($plane.responseDir)/config
    if ![file exist $file] {
	return -code error "$file does not exist, can not install!"
    }
    if {![APSMultipleChoice [APSUniqueName .] \
            -question "Link $OC($plane.responseDir) to $plane.default? Are you sure?" -returnList {1 0} \
            -labelList {Yes No}]} {
        return
    }
    catch {exec rm ${plane}.default}
    exec ln -s $OC($plane.responseDir) $plane.default
    cd $oldDir
}


proc PickFileFromDir {args} {
    set plane ""
    APSParseArguments {plane}
    global OC
    set desc 0
    set descFile  [set OC(dataDir)]/${plane}configDesc.sdds
    if [file exist $descFile] {
	set desc 1
    }
    if $desc {
	set itemList [split [exec sdds2stream $descFile -col=Description] \n]
	set choiceList [exec sdds2stream $descFile -col=Filename]
    } else {
	set oldDir [pwd]
	cd $OC(dataDir)
	set fileList [lsort -descreaing [glob -complain ${plane}.*]]
	if ![llenght $fileList] {
	    return -code error "No configuration found!"
	}
	set choiceList ""
	set itemList ""
	foreach file $fileList {
	    if [file isdirectory $OC(dataDir)/$file] {
		lappend choiceList $file
		if {[file type $OC(dataDir)/$file]=="link"} {
		    set link [file tail [file readlink $OC(dataDir)/$file]]
		    lappend itemList "$file -> $link"
		} else {
		    set description [lindex [exec sdds2stream -par=Description $OC(dataDir)/$file/config] 0]
		    lappend itemList "$file -> $description"
		}
	    }
	}
    }
    
    if ![llength $choiceList] {
	return -code error "No configuration found1"
    }
    set OC($plane.responseDir) [APSChooseItemFromList -name ChoiceList -height 30 \
                 -itemList $itemList -returnList $choiceList -multiItem 0]
    
}

proc BringUpBPMADT {args} {
    set plane ""
    APSParseArguments {plane}

   
    exec adt -f /home/helios/oagData/ADTFiles/srBpm/sr.bpm.lowPass1s.error.pv -a /home/helios/oagData/ADTFiles/srBpm &

}

proc ZeroCorrectors {args} {
    set plane ""
    APSParseArguments {plane}
    SetSROrbitStatus "Zero $plane correctors..."

    set file /home/helios/oagData/sr/lattices/default/${plane}.corr.defs
    set tmpfile /tmp/[APSTmpString]
    set amplitude 0
    if {0} {
    exec sddsprocess $file $tmpfile \
        -reedit=col,ControlName,%/CurrentM/CurrentC/ \
        "-def=col,Value,grnd $amplitude *,units=A" \
        -print=col,ValueString,%lf,Value
    }
    exec  sddsprocess $file $tmpfile \
        -reedit=col,ControlName,%/CurrentM/CurrentC/ \
	-reprint=col,ValueString,0 
    exec sddscasr -restore $tmpfile
    APSAddToTmpFileList -ID orbit -fileList $tmpfile
    SetSROrbitStatus "Zero $plane correctors done."
}

proc AbortControllaw {args} {
    set plane ""
    APSParseArguments {plane}
    global OC
    if [catch {exec cavget -list=$OC($plane.runControlPV).RUN } running] {
	return -code error "Error readding $plane runControlPV: $result"
    }
    if !$running {
	SetSROrbitStatus "$plane controllaw is not running."
	return
    }
    SetSROrbitStatus "Aborting $plane controllaw..."
    if [catch {exec cavput -list=$OC($plane.runControlPV).ABRT=1 } result] {
	return -code error "Error abort $plane controllaw: $result"
    }
    exec cawait -waitFor=$OC($plane.runControlPV).RUN,equalTo=0
    exec cavput -list=$OC($plane.runControlPV).CLR=1
    SetSROrbitStatus "$plane controllaw aborted."
}

proc ControllawInfo {args} {
    set plane ""
    APSParseArguments {plane}
    global OC
    exec medm -local -x -macro RCPV=$OC($plane.runControlPV) \
           /usr/local/iocapps/adlsys/sr/psApp/APSRunControlSingle.adl  &

}

proc Test {args} {
    set plane ""
    APSParseArguments {plane}
    global OC
    set dir $OC(dataDir)/$OC(${plane}.responseDir)
    
    set testsFile $dir/tests
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddscasr $testsFile -save -pipe=out \
		   | sddsprocess -pipe -scan=col,Value,ValueString,%lf \
		   | sddsprocess -pipe=in $tmpRoot.1 "-test=col,Value MinimumValue < Value MaximumValue > ||" \
		   -nowarnings } result] {
	return -code error "Error check tests: $result"
    }
    APSAddToTmpFileList -ID oc -fileList $tmpRoot.1
    
    set rows [exec sdds2stream -rows=bare $tmpRoot.1]
    if !$rows {
	SetSROrbitStatus "$plane tests passed."
	return
    }
    SetSROrbitStatus "$plane tests failed."  
    if [catch {exec sddsprintout $tmpRoot.1 $tmpRoot.print \
		   -col=ControlName,format=%30s -col=Value,format=%15.0f \
		   -col=MinimumValue,format=%15.0f -col=MaximumValue,format=%15.0f \
		   "-title=$plane tests out of range." } result] {
	return -code error "Error print out of range pvs: $result"
    }
    APSFileDisplayWindow [APSUniqueName .fileDisp] -fileName $tmpRoot.print -width 100 -height 30 \
	-deleteOnClose 1
}

proc MakePlaneActionFrame {args} {
    set plane ""
    set parent ""
    APSParseArguments {plane parent}
    global OC

    APSFrame .f1 -parent $parent -label ""
    set w $parent.f1.frame
    APSLabeledEntry .config  -parent $w -label "Configuration: "  \
	-textVariable OC($plane.responseDir) -width 40 \
	-contextHelp \
	"Name of the directory for the response file for the HORIZONTAL plane which can be used with sddscontrollaw."
    APSButton .pick -parent $w.config -text "F " -size small -command \
	"PickFileFromDir -plane $plane"
    APSButton .install -parent $w.config -text "I " -size small -command \
	"InstallFile -plane $plane"
    
    APSButton .start -parent $parent -text "Full Start" -command "StartControllaw -regenerate 1 -plane $plane" \
	-contextHelp "re-generate controllaw files and start controllaw"
    APSButton .start1 -parent $parent -text "Start" -command "StartControllaw -plane $plane" \
	-contextHelp "start controllaw without re-generating controllaw files."
    
    APSButton .gen -parent $parent -text "Generate" -command "GenerateControllawFiles -plane $plane" \
	-contextHelp "generate controllaw files."

    APSButton .abort -parent $parent -text "Abort" -command "AbortControllaw -plane $plane"
    APSButton .info -parent $parent -text "Info" -command "ControllawInfo -plane $plane"
    
    APSButton .adt -parent $parent -text "BPM ADT" -command "BringUpBPMADT -plane $plane"
    APSButton .zero -parent $parent -text "Zero Correctors" -command "ZeroCorrectors -plane $plane"
    APSButton .test -parent $parent -text "Test" -command "Test -plane $plane"
}


proc MakeActionFrame {widget args} {
    set parent ""
    APSParseArguments {parent}

    APSFrame $widget -parent $parent -label "sddscontrollaw Action Frame" \
	 -contextHelp "Frame for running orbit correction."
    set wList [APSTabFrame .plane -parent $parent$widget.frame -label "" \
	-labelList {Horizontal Vertical} -width 900 -height 200 -packOption "-expand yes -fill both"]
    
    MakePlaneActionFrame -plane h -parent [lindex $wList 0]
    MakePlaneActionFrame -plane v -parent [lindex $wList 1]
}

proc GenerateControllawFiles {args} {
    set plane ""
    APSParseArguments {plane}
    global OC
    set oldDir [pwd]
    set dir $OC(dataDir)/$OC($plane.responseDir)
    if ![file exist $dir] {
	return -code error "$dir does not exist!"
    }
    set config $dir/config
    if {![file exist $config]} {
	return -code error "$dir/config does not exist, please create the configuration first!"
    }
    if ![file exist $dir/irm] {
	return -code error "$dir/irm does not exist, please use the OC configuration tool to compute the irm first!"
    }
    SetSROrbitStatus "Generating controllaw files for $plane... ($OC(timeFilter)"
    if [catch {APSSRGenerateControllawFiles -config $OC($plane.responseDir) \
		   -currLimitH $OC(h.DCCTLimit) \
		   -currLimitV $OC(v.DCCTLimit) \
		   -timeFilter $OC(timeFilter) \
		   -statusCallback SetSROrbitStatus \
		   -XBPMLimit $OC(XBPMLimit) \
		   -BPMLimit $OC(BPMLimit) \
		   -hcorrLimitMargin $OC(hcorrLimitMargin) \
		   -vcorrLimitMargin $OC(vcorrLimitMargin) \
		   -regenerateFiles 1 \
		   -dataDir $OC(dataDir) } result] {
	return -code error "Error generating controllaw files: $result"
    }
    return
    
    set tmpRoot /tmp/[APSTmpString]
    switch $plane {
	h {
	    set coord x
	}
	v {
	    set coord y
	}
    }
    #generate definition file
    if [catch {exec sddsprocess $config -match=par,NameType=MonitorNames $tmpRoot.bpm \
		   -edit=col,ControlName,Name,ei/:$coord:LowPass1sErrorM/ \
		   -print=col,SymbolicName,%s,Name 
		exec sddsprocess $config -match=par,NameType=CorrectorNames $tmpRoot.corr \
		   -edit=col,ControlName,Name,ei/:PS:SetCurrentC/ \
		    -print=col,SymbolicName,%s,Name 
		exec sddscombine $tmpRoot.bpm $tmpRoot.corr -merge -overwrite $dir/definitions } result] {
	return -code error "Error generating definition file: $result"
    }
    
    SetSROrbitStatus "Generating controllaw files for $plane done."
}

proc StartPVTest {args} {
    

}

proc PrepareControllawOptions {args} {
    global OC
    set plane ""
    APSParseArguments {plane}

    set config $OC(${plane}.responseDir)
    if [catch {APSSRPrepareControllawOptions -config $config \
		   -dataDir $OC(dataDir) \
		   -runControlDesc $OC($plane.runControlDesc) \
		   -runControlPV $OC($plane.runControlPV) \
		   -RCTimeout $OC(RCTimeout) \
		   -averages $OC(averages) \
		   -averageInterval $OC(averageInterval) \
		   -deltaLimit $OC(deltaLimit) \
		   -dryRun $OC(dryRun) \
		   -verbose  $OC(verbose) \
		   -FFcompensation $OC(FFcompensation) \
		   -despike  $OC($plane.despike) \
		   -despikePasses $OC($plane.despikePasses) \
		   -despikeNeighbors $OC($plane.despikeNeighbors) \
		   -despikeAverage $OC($plane.despikeAverage) \
		   -despikeCountLimit $OC($plane.despikeCountLimit) \
		   -despikeThresholdSteps $OC($plane.despikeThresholdSteps) \
		   -despikeThresholdStart $OC($plane.despikeThresholdStart) \
		   -despikeThresholdEnd $OC($plane.despikeThresholdEnd) \
		   -logActuators $OC(logStats) \
		   -logStats  $OC(logStats) \
		   -logGlitch $OC(logGlitch) \
		   -steps $OC(steps) \
		   -gain $OC(gain) \
		   -interval $OC(interval)  } options] {
	return -code error "Error preparing options: $options"
    }
    return $options
}

proc StartControllaw {args} {
    set plane ""
    set regenerate 0
    APSParseArguments {plane regenerate}
    global OC
    if $regenerate {
	if [catch {GenerateControllawFiles -plane $plane} result] {
	    SetSROrbitStatus "Error generating controllaw files for $plane: $result"
	    return
	}
    }
    SetSROrbitStatus "preparing $plane controllaw options..."
    if [catch {PrepareControllawOptions -plane $plane} options] {
        SetSROrbitStatus "Error preparing controllaw options: $options"
        return
    }
    switch $plane {
	h {
	    set i0 0
	    set i1 2
	}
	v {
	    set i0 1
	    set i1 3
	}
    }
    SetSROrbitStatus "$plane options: $options"
    if [catch {AbortControllaw -plane $plane} result] {
	return -code error "Error aborting previous controllaw: $result"
    }
    global tabFrameWidgetListForLog
    APSExecLog .sr${plane}oc -parent [lindex $tabFrameWidgetListForLog $i0] \
	-lineLimit 2048 -width 95 -height 40  \
	-name "SR ${plane}-orbit Correction" \
	-unixCommand "sddscontrollaw $options" \
	-callback "" \
	-cancelCallback "AbortControllaw -plane $plane" \
	-abortCallback "AbortControllaw -plane $plane"
    SetSROrbitStatus "$plane OC started."
}

SetDefaultPars
cd $OC(dataDir)



APSApplication . -name "SROrbitControllaw" -version $CVSRevisionAuthor \
  -overview "SROrbitControllaw provides convenience controls for executing sddscontrollaw for correcting the SR orbit."

set SROrbitStatus "Initializing ..."
APSScrolledStatus .status -parent .userFrame -width 60 \
  -textVariable SROrbitStatus -packOption "-fill both -expand true"

MakeOptionAndParameterFrame .opt -parent .userFrame
MakeActionFrame .act -parent .userFrame

#create execLog window
set parent ""
APSFrame .execLog -parent $parent -packOption "-expand yes -fill both -side top"
$parent.execLog.frame configure -relief flat -bd 0

set sectionList [list controllaw_x controllaw_y]

set tabFrameWidgetListForLog [APSTabFrame .log -parent $parent.execLog.frame \
                                -label "" \
                                -labelList $sectionList \
                                -width 955 -height 700 \
                                -packOption "-expand yes -fill both"]

update
wm geometry .execLog +[expr [winfo rootx .] + 50]+[expr [winfo rooty .] + 300]

wm protocol $parent.execLog WM_DELETE_WINDOW {return} 
