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

# $Log: not supported by cvs2svn $
# Revision 1.19  2006/08/02 00:59:39  emery
# Shang's changes: use -infiniteLoop argument to sddscontrollaw.
#
# Revision 1.18  2005/10/24 20:48:14  shang
# added TEST button to sector dialogs.
#
# Revision 1.17  2005/09/30 21:45:04  shang
# added automatically updating controllaw files when sector button is clicked.
#
# Revision 1.16  2005/08/22 15:27:35  shang
# replaced all old SRIDSteering messages by the correct steering type
#
# Revision 1.14  2004/10/04 23:25:18  emery
# Added check of corrector mode consistency and added a missing
# -controlQuantityDefinition=$def argument to sddscontrollaw,
# which was somehow removed in a previous version.
#
# Revision 1.13  2002/10/09 10:19:17  emery
# Added status messages for bpms setpoint changes.
#
# Revision 1.12  2002/10/09 07:03:23  shang
# made it to be able to run controllaw in ioc and added transfer vector adjust
# vales when applying setpoints or doing transfer.
#
# Revision 1.11  2002/10/06 05:53:52  emery
# Simplified the coding of the cavput in ApplySetpoint.
# Replaced the string values PSCU and Diag with
# Maintenance and Operation.
#
# Revision 1.10  2002/02/26 21:07:19  emery
# Changed default steering interval to 0.5 sec since we are now
# using speedy corrector PVs.
#
# Revision 1.9  1999/02/15 16:24:01  emery
# Made variable errorCode global.
#
# Revision 1.8  1999/01/20 15:28:51  borland
# Added -fastClick 1 option to in/out/up/down buttons.
#
# Revision 1.7  1998/10/18 20:58:18  borland
# Uses new data directory.
#
# Revision 1.6  1998/05/27 16:08:25  emery
# Inserted logMessage command to log the start of the steering,
# which was somehow omitted when logMessage commands were inserted
# to log the exit and abort of the steering.
#
# Revision 1.5  1998/05/21 20:55:19  emery
# Changed data file for light source point bpm
# used in DoTransfer procedure.
#
# Revision 1.4  1998/04/02 22:33:40  emery
# Corrected the Instance value of the logMessage command.
#
# Revision 1.3  1997/11/13 23:06:43  emery
# Commented out the high level bpms.
#
# Revision 1.2  1997/07/24 23:09:31  emery
# By default only the light sources will have the sector button
# enabled. The command line option allowAllSectors
# may be used to allow steering in all sectors.
#
# Revision 1.1  1997/07/24 22:43:29  emery
# First version of SRAMSteering.
#

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)]
APSDebugPath
APSRenameExecToAPSBGExec
set CVSRevisionAuthor "\$Revision: 1.20 $ \$Author: emery $"

set args $argv
set adjustOnly 0
set allowTransfer 1
set allowAllSectors 0
APSStrictParseArguments {adjustOnly allowTransfer allowAllSectors}

set APSExecIDList ""
proc KillAPSExecLogs {} {
    global APSExecIDList
    forech id $APSExecIDList {
        APSExecLogAbort -id $id -destroy 1
    }
}
APSApplication . -name SRAMSteering \
  -overview "SRAMSteering provides convenience controls for AM steering using sddscontrollaw."
dp_atexit append KillAPSExecLogs

set tcl_precision 6

set AMSteeringStatus Ready.
APSScrolledStatus .status -parent .userFrame -width 80 \
  -textVariable AMSteeringStatus 

proc SetAMSteeringStatus {text} {
    global AMSteeringStatus
    set AMSteeringStatus $text
    update
    bell
}

proc MakeSectorsWidget {widget args} {
    global sector allowAllSectors

    set parent ""
    APSParseArguments {parent}

    set w $parent$widget
    APSFrame $widget -parent $parent \
      -label "Storage Ring AM selection for steering." \
      -contextHelp {AM selection frame} 

    if !$allowAllSectors {
        set sectorList [APSGetSDDSColumn -column Sector \
                          -fileName /home/helios/oagData/sr/AMs/sectors.sdds]
    }

    for {set quad 1} {$quad<5} {incr quad} {
        set start [expr ($quad-1)*10+1]
        set end   [expr $start+9]
        set buttonList {}
        set valueList {}
        APSFrame .sector$quad -parent $w.frame 
        $w.frame.sector$quad.frame configure -relief flat
        for {set sector $start} {$sector<=$end} {incr sector} {
            set cbLabel $sector
            if {$sector<10} {set cbLabel "0$sector"}
            APSButton .sector$sector -parent $w.frame.sector$quad.frame \
              -text "$cbLabel" \
              -command "AMSteeringDialog -sector $sector" \
              -contextHelp "Brings up dialog box for AM$cbLabel steering."
            if !$allowAllSectors {
                if [expr -1 == [lsearch $sectorList $sector]] {
                    APSDisableButton $w.frame.sector$quad.frame.sector$sector.button
                }
            }
        }
    }
}

proc MakeOptionWidget {widget args} {
    global sector tolerance timeLimit statusCallback 
    global gain interval

    set parent ""
    APSParseArguments {parent}

    set w $parent$widget
    APSFrame $widget -parent $parent -label "Options" \
      -contextHelp "Options in AM steering."
    
    APSFrame .parameters -parent $w.frame  -packOption  {-side top}
    set w $parent$widget.frame.parameters
    $w.frame configure -relief flat

    APSFrame .misc -parent $w.frame -packOption  {-side left}
    $w.frame.misc.frame configure -relief flat
    APSLabeledEntry .timeLimit -parent $w.frame.misc.frame -label "Time limit (sec)" \
      -textVariable timeLimit  -width 8 \
      -contextHelp "Time allowed for sddscontrollaw to steer the beam to the desired setpoints."
    APSLabeledEntry .interval -parent $w.frame.misc.frame -label "Interval (sec)" \
      -textVariable interval  -width 8 \
      -contextHelp "Time interval between sddscontrollaw interations."
    APSLabeledEntry .gain -parent $w.frame.misc.frame -label "Gain" \
      -textVariable gain  -width 8 \
      -contextHelp "Fraction of correction to be applied at every iterations. Use a value of 0 for safe debugging."
}

set includeSourcePoints 0
proc MakeTransferWidget {widget args} {
    set parent ""
    APSParseArguments {parent}

    set w $parent$widget
    APSFrame $widget -parent $parent -label "Orbit transfer to setpoints" \
      -contextHelp "Buttons to transfer x, y, or both orbits to setpoint values.  Not part of ID steering per se, but useful for related operations."
    
    APSFrame .parameters -parent $w.frame  -packOption  {-side top}
    set w $parent$widget.frame.parameters
    $w.frame configure -relief flat

    APSFrame .misc -parent $w.frame -packOption  {-side left}
    $w.frame.misc.frame configure -relief flat
    APSButton .xferAdjValues -parent $w.frame.misc.frame -text "Transfer both" \
      -command {DoTransfer -msType mswAve -plane both -includeSourcePoints $includeSourcePoints} \
      -contextHelp "Transfers present adjusted orbit values to steering setpoints, in order to lock in the present orbit.  Not part of ID steering per se, but useful for related operations."
    APSButton .hxferAdjValues -parent $w.frame.misc.frame -text "Transfer x" \
      -command {DoTransfer -msType mswAve -plane x -includeSourcePoints $includeSourcePoints} \
      -contextHelp "Transfers present adjusted x orbit values to steering setpoints, in order to lock in the present horizontal orbit.  Not part of ID steering per se, but useful for related operations."
    APSButton .vxferAdjValues -parent $w.frame.misc.frame -text "Transfer y" \
      -command {DoTransfer -msType mswAve -plane y -includeSourcePoints $includeSourcePoints} \
      -contextHelp "Transfers present adjusted y orbit values to steering setpoints, in order to lock in the present vertical orbit.  Not part of ID steering per se, but useful for related operations."
    global includeSourcePoints
    APSRadioButtonFrame .mode -parent $w.frame.misc.frame -label "Include source points" \
      -variable includeSourcePoints -buttonList "Yes No" -valueList "1 0" -orientation horizontal \
      -contextHelp "Determines whether setpoints for BPMs used by the fine orbit correction are also changed.  These setpoints are important in pinning down the source points for AM, BM and ID lines, and should not normalling be included in the transfer."
}

proc DoTransfer {args} {
    set msType ""
    set plane ""
    set includeSourcePoints 0
    APSStrictParseArguments {msType plane includeSourcePoints} 

    set dataDir /home/helios/oagData/sr/localSteering
    set excludeConfigFile ""
    SetAMSteeringStatus "Transferring present adjusted orbit to setpoints for $plane plane(s)"
    if !$includeSourcePoints {
        if [string compare $plane both]==0 {
            lappend excludeConfigFile \
              $dataDir/userLightSources.config \
              $dataDir/userLightSources.config
        } else {
            set excludeConfigFile $dataDir/userLightSources.config
        }
        SetAMSteeringStatus "Setpoints for ID/BM/AM source points are not being changed."
    } else {
        SetAMSteeringStatus "Setpoints for ID/BM/AM source points *are* being changed."
    }
    
    if [catch {APSSRTransferBPMAdjustedValues  -msType $msType -plane $plane \
                 -statusCallback SetAMSteeringStatus -excludeConfigFileList $excludeConfigFile} result] {
        SetAMSteeringStatus "$result"
        return 
    }
    if [catch {APSTransferVectorAdjust -coord $plane} result] {
        SetAMSteeringStatus "$result"
        return 
    }
    SetAMSteeringStatus "Transfer done."
}


proc AMSteeringDialog {args} {
    global AP3x AP3y AP4x AP4y allowTransfer adjustOnly sourcePointList errorCode
    set sector ""
    APSParseArguments {sector}
    if ![string length $sector] {
        APSAlertBox [APSUniqueName .] -errorMessage \
          "No sector variable specified in AMSteeringDialog"
        return 1
    }
    if [catch {APSCheckAndUpdateLocalSteeringConfigs -steeringType AM -sector $sector -statusCallback SetAMSteeringStatus} result] {
	SetAMSteeringStatus "$result"
        APSAlertBox [APSUniqueName .] -errorMessage \
          "Error in updating AM steering configs for sector $sector"
        return 1
    }
    set dialogFrame .dialogAM$sector.userFrame
    APSDialogBox .dialogAM$sector  \
      -name "AM$sector Dialog" \
      -contextHelp "Dialog box for steering in AM$sector."

    #    if {[expr -1 < [lsearch $sourcePointList $sector]] } {
    #        set useHighLevelPV($sector) 1
    #    } else {
    #        set useHighLevelPV($sector) 0
    #    }
    set useHighLevelPV($sector) 0
    set Sn $sector
    if !$useHighLevelPV($sector) {
        if {[pv linkw \
               [list AP3x($sector) AP3y($sector) AP4x($sector) AP4y($sector)] \
               [list S${Sn}A:P3:ms:x:SetpointAO S${Sn}A:P3:ms:y:SetpointAO \
                  S${Sn}A:P4:ms:x:SetpointAO S${Sn}A:P4:ms:y:SetpointAO ]] != 0} {
            APSAlertBox .alert -errorMessage "$errorCode"
            exit
        } 
    } else {
        # set high level PV to msAve
        if [catch {exec cavput -list=S${sector}B:P -list=3,4 -list=:y:ErrorCC:ModeMO=0 \
                 } result ] {
            APSAlertBox .alert -errorMessage "$result\nSomething wrong with a cavput command."
            return
        }
        if {[pv linkw \
               [list AP3x($sector) AP3y($sector) AP4x($sector) AP4y($sector)] \
               [list S${Sn}A:P3:ms:x:SetpointAO S${Sn}A:P3:ms:y:SetpointAO \
                  S${Sn}A:P4:ms:x:SetpointAO S${Sn}A:P4:ms:y:SetpointAO ]] != 0} {
            APSAlertBox .alert -errorMessage "$errorCode"
            exit
        }
    }
    if {[pv umon AP3x($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon AP3y($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon AP4x($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon AP4y($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    
    APSFrame .parameters -parent $dialogFrame -packOption "-side left"
    $dialogFrame.parameters.frame configure -relief flat
    APSFrame .setpoints -parent $dialogFrame.parameters.frame -packOption "-side left" \
      -label "Setpoints for bpms"  -width 10\
      -contextHelp "Enter setpoints for the four bpm readbacks of AM$sector"
    $dialogFrame.parameters.frame.setpoints.frame configure -relief flat
    APSLabeledEntry .ap3x \
      -parent $dialogFrame.parameters.frame.setpoints.frame \
      -label "S${Sn}A:P3:x (mm)"  -width 10\
      -textVariable AP3x($sector) \
      -contextHelp "Enter value for S${Sn}A:P3:ms:x:SetpointAO to be applied. These values change when one of the associated coordinate delta button is pressed."
    APSLabeledEntry .ap3y \
      -parent $dialogFrame.parameters.frame.setpoints.frame \
      -label "S${Sn}A:P3:y (mm)"  -width 10\
      -textVariable AP3y($sector) \
      -contextHelp "Enter value for S${Sn}A:P3:ms:y:SetpointAO to be applied. These values change when one of the associated coordinate delta button is pressed."
    APSLabeledEntry .ap4x \
      -parent $dialogFrame.parameters.frame.setpoints.frame \
      -label "S${Sn}A:P4:x (mm)"  -width 10\
      -textVariable AP4x($sector) \
      -contextHelp "Enter value for S${Sn}A:P4:ms:x:SetpointAO to be applied. These values change when one of the associated coordinate delta button is pressed."
    APSLabeledEntry .ap4y \
      -parent $dialogFrame.parameters.frame.setpoints.frame \
      -label "S${Sn}A:P4:y (mm)"  -width 10\
      -textVariable AP4y($sector) \
      -contextHelp "Enter value for S${Sn}A:P4:ms:y:SetpointAO to be applied. These values change when one of the associated coordinate delta button is pressed."

    APSButton .apply -parent .dialogAM$sector.buttonRow -text APPLY  -command "ApplySetpoints -sector $sector" -contextHelp  "Applies above setpoint values to setpoint PVs of AM$sector bpms."

    if !$adjustOnly {
        APSButton .start -parent .dialogAM$sector.buttonRow -text "START"  -command "StartControllaw -sector $sector" -contextHelp  "Starts sddscontrollaw on AM$sector. Note that the cancel button does not cancel the sddscontrollaw process."
    }

    if $allowTransfer {
        APSButton .transfer -parent .dialogAM$sector.buttonRow -text TRANSFER  -command "TransferValues -sector $sector" -contextHelp  "Transfers present adjusted bpm values to the setpoint values for AM $sector."
    }
    APSButton .test -parent .dialogAM$sector.buttonRow -text TEST \
      -command "APSCheckLocalSteeringTests -sector $sector -steeringType AM -statusCallback SetAMSteeringStatus" -contextHelp  "Check the tests for AM $sector."
    if {[pv linkw \
           [list AP3xOffset($sector) AP3yOffset($sector) AP4xOffset($sector) AP4yOffset($sector)] \
           [list S${Sn}A:P3:ms:x:OffsetAO S${Sn}A:P3:ms:y:OffsetAO \
              S${Sn}A:P4:ms:x:OffsetAO S${Sn}A:P4:ms:y:OffsetAO ]] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv linkw \
           [list AP3xAdjusted($sector) AP3yAdjusted($sector) AP4xAdjusted($sector) AP4yAdjusted($sector)] \
           [list S${Sn}A:P3:ms:x:AdjustedCC S${Sn}A:P3:ms:y:AdjustedCC \
              S${Sn}A:P4:ms:x:AdjustedCC S${Sn}A:P4:ms:y:AdjustedCC ]] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv linkw \
           [list AP3xError($sector) AP3yError($sector) AP4xError($sector) AP4yError($sector)] \
           [list S${Sn}A:P3:ms:x:ErrorCC S${Sn}A:P3:ms:y:ErrorCC \
              S${Sn}A:P4:ms:x:ErrorCC S${Sn}A:P4:ms:y:ErrorCC ]] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon AP3xOffset($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon AP3yOffset($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon AP4xOffset($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon AP4yOffset($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }

    if {[pv umon AP3xAdjusted($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon AP3yAdjusted($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon AP4xAdjusted($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon AP4yAdjusted($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }

    if {[pv umon AP3xError($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon AP3yError($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon AP4xError($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon AP4yError($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }

    APSFrame .moreParameters -parent $dialogFrame -packOption "-side left"
    $dialogFrame.moreParameters.frame configure -relief flat
    APSLabeledOutputFrame .offset -parent $dialogFrame.moreParameters.frame \
      -label Offsets -packOption "-side left" \
      -variableList "AP3xOffset($sector) AP3yOffset($sector) AP4xOffset($sector) AP4yOffset($sector)"\
      -orientation vertical -width 10 \
      -contextHelp "Electrical offset of AM$sector bpms."
    $dialogFrame.moreParameters.frame.offset.frame configure -relief flat

    APSLabeledOutputFrame .adjusted -parent $dialogFrame.moreParameters.frame \
      -label Adjusted -packOption "-side left" \
      -variableList "AP3xAdjusted($sector) AP3yAdjusted($sector) AP4xAdjusted($sector) AP4yAdjusted($sector)"\
      -orientation vertical -width 10 \
      -contextHelp "Adjusted readbacks of AM$sector bpms: raw readback - offsets."
    $dialogFrame.moreParameters.frame.adjusted.frame configure -relief flat

    APSLabeledOutputFrame .error -parent $dialogFrame.moreParameters.frame \
      -label Error -packOption "-side left" \
      -variableList "AP3xError($sector) AP3yError($sector) AP4xError($sector) AP4yError($sector)"\
      -orientation vertical -width 10 \
      -contextHelp "Error readbacks of AM$sector bpms: adjusted readback - setpoint."
    $dialogFrame.moreParameters.frame.error.frame configure -relief flat

    set border 3
    foreach outputFrame {offset adjusted error} {
        foreach entry {1 2 3 4} {
            $dialogFrame.moreParameters.frame.${outputFrame}.frame.entry${entry} \
              configure -borderwidth $border
        }
    }

    AdjustSetpoints -sector $sector -parent $dialogFrame
    APSEnableButton .dialogAM$sector.buttonRow.ok.button
    
    if [catch {exec cavput -list=S${Sn}A:P4,S${Sn}A:P3 -list=:msAve:AveEnbBO=Enable \
                 -pendIoTime=10 \
             } result ] {
        APSAlertBox .alert -errorMessage "$result\nSomething wrong with a cavput command. Averaging may not be enabled."
        return
    }
}

proc TransferValues {args} {
    global AP3xAdjusted AP3yAdjusted AP4xAdjusted AP4yAdjusted
    global timeLimit tolerance statusCallback

    set sector ""
    APSParseArguments {sector}
    if ![string length $sector] {
        APSAlertBox [APSUniqueName .] -errorMessage \
          "No sector variable specified in AMSteeringDialog"
        return 1
    }
    if ![APSYesNoPopUp "You are asking to transfer adjusted bpm values to setpoint values.  Are you sure?"] {
        setStatusText "Transfer cancelled."
        return 1
    }
    set Sn $sector
    set cavputList S${Sn}A:P3:ms:x:SetpointAO=$AP3xAdjusted($sector),
    append cavputList S${Sn}A:P3:ms:y:SetpointAO=$AP3yAdjusted($sector),
    append cavputList S${Sn}A:P4:ms:x:SetpointAO=$AP4xAdjusted($sector),
    append cavputList S${Sn}A:P4:ms:y:SetpointAO=$AP4yAdjusted($sector)
    if {$statusCallback!=""} {
        $statusCallback "Applying setpoints to sr bpm ioc PVs..."
    }
    if [catch {exec cavput -list=$cavputList -pendIoTime=10 \
             } result ] {
        APSAlertBox .alert -errorMessage "$result\nSomething wrong with a cavput command. Setpoints may not be asserted."
        return 1
    }
    if {$statusCallback!=""} {
        $statusCallback "Refreshing datapool vector of bpm adjust PVs..."
    }
    set pvList [list S${Sn}A:P3 S${Sn}A:P4]
    if [catch {APSRefreshVectorAdjust -pvList $pvList -waveformFile rfBpmInfo.sdds -plane both} result] {
        APSAlertBox .alert -errorMessage "$result\nSomething wrong with resetting vector adjust values."
        return 1
    }
    if {$statusCallback!=""} {
        $statusCallback "Done."
    }
    return 0
}

proc AdjustSetpoints {args} {
    global deltax deltaxp deltay deltayp
    global deltaxAcc deltaxpAcc deltayAcc deltaypAcc
    global AP3x AP3y AP4x AP4y

    set sector ""
    set parent ""
    APSParseArguments {sector parent}
    if ![string length $sector] {
        APSAlertBox [APSUniqueName .] -errorMessage \
          "No sector variable specified in AdjustSetpoints"
        return 1
    }
    set adjustFrame $parent.adjust.frame
    APSFrame .adjust -parent $parent
    $adjustFrame configure -relief flat

    # accumulators for steering changes.
    set deltaxAcc($sector) 0
    set deltaxpAcc($sector) 0
    set deltayAcc($sector) 0
    set deltaypAcc($sector) 0

    set Sn $sector
    set Sn1 [exec rpnl "$Sn 1 + 40 > pop ? 40 - : \$"]
    APSFrame .parameters -parent $adjustFrame -packOption "-side left"
    $adjustFrame.parameters.frame configure -relief flat
    APSFrame .deltas -parent $adjustFrame.parameters.frame -packOption "-side left" \
      -label "Coordinate deltas"  -width 10\
      -contextHelp "Enter deltas for the x, x', y, y' coordinates  in AM$sector"
    $adjustFrame.parameters.frame.deltas.frame configure -relief flat
    if ![info exists deltax($sector)] {
        set deltax($sector) 0.001
    }
    if ![info exists deltaxp($sector)] {
        set deltaxp($sector) 0.001
    }
    if ![info exists deltay($sector)] {
        set deltay($sector) 0.001
    }
    if ![info exists deltayp($sector)] {
        set deltayp($sector) 0.001
    }
    APSLabeledEntry .ap3x \
      -parent $adjustFrame.parameters.frame.deltas.frame \
      -label "delta x (mm)"  -width 10\
      -textVariable deltax($sector) \
      -contextHelp "Enter value for delta x"
    APSLabeledEntry .ap3y \
      -parent $adjustFrame.parameters.frame.deltas.frame \
      -label "delta xp (mrad)"  -width 10\
      -textVariable deltaxp($sector) \
      -contextHelp "Enter value for delta xp"
    APSLabeledEntry .ap4x \
      -parent $adjustFrame.parameters.frame.deltas.frame \
      -label "delta y (mm)"  -width 10\
      -textVariable deltay($sector) \
      -contextHelp "Enter value for delta y"
    APSLabeledEntry .ap4y \
      -parent $adjustFrame.parameters.frame.deltas.frame \
      -label "delta yp (mrad)"  -width 10\
      -textVariable deltayp($sector) \
      -contextHelp "Enter value for delta yp"

    APSLabeledOutputFrame .accumulation \
      -parent $adjustFrame.parameters.frame \
      -label "Accumulators" -packOption "-side left" \
      -variableList "deltaxAcc($sector) deltaxpAcc($sector) deltayAcc($sector) deltaypAcc($sector)" \
      -orientation vertical -width 10 \
      -contextHelp "Accumulated coordinate deltas. Values return to zero when dialog box is closed and reopened."
    $adjustFrame.parameters.frame.accumulation.frame configure -relief flat
    set border 3
    foreach entry {1 2 3 4} {
        $adjustFrame.parameters.frame.accumulation.frame.entry${entry} \
          configure -borderwidth $border
    }
    APSFrame .incrButtons -parent $adjustFrame.parameters.frame -packOption "-side left" \
      -label " "  -width 10\
      -contextHelp "Causes setpoints to increment by the corresponding coordinate"
    $adjustFrame.parameters.frame.incrButtons.frame configure -relief flat

    APSFrame .decrButtons -parent $adjustFrame.parameters.frame -packOption "-side left" \
      -label " "  -width 10\
      -contextHelp "Causes setpoints to decrement by the corresponding coordinate"
    $adjustFrame.parameters.frame.decrButtons.frame configure -relief flat

    APSButton .incrx -parent $adjustFrame.parameters.frame.incrButtons.frame  \
      -packOption "-side top" -text OUT -command "IncrX -sector $Sn" \
      -contextHelp  "Changes x setpoints using delta x." -fastClick 1
    APSButton .incrxp -parent $adjustFrame.parameters.frame.incrButtons.frame  \
      -packOption "-side top" -text OUT -command "IncrXp -sector $Sn" \
      -contextHelp  "Changes x setpoints using delta xp." -fastClick 1
    
    APSButton .incry -parent $adjustFrame.parameters.frame.incrButtons.frame  \
      -packOption "-side top" -text UP -command "IncrY -sector $Sn" \
      -contextHelp  "Changes y setpoints using delta y." -fastClick 1
    APSButton .incryp -parent $adjustFrame.parameters.frame.incrButtons.frame  \
      -packOption "-side top" -text UP -command "IncrYp -sector $Sn" \
      -contextHelp  "Changes y setpoints using delta yp." -fastClick 1
    
    APSButton .decrx -parent $adjustFrame.parameters.frame.decrButtons.frame  \
      -packOption "-side top" -text IN -command "IncrX -sector $Sn -sign -1" \
      -contextHelp  "Changes x setpoints using delta x." -fastClick 1
    APSButton .decrxp -parent $adjustFrame.parameters.frame.decrButtons.frame  \
      -packOption "-side top" -text IN -command "IncrXp -sector $Sn -sign -1" \
      -contextHelp  "Changes x setpoints using delta xp." -fastClick 1
    
    APSButton .decry -parent $adjustFrame.parameters.frame.decrButtons.frame  \
      -packOption "-side top" -text DOWN -command "IncrY -sector $Sn -sign -1" \
      -contextHelp  "Changes y setpoints using delta y." -fastClick 1
    APSButton .decryp -parent $adjustFrame.parameters.frame.decrButtons.frame  \
      -packOption "-side top" -text DOWN -command "IncrYp -sector $Sn -sign -1" \
      -contextHelp  "Changes y setpoints using delta yp." -fastClick 1
    set padding 2
    set width 4
    $adjustFrame.parameters.frame.incrButtons.frame.incrx.button configure -width $width -pady $padding
    $adjustFrame.parameters.frame.incrButtons.frame.incrxp.button configure -width $width -pady $padding
    $adjustFrame.parameters.frame.incrButtons.frame.incry.button configure -width $width -pady $padding
    $adjustFrame.parameters.frame.incrButtons.frame.incryp.button configure -width $width -pady $padding
    $adjustFrame.parameters.frame.decrButtons.frame.decrx.button configure -width $width -pady $padding
    $adjustFrame.parameters.frame.decrButtons.frame.decrxp.button configure -width $width -pady $padding
    $adjustFrame.parameters.frame.decrButtons.frame.decry.button configure -width $width -pady $padding
    $adjustFrame.parameters.frame.decrButtons.frame.decryp.button configure -width $width -pady $padding
    
    return 0
}

proc IncrX {args} {
    global deltax deltaxp deltay deltayp
    global deltaxAcc deltaxpAcc deltayAcc deltaypAcc
    global AP3x AP3y AP4x AP4y
    set sector ""
    set sign 1
    APSParseArguments {sector sign}
    if ![string length $sector] {
        APSAlertBox [APSUniqueName .] -errorMessage \
          "No sector variable specified in AMSteeringDialog"
        return 1
    }
    set deltaxAcc($sector) [expr $deltaxAcc($sector) + $sign * $deltax($sector)]
    set AP3x($sector) [expr $AP3x($sector) + $sign * $deltax($sector)]
    set AP4x($sector) [expr $AP4x($sector) + $sign * $deltax($sector)]
    return 0
}
proc IncrXp {args} {
    global deltax deltaxp deltay deltayp
    global deltaxAcc deltaxpAcc deltayAcc deltaypAcc
    global AP3x AP3y AP4x AP4y
    set sector ""
    set sign 1
    APSParseArguments {sector sign}
    if ![string length $sector] {
        APSAlertBox [APSUniqueName .] -errorMessage \
          "No sector variable specified in AMSteeringDialog"
        return 1
    }
    set deltaxpAcc($sector) [expr $deltaxpAcc($sector) + $sign * $deltaxp($sector)]
    set AP3x($sector) [expr $AP3x($sector) - $sign * 0.5015 * $deltaxp($sector)]
    set AP4x($sector) [expr $AP4x($sector) + $sign * 2.8310 * $deltaxp($sector)]
    return 0
}

proc IncrY {args} {
    global deltax deltaxp deltay deltayp
    global deltaxAcc deltaxpAcc deltayAcc deltaypAcc
    global AP3x AP3y AP4x AP4y
    set sector ""
    set sign 1
    APSParseArguments {sector sign}
    if ![string length $sector] {
        APSAlertBox [APSUniqueName .] -errorMessage \
          "No sector variable specified in AMSteeringDialog"
        return 1
    }
    set deltayAcc($sector) [expr $deltayAcc($sector) + $sign * $deltay($sector)]
    set AP3y($sector) [expr $AP3y($sector) + $sign * $deltay($sector)]
    set AP4y($sector) [expr $AP4y($sector) + $sign * $deltay($sector)]
    return 0
}
proc IncrYp {args} {
    global deltax deltaxp deltay deltayp
    global deltaxAcc deltaxpAcc deltayAcc deltaypAcc
    global AP3x AP3y AP4x AP4y
    set sector ""
    set sign 1
    APSParseArguments {sector sign}
    if ![string length $sector] {
        APSAlertBox [APSUniqueName .] -errorMessage \
          "No sector variable specified in AMSteeringDialog"
        return 1
    }
    set deltaypAcc($sector) [expr $deltaypAcc($sector) + $sign * $deltayp($sector)]
    set AP3y($sector) [expr $AP3y($sector) - $sign * 0.5015 * $deltayp($sector)]
    set AP4y($sector) [expr $AP4y($sector) + $sign * 2.8310 * $deltayp($sector)]
    return 0
}

proc ApplySetpoints {args} {
    global AP3x AP3y AP4x AP4y
    global timeLimit tolerance statusCallback

    set sector ""
    APSParseArguments {sector}
    if ![string length $sector] {
        APSAlertBox [APSUniqueName .] -errorMessage \
          "No sector variable specified in AMSteeringDialog"
        return 1
    }

    set Sn $sector
    set cavputList S${Sn}A:P3:ms:x:SetpointAO=$AP3x($sector),
    append cavputList S${Sn}A:P3:ms:y:SetpointAO=$AP3y($sector),
    append cavputList S${Sn}A:P4:ms:x:SetpointAO=$AP4x($sector),
    append cavputList S${Sn}A:P4:ms:y:SetpointAO=$AP4y($sector)
    if {$statusCallback!=""} {
        $statusCallback "Applying setpoints to sr bpm ioc PVs..."
    }
    if [catch {exec cavput -list=$cavputList -pendIoTime=10 \
             } result ] {
        APSAlertBox .alert -errorMessage "$result\nSomething wrong with a cavput command. Setpoints may not be asserted."
        return 1
    }
    if {$statusCallback!=""} {
        $statusCallback "Refreshing datapool vector of bpm adjust PVs..."
    }
    set pvList [list S${Sn}A:P3 S${Sn}A:P4]
    if [catch {APSRefreshVectorAdjust -pvList $pvList -waveformFile rfBpmInfo.sdds -plane both} result] {
        APSAlertBox .alert -errorMessage "$result\nSomething wrong with resetting vector adjust values."
        return 1
    }
    if {$statusCallback!=""} {
        $statusCallback "Done."
    }
    return 0
}

proc StartControllaw {args} {
    global AP3x AP3y AP4x AP4y
    global timeLimit tolerance statusCallback
    global gain interval runControlPV

    set sector ""
    APSParseArguments {sector}
    if ![string length $sector] {
        APSAlertBox [APSUniqueName .] -errorMessage \
          "No sector variable specified in AMSteeringDialog"
        return 1
    }
    
    if [catch {APSSRCheckCorrectorMode -plane h} hCorrMode] {
        APSAlertBox .alert -errorMessage "$hCorrMode"
        return
    }
    if [catch {APSSRCheckCorrectorMode -plane v} vCorrMode] {
        APSAlertBox .alert -errorMessage "$vCorrMode"
        return
    }
    if [string compare $hCorrMode $vCorrMode]!=0 {
        APSAlertBox .alert -errorMessage "The corrector modes in x and y plane are not consistent!"
        return
    }
    if [string compare $hCorrMode vector]==0 {
        set runControlPV DP:S:SteeringSDDS
    } else {
        set runControlPV S:SteeringSDDS
    }
    if [catch {exec cavget -list=$runControlPV.RUN -pend=30} running] {
        return -code error $running
    }
    if $running {
        if [APSYesNoPopUp "Another steering is running, would you like to abort it and continue?"] {
            if [catch {exec cavput -list=$runControlPV.ABRT=1 -pend=30} result] {
                return -code error "Unable to abort steering: $result"
            }
            after 2000
            if [catch {exec cavput -list=$runControlPV.CLR=1 \
                           -pend=30} result] {
                return -code error "Unable to abort steering: $result"
            }
        } else {
            APSAlertBox .alert -errorMessage "SRAMSteering: another steering is running!"
            return
        }
    }
    
    set Sn $sector
    #set cavputList S${Sn}A:P3:ms:x:SetpointAO=$AP3x($sector),
    #append cavputList S${Sn}A:P3:ms:y:SetpointAO=$AP3y($sector),
    #append cavputList S${Sn}A:P4:ms:x:SetpointAO=$AP4x($sector),
    #append cavputList S${Sn}A:P4:ms:y:SetpointAO=$AP4y($sector)
    #if [catch {exec cavput -list=$cavputList -pendIoTime=10 \
    #         } result ] {
    #    APSAlertBox .alert -errorMessage "$result\nSomething wrong with a cavput command. Setpoints may not be asserted."
    #    return
    #}
    if {$statusCallback!=""} {
        $statusCallback "Refreshing datapool vector of bpm adjust PVs..."
    }
    set pvList [list S${Sn}A:P3 S${Sn}A:P4]
    if [catch {APSRefreshVectorAdjust -pvList $pvList -waveformFile rfBpmInfo.sdds -plane both} result] {
        APSAlertBox .alert -errorMessage "$result\nSomething wrong with resetting vector adjust values."
        return 1
    }
    if {$statusCallback!=""} {
        $statusCallback "Done."
    }
    set controllawDir /home/helios/oagData/sr/localSteering/lattices/default/AMs/[format %02ld ${sector}]AM
    if {![file exist $controllawDir]} {
        APSAlertBox .alert -errorMessage "SRAMSteering: $controllawDir does not exist!"
        return
    }
    if {![file exist $controllawDir/irm] || ![file exist $controllawDir/tests] || \
          ![file exist $controllawDir/plain.defs] || ![file exist $controllawDir/dynamic.defs]} {
        APSAlertBox .alert -errorMessage "SRAMSteering: some controllaw files in $controllawDir do not exist!"
        return
    }
    if [catch {exec sdds2stream -par=ConditionNumber $controllawDir/irm} ConditionNumber] {
        APSAlertBox .alert -errorMessage "SRAMSteering: Problem with getting ConditionNumber from $controllawDir/irm!"
        return
    }
    if {$ConditionNumber>1.0e3} {
        APSAlertBox .alert -errorMessage "SRAMSteering: The ConditionNumber of $controllawDir/irm is greater than 1.0e3!"
        return
    }
    # determine what mode the correctors are in to pick the correct 
    # definitions file to use.
    if [catch {exec sdds2stream -col=ControlName $controllawDir/irm} correctors] {
        APSAlertBox .alert -errorMessage "SRAMSteering: Problem with getting correctors from $controllawDir/irm"
    }
    if [catch {exec cavget -pend=15 -list=[join $correctors ,] \
                 -list=:ControlSrcBO -label -embrace} tagValuePairs] {
        APSAlertBox .alert -errorMessage "SRAMSteering: Problem with getting source for correctors: $tagValuePairs"
    }
    # Take first one corrector as giving the reference mode
    set mode [lindex [lindex $tagValuePairs 0] 1]
    set incorrectMode 0
    foreach tagValue $tagValuePairs {
        if {[string compare [lindex $tagValue 1] $mode]} {
            incr incorrectMode
        }
    }
    if $incorrectMode {
        APSAlertBox .alert -errorMessage "Found $incorrectMode correctors not in mode $mode. Correction can't proceed."
        return
    }
    switch $mode {
        Maintenance {
            set defs plain.defs
        }
        Operation {
            set defs dynamic.defs
        }
    }
   
    set oldDir [pwd]
    cd $controllawDir
    
    if [catch {exec logMessage  -sourceId=steeringAudit\
                   -tag=Instance AM${sector} -tag=Action Start \
               } result ] {
        APSAlertBox .alert -errorMessage "error with logMessage: $result"
        return
    }
    if [string length $statusCallback]  {
        $statusCallback "Starting sddscontrollaw on AM$sector."
    }
    if [string compare $hCorrMode vector]==0 {
        APSAlertBox .alert -errorMessage "You can not run AM steering in datapool."
        return 1
        exec medm -attach -x -macro SDDSPV=$runControlPV \
	    /usr/local/iocapps/adlsys/srbpm/datapool/sddsEpicsLauncher.adl &
        if [catch {APSSRStartLocalSteeringInIOC -interval $interval -gain $gain \
                       -definition $defs -controllawDir $controllawDir -infiniteLoop 1 } result] {
            APSAlertBox .alert -errorMessage "$result!"
            return 
        }
    } else {
        exec medm -attach -x -macro RCPV=$runControlPV  \
            /usr/local/iocapps/adlsys/sr/psApp/APSRunControlSingle.adl &
        APSExecLog .controllaw -width 100 \
            -lineLimit 1024 \
            -name "$controllawDir local correction" \
            -unixCommand "sddscontrollaw irm \
              -test=tests \
              -runControlPV=string=$runControlPV,pingTimeout=30 \
              \"-runControlDescription=string=AM steering\" \
              -controlQuantityDefinition=$defs \
              -gain=$gain -interval=$interval -deltaLimit=value=2 \
              -verbose=1 -infiniteLoop" \
            -callback "controllawCallback -sector $sector" \
            -abortCallback "abortControllawCallback  -sector $sector" \
            -cancelCallback "abortControllawCallback  -sector $sector"
    }
    cd $oldDir
    return 0
}

proc controllawCallback {args} {
    global statusCallback

    APSParseArguments {sector}

    if [string length $statusCallback] {
        $statusCallback "sddscontrollaw on AP3 and AP4 for AM$sector completed."
    }
    if [catch {exec logMessage -sourceId=steeringAudit \
                 -tag=Instance AM${sector} -tag=Action Exit \
             } result ] {
        APSAlertBox .alert -errorMessage "error with logMessage: $result"
        return
    }
    return
}

proc abortControllawCallback {args} {
    global statusCallback

    APSParseArguments {sector}

    if [string length $statusCallback] {
        $statusCallback "sddscontrollaw on BP1 and AP1 bpms for ID$sector aborted."
    }
    if [catch {exec logMessage  -sourceId=steeringAudit \
                 -tag=Instance AM${sector} -tag=Action Abort \
             } result ] {
        APSAlertBox .alert -errorMessage "error with logMessage: $result"
        return
    }
    return
}

set sourcePointList [APSGetSourcePointSectors -group AM]

MakeSectorsWidget .sectors -parent .userFrame
MakeOptionWidget .options -parent .userFrame
if $allowTransfer {
    MakeTransferWidget .actions -parent .userFrame
}

set tolerance 0.050
set timeLimit 25
set statusCallback SetAMSteeringStatus
set interval 0.5
set gain 0.3
