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

#
# $Log: not supported by cvs2svn $
# Revision 1.3  1998/02/27 20:31:06  borland
# Added display of error message from APScaRamp.
#
# Revision 1.2  1997/03/26 21:42:35  borland
# Fixed typo/bug in application overview text.
#
# Revision 1.1  1997/03/26 21:38:48  borland
# First version.
#
#

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

set PVList {}
set startList {}
set endList {}
set functionList {}
set rampTime 60
set rampSteps 60
set configFile ""
set args $argv 
set usage "Usage: RampPVs \[-configFile <name>\]"

if {[APSStrictParseArguments {configFile}]} {
    puts stderr $usage
    exit 1
}

source /home/oxygen/SHANG/oag/apps/src/tcltkapp/oagapp/caramp.tcl

lappend parameterList rampTime rampSteps 
lappend columnList pvName startValue endValue functionType
set paramType(rampTime) SDDS_DOUBLE
set paramType(rampSteps) SDDS_LONG
set columnType(pvName) SDDS_STRING
set columnType(startValue) SDDS_DOUBLE
set columnType(endValue) SDDS_DOUBLE
set columnType(functionType) SDDS_STRING

#
# Permits reading in an SDDS file. 
#
set workingDir ""
proc readFile {args} {
    set fileName ""
    set scrollFrame ""
    if [APSStrictParseArguments {fileName scrollFrame}] {
        return -code error "readFile: bad arguments"
    }

    global workingDir parameterList columnList paramType columnType cpIndex 

    if ![string length $fileName] {
        set fileName \
          [APSFileSelectDialog .readDialog -listDir $workingDir \
             -contextHelp "Select a file to edit." \
             -title "Select file to edit."]
        update idletasks
    }

    if {![string length $fileName] || ![file exists $fileName]} {
        return
    }
    if ![APSCheckSDDSFile -fileName $fileName] {
        APSSetVarAndUpdate status "$fileName is not an SDDS file."
        return
    }
    set workingDir [file dirname $fileName]
    if [catch {sdds open $fileName r} inputID] {
        APSSetVarAndUpdate status "Error reading $fileName: $inputID"
        return
    }

    foreach parameterName $parameterList {
        global $parameterName
        if [catch {sdds getParameter $inputID $parameterName} $parameterName] {
            APSSetVarAndUpdate status \
              "Error getting parameter data for $parameterName: [subst \$$parameterName]"
            return
        }
    }

    foreach columnName $columnList {
        global $columnName
        if [catch {sdds getColumn $inputID $columnName} ${columnName}List] {
            APSSetVarAndUpdate status "Error getting column data for $columnName: [subst \$${columnName}List]"
            return
        }
    }

    global cpIndex
    while {$cpIndex} {
        DeletePVSlot $scrollFrame
    }
    set index 0
    foreach elem $pvNameList {
        AddPVSlot -parent $scrollFrame -pvName [lindex $pvNameList $index] \
          -startValue [lindex $startValueList $index] \
          -endValue [lindex $endValueList $index] \
          -functionType [lindex $functionTypeList $index]
        incr index
    }

    if [catch {sdds close $inputID} result] {
        APSSetVarAndUpdate status "Problem closing SDDS file: $result"
        return
    }
    APSSetVarAndUpdate status "File read successfully."
    global inputFile
    set inputFile $fileName
}

proc saveFile {} {
    global inputFile
    saveFileAs -fileName $inputFile
}

#
# Allows saving the data into a named file.
#
proc saveFileAs {args} {
    set fileName ""
    APSStrictParseArguments {fileName}
    
    global workingDir parameterList columnList paramType columnType cpIndex columnVarRoot
    if !$cpIndex {
        APSSetVarAndUpdate status "Can't save--no PVs given."
        return
    }

    APSSetVarAndUpdate status "Saving data..."

    if ![string length $fileName] {
        set outputFile \
          [APSInfoDialog [APSUniqueName .] -name "Output file dialog" \
             -width 40 -infoMessage "Output filename: " \
             -contextHelp "Enter the name of the file to which to write the data." \
             -default ""]
    } else {
        set outputFile $fileName
    }

    if [catch {sdds open $outputFile w SDDS_BINARY} fid] {
        APSSetVarAndUpdate status "$fid"
        return
    }
    foreach parameter $parameterList {
        if [catch {eval sdds defineParameter $fid $parameter -type $paramType($parameter)} result] {
            APSSetVarAndUpdate status "$result"
            return
        }
    }

    foreach column $columnList {
        if [catch {eval sdds defineColumn $fid $column -type $columnType($column)} result] {
            APSSetVarAndUpdate status "$result"
            return
        }
    }
    
    if {[catch {sdds writeLayout $fid} result] || [catch {sdds startPage $fid $cpIndex} result]} {
        APSSetVarAndUpdate status "$result"
        return
    }

    foreach parameter $parameterList {
        global $parameter
        if [catch {sdds setParameter $fid $parameter [subst \$$parameter] } result] {
            APSSetVarAndUpdate status "$result"
            return
        }
    }

    foreach column $columnList {
        set dataList ""
        for {set index 1} {$index<=$cpIndex} {incr index} {
            global $column$index
            lappend dataList [subst \$$column$index]
        }
        if [catch {eval sdds setColumn $fid $column $dataList} result] {
            APSSetVarAndUpdate status "$result"
            return
        }
    }

    if {[catch {sdds writePage $fid} result] || \
          [catch {sdds close $fid} result]} {
        APSSetVarAndUpdate status "$result"
        return
    }
    APSSetVarAndUpdate status "Data saved to $outputFile"
}


set cpIndex 0
proc AddPVSlot {args} {
    set parent ""
    set pvName ""
    set startValue 0
    set endValue 0
    set functionType line
    APSStrictParseArguments {parent pvName startValue endValue functionType}

    global cpIndex
    incr cpIndex
    set widget .$cpIndex

    global pvName$cpIndex startValue$cpIndex endValue$cpIndex functionType$cpIndex
    set pvName$cpIndex $pvName
    set startValue$cpIndex $startValue
    set endValue$cpIndex $endValue
    set functionType$cpIndex $functionType

    APSFrameGrid $widget -parent $parent.frame.canvas.frame -yList {one two three} \
      -relief ridge -contextHelp "Allows specification of ramping parameters for a single PV. Use Add to add more slots for more PVs."
    set w $parent.frame.canvas.frame$widget
    APSLabeledEntry .le0 -parent $w.one -label "PV name: " \
      -width 32 -textVariable pvName$cpIndex -packOption "-side  left" \
      -contextHelp "Enter the name of the process variable to be ramped."
  #  bind $w.one.le0.entry <Leave> "GetPVValue -index $cpIndex"
    APSLabeledEntry .le1 -parent $w.two -label "Start: " \
      -width 32 -textVariable startValue$cpIndex -packOption "-side  left" \
      -contextHelp "Enter the value from which ramping should start."
    APSButton .get -parent $w.two.le1 -text Get -contextHelp \
      "Requests loading of the present value of the PV from the IOC into the Start entry." \
      -command "GetPVValue -index $cpIndex"
    APSLabeledEntry .le2 -parent $w.two -label "End: " \
      -width 32 -textVariable endValue$cpIndex -packOption "-side  left" \
      -contextHelp "Enter the value to which the PV should be ramped."
    APSRadioButtonFrame .rb0 -parent $w.three -label "Function: " \
      -orientation horizontal -variable functionType$cpIndex \
      -buttonList {line decay1 decay2 decay3 decay4 decay5 cosin} \
      -valueList {line decay1 decay2 decay3 decay4 decay5 cosin} \
      -contextHelp "Choose the type of function to use to go between the start and \
end point.  decay<n> refers to an exponential decay covering <n> factors of e during \
the alloted time.  So decay1 is a slow decay while decay5 is quite fast."

    tkwait visibility $w.three.rb0
    APSScrollAdjust $parent -numVisible 5
}

proc GetPVValue {args} {
    set index -1
    APSStrictParseArguments {index}
    global pvName$index startValue$index
    if ![string length [subst \$pvName$index]] {
        return
    }
    if [catch {exec cavget -list=[subst \$pvName$index] -floatformat=%.9e} startValue] {
        APSSetVarAndUpdate status $startValue
    } elseif [string compare $startValue ?]==0 {
        APSSetVarAndUpdate status "[subst \$pvName$index]: not found"
    } else {
        set startValue$index $startValue
    }
}

proc MakeAddDeleteButtons {widget args} {
    set parent ""
    set scrollFrame ""
    APSStrictParseArguments {parent scrollFrame}
    APSFrame $widget -parent $parent -label ""
    set w $parent$widget.frame
    APSButton .add -parent $w -text Add -command \
      "AddPVSlot -parent $scrollFrame" -contextHelp \
      "Add a slot for another PV to include in the ramp."
    APSButton .del -parent $w -text Delete -command \
      "DeletePVSlot $scrollFrame" -contextHelp \
      "Delete the last slot from the list of PVs to include in the ramp."
}

proc DeletePVSlot {scrollFrame} {
    global cpIndex
    if $cpIndex {
        destroy $scrollFrame.frame.canvas.frame.$cpIndex
        incr cpIndex -1
    }
}

proc MakeRunStopButtons {widget args} {
    set parent ""
    APSStrictParseArguments {parent}
    APSFrame $widget -parent $parent -label ""
    
    global w
    set w $parent$widget.frame
    
    APSButton .review -parent $w -text Review -command "RunRamp $w -review 1"
    APSButton .dry -parent $w -text DryRun -command \
      "RunRamp $w -dryRun 1" \
      -contextHelp \
      "Begins the ramps."
    APSButton .run -parent $w -text Run -command \
      "RunRamp $w" \
      -contextHelp \
      "Begins the ramps."
    APSButton .stop -parent $w -text Stop -command \
      "set abortRamp 1" -contextHelp \
      "Aborts the ramps at the next step."
    APSDisableButton $w.stop.button
    
   
}

set abortRamp 0
proc RunRamp {buttonRoot args} {
    set review 0
    set dryRun 0
    APSParseArguments {review dryRun}
    
    global cpIndex apsAlertStopBeep
    if !$cpIndex {
        APSSetVarAndUpdate status "No PVs given to ramp."
        return
    }
    set pvList ""
    set startList ""
    set endList ""
    set varList ""
    set functionList ""
    for {set index 1} {$index<=$cpIndex} {incr index} {
        global pvName$index startValue$index endValue$index pvVar$index functionType$index
        set pvVar$index 0
        lappend pvList [subst \$pvName$index]
        lappend startList [subst \$startValue$index]
        lappend endList [subst \$endValue$index]
        lappend varList pvVar$index
        lappend functionList [subst \$functionType$index]
    }
    global abortRamp rampTime rampSteps
    if {!$review} {
        set abortRamp 0
        APSDisableButton $buttonRoot.run.button
        APSEnableButton $buttonRoot.stop.button
        APSSetVarAndUpdate status "Starting ramp"
    }
    set pause [expr (1.0*$rampTime)/$rampSteps]
    if {[catch {APScaRamp -pvList $pvList -variableList $varList -review $review \
                  -beginList $startList -endList $endList -dryRun $dryRun \
                  -functionList $functionList -steps $rampSteps -pause $pause \
                  -postStepCallback PostStepCallback -abortVariable abortRamp } result] || \
          [string length $result]} {
        APSSetVarAndUpdate status "$result"
    }
    if !$review {
        APSDisableButton $buttonRoot.stop.button
        APSEnableButton  $buttonRoot.run.button
        APSSetVarAndUpdate status "Done with ramp"
        global Alert
        if {$Alert!="no"} {
            APSAlertBox .alertinfo -name "Ramp Done" -type done -name Done \
              -errorMessage "Done with ramp PVs." -modeless 1 -beep $Alert
        }
    }
}

proc PostStepCallback {step steps} {
    APSSetVarAndUpdate status "Done with step $step of $steps"
}

APSApplication . -name RampPVs -version $CVSRevisionAuthor \
    -overview {This tool ramps the values of process variables using a line or a selection of exponential decays.}
set status Working
APSScrolledStatus .status -parent .userFrame -width 60 -textVariable status

APSLabeledEntry .rampTime -parent .userFrame -label "Ramp time (s): " \
  -contextHelp "Total time to take in ramping from start to end, in seconds." \
  -textVariable rampTime -width 30
APSLabeledEntry .rampSteps -parent .userFrame -label "Steps in ramp: " \
  -contextHelp "Number of steps for complete ramp." -textVariable rampSteps -width 30
set Alert no
APSRadioButtonFrame .alert -parent .userFrame -label "Alert after ramp is done or aborted?" \
  -buttonList {No "Beep Once" "Beep Continuously"} -valueList {no once continuous} \
  -variable Alert -orientation horizontal \
  -contextHelp "choose to play alert sound when ramp is done or aborted."
MakeRunStopButtons .runStop -parent .userFrame

APSFrame .pvFrame -parent .userFrame -label "PV List Control" 
set name [APSUniqueName .x]
APSScroll $name -parent .userFrame.pvFrame.frame
set mainScrollFrame .userFrame.pvFrame.frame$name

MakeAddDeleteButtons .addDel -parent .userFrame -scrollFrame $mainScrollFrame

# Add Read..., Save, Save as... entries to File menu
.menu.file.menu insert 1 command -label "Read..." -command "readFile -scrollFrame $mainScrollFrame"
.menu.file.menu insert 1 command -label "Save" -command saveFile
.menu.file.menu insert 1 command -label "Save as..." -command saveFileAs

APSMenubarAddMenu .programs -text Programs -parent .menu
.menu.programs.menu add command -label quickMonitor -underline 0 -command "exec quickMonitor &"
.menu.programs.menu add command -label namecapture -underline 0 -command "exec namecapture &"


if [string length $configFile] {
    if ![file exists $configFile] {
        puts stderr "Not found: $configFile"
        exit 1
    }
    readFile -fileName $configFile -scrollFrame $mainScrollFrame
} elseif [llength $PVList] {
    set index 0
    foreach elem $PVList {
        AddControlPanel -parent $mainScrollFrame \
          -pvName $elem -amplitude [lindex $amplitudeList $index]
        incr index
    }
} 

APSSetVarAndUpdate status "Function documentation: 1) line -- ramp the pvs linearly \n 2) decay1, decay2, decay3, decay4, and decay5: ramp the pvs exponentially with rate of 1, 2, 3, 4, and 5 respectivley .\n 3) cosin: ramp the pvs with cosin function."

