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

#
# $Log: not supported by cvs2svn $
# Revision 1.255  2011/06/03 17:33:28  shang
# added display the datapool controllaw options in a popup window when "INFO" button is clicked.
#
# Revision 1.254  2011/04/12 20:41:27  shang
# renamed "CheckCorrector" button as "Corrector Sanity Check", and added contextHelp; corrected contextHelp for "CompareVector" button.
#
# Revision 1.253  2010/08/04 08:24:39  sajaev
# Changes by H. Shang: Gain values for FPGA bpms are set to 1.0 always in the gain vector.
#
# Revision 1.252  2010/07/27 18:08:55  shang
# added \"Guidance\" to fix the bpm ErrorCC or waveform values when the difference between scalar pvs and waveform is too big.
#
# Revision 1.251  2010/07/13 20:04:36  shang
# added corrector sanity check before initialzing corrector vector and added a check button to check the corrector CurrentAO-CurrentAI, DacAI-DacAO differences
#
# Revision 1.250  2010/07/08 19:23:55  shang
# disabled the "FULL START" button temporarily.
#
# Revision 1.249  2010/06/28 18:35:22  shang
# fixed a typo "linelimit" should be "lineLimit"
#
# Revision 1.248  2010/02/17 03:22:10  lemery
# Fixed syntax problems in recent additions to CheckTests.
#
# Revision 1.247  2010/02/09 21:43:30  shang
# added "InUse" column for comparison of waveform with scalar and added description of out-of-range tests so that operators would know what
# kind of limits need to be adjusted.
#
# Revision 1.246  2009/09/24 13:10:19  shang
# removed entries for corrector limit and CU corrector limit since the corrector limits are handled by corrector status management from now on.
#
# Revision 1.245  2009/04/08 14:38:36  shang
# added linelimit 2048 to sddspvtest exec log window to free the memories used by sddspvtest
#
# Revision 1.244  2009/03/16 16:37:04  shang
# added log message to start pv test.
#
# Revision 1.243  2008/11/27 10:31:44  emery
# Changed the behavior of "TRANSFER CORRECTOR REFERENCE" in the
# action tab to run only for on plane. To do for both planes at
# a time, use the "Setup X and Y" tab.
#
# Revision 1.242  2008/06/03 22:26:51  emery
# Added comments and context help to initialize correctors
# procedure and buttons to indicate that BPM setpoints are
# also initialized at the same time.
#
# Revision 1.241  2008/02/13 08:22:47  emery
# Added -noWarning for sddsprocess in a pipe for compring vector bpms
# and scalar bpms in CheckBpmVectorValues. Warning occurs when any one
# type of bpms is absent from config.
#
# Revision 1.240  2008/02/13 06:38:47  emery
# Updated a context help for restore scalar correctors.
#
# Revision 1.239  2007/08/06 15:38:56  emery
# Reordered how the reference files and default reference files
# are defined.
#
# Revision 1.238  2007/08/06 15:35:52  emery
# Wrote correct context help for the corrector reference file entry box,
# and added more help to the "TRANSFER CORR REFERENCE " button.
#
# Revision 1.237  2007/07/27 15:24:43  shang
# modified start/abort pv test procedure to catch errors
#
# Revision 1.236  2007/07/10 22:03:01  shang
# changed the CU corrector limit from 5.0 to 3.5
#
# Revision 1.235  2006/11/24 03:01:05  shang
# removed restoring ID xbpm offsets and setpoints when starting DP controllaw.
#
# Revision 1.234  2006/10/02 23:44:26  emery
# Changed the way corrector difference are checked. Only thise
# in orbit correction are checked (Shang).
#
# Revision 1.233  2006/10/02 08:18:49  emery
# For corrector-waveform comparison, compares with SFB: PVs,
# which is more up-to-date with the vector arrays than
# the regular plain PVs. The plain PVs may be different
# by up to 50 mA, when running or exiting datapool OC.
#
# Revision 1.232  2006/08/16 17:46:07  shang
# added hResponseDir and vResponseDir commanline arguments.
#
# Revision 1.231  2006/03/28 15:39:06  shang
# added CU corrector limit for generating tests of CU correctors and changed the default
# tolerance for comparing waveform with individual bpms from 0.01 to 0.02.
#
# Revision 1.230  2006/02/21 20:02:17  shang
# added checking if rmFF file exists if "RTDC overlap compensation" is selected before
# starting controllaw, a warning message will be given if rmFF does not exist to prevent
# starting the correction when it won't work.
#
# Revision 1.229  2006/02/09 18:07:48  shang
# added the BM bpms back to restoring vector bpm gains.
#
# Revision 1.228  2006/02/08 20:39:25  shang
# removed xray bpms from restore gains to verctor
#
# Revision 1.227  2006/02/02 16:51:18  shang
# added plane indicator for displaying the bpms that have different errorCC from
# waveform PV in CheckBpmVectorValues proc.
#
# Revision 1.226  2006/01/31 21:39:14  shang
# added CheckBpmVectorValues button which checks the bpm vector error waveform with individual bpm and added "email" and "print" buttons to the file display window that shows these difference.
#
# Revision 1.225  2005/11/01 22:47:45  shang
# made the "START PVTEST" button work after separating the datapool and workstation
# intervals.
#
# Revision 1.224  2005/10/24 20:47:26  shang
# separated the interval for datapool and work station orbit correction.
#
# Revision 1.223  2005/10/12 05:48:40  emery
# Indented code.
#
# Revision 1.222  2005/05/31 14:18:56  shang
# added setting corrector range error limits before starting pv test
#
# Revision 1.221  2005/03/07 20:11:33  emery
# Modified an adt bpm file name for use with running SR simulator on
# oxygen workstation. Added argumens to APSExecLogAbortInternal.
#
# Revision 1.220  2004/11/02 19:35:03  shang
# replaced APSInitializeCorrVector1 by APSInitializeCorrVector (the former proc
# was for testing and no long exist)
#
# Revision 1.219  2004/10/06 18:02:03  shang
# fixed a bug in CompareInUseBPM with vector proc which took waveform data without
# matching pv name -- added -match=Name=DeviceName to sddsxref statement
#
# Revision 1.218  2004/10/05 22:41:41  emery
# Shang added filtering of config data to the waveform tests of the
# TEST button.
#
# Revision 1.217  2004/10/05 22:11:51  emery
# Shang's change in testing additional datapool-related tests file
# for the TEST button.
#
# Revision 1.216  2004/08/18 00:07:14  shang
# added ramp/re-reramp despike threshold feature and rearraged the options widget
#
# Revision 1.215  2004/06/15 22:33:49  emery
# Made the pend timeout for sddspvtest 5 seconds less than the
# ping timeout. That way a CA error will show up as an error before
# a runcontrol timeout occurs.
#
# Revision 1.214  2004/06/15 21:54:49  emery
# Added corrector delta medm screen to Info button for datapool mode.
#
# Revision 1.213  2004/05/22 21:47:44  emery
# Added Shang's new quick start button.
#
# Revision 1.212  2004/04/12 23:36:07  shang
# rewrote procedures called in the controllaw startup to improve the startup speed
# and added TransferCorrectorReference proc to use the corrector reference file, added
# CheckCorrectorCurrentDifference proc to check the corrector current difference before
# switching to operation mode
#
# Revision 1.211  2004/02/17 14:38:36  emery
# Changes per shang: replaced bpm adt with one with regular averaging
# instead of weighted averaging. Changes scales for bpm adt.
#
# Revision 1.210  2003/11/04 16:00:22  shang
# fixed the problem for closing execLog window which does not exist for
# brief controllaw
#
# Revision 1.209  2003/11/03 22:36:56  shang
# added "Launch XBPM ADT" button to dislay the adt of xbpms that used in
# controllaw
#
# Revision 1.208  2003/10/30 16:03:32  shang
# added "wm protocol $parent.execLog WM_DELETE_WINDOW {return}" to the last line to
# prevent the execlog window be deleted.
#
# Revision 1.207  2003/10/28 21:25:11  shang
# added beep after controllaw is started.
#
# Revision 1.206  2003/10/24 14:54:33  shang
# modified SetSROrbitStatus so that it beeps only with error and warning messages.
#
# Revision 1.205  2003/10/21 21:27:10  shang
# removed the last duplicate message for CompareVector
#
# Revision 1.204  2003/10/21 21:24:46  shang
# returned "no difference message" if no bpm differences found between scalar pvs and vector
# pv for CompareVector proc.
#
# Revision 1.203  2003/10/16 19:22:55  soliday
# Fixed problem when displaying the adt screen while not logged in as asdops,
# oag,emery,borland,shang,sr,cyao.
#
# Revision 1.202  2003/10/02 20:54:18  shang
# CompareVector now accepts multiply choices
#
# Revision 1.201  2003/09/26 23:25:33  shang
# removed disabling bpm averaging (which was done by mistake)
#
# Revision 1.200  2003/09/26 22:40:29  shang
# fixed a type error
#
# Revision 1.199  2003/09/26 22:13:36  shang
# moved the setting env(EPICS_CA_ADDR_LIST) for oxygen station to StartControllaw proc.
#
# Revision 1.198  2003/09/26 22:10:45  shang
# only the bpms whose inUse status is different will be reset when controllaw is
# started, and the inUse status will no longer be cleared when controllaw is
# aborted; added compare in-use bpms with waveform button; modified compare
# vector feature to make it work more efficiently.
#
# Revision 1.197  2003/07/29 15:14:43  soliday
# Changed the default value for S35DCCT lower limit (mA) for H plane.
#
# Revision 1.196  2003/07/14 15:56:59  shang
# added -regenerateFiles 0 to StartControllaw command
#
# Revision 1.195  2003/07/08 19:07:34  shang
# modified installFile proc to link the default by the type of bpm and corrector
#
# Revision 1.194  2003/06/26 15:11:31  shang
# added packOption for execLog frame to make it expandable
#
# Revision 1.193  2003/06/24 21:26:49  shang
# made controllaw running with simulator if SROrbitControllaw is running on oxygen
# station
#
# Revision 1.192  2003/06/05 23:00:46  shang
# remove clear inUse PVs from AbortPVTest proc
#
# Revision 1.191  2003/05/28 12:28:48  emery
# Added more info for some error messages.
# Reenabled the function of the MSI reset button.
# Changed logic of MSI button to allow the action when
# all OC and RTFB are turned off.
#
# Revision 1.190  2003/05/23 16:53:54  emery
# Realized that I didn't need to change the name of the FFdefs file
# even though for different planes they would have different contents.
# I reverted to the original name of FFdefs.
#
# Revision 1.189  2003/05/23 16:26:05  emery
# Changed FFdefs file to FFdefs.$coord
#
# Revision 1.188  2003/04/22 15:11:13  shang
# added InitializeCorrFromFile button, which ramps the scalar correctros to UBOP file
# and then initialzie the corrector vector from UBOP file
#
# Revision 1.187  2003/04/15 03:28:15  shang
# added timing for each step in run controllaw and removed setting corrector
# InUse in quick-start mode
#
# Revision 1.186  2003/04/15 02:15:51  shang
# added Quick Start button
#
# Revision 1.185  2003/04/07 15:30:51  shang
# increased the runcontrol timeout to 30 seconds
#
# Revision 1.184  2003/03/12 01:07:41  shang
# added resetting boxcar averaging the StartControllaw proc
#
# Revision 1.183  2003/03/11 23:33:30  emery
# Put command string in  curly braces to prevent immediate evaluation of $plane.
#
# Revision 1.182  2003/03/11 21:38:59  emery
# Made the launcherpv option the first argument of sddscontrollaw
#
# Revision 1.181  2003/03/10 16:03:50  shang
# removed clear corrector InUse from ClearInUse proc
#
# Revision 1.180  2003/03/07 22:58:36  shang
# added SetCorrectorInUse which calls the libary proc-APSSetCorrectorInUse to
# start procedure and added SetInUseDC, SetInUseNone buttons to setup frames
#
# Revision 1.179  2003/02/05 19:25:52  emery
# Changed the ADTFiles subdirectory for bpm and corrector adt files.
#
# Revision 1.178  2002/12/10 20:25:38  shang
# "info" now is able to display the ioc runcontrol pv infomation for data pool
# configuration.
#
# Revision 1.177  2002/11/18 16:01:17  shang
# added pausing 2 seconds after aborting controllaw
#
# Revision 1.176  2002/10/29 23:45:07  shang
# put set corrector reference back to brief mode
#
# Revision 1.175  2002/10/29 21:46:07  emery
# Better context help for RESTORE SCALAR CORRECTOR button.
#
# Revision 1.174  2002/10/23 04:57:53  shang
# returned to the starting directory after running controllaw
#
# Revision 1.173  2002/10/23 03:57:39  shang
# removed the source and local library path after testing
#
# Revision 1.172  2002/10/22 00:11:15  shang
# removed "CompareIOCWithPolynormial" button and added "Restore Scalar Corrector"
#
# Revision 1.171  2002/10/22 00:01:37  shang
# fixed a bug
#
# Revision 1.170  2002/10/10 14:40:28  shang
# added "Global" back to the controllaw description to indicate the global feature
#
# Revision 1.169  2002/10/09 11:20:47  emery
# Fixed some argument of AbortControllaw.
#
# Revision 1.168  2002/10/09 07:20:29  shang
# revised comments for KillAllControllaws
#
# Revision 1.167  2002/10/09 07:16:36  shang
# added statement for killing controllaws
#
# Revision 1.166  2002/10/09 06:30:46  shang
# recommitted the previous reversion, which was committed by SR by mistake
#
# Revision 1.165 2002/10/09 06:18:38 sr
# modified KillAllControllaws since rsh no longer worked and aborted the corresponding
# controllaw whenever the start button is pressed.
#
# Revision 1.164  2002/10/07 17:03:43  soliday
# Restored the auto_path to the correct value.
#
# Revision 1.163  2002/10/06 16:47:58  emery
# Replaced calls to SetVectorOrScalarMode with APSSetCorrMode
#
# Revision 1.162  2002/10/05 16:57:11  shang
# changed action widget and removed those procedures which are included in oag tklib
#
# Revision 1.161  2002/10/05 09:10:47  shang
# made extensive changes for running controllaw in ioc
#
# Revision 1.160  2002/07/08 20:58:29  borland
# Added glitch logging back.
#
# Revision 1.159  2002/06/19 18:37:25  emery
# Use brief mode for sddscontrollaw statistics. Replaced a "puts stderr"
# and exit statements with return -code error statement in MSI reset procedure.
# (not used anyway). Removed "puts stderr $corrType" in setting up corrector
# modes.
#
# Revision 1.158  2002/04/30 03:10:47  shang
# added set bpm, corrector mode, reading vectors from RM, set MSI, compare vector
# bpm with scalar bpm while starting controllaw etc.
#
# Revision 1.157  2002/04/09 17:47:39  shang
# moved checkCorrReadbacks to run it before setCorrMode
#
# Revision 1.156  2002/04/02 00:41:29  emery
# Fixed checking of presence of BPMs.
#
# Revision 1.155  2002/03/01 00:06:07  emery
# Added procedure setParameters to set the interval, deltaLimit, num2Ave
# to minimum values according to corrector mode.
#
# Revision 1.154  2002/02/27 14:51:34  shang
# reduce redundant work in comparison and change the display format
#
# Revision 1.153  2002/02/26 22:54:25  emery
# Set pvTest to 1 as default.
#
# Revision 1.152  2002/02/26 22:14:32  emery
# changed default interval corrector delta limit and averaging.
#
# Revision 1.151  2002/02/25 23:38:02  shang
# added procedures to compare reflective memory waveform for bpm errors
# with individual PVs
#
# Revision 1.150  2002/02/20 07:14:50  emery
# Restored some loop parameters. Interval to 2.5 seconds, steps to 30k.
#
# Revision 1.149  2002/02/20 05:10:52  shang
# enable tabFrame button and unfreeze variables when return from errors.
#
# Revision 1.148  2002/02/20 04:42:11  shang
# fixed the bug in SetCorrMode proc
#
# Revision 1.147  2002/02/20 04:07:55  shang
# added comments for SetCorrMode proc.
#
# Revision 1.146  2002/02/20 04:00:15  shang
# added set corrector's mode feature
#
# Revision 1.145  2002/02/19 22:49:50  shang
# added deleting existing execLog window if start the controllaw again.
#
# Revision 1.144  2002/02/19 22:39:31  emery
# Added -noWarning to all sddsprocess commands.
#
# Revision 1.143  2002/02/19 22:31:39  emery
# Reverted to h.default as starting h-configuration.
#
# Revision 1.142  2002/02/19 22:29:20  emery
# Added rangeError PV tests. Added tab frame widget for pvtest
# and sddscontrollaw exec logs.
#
# Revision 1.141  2002/02/06 12:37:38  shang
# changed the minimum value for bpm waveform tests from 0 to -BPMLimit
#
# Revision 1.140  2002/01/29 16:40:14  shang
# added clear all inuse correctors before running controllaw
#
# Revision 1.139  2002/01/29 16:16:40  shang
# change InUser corrector values to DC.
#
# Revision 1.138  2002/01/23 16:35:50  emery
# Commented out lines after the sddscontrollaw APSExecLogs
# that aborts the pvtests. They prevent the procedure
# from exiting.
#
# Revision 1.137  2002/01/23 15:27:17  emery
# Fixed variable pvTest in last change.
#
# Revision 1.136  2002/01/23 15:23:21  emery
# Initialized variable pvtest
#
# Revision 1.135  2002/01/23 15:02:03  emery
# Added missing callback arguments to APSExecLog in brief mode.
#
# Revision 1.134  2002/01/22 18:07:09  emery
# Indented code. Added a cd $dataDir near the start of execution.
# Added missing arguments to string compare.
#
# Revision 1.133  2002/01/22 17:48:47  emery
# Removed temporary parameters.
#
# Revision 1.132  2002/01/22 16:26:43  shang
# modified GenerateFiles proc and createwaveforms proc which create both waveforms
# and waveform test file as needed.
#
# Revision 1.131  2002/01/15 15:43:30  shang
# added inUse correctors
#
# Revision 1.130  2002/01/11 20:14:48  shang
# added waveforms and sddspvtest options
#
# Revision 1.129  2001/12/11 17:02:01  emery
# Made "no despike" default for v plane.
#
# Revision 1.128  2001/12/01 00:33:59  emery
# Changed case of button text.
#
# Revision 1.127  2001/11/30 23:08:51  emery
# Added launch corrector reference button.
#
# Revision 1.126  2001/10/03 21:11:06  shang
# added data pool definitons for msAve BPMs
#
# Revision 1.125  2001/09/26 15:12:15  borland
# Tests for BM PS1 shutters are based only on whether the P2 BPM is being used.
# Previously, the test was based on whether the BPM existed.
#
# Revision 1.124  2001/08/14 18:39:57  emery
# In generating test files, replaced explicit list of file names
# with a variable that gets various component files appended
# as needed.
#
# Revision 1.123  2001/08/09 15:48:44  emery
# Added more files to APSAddToTmpFileList.
#
# Revision 1.122  2001/08/01 12:25:26  emery
# Changed default correction parameters.
#
# Revision 1.121  2001/07/30 08:16:03  emery
# Added some "cd $oldDir" before returning an error code in
# proc StartControllaw.
#
# Revision 1.120  2001/06/27 19:08:15  emery
# Updated context help for "Launch ADT" button
#
# Revision 1.119  2001/06/12 18:53:54  borland
# Changed default gain to 0.15 from 0.4 and default interval to 4s from 2.5s.
# This was to make correction with the x-ray bpms stable.
#
# Revision 1.118  2001/06/05 18:34:51  emery
# Added a mechanism to check for CA error when collecting
# bpm name data from RTFB.
#
# Revision 1.117  2001/06/05 18:16:37  emery
# Added a -noWarning on sddsxref for gap limits test file.
#
# Revision 1.116  2001/06/05 18:08:11  emery
# Rewrote section on xray bpm tests because a formatted sector
# number is required in the EPS PVs.
#
# Revision 1.115  2001/05/23 06:06:54  emery
# Changed the default parameters to 0.4 gain, RT/DC overlap compensation on
# and 2.5 second interval.
#
# Revision 1.114  2001/05/15 18:28:42  emery
# Removed a emery path which was commited by accident last time.
#
# Revision 1.113  2001/05/14 22:10:14  emery
# Replace control for hold present values (hardly ever used) with
# RT/DC overlap control.
#
# Revision 1.112  2001/02/06 18:25:47  emery
# Replaced calls to TransferCorrectorReference
# with calls to APSMpSRTransferCorrectorReference.
# Removed procedure TransferCorrectorReference.
#
# Revision 1.111  2001/02/06 18:13:01  emery
# Added TransferCorrectorReference procedure and
# button for setting the <corr>:ErrorRangeCALC.B PVs
# equalk to the present values of CurrentAO
# at the start of orbit correction and at the press of a button.
#
# Revision 1.110  2000/11/23 10:33:39  emery
# Previous version had wrong default interval value.
#
# Revision 1.109  2000/11/23 10:32:26  emery
# The previous version was inadvertently
# using a private version of the sddscontrollaw executable.
#
# Revision 1.108  2000/11/23 06:57:39  emery
# Replace swap frame for x/y with tab frame.
# Put tab in disabled state when running START
# to prevent plane variable from changing during execution.
#
# Revision 1.107  2000/10/28 06:57:56  emery
# In proc ClearInUsePVs changed the blanket cavput
# that relied on -blunder ahead with a list created from
# /home/helios/oagData/sr/BPMStatus/config.sdds.
# This should reduce the execution time as the
# pending io wait isn't necesary.
#
# Revision 1.106  2000/10/28 03:09:13  emery
# Changed a msType to PVSuffix (left-over form elimination of mapped PVs).
#
# Revision 1.105  2000/10/28 02:59:03  emery
# added =silently to -blunder option of cavputs.
# Use lappend to assign the widget name to SensitiveWidgetList
#
# Revision 1.104  2000/10/19 19:11:58  emery
# In ClearInUse procedure replaced use of APSSRGetInstalledBPMList with
# larger set of bpms in cavput command.
#
# Revision 1.103  2000/10/17 21:31:56  emery
# Removed lines relating to mapped bpm PVs as these PVs are now
# obsolete.
#
# Revision 1.102  2000/09/27 17:04:52  emery
# Added IDgap.tests to list of files to delete before processing.
#
# Revision 1.101  2000/09/19 23:34:14  emery
# Added customized gap limits for Xray bpms tests.
#
# Revision 1.100  2000/09/18 22:11:26  emery
# Changed interval and gain according to O. Singh and G. Decker's
# optimization.
#
# Revision 1.99  2000/09/12 19:55:18  emery
# Changed default time interval and gain.
#
# Revision 1.98  2000/08/29 17:30:22  emery
# Changed gap limit fro tests of ID Xray bpms.
# Changed method of generating S35DCCT test file.
#
# Revision 1.97  2000/07/30 05:37:16  emery
# Removed command that deletes definitions file.
#
# Revision 1.96  2000/07/27 02:38:42  emery
# Use the APSAddToTmpFileList APSDeleteTmpFileList procedures
#
# Revision 1.95  2000/07/20 20:30:23  emery
# Uncommented the APSDeleteTmpFileList statement in LaunchADT.
#
# Revision 1.94  2000/07/20 20:29:18  emery
# Removed unnecessary sddsconvert -dele=par,* command in
# LaunchADT.
#
# Revision 1.93  2000/07/20 18:57:58  emery
# In LaunchADT take the list of bpms from the config files of
# the x and y planes instead of the good bpm file.
#
# Revision 1.92  2000/07/06 19:56:51  emery
# added file despike to list of deleted file when regenerating files.
#
# Revision 1.91  2000/07/06 19:47:13  emery
# Re-inserted "} result {" lines removed by mistake in last code change.
#
# Revision 1.90  2000/07/06 19:24:22  emery
# Removed permission setting commands to allow default facl
# to operate on base directories.
#
# Revision 1.89  2000/06/21 12:18:41  emery
# changed interval to 3.5 seconds.
#
# Revision 1.88  2000/03/03 08:07:13  emery
# Changed permissions from 777 or 666 to 775 or 664
# to remove the world write access.
#
# Revision 1.87  2000/02/04 21:18:04  emery
# Fixed error in typing in the Xray bpm names.
#
# Revision 1.86  2000/02/04 21:16:59  emery
# Added Xray bpms to ioc averaging commands.
#
# Revision 1.85  2000/02/01 01:19:07  emery
# Check the number of Xray bpms. If zero, then skip
# creating Xray bpms files.
#
# Revision 1.84  2000/01/25 21:19:43  emery
# Added shutter position test to Xray bpms.
#
# Revision 1.83  2000/01/04 19:30:09  borland
# Added "Launch ADT" button, which prepares an ADT input file including only
# the good bpms, then runs ADT with that file.  Not heavily tested.
#
# Revision 1.82  1999/12/14 05:59:12  emery
# Added explicitly the list of all bpm types including the
# P0 bpms for the APSSRSetIOCAveraging command.
# The averaging for P0s were originally not being done properly.
#
# Revision 1.81  1999/11/10 18:26:02  emery
# Added proceed/abort dialog in case bpm connection fails.
#
# Revision 1.80  1999/11/05 22:27:20  emery
# catch the return of file attributes commands.
#
# Revision 1.79  1999/10/31 11:02:39  emery
# Made despike file writable by other users.
#
# Revision 1.78  1999/10/29 18:10:59  emery
# Indented code.
# Fixed bug in generating file despike where a blank
# entry was generate in SymbolicName. Now the column Symbolic name
# is explicitly reeditted.
#
# Revision 1.77  1999/09/07 21:34:56  emery
# Remove extra ] following APSGetBMXRayBPMList from AbortControllaw procedure.
#
# Revision 1.76  1999/09/07 18:32:34  emery
# Added Xray bpm limits with a default value of 0.2 mm.
#
# Revision 1.75  1999/09/07 15:13:00  emery
# Added cavputs to InUse PVs for Xray bpms.
#
# Revision 1.74  1999/08/17 18:22:22  emery
# Changed maximum gap for ID test from 25 mm to 30 mm.
#
# Revision 1.73  1999/08/06 15:07:48  emery
# Added button to force a regeneration of controllaw files.
#
# Revision 1.72  1999/08/03 15:41:19  emery
# Added test to check that a valid bpm and corrector
# is present in file irm for the plane or coordinate
# selected.
#
# Revision 1.71  1999/07/27 19:06:33  borland
# Eliminated messages about setting InUseBO for non-existent P0's.
#
# Revision 1.70  1999/07/08 15:22:44  emery
# Added the missing P0s in the ClearInUsePVs procedure.
#
# Revision 1.69  1999/05/24 18:46:15  borland
# Added sort to dirSelectDialog so files are displayed in a reasonable order.
#
# Revision 1.68  1999/04/23 22:50:03  emery
# Added several -noWarning argumetns in the
# IDbpms tests file generation to avoid warning messages
# and subsequent procedure halts
# when there are no ID bpms in the configuration.
#
# Revision 1.67  1999/04/19 22:52:57  emery
# Added tests variables to ID gaps when ID bpms are used.
# Changed exec rm and exec chmod with file delete and file
# attribute commands where applicable.
#
# Revision 1.66  1998/10/30 15:19:35  emery
# set run control timeout to 12 seconds.
#
# Revision 1.65  1998/08/03 01:12:24  emery
# Changed correction interval to 1 sec.
#
# Revision 1.64  1998/08/01 14:00:47  emery
# Changed default interval to 0.1 and PV type to msAve
#
# Revision 1.63  1998/07/21 19:58:52  emery
# Added -attach argument to medm command.
#
# Revision 1.62  1998/07/06 23:30:53  emery
# Added default RCTimeout value.
#
# Revision 1.61  1998/07/06 23:29:16  emery
# Added possibility of setting the run control timeout.
#
# Revision 1.58  1998/06/30 13:12:59  emery
# Added sddscontrollaw options readbackRmsThreshold and
# controlRmsThreshold.
#
# Revision 1.57  1998/06/19 23:16:12  emery
# Added statistics logging file for directory
# /home/helios/oagData/controllaw/SRorbit/loggedData
#
# Revision 1.56  1998/06/16 13:35:50  emery
# Commented out generate button (used for testing)
#
# Revision 1.55  1998/06/16 13:35:06  emery
# Corrected PVSuffix typing bug and directory existence test bug.
#
# Revision 1.53  1998/04/09 18:40:29  emery
# Added procedures ClearInUse and KillAllControllaws.
#
# Revision 1.52  1998/01/18 23:23:30  borland
# Set a retry count of 10 for burtrb, to make script less sensitive to
# communications problems.
#
# Revision 1.51  1998/01/13 19:10:40  borland
# New version for new directory organization.
#
# Revision 1.49  1997/10/27 23:27:58  borland
# Fixed bug in last modification (missing close quote).
#
# Revision 1.48  1997/10/20 18:27:16  emery
# Added the status message "abort pending" when the abort
# button is pressed.
#
# Revision 1.47  1997/07/30 20:43:47  emery
# Added log actuator switch to use the controlLogFile option
# of sddscontrollaw. Logging actuators is now a default.
# Data file is in /home/helios/oagData/controllaw/SRorbit/loggedData.
#
# Revision 1.46  1997/07/09 05:42:47  emery
# Due to changes in the APSWidgetSwapFrame procedure
# the buttonRow widget was changed to buttonFrame.
#
# Revision 1.45  1997/06/10 05:02:22  emery
# Added a test of the existence of the tests file.
#
# Revision 1.44  1997/06/10 04:11:51  emery
# Changed lineLimit on APSExecLog to 2048
#
# Revision 1.43  1997/05/29 17:13:25  emery
# Used the construct [string compare ...] and [string length ...]
# where applicable.
#
# Revision 1.42  1997/04/25 19:38:43  emery
# Added -lineLimit 1024 to APSExecLog
#
# Revision 1.41  1997/04/11 22:04:36  emery
# Fixed bug in comparing mode value with "Fine" which
# gave the wrong value to the S:OrbitControlLaw[XY]FineBO
# PVs.
#
# Revision 1.40  1997/04/03 11:53:41  emery
# Increased a pendIOtime value for the cavput for bpm alarms
#
# Revision 1.39  1997/04/01 22:04:43  emery
# Added tests for mapped bpms.
#
# Revision 1.38  1997/03/28 21:54:51  emery
# Added ms type mswAve/mapped so that mapped bpms
# can be used in orbit correction.
# Removed a chmod command which is giving me
# headaches.
#
# Revision 1.37  1997/01/18 09:37:46  emery
# Changed variable name scorrResponseFile to responseFile.
# Changed quantity scorr${plane}... to ${plane}...
#
# Revision 1.36  1997/01/17 22:12:15  emery
# Changed default mode from Global to Fine.
# Made the revert-to-default sensitive to the
# correction mode.
#
# Revision 1.35  1997/01/17 21:53:45  emery
# Removed path component of the selected file in the
# response and configuration file entry boxes.
# The link names are written back into the
# file entry boxes after the install of
# a file is made.
# Changed the way the procedure InstallFile passes
# the name of the file. The name of the variable is
# passed rather than the name, so that is the name is
# update somehow, then a global statement will retrieve the updated
# name.
#
# Revision 1.34  1997/01/17 21:02:36  emery
# Added Install buttons for the response and configuration files.
#
# Revision 1.33  1997/01/17 18:12:29  emery
# Added revert buttons for despike defaults
#
# Revision 1.32  1996/12/18 18:09:14  emery
# Changed variable Rank with variable mode.
# Changed variable names containing numbers 1 and 2
# to Fine and Global.
#
# Revision 1.31  1996/12/10 06:18:31  emery
# Added SROrbitControllawBrief to the Programs meun
#
# Revision 1.30  1996/12/08 07:54:09  emery
# Removed procedure UpdateSoftLink and replaced
# calls to UpdateSoftLink with APSUpdateSoftLink.
#
# Revision 1.29  1996/12/07 09:06:55  emery
# Added a chmod g+w to file bpm.data.
#
# Revision 1.28  1996/12/04 14:07:58  emery
# Added graying out of the H and V buttons while procedures
# are executing.
# Fixed "errror" typo.
# Used more consistent variable names for enable and InUse files.
# Use the file bpm.list as template for creating InUse burt file.
# Added UpdateSoftLink procedure to update soft links.
#
# Revision 1.27  1996/10/14 16:44:16  borland
# Replaced G:S:injectingStatusBI with S:InjectingStatusMBBI, as the former is
# in the gateway IOC and isn't reliable.
#
# Revision 1.26  1996/10/10 22:50:22  borland
# Increased default gain to 0.4
#
# Revision 1.25  1996/10/08 17:59:23  borland
# Removed 'Mp' from APSMpSRSetIOCAveraging.
#
# Revision 1.24  1996/10/08 06:19:36  emery
# Added to the test file a column Despike with
# value 1 for bpm readbacks.
#
# Revision 1.23  1996/10/07 07:12:28  emery
# Added setting of InUseBO PVs for the bpms.
# Made the tests file re-generate itself at every START.
#
# Revision 1.22  1996/10/06 17:43:34  borland
# Changed default BPMLimit to 10mm.
#
# Revision 1.21  1996/10/05 18:15:41  borland
# Added separate entry boxes and controls for h and v despiking.
# Also changed 'atime' to 'mtime' in file age comparisions to get
# proper behavior.
#
# Revision 1.20  1996/10/05 10:34:18  emery
# Changed the width of the ExecLog window and made the
# automatic abort before an actual start of sddscontrollaw
# condition on whether the runcontrol PV is running.
#
# Revision 1.19  1996/10/05 02:03:35  borland
# Revised default despiking parameters.
#
# Revision 1.18  1996/10/05 00:27:58  borland
# Proper implementation of despike checkbutton.
#
# Revision 1.17  1996/10/05 00:23:39  borland
# Fixed syntax error.
#
# Revision 1.16  1996/10/05 00:22:00  borland
# Added widgets, variables, and sddscontrollaw options for despiking.
#
# Revision 1.15  1996/09/28 00:13:59  emery
# Added log Daemon message for starting and aborting the correction
# in each plane. Tags are "steering" "action".
#
# Revision 1.14  1996/09/27 19:54:27  emery
# Changed the words Primary to Global and Secondary to Fine to better
# match the application of the two sets of matrices we've been using.
#
# Revision 1.13  1996/09/26 00:10:09  emery
# Added primary and secondary matrices.
# A press of the START button will send an abort
# signal to the run control PV of the plane selected, and
# start a new sddscontrollaw process.
#
# Revision 1.12  1996/09/23 22:41:44  emery
# Changed default interval.
# Made more explicit in the status window
# the reason for re-generating the inverse response matrix.
# A string parameter bpmPVType is written to the inverse response
# file, in order to make a test on whether the
# inverse response file needs to be re-generated because
# a different bpm PV type is selected in the interface.
# Also the inverse response matrix is re-generated when
# doesn't exist as a parameter in the inverse response file.
#
# Revision 1.11  1996/09/21 00:43:19  emery
# Changed corrector limit default.
#
# Revision 1.10  1996/09/20 11:50:42  emery
# Resized ExecLog window so that the sddscontrollaw messages
# fix in exactly.
#
# Revision 1.9  1996/09/19 22:03:49  emery
# Restored testing of the injection status.
#
# Revision 1.8  1996/09/18 16:28:31  emery
# changed ms type default.
#
# Revision 1.7  1996/09/18 16:27:25  emery
# Change default ioc bpm averaging.
#
# Revision 1.6  1996/09/16 15:54:59  emery
# Allows separate exec log windows for x and y planes.
#
# Revision 1.5  1996/09/16 13:31:16  emery
# Added enabling of the bpm ioc averaging.
# Changed some defaults.
#
# Revision 1.4  1996/09/12 11:32:30  emery
# Fixed some variable substituions in variable names.
#
# Revision 1.3  1996/09/04 13:36:05  emery
# Added a selection box for H and V correction. Internal
# runcontrolPV selection still need to be done.
#
# Revision 1.2  1996/09/03 15:34:15  emery
# Added testing of status PV :ms.[XY]AVS, and testing
# of the injecting status PV G:S:injectingStatusBI.
# Fixed a bug in the bpm limit tests file where two identical pages
# were being produced.
#
# Revision 1.1  1996/09/02 21:26:14  emery
# First installation of SROrbitControllaw. Tested without beam.
#

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.256 $ \$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 MakeBriefPlaneFrame {widget args} {
    global plane
    APSParseArguments {parent}

    APSFrame $widget -parent $parent \
      -contextHelp "Frame for containing options."
    $parent$widget.frame configure -relief flat
    APSRadioButtonFrame .plane -parent $parent$widget.frame \
      -buttonList {H/x V/y} \
      -commandList {{setCorrPlane H} {setCorrPlane V}} \
      -variable plane \
      -valueList {h v} \
      -orientation Horizontal -label "" \
      -contextHelp "Selects the plane in effect when an action button is pressed."
    global SensitiveWidgetList
    lappend SensitiveWidgetList $parent$widget.frame.plane.frame.button1 $parent$widget.frame.plane.frame.button2
    return
}


proc MakeOptionFrame {widget args} {
    global steps gain intervalDP intervalWS averages averageInterval deltaLimit RCTimeout
    global runControlPV runControlDesc logStats
    global verbose dryrun FFcompensation logActuators datapool pvTest
    global hDespikeNeighbors hDespikeAverage hDespikePasses hDespikeThresholdStart hDespike
    global vDespikeNeighbors vDespikeAverage vDespikePasses vDespikeThresholdStart vDespike
    global hDespikeThresholdEnd hDespikeThresholdSteps hDespikeCountLimit
    global vDespikeThresholdEnd vDespikeThresholdSteps vDespikeCountLimit

    APSParseArguments {parent}

    APSFrame $widget -parent $parent -label "sddscontrollaw options" \
      -contextHelp "Frame to specify command line options for the sddscontrollaw command."
    set w0 $parent$widget.frame
    APSFrameGrid .fg -parent $w0 -xList {x1 x2}
    set w $w0.fg.x1
    APSLabeledEntry .steps -parent $w -label "steps" \
      -textVariable steps -width 10 \
      -contextHelp "Enter the number of steps to perform."
    APSLabeledEntry .gain -parent $w -label "gain" \
      -textVariable gain -width 10 \
      -contextHelp "Enter the gain (i.e. fraction of correction at each interval)"
    APSLabeledEntry .intervaldp -parent $w -label "interval for datapool (s)" \
      -textVariable intervalDP -width 10 \
      -contextHelp "Enter the interval between correction steps for datapool orbit correction."
    APSLabeledEntry .intervalws -parent $w -label "interval for workstation (s)" \
      -textVariable intervalWS -width 10 \
      -contextHelp "Enter the interval between correction steps for workstation orbit correction."
    APSLabeledEntry .deltaLimit -parent $w -label "corrector delta limit (A)" \
      -textVariable 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."
    APSLabeledEntry .averages -parent $w -label "averages" \
      -textVariable averages -width 10 \
      -contextHelp "Enter the number of averages of bpms at each iteration."
    APSLabeledEntry .averageInterval -parent $w -label "interval in averaging" \
      -textVariable averages -width 10 \
      -contextHelp "Enter the interval between readbacks for the bpm averaging."
    APSLabeledEntry .timeout -parent $w -label "runControl timeout (s) " \
      -textVariable RCTimeout -width 10 -contextHelp \
      "Enter the run control timeout in seconds."
    set w $w0.fg.x2
    APSLabeledEntryFrame .despike2 -parent $w  \
      -label "Despike passes (H, V):         " \
      -variableList {hDespikePasses vDespikePasses} -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 {hDespikeNeighbors  vDespikeNeighbors} -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 {hDespikeAverage vDespikeAverage} -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 .despike3 -parent $w \
      -label "Initial spike threshold in mm (H, V):  " \
      -variableList {hDespikeThresholdStart vDespikeThresholdStart} -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 {hDespikeThresholdEnd vDespikeThresholdEnd} -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 {hDespikeThresholdSteps vDespikeThresholdSteps} -width 5 -orientation horizontal \
      -contextHelp "Enter the number of correction steps to take in ramping from the initial to the final spike threshold."
    APSLabeledEntryFrame .despike6 -parent $w \
      -label "Spikes count limit (H, V):  " \
      -variableList {hDespikeCountLimit vDespikeCountLimit} -width 5 -orientation horizontal \
      -contextHelp "Enter the number of limit to avoid despiking if there are more than CountLimit readings outside the despiking threshold."

    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 {"Use pvTest " "dry run" "RTDC overlap compensation" "log actuators " "log stats" "despike H " "despike V " "log glitch"} \
      -variableList {pvTest dryrun FFcompensation logActuators logStats hDespike vDespike 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
}

proc MakeFileFrame {widget args} {
    global hResponseDir vResponseDir tolerance hCorrectorType vCorrectorType hBpmType vBpmType
    global PVSuffix BPMLimit XBPMLimit  rangeErrorLimit S35DCCTLimitH S35DCCTLimitV num2Ave filterCoeff
    global plane
    global SensitiveWidgetList
    global dataDir
    APSParseArguments {parent}

    set w $parent$widget.frame
    APSFrame $widget -parent $parent -label "Additional options" \
      -contextHelp "Frame to specify additional options, such as the directory of the response file, the type of bpm data, validity ranges for the sddscontrollaw tests file."

    set widgetList [APSTabFrame .planes -parent $parent$widget.frame -label "" \
                      -labelList "Horizontal Vertical" -width 900 -height 100 \
                      -commandList {{setCorrPlane H} {setCorrPlane V}} ]

    pack $parent$widget.frame.planes -side top
    $parent$widget.frame.planes.frame.tn select 0
    lappend SensitiveWidgetList $parent$widget.frame.planes.frame.tn
    set windex 0

    # Horizontal Response Directory
    set tabwidget [lindex $widgetList $windex]
    incr windex
    APSFrame .dir -parent $tabwidget -label "" \
      -contextHelp "Frame to specify directories in which files related to horizontal plane correction are found."
    set w $tabwidget.dir.frame
    APSLabeledEntry .responseDir -parent $w -label "Configuration" \
      -textVariable hResponseDir -width 40 -contextHelp \
      "Name of the directory for the response file for the HORIZONTAL plane which can be used with sddscontrollaw."
    APSButton .install -parent $w.responseDir \
      -text I -packOption "-side right" \
      -command "InstallFile -link h.default -fileVariable hResponseDir" \
      -contextHelp "Installs the directory selected (must be a simple directory, not a link) as the new horizontal response directory."
    APSButton .dir -parent $w.responseDir \
      -text F -packOption "-side right" \
      -command "findDir -dirVariable hResponseDir -filter h.*;GetBPMAndCorrectorType -fileVariable hResponseDir" \
      -contextHelp "Bring up a directory selection dialog box to choose the directory."
    APSFrame .type -parent $w 
    $w.type configure -relief flat -bd 0
    set w $w.type.frame
    APSLabeledEntry .type1 -parent $w -label "bpm type:" \
      -textVariable hBpmType -width 15 -contextHelp \
      "bpm type: DP or plain." -packOption  "-side left"
    APSLabeledEntry .type2 -parent $w -label "corrector type:" \
      -textVariable hCorrectorType -width 15 -contextHelp \
      "corrector type: DP, plain or dynamic." -packOption "-side left"
    APSButton .get -parent $w \
      -text Get -packOption "-side right" \
      -command "GetBPMAndCorrectorType -fileVariable hResponseDir" \
      -contextHelp "get the bpm and corrector type from the configuration file"
    

    # Vertical Response Directory
    set tabwidget [lindex $widgetList $windex]
    incr windex
    APSFrame .dir -parent $tabwidget -label ""  \
      -contextHelp "Frame to specify directories in which files related to vertical plane correction are found."

    set w $tabwidget.dir.frame
    APSLabeledEntry .responseDir -parent $w -label "Configuration" \
      -textVariable vResponseDir -width 40 -contextHelp \
      "Name of the directory for the response file for the VERTICAL plane which can be used with sddscontrollaw."
    APSButton .install -parent $w.responseDir \
      -text I -packOption "-side right" \
      -command "InstallFile -link v.default -fileVariable vResponseDir" \
      -contextHelp "Installs the directory selected (must be a simple directory, not a link) as the new vertical response file."
    APSButton .dir -parent $w.responseDir \
      -text F -packOption "-side right" \
      -command "findDir -dirVariable vResponseDir -filter v.*;GetBPMAndCorrectorType -fileVariable vResponseDir" \
      -contextHelp "Bring up a directory selection dialog box to choose the directory."
    APSFrame .type -parent $w 
    $w.type configure -relief flat -bd 0
    set w $w.type.frame
    APSLabeledEntry .type1 -parent $w -label "bpm type:" \
      -textVariable vBpmType -width 15 -contextHelp \
      "bpm type: DP or plain." -packOption  "-side left"
    APSLabeledEntry .type2 -parent $w -label "corrector type:" \
      -textVariable vCorrectorType -width 15 -contextHelp \
      "corrector type: DP, plain or dynamic." -packOption "-side left"
    APSButton .get -parent $w \
      -text Get -packOption "-side right" \
      -command "GetBPMAndCorrectorType -fileVariable vResponseDir" \
      -contextHelp "get the bpm and corrector type from the configuration file"

    set w $parent$widget.frame
    APSRadioButtonFrame .pvSuffix -parent $w -label "bpm PV type" \
      -variable PVSuffix -valueList {ms msAve mswAve} \
      -buttonList {ms msAve mswAve} -orientation horizontal -contextHelp \
      "Select the memory/scanner PV type (i.e. bpm data type)."
    
    APSLabeledEntry .num2ave  -parent $w -label "number to average" \
      -textVariable num2Ave -width 10 \
      -contextHelp "Enter the number of memory/scanner readback for averaging in the ioc at 10 Hz rate. Relevant for msAve and mswAve data."
    APSLabeledEntry .filterCoeff  -parent $w -label "filter coefficient" \
      -textVariable filterCoeff -width 10 \
      -contextHelp "Enter the value for the filter coefficient. Relevant for the mswAve data."
    APSLabeledEntry .currLimitH -parent $w -label "S35DCCT lower limit (mA) for H plane" \
      -textVariable S35DCCTLimitH -width 10 \
      -contextHelp "Enter the lower limit of S35DCCT readback below which the sddscontrollaw correction iteration is skipped."
    APSLabeledEntry .currLimitV -parent $w -label "S35DCCT lower limit (mA) for V plane" \
      -textVariable S35DCCTLimitV -width 10 \
      -contextHelp "Enter the lower limit of S35DCCT readback below which the sddscontrollaw correction iteration is skipped."
    APSLabeledEntry .bpmLimit -parent $w -label "bpm limit (mm)" \
      -textVariable BPMLimit -width 10 \
      -contextHelp "Enter the range of bpm readback outside of which the sddscontrollaw correction iteration is skipped."
    APSLabeledEntry .xbpmLimit -parent $w -label "Xray bpm limit (mm)" \
      -textVariable XBPMLimit -width 10 \
      -contextHelp "Enter the range of Xray bpm readback outside of which the sddscontrollaw correction iteration is skipped."
    
    APSLabeledEntry .rangeErrorLimit -parent $w -label "Range Error limit (A)" \
      -textVariable rangeErrorLimit -width 10 \
      -contextHelp "Enter the range error limit of corrector setpoints outside of which the sddscontrollaw correction iteration is skipped."
    APSLabeledEntry .tolerance -parent $w -label "Compare Tolerance" \
      -textVariable tolerance -width 10 \
      -contextHelp "Enter the tolerance for the difference of bpm's errors obtained through reflective memory (waveforms) and individual bpms" 
    
    return 0
}

proc MakeActionWidget {widget args} {
    global Plane plane coord Coord brief DPButtonList startButton loopClosed
    global vectorButtonsDisabled password correctorReferenceFile
    set parent ""
    APSParseArguments {parent}

    APSFrame $widget -parent $parent -label "Controllaw Buttons" \
      -contextHelp "Frame for containing controllaw buttons." -packOption "-side top"

    set w0 $parent$widget.frame
    if $brief  {
        set widgetList {"Action" "Information"}
    } else {
        set widgetList {"Action for selected plane" "Information for selected plane" "Setup X/Y for selected plane" "Setup for both planes" "Setup Vector in selected plane" "Despike Threshold Ramp"}
    }
    set tabFrameWidgetList [APSTabFrame .buttons -parent $w0 -label ""\
                              -labelList $widgetList -width 950 -height 130 -packOption "-expand true"]
    
    set index 0
    set w0 [lindex $tabFrameWidgetList $index]
    incr index
    APSFrameGrid .fg -parent $w0 -yList {y1 y2}
    set w $w0.fg.y1
    APSLabeledEntry .passwd -parent $w -label "password for KILL ALL:" -width 60 \
      -textVariable password -contextHelp "Password is only need for killing all controllaws"
    $w.passwd.entry configure -show "*"
    # APSButton .test -parent $w -text "test inuse" -command SetInUseBPMPVs
    APSButton .fullstart -parent $w -text "FULL START" -command \
      "APSFreezeVars [list Plane plane coord Coord]; DisableTabs; StartControllaw -fullStart 1; APSUnfreezeVars [list Plane plane coord Coord]; EnableTabs" \
      -contextHelp "Starts a sddscontrollaw command with regenerating files, setups and checks.\n\nThis should be used in operations."
    
    APSButton .quickstart -parent $w -text "Quick START" -command \
      "APSFreezeVars [list Plane plane coord Coord]; DisableTabs; StartControllaw -fullStart 0 -quickstart 1; APSUnfreezeVars [list Plane plane coord Coord]; EnableTabs" \
      -contextHelp "Starts a sddscontrollaw command with regenerating files, setups and checks.\n\nThis should be used in operations."

   
    APSButton .abort -parent $w -text ABORT \
      -command "AbortControllaw; SetSROrbitStatus \"Abort pending\"" -contextHelp \
      "Aborts the sddscontrollaw command through the ABORT run control mechanism." 

    APSButton .killAll -parent $w -text "KILL ALL"  \
      -command "KillAllControllaws" -contextHelp \
      "Find all the SR orbit correction sddscontrollaw processes running on herema and phoenix and kills them."

    APSButton .startUnified -parent $w -text "Start Unified" -command \
      "APSFreezeVars [list Plane plane coord Coord]; DisableTabs; StartControllaw -unified 1 ; APSUnfreezeVars [list Plane plane coord Coord]; EnableTabs" \
      -contextHelp "Does a special setup (skipping some normal steps) and launches sddscontrollaw. Generates new tests files, sets the appropriate averaging parameters to the bpm IOCs, and launches a sddscontrollaw command with the specified options." 

    APSButton .pvtest -parent $w -text "START PVTEST" \
      -command "StartPVTest" -contextHelp \
      "Start the pv testing process for selected plane. This is a required manual step if the testing parameters in the \"Parameters\" tab are changed followed by a \"GENERATE\" button press."
    APSButton .generate -parent $w -text GENERATE  -command \
      "APSFreezeVars [list Plane plane coord Coord]; DisableTabs; StartControllaw -regenerateFilesOnly 1; APSUnfreezeVars [list Plane plane coord Coord]; EnableTabs" \
      -contextHelp "Forces a regeneration of tests, bpm-in-use, and other files for response matrix selected. Necessary when bpm or corrector limits are changed.\n\nThis button does not start controllaw."
    
    set w $w0.fg.y2
    #APSButton .restorescalar -parent $w -text "Restore Sccalar Corrector from UBOP" \
    #    -command {APSMpRestoreScalarCorrectors -plane $plane -statusVar SROrbitStatus} -contextHelp \
     # "Switch correctors to scalar mode and restore setpoint values from UBOP file."
    APSButton .transferCorr -parent $w -text "TRANSFER CORR REFERENCE"  \
        -command {TransferCorrectorReference -plane $plane} \
        -contextHelp \
        "Sets the corrector reference values for alarms on future changes.  Only one plane is affected. The values are taken from the corrector reference file selected in the \"Corrector:\" entry box under the \"References\" tab."
    APSButton .startxray -parent $w -text "Start XBPM Status Update Server" -command "exec SRXrayBPMStatusUpdate &"
      

    set w0 [lindex $tabFrameWidgetList $index]
    incr index
    APSFrameGrid .fg -parent $w0 -yList {y1 y2}
    set w1 $w0.fg.y1
    set w2 $w0.fg.y2
    #APSFrame .w1 -parent $w
    #APSFrame .w2 -parent $w
    #set w1 $w.w1.frame
    #set w2 $w.w2.frame
    APSButton .info -parent $w1 -text INFO -command ControllawInfoButton \
      -contextHelp "Displays an medm screen for the run control PV of the particular plane selected."

    APSButton .test -parent $w1 -text TEST -command \
      "APSFreezeVars [list Plane plane coord Coord]; DisableTabs; StartControllaw -checkTests 1; APSUnfreezeVars [list Plane plane coord Coord]; EnableTabs" \
      -contextHelp "Checks the test conditions and displays any that are not satisfied."

    APSButton .adtb -parent $w2 -text "Launch BPM ADT"  \
      -command "LaunchADT -type Monitor" \
      -contextHelp \
      "Launches ADT (Array Display Tool) for BPMs, showing only those BPMs that are selected in the configuration file selected."
    APSButton .adtb1 -parent $w2 -text "Launch XBPM ADT"  \
      -command "LaunchADT -type XMonitor" \
      -contextHelp \
      "Launches ADT (Array Display Tool) for BPMs, showing only those XBPMs that are selected in the configuration file selected."

    APSButton .adtc -parent $w2 -text "Launch Corr. Range Error ADT"  \
      -command "LaunchADT -type Corrector" \
      -contextHelp \
      "Launches ADT (Array Display Tool) for correctors range errors, showing only those correctors that are selected in the configuration file selected."
   
    APSButton .compare -parent $w1 -text "CompareVector"  \
      -command "CompareVector" \
      -contextHelp "Compare the BPM and corrector individual PVs to corresponding waveform \
           PVs in the datapool ioc. In the case of correctors, the individual PV is \
           the DacAI PV."
    APSButton .compare1 -parent $w1 -text "CompareInUseBPM" \
      -command "CompareInUseBPMWithVector" \
      -contextHelp "Compare reflective memory waveform for bpm errors and sums with in using individual PVs"
    APSButton .checkbpm -parent $w1 -text "CheckBpmVectorValues"  \
	-command "CheckBpmVectorValue" \
	-contextHelp "works only for datapool configuration; compare reflective memory waveform for bpm errors with individual PVs in the configuration"
    APSButton .checkcorr -parent $w1 -text "Corrector Sanity Check" -command "CorrectorSanityCheck" \
        -contextHelp "Compares for all the correctors: CurrentAO, DacAI, and CurrentAI. This \
              useful for identifying a power supply control issue. Note that this \
              button doesn't compare these corrector PVs to the corrector vector. \
              Another button is defined for that."
    
    #APSButton .compare1 -parent $w2 -text "CompareIOCWithPolynomial" \
      # -command "CompareReadbackIOCWithPolynomial" \
      #	-contextHelp "Compare the readback with polynormial calculations from reading Vx,Vy"
    
    if $brief { return }
    set w0 [lindex $tabFrameWidgetList $index]
    incr index
    APSFrameGrid .fg -parent $w0 -yList {y1 y2}
    set w1 $w0.fg.y1
    set w2 $w0.fg.y2
    APSButton .setScarlar -parent $w1 -text "Disable Vector mode" \
      -command "SetCorrMode -corrMode scalar"  \
      -contextHelp "Set corrector and setpoints to scalar mode"
    APSButton .setvector -parent $w1 -text "Enable Vector mode" \
      -command "SetCorrMode -corrMode vector"  \
      -contextHelp "Set corrector and setpoints to vector mode"
    APSButton .init -parent $w1 -text "Init Corr Vector from DacAI and\n RTFB BPM from Setpoint" \
      -command "InitializeCorrVector -setpoint 0"  \
      -contextHelp \
      "Initialize corrector from DacAI and BPM setpoint (for RTFB) vectors from the scalar PVs in IOCs. Use SetpointAO values for now"
    APSButton .setPSCU -parent $w2 -text "Set Operation mode" \
      -command "SetCorrMode -sourceMode Operation"  \
      -contextHelp "Set all RTFB corrector source mode to Operation"
    APSButton .setDiag -parent $w2 -text "Set Maintenance mode" \
      -command "SetCorrMode -sourceMode Maintenance"  \
      -contextHelp "Set all RTFB corrector source mode to Maintenance"
    
    APSButton .setinuse -parent $w2 -text "SetInUseDC" \
      -command "SetCorrectorInUse" -contextHelp "Set the corrector InUse to DC."
    APSButton .setnon -parent $w2 -text "ClearCorrectorInUse" \
      -command "SetCorrectorInUse -type none" \
      -contextHelp "set all corrector InUse in selected plane to 0"
    
    set w0 [lindex $tabFrameWidgetList $index]
    incr index
    APSFrameGrid .fg -parent $w0 -yList {y1 y2}
    set w1 $w0.fg.y1
    set w2 $w0.fg.y2
    APSButton .setScarlar -parent $w1 -text "Disable Vector Mode" \
      -command "SetCorrMode -corrMode scalar -plane both" \
      -contextHelp "Set corrector and setpoints to scalar mode"
    APSButton .setVector -parent $w1 -text "Enable Vector Mode" \
      -command "SetCorrMode -corrMode vector -plane both"  \
      -contextHelp "Set corrector and setpoints to vector mode"
    
    
    APSButton .init -parent $w1 -text "Init Corr Vector from DacAI and\n RTFB BPM vector from Setpoint" \
      -command "InitializeCorrVector -plane h -setpoint 0;InitializeCorrVector -plane v -setpoint 0"  \
      -contextHelp \
      "Initialize corrector from DacAI and BPM setpoint (for RTFB) vectors from the scalar PVs in IOCs. Use SetpointAO values for now."
    APSButton .restorescalar -parent $w1 -text "Restore Scalar Corrector\n from UBOP" \
      -command "APSMpRestoreScalarCorrectors -plane both -statusVar SROrbitStatus" -contextHelp \
      "Switch correctors to scalar mode and restore setpoint values from UBOP file."
    APSButton .setPSCU -parent $w2 -text "Set Operation Mode" \
      -command "APSSetCorrMode -sourceMode Operation -plane both"  \
      -contextHelp "Set all correctors except RT Feedback to PSCU mode"
    APSButton .setDiag -parent $w2 -text "Set Maintenance mode" \
      -command "APSSetCorrMode -sourceMode Maintenance -plane both"  \
      -contextHelp "Set all correctors except RT Feedback to Diagnostic mode"
    APSButton .setinuse -parent $w2 -text "SetInUseDC" \
      -command "SetCorrectorInUse -plane both" -contextHelp "Set the corrector InUse to DC."
    APSButton .setnon -parent $w2 -text "ClearCorrectorInUse" \
      -command "SetCorrectorInUse -type none -plane both" \
      -contextHelp "set all corrector InUse in both plane to 0"
    
    APSButton .transferCorr -parent $w2 -text "Transfer Corr. Reference"  \
      -command "TransferCorrectorReference" \
      -contextHelp \
      "Sets the corrector reference values for alarms on future changes. Both planes are done. The values are taken from the corrector reference file selected in the \"Corrector:\" entry box under the \"References\" tab."
    APSButton .setMsi -parent $w1 -text "Reset MSI"  \
      -command "SetMSIOn" -contextHelp "set MSI Mode"
    APSButton .clearsetpoint -parent $w2 -text "Clear FF BPM setpoints" -contextHelp "set the datapool BPM setpoint to zero." \
      -command "ZeroFFBPMSetpoints"
    
    set w0 [lindex $tabFrameWidgetList $index]
    incr index
    APSFrameGrid .fg -parent $w0 -yList {y1 y2}
    set w1 $w0.fg.y1
    set w2 $w0.fg.y2
    #  APSButton .close -parent $w1 -text "Enable/Disable Vector Buttons" -command "ChangeDPButtonState 2" \
      #-contextHelp "Enable the setting vector modes buttons"
    APSButton .initvector -parent $w1 -text "Init All Vector" -command \
      "InitializeVector" -contextHelp \
      "This is the combination of following buttons, the corrector and BPM setpoints (for RTFB) values are initialized from ioc, and the offset and setpoints are initialized from UBOP file"
    lappend DPButtonList $w1.initvector.button
    APSButton .init -parent $w1 -text "Init Corr Vector from DacAI and\n RTFB BPM vector from Setpoint" \
      -command "InitializeCorrVector -setpoint 0"  \
      -contextHelp \
      "Initialize corrector and BPM setpoint (for RTFB) vectors from the scalar PVs in IOCs (from DacAI)"
     APSButton .init1 -parent $w1 -text "Init Corr Vector from CurrentAO and\n RFTB BPM vector from Setpoint" \
      -command "InitializeCorrVector -setpoint 1"  \
      -contextHelp \
      "Initialize corrector and BPM setpoint (for RTFB) vectors from the scalar PVs in IOCs (from CurrentAO)"
    
    lappend DPButtonList $w1.init.button
    APSButton .setVector -parent $w2 -text "Enable Vector Mode" \
      -command "SetCorrMode -corrMode vector" \
      -contextHelp "Set corrector and setpoints to vector mode"

    APSButton .zeroff -parent $w2 -text "Zero FF corrector" \
      -command "ZeroFFCorrector" -contextHelp "zero out feedforward corrector and corrector vector."

    APSButton .refoff -parent $w2 -text "RestoreDPOffsetFromFile" -command \
      "RestoreOffsetsAndSetpoints -datapool 1" -contextHelp "Tranfer DP offset+setpoint from reference"
    
    APSButton .refgain -parent $w2 -text "RestoreDPGainFromFile" -command \
      "RestoreBpmGains -datapool 1" -contextHelp "Tranfer DP gain from reference"
    
    APSButton .refcorr -parent $w1 -text "Init Corrector From File" -command \
      "InitializeCorrectorFromFile" -contextHelp "Initialize corrector vector from UBOP file, first ramp the scalar correctors to the UBOP file and then initialize corrector vector from UBOP file. The BPM setpoint vector is also initialized from values in the RTFB IOCs."

    global hDespikeThresholdRampPV vDespikeThresholdRampPV
    global hDespikeThresholdReramp vDespikeThresholdReramp
    set w [lindex $tabFrameWidgetList $index]
    incr index
    APSButton .reramp -parent $w -text "Re-ramp Despike Threshold" \
      -contextHelp "Press to ramp the despike threshold from start threshold" \
      -command {
          if [set ${plane}DespikeThresholdReramp] {
              if [catch {exec cavput -list=[set ${plane}DespikeThresholdRampPV]=1 -pend=10} result] {
                  return -code error $result
              }
          } else {
              APSAlertBox .warning -type warning \
                -errorMessage "Re-ramping despike threshold for $plane plane is disabled. To have this feature, you should check the \"reramp despike threshold [string toupper $plane]\" button and restart controllaw."
              if [catch {exec cavput -list=[set ${plane}DespikeThresholdRampPV]=0 -pend=10} result] {
                  return -code error $result
              }
          }
      }
}

# Note that this procedure also initializes the datapool BPM setpoint vector
# because APSInitializeCorrVector does this internally.
proc InitializeCorrectorFromFile {} {
    global correctorReferenceFile Plane plane corrDacAOtolerance corrAOAItolerance
    
    if ![file exist $correctorReferenceFile] {
        return -code error "$corretorReferenceFile does not exist"
    }
    SetSROrbitStatus "Initializing $Plane plane corrector vector from file..."
    set corrFile /tmp/[APSTmpString]
    APSAddToTmpFileList -ID orbitcorrection -fileList $corrFile
    if [catch {exec sddsprocess $correctorReferenceFile $corrFile \
                 -match=col,ControlName=SFB*${Plane}*CurrentAO } result] {
        return -code error $result
    }
    SetSROrbitStatus "Ramping scalar correctors..."
    if [catch {APSRampToSnapshot -initDialog 1 -fileName $corrFile } result] {
        return -code error $result
    }
    if [catch {APSInitializeCorrVector -plane $plane -correctorFile $corrFile \
                   -AOAItolerance $corrAOAItolerance -dacAOtolerance $corrDacAOtolerance} result] {
        return -code error $result
    }
    SetMainStatus "done"
}

proc LaunchADT {args} {
    global dataDir hResponseDir vResponseDir oxygenStation
    set type Monitor
    APSParseArguments {type}

    # adtFile is a reference file with all possible bpms or correctors.
    switch $type {
        Monitor {
            set adtFile /home/helios/OAG/oagData/ADTFiles/srBpm/sr.bpm.ave.error.pv
            if $oxygenStation {
                set adtFile /home/helios/OAG/oagData/ADTFiles/srBpm/sr.bpm.error.pv
            }
        }
        Corrector {
            set adtFile /home/helios/OAG/oagData/ADTFiles/srOther/sr.corr.rangeError.pv
        }
        XMonitor {
            set adtFile /home/helios/OAG/oagData/ADTFiles/srBpm/sr.xbpm.ave.error.pv
        }
        default {
            return -code error "LaunchADT: unknown type $type."
        }
    }
    if ![file exists $adtFile] {
        return -code error "Not found: $adtFile"
    }
    
    set tmpRoot /tmp/[APSTmpString]
    if {$type=="XMonitor"} {
        APSAddToTmpFileList -ID LaunchADT -fileList "$tmpRoot.x $tmpRoot.y $tmpRoot.xy $tmpRoot.bm.1"
        APSAddToTmpFileList -ID LaunchADT -fileList "$tmpRoot.id.x $tmpRoot.id.y $tmpRoot.bm $tmpRoot.pv"
        if [catch {exec sddsprocess $adtFile $tmpRoot.id.x "-match=par,ADTHeading=SR X*" \
                     -match=col,ControlName=S*ID*:x* \
                     -edit=col,BPMName,ControlName,2S/:/100D \
                     -noWarnings
            exec sddsprocess $adtFile $tmpRoot.id.y "-match=par,ADTHeading=SR Y*" \
                     -match=col,ControlName=S*ID*:y* \
                     -edit=col,BPMName,ControlName,2S/:/100D \
                     -noWarnings
            exec  sddsprocess $adtFile $tmpRoot.bm "-match=par,ADTHeading=SR BM*" \
                     -match=col,ControlName=S*BM* \
                     -edit=col,BPMName,ControlName,2S/:/100D  -noWarnings } result] {
            return -code error $result
        }
        foreach xy {x y} hv {h v} {
            set config $dataDir/[set ${hv}ResponseDir]/config
            if [catch {exec sddsprocess $config $tmpRoot.config \
                         -match=para,NameType=MonitorNames
                exec sddsselect $tmpRoot.id.$xy $tmpRoot.config $tmpRoot.$xy \
                         -match=BPMName=Name } result] {
                return -code error $result
            }
        }
        if [catch {exec sddsselect $tmpRoot.bm $tmpRoot.config $tmpRoot.bm.1 \
                     -match=BPMName=Name } result] {
            return -code error $result
        }
        set fileList ""
        foreach file [list $tmpRoot.x $tmpRoot.y $tmpRoot.bm.1] {
            set row [exec sdds2stream $file -rows=bar]
            if $row {
                lappend fileList $file
            }
        }
        set arrays [llength $fileList] 
        if $arrays {
            if [catch {eval exec sddscombine $fileList -pipe=out \
                         | sddsprocess -pipe=in $tmpRoot.pv \
                         -redefine=par,ADTNArrays,$arrays,type=short \
                         -redefine=par,ADTNAreas,$arrays,type=short \
                         -redefine=par,ADTUnitsPerDiv,0.02,type=double } result] {
                return -code error $result
            }
            exec adt -f $tmpRoot.pv &
        } else {
            SetSROrbitStatus "No XBPM contained in the config file!" -code warning
            return
        }
        return
    } else {
        APSAddToTmpFileList -ID LaunchADT -fileList "$tmpRoot.x $tmpRoot.y $tmpRoot.xy $tmpRoot.pv"
        foreach hv {h v} xy {x y} {
            set config $dataDir/[set ${hv}ResponseDir]/config
            if ![file exists $config] { 
                return -code error "Not found:  $config"
            }
            switch $type {
                Monitor {
                    if [catch {exec sddsprocess $config $tmpRoot.config \
                                 -match=para,NameType=MonitorNames
                        exec sddscombine $adtFile -pipe=out -merge \
                                 -delete=column,BPMName \
                                 | sddsprocess -pipe \
                                 -match=column,ControlName=S*:P?:*:$xy:ErrorCC \
                                 -edit=column,BPMName,ControlName,2S/:/100D \
                                 | sddsselect -pipe=in \
                                 $tmpRoot.config $tmpRoot.$xy -match=BPMName=Name \
                             } result] {
                        return -code error "LaunchADT: $result"
                    }
                }
                Corrector {
                    set HV [string toupper $hv]
                    if [catch {exec sddsprocess $config $tmpRoot.config \
                                 -match=para,NameType=CorrectorNames
                        exec sddscombine $adtFile -pipe=out -merge \
                                 -delete=column,CorrName \
                                 | sddsprocess -pipe \
                                 -match=column,ControlName=S*:${HV}?:RangeErrorCALC \
                                 -edit=column,CorrName,ControlName,2S/:/100D \
                                 | tee $tmpRoot.adt.$hv \
                                 | sddsselect -pipe=in \
                                 $tmpRoot.config $tmpRoot.$xy -match=CorrName=Name \
                             } result] {
                        return -code error "LaunchADT: $result"
                    }
                }
            }
        }
        # instead of using tmpRoot.xy as input to ADT directly, 
        # I use tmpRoot.xy to filter the original ADT file, 
        # so I'm sure to get the right parameter values for each page
        if [catch {eval exec sddscombine $tmpRoot.x $tmpRoot.y $tmpRoot.xy} result] {
            return -code error "$result"
        }
        if [catch {exec sddsxref $adtFile $tmpRoot.xy -pipe=out \
                     -match=ControlName -noWarning \
                     | sddsprocess -pipe=in $tmpRoot.pv \
                     "-test=para,n_rows 0 >" -noWarning} result] {
            return -code error "$result"
        }
        set arrays [llength [exec sdds2stream $tmpRoot.pv -rows=bare]]
        set origDir [pwd]
        cd /tmp
        switch $type {
            Corrector {
                if [catch {exec sddsprocess $tmpRoot.pv -noWarning \
                             -redefine=param,ADTNArrays,$arrays,type=short
                } result] {
                    return -code error "$result"
                }
            }
            Monitor {
                if [catch {exec sddsprocess $tmpRoot.pv -noWarning \
                             -redefine=param,ADTNArrays,$arrays,type=short \
                             -redefine=param,ADTUnitsPerDiv,0.02,type=double \
                         } result] {
                    return -code error "$result"
                }
                if $oxygenStation {
                    #remove PVs of bpm status
                    if [catch {exec sddsconvert $tmpRoot.pv -noWarning \
                                 -dele=col,StatusName
                    } result] {
                        return -code error "LaunchADT: $result"
                    }
                }
            }
        }
        cd $origDir
        exec adt -f $tmpRoot.pv &
        after 60000 "APSDeleteTmpFileList -ID LaunchADT"
    }
}

proc setCorrPlane {value} {
    global Plane plane Coord coord
    if ![string compare [string toupper $value] "H"] {
        set Plane H
        set plane h
        set coord x
        set Coord X
    } else {
        set Plane V
        set plane v
        set coord y
        set Coord Y
    }
    SetSROrbitStatus "$Plane Plane selected."
    return
}

proc ZeroFFBPMSetpoints {args} {
    set tmpRoot /tmp/[APSTmpString]
    SetSROrbitStatus "Clear FF BPM setpoint..."
    foreach plane {h v} term {Hor Vert} coord {X Y} {
        if [catch {exec cavget -list=SRFB:GBL:${term}:CloseLoopBO -pend=20} loop] {
            return -code error "Error reading SRFB:GBL:${term}:CloseLoopBO : $loop"
        }
        set dox 1
        if {$loop=="Open"} {
            set answer [tk_dialog .dialog "Warning" \
                          "Warning: $plane plane RTFB loop is open, do you want to do it at your own risk or cancel?" \
                          warning -1 Do-at-your-risk Cancel]
            if $answer {
                SetSROrbitStatus "Clear $plane plane FF BPM setpoint was cancelled."
                set dox 0
            }
        }
        if $dox {
            APSAddToTempFileList -ID srorbitcontrollaw -fileList "$tmpRoot.$plane $tmpRoot.$plane.zero"
            if [catch {exec sddswget -pv=DP:${coord}bpmSetPt:WF -pend=30 $tmpRoot.$plane} result] {
                return -code error "Error reading DP:${coord}bpmSetPt:WF : $result"
            }
            if [catch {exec sddsprocess $tmpRoot.$plane $tmpRoot.$plane.zero "-redefine=col,Waveform,0" } result] {
                return -code error "Error define waveform as zero: $result"
            }
            if [catch {exec sddswput $tmpRoot.$plane.zero -pend=30} result] {
                return -code error "Error loading zeros to $plane setpoint waveform: $result"
            }
        }
    }
    SetSROrbitStatus "done."
}

proc catchGenerateFiles {args} {
    if [catch {GenerateFiles} result] {
        SetSROrbitStatus "$result" -code error 
    }
}

proc StartControllaw {args} {
    global steps gain interval intervalDP intervalWS averages averageInterval deltaLimit RCTimeout
    global verbose dryrun FFcompensation logActuators logStats
    global hResponseDir vResponseDir tolerance logGlitch logActuators logStats
    global hRunControlPV vRunControlPV 
    global hRunControlDesc vRunControlDesc 
    global plane Plane coord Coord hDespike vDespike
    global num2Ave filterCoeff useCorrRefFile
    global hDespikeNeighbors hDespikeAverage hDespikePasses hDespikeThreshold hDespike  hDespikeCountLimit hDespikeThresholdStart hDespikeThresholdEnd
    global vDespikeNeighbors vDespikeAverage vDespikePasses vDespikeThreshold vDespike  vDespikeCountLimit vDespikeThresholdStart vDespikeThresholdEnd
    global hDespikeThresholdSteps vDespikeThresholdSteps hDespikeThresholdReramp vDespikeThresholdReramp
    global PVSuffix BPMLimit XBPMLimit rangeErrorLimit S35DCCTLimitH S35DCCTLimitV dataDir
    global brief pvTest controllawDone tabFrameWidgetListForLog loopClosed
    global hCorrectorType vCorrectorType hBpmType vBpmType oxygenStation  
    global corrAOAItolerance corrDacAOtolerance
    
    #set logGlitch 1
    set regenerateFilesOnly 0
    set checkTests 0
    set controllawDone 0
    set quickstart 0
    set fullStart 0
    set unified 0
    APSParseArguments {regenerateFilesOnly checkTests quickstart fullStart unified}
    set time [clock seconds]
    switch $plane {
        h {
            set directory $hResponseDir
            set control_parent [lindex $tabFrameWidgetListForLog 0]
            set pvtest_parent [lindex $tabFrameWidgetListForLog 2]
        }
        v {
            set directory $vResponseDir
            set control_parent [lindex $tabFrameWidgetListForLog 1]
            set pvtest_parent [lindex $tabFrameWidgetListForLog 3]
        }
    }
    
    if {!$quickstart && $checkTests} {
        CheckTests -directory $directory -Plane $Plane
        return
    }
    set oldDir $dataDir
    # It seems that auxiliary files and tests files are always regenerated now. It is no longer an option.
    if [catch {GenerateFiles -regenerateFiles 1 \
                   -directory $directory -PVSuffix $PVSuffix \
                   -BPMLimit $BPMLimit -XBPMLimit $XBPMLimit \
                   -dataDir $dataDir\
                   -rangeErrorLimit $rangeErrorLimit \
                   -S35DCCTLimitH $S35DCCTLimitH \
                   -S35DCCTLimitV $S35DCCTLimitV \
                   -unified $unified} result] {
        SetSROrbitStatus "$result" -code error
        SetSROrbitStatus "Warning: Files for correction may not be fully generated."
        SetSROrbitStatus "Warning: Orbit correction may not work properly."
        return
    }
    
    SetSROrbitStatus "Generate files spent [expr [clock seconds] - $time] seconds"
    if $regenerateFilesOnly {
        return
    }
    GetBPMAndCorrectorType -fileVariable ${plane}ResponseDir
    cd $dataDir/$directory
    # when we do unified orbit correction there is no feedforward, by definition.
    # so this is skipped with unified mode.
    if {$FFcompensation && !$unified} {
        if {![file exist rmFF]} {
            APSAlertBox .alert -name warning -type warning \
              -errorMessage "The realtime feedback overlap compensation file was not found for your configuration.  Either create the file (from the orbit correction configuration application) or deselect \"RTDC overlap compensation\" on the Options panel.."
            return
        }
        SetSROrbitStatus "checking overlap compensation ..."
        if [catch {CheckFFCompenstation -rmFF rmFF -irm irm -def FFdefs} result] {
            SetSROrbitStatus "checking overlap compensation ..."
            APSAlertBox .alert -name warnings -type error -errorMessage \
              "rmFF and irm do not match: $result\nplease check and regenerate them."
            return
        } 
    } else {
       SetSROrbitStatus "Skipping checking of FF compensation because of unified=1" 
    }
    set conNumber [exec sdds2stream -par=ConditionNumber irm]
    if {$conNumber>1.0e4} {
        APSAlertBox .alert -name warnings -type error -errorMessage \
          "The irm condition number for the configuration selected is greater than 1.0e4, can not start controllaw. Contact the SR CO or designee."
        return
    }
    set corrType [set ${plane}CorrectorType]
    if {$corrType=="DP"} {
        set datapool 1
        set interval $intervalDP
    } else {
        set datapool 0
        set interval $intervalWS
    }
    
    if !$quickstart {
        SetSROrbitStatus "Checking corrector current difference..."
        if [catch {CheckCorrectorCurrentDifference -plane $plane} result] {
            SetSROrbitStatus $result
            return
        } else {
            if {$result=="cancel"} {
                SetSROrbitStatus "Controllaw was cancelled because the current difference of some correctors are bigger than 0.5A"
                return
            } elseif {$result=="ok"} {
                if ![APSYesNoPopUp "The corrector current difference is bigger than 0.5A, are you sure to continue"] {
                    return
                }
            }
        }
    }
    
# kludge to set the SCU6 FF correctors to zero, as the FF-setpoint gets
# written as a setpoint in SR SCR. This seems the easiest way to
# include a procedure step that fixes some problem.
# This line will go away as soon as a method is found to
# properly handle FF corrector setpoints in RTFB.
   
#    SetSROrbitStatus "Setting S6C:V2 S7A:V1 CurrentAO and FFCurrentAO to 0"
#    if [catch {exec cavput -list=SFB:, -list=S6C,S7A -list=:V1:CurrentAO=0} result] {
#         cd $oldDir
#         SetSROrbitStatus "Error in setting set points of SCU6 FF correctors to zero: $result" -code error
#         return
#    }
    
    if $datapool {
        #abort normal controllaw in both planes
        foreach pl {h v} cd {x y} {
            set runControlPV [set ${pl}RunControlPV]
            if [exec cavget -list=$runControlPV.RUN -pend=30] {
                clearRCRecord -PV $runControlPV
                catch {AbortControllaw -runControlPV $runControlPV -inputCoord $cd}
                #after [expr int(1000 * ${interval})]
                # after 2000
            }
        }
        #abort vector controllaw if it is running
        set vectorControlPV DP:S:OrbitControlLaw${Coord}SDDS
        if [catch {AbortControllaw -runControlPV $vectorControlPV \
                     -coord $coord -datapool 1} result] {
            cd $oldDir
            SetSROrbitStatus "Error: $result!" -code error
            return
        }
        # after 2000
    } else {
        #abort vector controllaw in both planes
        foreach CD {X Y} cd {x y} {
            set vectorControlPV DP:S:OrbitControlLaw${CD}SDDS
            SetSROrbitStatus "Aborting $vectorControlPV ...."
            if [exec cavget -list=$vectorControlPV.RUN -pend=30] {
                if [catch {AbortControllaw -runControlPV $vectorControlPV \
                             -coord $cd -datapool 1} result] {
                    cd $oldDir
                    SetSROrbitStatus "Error: $result!" -code error
                    return
                }
                #  after 2000
            }
        }
        #abort sddscontrollaw in current plane
        set runControlPV [set ${plane}RunControlPV]
        clearRCRecord -PV $runControlPV
        catch {AbortControllaw -runControlPV $runControlPV -inputCoord $coord}
        #   after 2000
    }
    SetSROrbitStatus "Abort controllaw done; start pv test"
    if {$datapool} {
        StartPVTest   
        SetSROrbitStatus "start pv test done"
    }
    
    global defaultCorrRef defaultSetpointRef defaultGainRef defaultOffsetRef
    global setpointReferenceFile gainReferenceFile offsetReferenceFile correctorReferenceFile
    if {[string compare $defaultGainRef $gainReferenceFile]!=0 || \
          [string compare $defaultSetpointRef $setpointReferenceFile]!=0 || \
          [string compare $defaultOffsetRef $offsetReferenceFile]!=0 || \
          [string compare $defaultCorrRef $correctorReferenceFile]!=0 } {
        if ![APSYesNoPopUp "You are about to start orbit correction with non-standard initialization files (see reference tab). Are you sure you want to proceed?"] {
            return
        }
    }
    
    SetSROrbitStatus "prepare oc in parallel..."
    if [catch {exec prepareOrbitCorrection \
                 -quickStart $quickstart \
                 -config [set ${plane}ResponseDir] \
                 -despike [set ${plane}Despike] \
                 -detlaLimt $deltaLimit \
                 -gain $gain \
                 -interval $interval \
                 -average $averages \
                 -BPMType $PVSuffix \
                 -despike [set ${plane}Despike] \
                 -despikePasses [set ${plane}DespikePasses]  \
                 -despikeNeighbors [set ${plane}DespikeNeighbors] \
                 -despikeAverage [set ${plane}DespikeAverage] \
                 -despikeCountLimit [set ${plane}DespikeCountLimit] \
                 -despikeThresholdStart [set ${plane}DespikeThresholdStart] \
                 -despikeThresholdEnd [set ${plane}DespikeThresholdEnd] \
                 -despikeThresholdSteps [set ${plane}DespikeThresholdSteps] \
                 -despikeThresholdReramp [set ${plane}DespikeThresholdReramp] \
                 -filterCoeff $filterCoeff \
                 -num2Ave $num2Ave \
                 -useCorrRefFile $useCorrRefFile \
                 -corrSCRFile $correctorReferenceFile \
                 -corrAOAItolerance $corrAOAItolerance \
                 -corrDacAOtolerance $corrDacAOtolerance \
                 -unified $unified \
                 -offsetFile $offsetReferenceFile \
                 -setpointFile $setpointReferenceFile \
                 -gainFile $gainReferenceFile \
                 -FFcompensation $FFcompensation \
                 -averageInterval $averageInterval \
                 -steps $steps \
                 -verbose $verbose \
                 -logActuators $logActuators \
                 -logStats $logStats \
                 -logGlitch $logGlitch } result] {
        SetSROrbitStatus "Error starting orbit correction for $plane plane: $result"
        cd $oldDir
        return
    }
    #SetSROrbitStatus "$result"
    SetSROrbitStatus "prepare oc in parallel done -- $result"
    if $datapool {
        #check bpm difference
        #SetSROrbitStatus "set corrector mode to vector and write corrector and bpm data to RM (this has to be done after corrector and bpm vector are being initialized..."
        #if [catch {SetCorrMode -corrType $corrType -plane $plane} result] {
          #  SetSROrbitStatus "Error setting corrector mode to vector: $result"
         #   cd $oldDir
          #  return
        #}
        SetSROrbitStatus "Restore BPMs gains...."
        if [catch {RestoreBpmGains -datapool 1} result] {
            SetSROrbitStatus "Error restore BPMs gains: $result"
            cd $oldDir
        }
        
        SetSROrbitStatus "Checking bpm vector values..."
        while {1} {
            if [catch {CheckBpmVectorValues} result] {
                set answer [APSMultipleChoice .bpmVectorCheck -question "CheckBpmVectorValues: $result\n\nYou could do following things:\n\n\(1) If the bpm value (msAve:ErrorCC) is too big, check the Num2Ave value for that bpm, put the correct value and press enter. This will fix the abnomal bpm's msAve:ErrorCC.\n\n\(2) If the waveform value is bigger than the msAve:ErrorCC, the MSI of that bpm could be wrong, check that bpm's MSI from \"BPM Global Feedback Readback\" and press \"reset MSI\" if it is abnormal.\n\n(3) When a lot of P0 and P1s disagree between waveform and scalar values, it is beause datapool got rebooted somehow and the gains waveforms for P0 P1 have reverted to 1's, try \"RestoreDPGainFromFile\" button in \"setup Vector in Selected plane\" tab to restore DP gain for both planes. \n\nIf this does not fix the waveform values, contact Frank LENKSZUS or control group guys. .\n\n What would you like to do?" \
                              -labelList {Check-Again Continue-At-Your-Own-Risk Abort} \
                              -returnList {check continue abort}]
                switch $answer {
                    check {
                    }
                    abort {
                        SetSROrbitStatus "$result"
                        return
                    }
                    continue {
                        if ![APSYesNoPopUp "The bpm ErrorCC difference between vector and individual bpms are bigger than tolerance, are you sure to continue?"] {
                            return
                        }
                        break
                    }
                }
            } else {
                break
            }
        }
        SetSROrbitStatus "Start $vectorControlPV."
        if [catch {exec cavput -list=DP:S:OrbitControlLaw${Coord}SDDS.CMND=1 -pend=30} result] {
            return -code error $result
        }
        cd $oldDir
        return
    }
    
    SetSROrbitStatus "GetControllaw options"
    if [catch {PrepareControllawOptions -plane $plane} options] {
        SetSROrbitStatus "Error preparing controllaw options: $options"
        return
    }
    #use the old procedure to get options because it does not print message, use the options read from following pv
    #SetSROrbitStatus "reading controallw options from  DP:S:OrbitControlLaw${Coord}SDDS.OPTN"
    #if [catch {APScagetTextFromWaveform -pvName DP:S:OrbitControlLaw${Coord}SDDS.OPTN } options] {
    #    SetSROrbitStatus "Error reading options: $options!" -code error
    #    return
    #}
    
    set runControlPV [set ${plane}RunControlPV]
    clearRCRecord -PV $runControlPV
    if [exec cavget -list=$runControlPV.RUN -pend=30] {
        catch {AbortControllaw -runControlPV $runControlPV}
        after [expr int(1000 * ${interval})]
    }
    SetSROrbitStatus "$runControlPV started."
    if [catch {exec logMessage -sourceId=steeringAudit\
                 -tag=Instance $runControlPV -tag=Action Start \
             } result ] {
        APSAlertBox .alert -errorMessage "error with logMessage: $result"
        return -code error "Error!"
    }
    SetSROrbitStatus "Clearing controllaw records and log messages done."
    if [winfo exist ${control_parent}.sr${Plane}OrbitControllaw ] {
        destroy ${control_parent}.sr${Plane}OrbitControllaw
    }
    if $brief {
        APSExecLog .sr${Plane}OrbitControllaw -height 30 \
          -lineLimit 2048 -width 95 -parent $control_parent \
          -name "SR ${Plane}-orbit Correction from brief display" \
          -unixCommand "sddscontrollaw $options" \
          -callback "set controllawDone done" \
          -cancelCallback "set controllawDone cancel" \
          -abortCallback "set controllawDone abort"
    } else {
        APSExecLog .sr${Plane}OrbitControllaw -height 30 \
          -lineLimit 2048 -width 95 -parent $control_parent\
          -name "SR ${Plane}-orbit Correction from expert display" \
          -unixCommand "sddscontrollaw $options" \
          -callback "set controllawDone done" \
          -cancelCallback "set controllawDone cancel" \
          -abortCallback "set controllawDone abort"
    }
    
    cd $oldDir
    bell
    return
}

proc PrepareControllawOptions {args} {
    global steps gain interval intervalDP intervalWS averages averageInterval deltaLimit RCTimeout
    global verbose dryrun FFcompensation logActuators logStats
    global hResponseDir vResponseDir tolerance logGlitch
    global hRunControlPV vRunControlPV 
    global hRunControlDesc vRunControlDesc 
    global num2Ave filterCoeff
    global hDespikeNeighbors hDespikeAverage hDespikePasses hDespike
    global vDespikeNeighbors vDespikeAverage vDespikePasses vDespike
    global PVSuffix BPMLimit XBPMLimit rangeErrorLimit S35DCCTLimitH S35DCCTLimitV dataDir
    global brief pvTest controllawDone tabFrameWidgetListForLog loopClosed
    global hCorrectorType vCorrectorType hBpmType vBpmType oxygenStation
    global hDespikeThresholdStart vDespikeThresholdStart
    global hDespikeThresholdEnd hDespikeThresholdSteps hDespikeCountLimit
    global vDespikeThresholdEnd vDespikeThresholdSteps vDespikeCountLimit
    global hDespikeThresholdRampPV vDespikeThresholdRampPV
    global hDespikeThresholdReramp vDespikeThresholdReramp

    set datapool 0
    set corrType ""
    set bpmType ""
    set plane ""
    APSParseArguments {plane}
    switch $plane {
        h {
            set directory $hResponseDir
            set coord x
            set Coord X
            set Plane H
        }
        v {
            set directory $vResponseDir
            set coord y
            set Coord Y
            set Plane V
        }
        default {
            return -code error "PrepareOptions1: plane has to be h or v!"
        }
    }
    
    set dir $dataDir/$directory
    GetBPMAndCorrectorType -fileVariable ${plane}ResponseDir
    set corrType [set ${plane}CorrectorType]
    set bpmType [set ${plane}BpmType]
    set options "$dir/irm "
    if [string compare $corrType DP]==0 {
        set datapool 1
        set interval $intervalDP
        if {![file exist corrWaveform]} {
            return -code error "PrepareOptions2: File corrWaveform does not exist, use Generate to generate it first"
        }
        # launcherpv should be the first option. If there is a 
        # problem with arguments, then the ioc will at least know which
        # runcontrol has started.
        set options "-launcherpv=DP:S:OrbitControlLaw${Coord}SDDS $dir/irm"
        append options " -waveforms=$dir/corrWaveform,actuator -proportional"
        if $FFcompensation {
            if {![file exist ffWaveform] } {
                return -code error "PrepareOptions3: File ffWaveform does not exist, use Generate to generate it first"
            }
            append options " -waveforms=$dir/ffWaveform,ffSetpoint"
        }
        #append options " -searchPath=$dataDir/$directory"
    } else {
        set interval $intervalWS
    }
    if [string compare $bpmType DP]==0 {
        set datapool 1
        if {![file exist bpmWaveform]} {
            return -code error "PrepareOptions4: File bpmWaveform does not exist, use Generate to generate it first"
        }
        
        append options " -waveforms=$dir/bpmWaveform,readback"
    }
    if $datapool {
        if {![file exist waveformTest]} {
            return -code error "PrepareOptions6: File waveformTest does not exist, use Generate to generate it first"
        }
        if {1} {
            SetSROrbitStatus "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 "PrepareOptions7: $result"
            }
            #after 5000
            SetSROrbitStatus "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 "PrepareOptions8: $result"
            }
            #after 5000
            SetSROrbitStatus "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 "PrepareOptions9: $result"
            }
            # after 5000
        }
        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"
    } else {
        append options " -steps=$steps -gain=$gain -interval=$interval"
        if {$averages > 1} {
            append options " -average=$averages,interval=$averageInterval"
        }
    }
    if {$deltaLimit > 0 } {
        append options " -deltaLimit=value=$deltaLimit"
    } else {
        SetSROrbitStatus "Warning: negative deltaLimit ignored."  -code warning
    }
    if $dryrun {
        append options " -dryrun"
    }
    if {$verbose && !$datapool} {
        append options " -verbose"
    }
    if {!$oxygenStation && $FFcompensation } {
        if !$datapool {
            append options " -auxiliaryOutput=gain=1.0,matrix=$dir/rmFF,controlquantitydefinition=$dir/FFdefs"
        } else {
            append options " -auxiliaryOutput=gain=1.0,matrix=$dir/rmFF,controlquantitydefinition=$dir/FFdefs,mode=proportional"
        }
    }
    if [subst \$${plane}Despike] {
        if [file exists despike] {
            if $oxygenStation {
                set despikeFile /tmp/[APSTmpString].despike
                APSAddToTmpFileList -ID Controllaw -fileList "$despikeFile"
                if [catch {exec sddsprocess $dir/despike $despikeFile \
                             -reedit=col,ControlName,%/msAve/ms/ } result] {
                    return -code error $result
                }
                set optionExten ",file=$despikeFile"
            } else {
                set optionExten ",file=$dir/despike"
            }
        } else {
            set optionExten ""
        }
        switch $Plane {
            H {
                #set despikeshreshold to the default value
                if $datapool {
                    if [catch {exec cavput \
                                 -list=DP:S:OrbitControlLaw${Coord}SDDS.SPKE=$hDespikeThresholdStart \
                                 -pend=30 } result] {
                        return -code error $result
                    }
                    append options " -despike=passes=$hDespikePasses,neighbors=$hDespikeNeighbors,averageOf=$hDespikeAverage,countLimit=$hDespikeCountLimit,pvthreshold=DP:S:OrbitControlLaw${Coord}SDDS.SPKE$optionExten"
                } else {
                    append options " -despike=passes=$hDespikePasses,neighbors=$hDespikeNeighbors,averageOf=$hDespikeAverage,countLimit=$hDespikeCountLimit,threshold=$hDespikeThresholdEnd$optionExten"
                }
                if $hDespikeThresholdSteps>2 {
                    append options ",startThreshold=$hDespikeThresholdStart,endThreshold=$hDespikeThresholdEnd,stepsThreshold=$hDespikeThresholdSteps"
                    if $hDespikeThresholdReramp {
                        append options ",rampThresholdPV=$hDespikeThresholdRampPV"
                    }
                }
            }
            V { 
                #set despikeshreshold to the default value
                if $datapool {
                    if [catch {exec cavput \
                                 -list=DP:S:OrbitControlLaw${Coord}SDDS.SPKE=$vDespikeThresholdStart \
                                 -pend=30 } result] {
                        return -code error $result
                    }
                    append options " -despike=passes=$vDespikePasses,neighbors=$vDespikeNeighbors,averageOf=$vDespikeAverage,countLimit=$vDespikeCountLimit,pvthreshold=DP:S:OrbitControlLaw${Coord}SDDS.SPKE$optionExten"
                } else {
                    append options " -despike=passes=$vDespikePasses,neighbors=$vDespikeNeighbors,averageOf=$vDespikeAverage,countLimit=$vDespikeCountLimit,threshold=$vDespikeThresholdEnd$optionExten"
                }
                if $vDespikeThresholdSteps>2 {
                    append options ",startThreshold=$vDespikeThresholdStart,endThreshold=$vDespikeThresholdEnd,stepsThreshold=$vDespikeThresholdSteps"
                    if $vDespikeThresholdReramp {
                        append options ",rampThresholdPV=$vDespikeThresholdRampPV"
                    }
                }
            }
        }
    }
    if ![file exists tests] {
        return -code error "Can't find file tests."
    }
    if ![file exists definitions.${PVSuffix}] {
        return -code error "Can't find file definitions.${PVSuffix}."
    }
    if ![file exists irm] {
        return -code error "Can't find file irm."
    }
    if ![file exists inUse] {
        return -code error "Can't find file inUse."
    }
    if ![file exists enables] {
        return -code error "Can't find file enables."
    }
    if {!$datapool && !$oxygenStation} {
        set runControlPV [subst $[subst ${plane}RunControlPV]]
        set runControlDesc "Global ${corrType}(corr) ${bpmType}(bpm)"
        
        if $RCTimeout>0 {
            append options " -runControlPV=string=$runControlPV,pingTimeout=$RCTimeout"
        } else {            
            append options " -runControlPV=string=$runControlPV"
        }
        append options " \"-runControlDescription=string=$runControlDesc\""
    }
    # check plane of response matrix
    set foundBPM 0
    set foundCorr 0
    catch {exec sddsquery -col irm} irmColumns
    foreach bpm $irmColumns {
        if [regexp S..+:P. $bpm] {
            set foundBPM 1
            continue
        }
    }
    catch {exec sdds2stream -col=ControlName 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 $dataDir/$directory/irm for correction in ${coord} plane."
        return -code error "Error!"
    }
    set logDataDir /home/helios/oagData/controllaw/SRorbit/loggedData
    if !$datapool {
        if $logActuators {
            set logFile $logDataDir/sr.${coord}-[exec date +%Y-%m%d-%H%M%S].log
            append options " -controlLogFile=$logFile"
        }
        if $logStats {
            set statsFile $logDataDir/sr.${coord}-[exec date +%Y-%m%d-%H%M%S].stats
            append options " -statistics=$statsFile,mode=brief"
        }
        if $logGlitch {
            set glitchFile $logDataDir/sr.${coord}-[exec date +%Y-%m%d-%H%M%S].glog
            # these essentially disable rms-based glitching and rely on the tests only
            set readbackRmsThreshold 500
            set controlRmsThreshold  500
            append options " -glitchLogFile=file=$glitchFile,readbackRmsThreshold=$readbackRmsThreshold,controlRmsThreshold=$controlRmsThreshold,rows=10"
        }
    }
    if !$oxygenStation {
        if !$pvTest {
            set controlTest tests
        } else {
            switch $Plane {
                H {
                    set controlTest DPHtests
                }
                V {
                    set controlTest DPVtests
                }
            }
            StartPVTest
        }
        append options " -testValues=$dir/$controlTest -actuator=ControlName -controlQuantityDefinitions=$dir/definitions.$PVSuffix"
    } else {
        set corrType [set ${plane}CorrectorType]
        set tmpfile /tmp/[APSTmpString].def
        APSAddToTmpFileList -ID Controllaw -fileList $tmpfile
        if {$corrType=="dynamic"} {
            if [catch {exec sddsprocess $dir/definitions.ms $tmpfile \
                         -reedit=col,ControlName,%/SFB:// } result] {
                return -code error $result
            }
        } else {
            exec cp $dir/definitions.ms $tmpfile
        }
        append options " -actuator=ControlName -controlQuantityDefinitions=$tmpfile"
    }
    return $options
}

proc CheckFFCompenstation {args} {
    set rmFF ""
    set irm ""
    set def ""
    APSParseArguments {rmFF irm def}
    set ffCorrs [exec sddsquery -col $rmFF | grep S]
    set ffBpms [exec sdds2stream -col=BPMName $rmFF]
    set corrs [exec sdds2stream -col=ControlName $irm]
    set pvs [exec sdds2stream -col=SymbolicName $def]
    if {[llength $ffCorrs]!=[llength $corrs]} {
        return -code error "correctors of rmFF and irm do not match [llength $ffCorrs] [llength $corrs]!"
    }
    set notList ""
    foreach corr $ffCorrs {
        if [lsearch -exact $corrs $corr]<0 {
            lappend notList $corr
        }
    }
    if [llength $notList] {
        return -code error "[join $notList ,] not found in irm matrix"
    }
    set notList ""
    foreach corr $ffCorrs {
        if [lsearch -exact $pvs $corr]<0 {
            lappend notList $corr
        }
    }
    foreach bpm $ffBpms {
        if [lsearch -exact $pvs $bpm]<0 {
            lappend notList $bpm
        }
    }
    if [llength $notList] {
        return -code error "[join $notList ,] not found in FFdefs"
    }
}

proc ControllawInfoButton {args} {
    global hRunControlPV vRunControlPV plane Coord
    global hCorrectorType vCorrectorType hBpmType vBpmType 
    
    GetBPMAndCorrectorType -fileVariable ${plane}ResponseDir
    set type [set ${plane}BpmType]
    set Plane [string toupper $plane]
    
    switch $type {
        scalar -
        plain {
            set runControlPV [subst $[subst ${plane}RunControlPV]]
            if [string length $runControlPV] {
                if [catch {exec medm -x -attach -macro RCPV=$runControlPV \
                             ./sr/psApp/APSRunControlSingle.adl & \
                         } result ] {
                    return -code error  $result
                }
            } else {
                SetSROrbitStatus "No string value for runControlPV." -code error
                APSSound -type alert
                return -code error "No string value for runControlPV."
            }
        }
        vector -
        DP {
            if [catch {exec medm -x -attach -macro "SDDSPV=DP:S:OrbitControlLaw${Coord}SDDS" \
                         /home/helios/FRL/adlsys/srbpm/datapool/sddsEpicsLauncher.adl & } result] {
                return -code error $result
            }
            if [catch {exec medm -dg 451x173 -x -attach -macro "U=Datapool,A=${Plane},T=Delta,PV=${Plane}CorDelta:WF,E=Amps" \
                         /home/helios/FRL/adlsys/srbpm/datapool/dpVectorDisplayC.adl & } result] {
                return -code error $result
            }
            global env
            if {$env(HOST_ARCH)=="linux-x86_64"} {
                set option [exec /usr/local/iocapps/R3.14.11/base/3-14-11-asd1/bin/linux-x86_64/caget \
                                -S DP:S:OrbitControlLaw${Coord}SDDS.OPTN]
                APSInfoWindow .info$Coord -name "$Coord plane DP Controllaw Options" -width 70 -infoMessage "$option"  \
                    -packOption "-side top -fill both" -copyable 1
            }
        }
    }
    switch $plane {
        h {
            set testControlPV DP:HOCtestRC
        }
        v {
            set testControlPV DP:VOCtestRC
        }
    }
    if [catch {exec medm -x -attach -dg +250+10 -macro "RCPV=$testControlPV" \
                 ./sr/psApp/APSRunControlSingle.adl & \
             } result ] {
        return -code error  $result
    }
    if [catch {exec medm -x -attach -dg +500+10 -macro "RCPV=DP:SRXrayBPMStatus" \
                 ./sr/psApp/APSRunControlSingle.adl & \
             } result ] {
        return -code error  $result
    }
    return
}

proc AbortControllaw {args} {
    # Variables plane and coord are set by setCorrPlane
    global hRunControlPV vRunControlPV plane coord Coord oxygenStation hsimulatorControllawID
    global hsimulatorControllawInput vsimulatorControllawID vsimulatorControllawInput
    set runControlPV ""
    set inputCoord ""
    set datapool 0
    
    APSParseArguments {runControlPV inputCoord datapool plane}
    
    if {![string length $runControlPV]} {
        lappend runControlPV [subst $[subst ${plane}RunControlPV]]
        lappend runControlPV DP:S:OrbitControlLaw${Coord}SDDS
    }
    if ![string length $inputCoord]  {
        set inputCoord $coord
    }
    if ![string length $runControlPV] {
        return -code error "AbortControllaw: No runControlPV supplied."
    }
    if !$datapool {
        if [catch {exec logMessage  -sourceId=steeringAudit\
                     -tag=Instance $runControlPV -tag=Action Abort \
                 } result ] {
            return -code error "AbortControllaw: $result"
        }
    }
    
    foreach runControl $runControlPV {
        SetSROrbitStatus "Sent abort signal to $runControl"
        if [catch {exec cavput -list=${runControl}.ABRT=1 -pend=30} result ] {
            return -code error "AbortControllaw: $result"
        }
    }
    return
}


proc SetInUseBPMPVs {args} {
    # These variables are set by setCorrPlane
    #global plane Plane coord Coord
    global Coord hResponseDir vResponseDir dataDir
    set coord ""
    APSParseArguments {coord} 
    if ![string length $coord] {
        set coord [string tolower $Coord]
    }
    switch $coord {
        x {
            set plane h
            set Plane H
            set directory $dataDir/$hResponseDir
        }
        y {
            set plane v
            set Plane V
            set directory $dataDir/$vResponseDir
        }
        default {
            return -code error "SetInUseBPMPVs: coord argument $coord should be x or y!"
        }   
    }
    set bpmStatusDir /home/helios/oagData/sr/BPMStatus
    set oldDir [pwd]
    cd $directory
    if {![file exist inUse] || ![file exist enables]} {
        cd $oldDir 
        return -code error "inUse or enables file does not exist!"
    }
    if ![file exist notUse] {
        if [catch {exec sddsprocess $bpmStatusDir/config.sdds -pipe=out \
                     -filter=col,Nonexistent${Plane},0,0 \
                     -filter=col,OkForDCOrbitCorrection${Plane},1,1 \
                     -edit=col,ControlName,DeviceName,ei/:ms:${coord}:InUseBO/ \
                     | sddsconvert -pipe -retain=col,ControlName \
                     | sddsselect -pipe inUse -match=ControlName -invert \
                     | sddsprocess -pipe=in notUse \
                     -reprint=col,ValueString,0 } result ] {
            cd $oldDir
            return -code error "SetInUseBPMPVs: $result"
        }
    }
    set tmpfile /tmp/[APSTmpString]
    APSAddToTmpFileList -ID SROrbitControllaw -fileList "$tmpfile.expected $tmpfile.current $tmpfile.setInUse"
    APSAddToTmpFileList -ID SROrbitControllaw -fileList "$tmpfile.disable $tmpfile.enable"
    if [catch {exec sddscombine inUse notUse -merge -pipe=out \
                 | sddsprocess -pipe=in $tmpfile.expected -scan=col,Value,ValueString,%ld,type=long } result] {
        cd $oldDir
        return -code error $result
    }
    set bpmList [exec sdds2stream $tmpfile.expected -col=ControlName]
    if [catch {exec cavget -list=[join $bpmList ,] -pend=30 -num} valueList] {
        cd $oldDir
        return -code error $valueList
    }
    set badBpms ""
    set validBpms ""
    set validVals ""
    foreach bpm $bpmList val $valueList {
        if {$val=="?"} {
            lappend badBpms $bpm
        } else {
            lappend validBpms $bpm
            lappend validVals $val
        }
    }
    if [llength $badBpms] {
        cd $oldDir
        return -code error "No connection for following bpms:\n[join $badBpms \n]"
    }
    if [catch {exec sddsmakedataset -col=ControlName,type=string -data=[join $validBpms ,] \
                 -col=ValueC,type=long -data=[join $validVals ,] $tmpfile.current } result] {
        cd $oldDir
        return -code error $result
    }
    if [catch {exec sddsxref $tmpfile.expected $tmpfile.current -match=ControlName \
                 -take=ValueC -pipe=out -noWarnings \
                 | sddsprocess -pipe "-define=col,diff,Value ValueC -,type=long" \
                 | sddsprocess -pipe=in  "-filter=col,diff,-0.5,0.5,!" \
                 -print=col,SetCommand,%s=%s,ControlName,ValueString \
                 $tmpfile.setInUse -nowarnings} result] {
        cd $oldDir
        return -code error $result
    }
    set rows [exec sdds2stream $tmpfile.setInUse -rows=bar]
    if $rows {
        set SetCommand [exec sdds2stream $tmpfile.setInUse -col=SetCommand]
        
        if [catch {exec cavput -list=[join $SetCommand ,] -pend=30} result] {
            return -code error $result
        }
        if {0} {
            if [catch {exec sddscasr -restore $tmpfile.setInUse -pend=60 } result] {
                cd $oldDir
                return -code error $result
            }
        }
    } else {
        SetSROrbitStatus "No need to set inUse bpms!"
    }
    set rows [exec sdds2stream -rows=bar enables]
    if !$rows {
        #there no P0 or P1s in the config, no enable PVs
        cd $oldDir
        return
    }
    set SetCommand [exec sddsprocess enables -pipe=out \
                      -print=col,SetCommand,%s=%s,ControlName,ValueString \
                      | sdds2stream -pipe -col=SetCommand]
    
    if [catch {exec cavput -list=[join $SetCommand ,] -pend=30} result] {
        return -code error $result
    }
   
    cd $oldDir
    return
}

set password ""
set hostList {phoenix herema}
foreach elem $hostList {
    set $elem 1
}
proc KillAllControllaws {args} {
    global password hostList

    if {![string length $password]} {
        SetSROrbitStatus "Please supply a password" -code error
        return
    }
    SetSROrbitStatus "Searching for SR orbit correction sddscontrollaw processes running on herema and phoenix ..."
    set tmpRoot /tmp/[APSTmpString]
    set tmpFileList ""
    foreach host $hostList {
        set tmpFile $tmpRoot.$host
        global $host
        if ![subst \$$host] continue
        if [catch {exec ping $host 2} result] {
            SetSROrbitStatus "Problem pinging $host: $result" -code error
            set $host 0
            continue
        }
        if [string compare $result "$host is alive"]!=0 {
            SetSROribtStatus "$host is not responding"
            set $host 0
            continue
        }
        global timeout expect_out 
        
        set timeout 10
        spawn -noecho ssh -n $host ps -fed
        match_max -i $spawn_id 10000
        log_user 0
        expect {
            "Are you sure you want to continue connecting (yes/no)?" {	
                exp_send "yes\r"
                exp_continue
            } "password" {
                exp_send "${password}\r"
                exp_continue
            } "Authentication failed" {
                APSSetVarAndUpdate status "Authentication failed for $host"
                catch {exp_close}
                continue
            } timeout {
                APSSetVarAndUpdate status "connection to $host timed out"
                catch {exp_close}
                continue
            } eof {
            }
        }
        set i [string first $password $expect_out(buffer)]
        if {$i != -1} {
            set expect_out(buffer) [string replace $expect_out(buffer) $i [expr $i + [string length $password]]]
        }
        set i [string first \" $expect_out(buffer)]
        while {$i != -1} {
            set expect_out(buffer) [string replace $expect_out(buffer) $i $i]
            set i [string first \" $expect_out(buffer)]
        }
        set expect_out(lines) [split $expect_out(buffer) \n]
        set expect_out(buffer) ""
        foreach line $expect_out(lines) {
            if {[llength $line] > 3} {
                if {([lindex $line 0] != "20") && ([lindex $line 0] != "Connection")} {
                    set line "[lindex $line 0] [lindex $line 1] \"[lrange $line 2 end]\""
                    lappend expect_out(buffer) $line
                }
            } elseif {[llength $line] == 3} {
                if {([lindex $line 0] != "20") && ([lindex $line 0] != "Connection")} {
                    set line "[lindex $line 0] [lindex $line 1] [lindex $line 2]"
                    lappend expect_out(buffer) $line
                }
            }
        }
        set expect_out(buffer) [join $expect_out(buffer) \n]
        file copy -force /home/helios/OAG/oagData/controllaw/NetProcessControl.header $tmpFile
        exec echo $expect_out(buffer) \
          | grep -v defunct >> $tmpFile
        if [catch {eval exec sddsprocess $tmpFile $tmpFile.sdds \
                     -nowarning \
                     -print=column,Host,$host \
                     "-match=column,Args=*sddscontrollaw*orbitControllaw*"  } result] {
            APSSetVarAndUpdate status "Problem scanning $host: $result"
        } else {
            catch {file delete -force $tmpFile}
            lappend tmpFileList $tmpFile.sdds
        }
    }
    if {![llength $tmpFileList]} {
        SetSROrbitStatus "No SR Orbit Controllaw is running on phoebix and herema!" -code error
        return
    }
    if [catch {eval exec sddscombine $tmpFileList -merge $tmpRoot.all} result] {
        SetSROrbitStatus "Problem combining files: $result" -code error
        return
    }
    catch {eval file delete -force $tmpFileList}

    if [catch {exec sdds2stream -rows $tmpRoot.all | token -n=1} processes] {
        catch {file delete -force $tmpRoot.all}
        SetSROrbitStatus "Problem counting processes: $processes" -code error
        return
    }
    APSSetVarAndUpdate status "$processes processes found."
    if !$processes {
        SetSROrbitStatus "No process is running SRorbit sddscontrollaw!" -code error
        return
    }
    if {[catch {sdds open $tmpRoot.all r} SDDSfd]} {
        catch {file delete -force $tmpRoot.all}
        SetSROrbitStatus "Problem reading data file: $SDDSfd." -code error
        return
    }
    foreach column {Host Args PID User} {
        global ${column}List
        if [catch {sdds getColumn $SDDSfd $column} results] {
            SetSROrbitStatus "Problem reading column $column: $results" -code error
            return
        }
        set ${column}List $results
    }
    catch {sdds close $SDDSfd}
    catch {file delete -force $tmpRoot.all}

    global LabelList
    set LabelList ""
    for {set i 0} {$i<$processes} {incr i} {
        set host  [lindex $HostList $i]
        set pid [lindex $PIDList $i] 
        lappend LabelList [format "%10s %10s %10s %50s" \
                             [lindex $HostList $i] \
                             [lindex $UserList $i] \
                             [lindex $PIDList $i] \
                             [lindex $ArgsList $i] ]
    }
    set w [APSUniqueName .]
    APSScrolledListWindow $w \
      -name "Following processes will be killed" -itemList $LabelList \
      -clearButton 1 -acceptButton 0 -selectionVar listSelection \
      -autoAccept 1
    if ![APSYesNoPopUp "Are you sure to kill all controllaw process?"] {
        SetSROrbitStatus "Killing processes was cancelled!" -code error
        return
    }
    for {set i 0} {$i<$processes} {incr i} {
        set host  [lindex $HostList $i]
        set pid [lindex $PIDList $i] 
        set timeout 10
        spawn -noecho ssh -n $host kill -9 $pid
        log_user 0
        expect {
            "Are you sure you want to continue connecting (yes/no)?" {	
                exp_send "yes\r"
                exp_continue
            } "password" {
                exp_send "${password}\r"
                exp_continue
            } "Authentication failed" {
                APSSetVarAndUpdate status "Authentication failed for $host"
                catch {exp_close}
                continue
            } timeout {
                APSSetVarAndUpdate status "connection to $host timed out"
                catch {exp_close}
                continue
            } eof {
                
            }
        }	
    }
}


proc GenerateFiles {args} {

    # Takes the irm file in the specified directory and creates a test
    # files, a inUse file, an average enable file and a control
    # quantity definitions file. For the tests file some limits must
    # be passed.  The variables coord are set in the setCorrPlane
    # procedure and they are frozen during the call to
    # StartControllaw.

    global coord Coord datapool 

    set dataDir ""
    set directory ""
    set PVSuffix ""
    set BPMLimit ""
    set XBPMLimit ""
    set rangeErrorLimit ""
    set S35DCCTLimitH ""
    set S35DCCTLimitV ""
    set unified 0
    APSParseArguments {dataDir directory PVSuffix BPMLimit XBPMLimit rangeErrorLimit S35DCCTLimitH S35DCCTLimitV unified}

    set testFileList ""
    if ![regexp {([^.]*).} $directory match plane] {
        return  -code error "GenerateFiles: Can't determine plane from directory name."
    }
    SetSROrbitStatus "generating files for $plane plane."
    if ![string length $directory] {
        APSSound -type alert
        return -code error "GenerateFiles: Select a directory for the response file."
    }
    set Plane [string toupper $plane]
    set oldDir $dataDir
    if ![file exists ${dataDir}/$directory] {
        return -code error "GenerateFiles: Can't find directory ${dataDir}/$directory"
    }
    #cd $dataDir/$directory
    if [catch {exec generateControllawFiles -configList $directory -pvSuffix $PVSuffix -bpmLimit $BPMLimit -xbpmLimit $XBPMLimit \
                 -rangeError $rangeErrorLimit -dccLimit [set S35DCCTLimit$Plane] -debug 1} results] {
        return -code error "GenerateFilesWithPython: $results"
    }
    SetSROrbitStatus "$results"
    return
    if [catch {APSGenerateControllawFiles -regenerateFiles 1 \
                   -dataDir $dataDir -directory $directory \
                   -PVSuffix $PVSuffix -BPMLimit $BPMLimit -XBPMLimit $XBPMLimit \
                   -rangeErrorLimit $rangeErrorLimit \
                   -S35DCCTLimitH $S35DCCTLimitH -S35DCCTLimitV $S35DCCTLimitV \
                   -unified $unified
             } result] {
        return -code error "GenerateFiles: $result"
    }
    SetSROrbitStatus "done!"
}

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 0
                set hDespikeThresholdRampPV S:OC:rampDespikeThreshX
                set hDespikeThresholdReramp 0
            }
            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 InstallFile {args} {
    set fileVariable ""
    set link ""
    global plane hCorrectorType vCorrectorType hBpmType vBpmType dataDir
    APSParseArguments {fileVariable link}
    
    if ![string length $fileVariable] {
        return -code error "InstallFile: No fileVariable supplied."
    }
    
    global $fileVariable
    set config $dataDir/[set $fileVariable]/config
    
    eval set file [file tail $[subst $fileVariable]]
    if [string compare [file type $file] link]==0 {
        return -code error "InstallFile: File $file is not a simple file."
    }
    set types [exec sdds2stream $config -par=PVType]
    set bpmType [lindex $types 0]
    set corrType [lindex $types 1]
    if [catch {exec sddsprocess $config -match=par,NameType=MonitorNames \
                 -match=col,Name=*BM*,Name=*ID*,| -pipe=out -nowarnings \
                 | sdds2stream -pipe -rows=bar } rows] {
        return -code error $rows
    }
    if $rows {
        if {$bpmType=="DP" || $corrType=="DP"} {
            set link ${plane}.defaultXRDP
        } else {
            set link ${plane}.defaultXP
        }
    } else {
        if {$bpmType=="DP" || $corrType=="DP"} {
            set link ${plane}.defaultDP
        } else {
            set link ${plane}.default
        }
    }
    
    if {![APSMultipleChoice [APSUniqueName .] \
            -question "Link $link to $file? Are you sure?" -returnList {1 0} \
            -labelList {Yes No}]} {
        return
    }
    if [catch {APSUpdateSoftLink -file $file -link $link} result ] {
        return -code error "InstallFile: $result"
    }
    set $fileVariable $link
    SetSROrbitStatus "File $file installed as $link" -code error
    return
}

# **************************** findDir ********************************
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 dirSelectDialog {widget args} {
    global dirSelection
    set filter ""
    APSParseArguments {filter}
    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 DisableTabs {} {
    global SensitiveWidgetList
    foreach widget $SensitiveWidgetList {
       # $widget state disabled
        #if [regexp .tn $widget] {
        #    ttk::style configure $widget -state disabled
        #} else {
            #$widget configure -state disabled
            APSDisableWidget $widget
       # }
    }
}

proc EnableTabs {} {
    global SensitiveWidgetList
    foreach widget $SensitiveWidgetList {
        # $widget state !disabled
       # if [regexp .tn $widget] {
       #     ttk::style configure $widget -state normal
       # } else {
           # $widget configure -state normal
            APSEnableWidget $widget
        #}
    }
}


proc AbortPvtest {args} {
    # Variables plane and coord are set by setCorrPlane
    global plane coord
    switch $plane {
        h {
            set runControlPV DP:HOCtestRC
        }
        v {
            set runControlPV DP:VOCtestRC
        }
    }
    if ![string length $runControlPV] {
        return -code error "AbortPvtest: No runControlPV supplied."
    }
    if [catch {exec logMessage  -sourceId=steeringAudit\
                 -tag=Instance $runControlPV -tag=Action Abort \
             } result ] {
        return -code error "AbortPvtest: $result"
    }
    if [catch {exec cavput -list=$runControlPV.ABRT=1 -pend=30} result ] {
        return -code error "AbortPvtest: $result"
    }
    SetSROrbitStatus "Sent abort signal to $runControlPV"
    return
}

proc clearRCRecord {args} {
    set PV ""
    if {[APSStrictParseArguments {PV}] || ![string length $PV]} {
        return -code error "clearRCRecord: bad arguments"
    }
    if [catch {exec cavget -list=$PV.RUN -printErrors} status] {
        return -code error "Unable to read $PV.RUN: $status"
    }
    if $status {
        exec cavput -list=$PV.ABRT=1 -pend=30
        SetSROrbitStatus "Waiting for $PV to clear..."
        exec cawait -waitfor=$PV.RUN,equal=0
    }
    exec cavput -list=$PV.CLR=1 -pend=30
}

# This is called only from buttons in the GUI tabs.
# Either a sourceMode is specified or a corrMode is specified, not both.
# This procedure will not be used for unified mode of datapool.
proc SetCorrMode {args} {
    global Plane
    set sourceMode ""
    set plane ""
    set corrMode ""
    set corrType ""
    APSParseArguments {sourceMode corrMode plane corrType}
    global unified
    
    set option ""
    if [string length $sourceMode] {
        append option " -setSource"
    }
    if [string length $corrMode] {
        append option " -corrType=$corrMode"
    }
    if [string length $corrType] {
        append option " -corrType=$corrType"
    }
    if ![string length $plane] {
        set plane [string tolower $Plane]
    }
    if $unified {
        append option " -unified"
    }
    #lappend option " -plane=$plane"
    if {$plane=="both"} {
        set planeList {h v}
    } else {
        set planeList $plane
    }
    if {[string length $sourceMode]} {
        foreach pl $planeList {
            if [string length $sourceMode] {
                SetSROrbitStatus "Set corrector source mode to $sourceMode in $pl plane ..."
                if [catch {APSSetCorrMode -sourceMode $sourceMode -plane $pl} result] {
                    SetSROrbitStatus "Error: $result" -code error
                    return
                }
            }
            if [string length $corrMode] {
                SetSROrbitStatus "Set corrector mode to $corrMode in $pl plane..."
                if [catch {APSSetCorrMode -corrMode $corrMode -plane $pl} result] {
                    SetSROrbitStatus "Error: $result" -code error
                    return
                }
            }
        }
    } else {
        foreach pl $planeList {
            SetSROrbitStatus "Set corrector mode to $corrMode in $pl plane."
            if [catch {eval exec setsrcorrmode $option -plane=$pl } result] {
                return -code error "Error setting corr mode: $result"
            }
            SetSROrbitStatus "set corrector mode done."
        }
    }
    SetSROrbitStatus "Set done."
    return
    if ![string length $plane] {
        set plane $Plane
    }
    if [string length $sourceMode] {
        SetSROrbitStatus "Set corrector source mode to $sourceMode in $plane plane ..."
        if [catch {APSSetCorrMode -sourceMode $sourceMode -plane $plane} result] {
            SetSROrbitStatus "Error: $result" -code error
            return
        }
    }
    if [string length $corrMode] {
        SetSROrbitStatus "Set corrector mode to $corrMode in $plane plane..."
        if [catch {APSSetCorrMode -corrMode $corrMode -plane $plane} result] {
            SetSROrbitStatus "Error: $result" -code error
            return
        }
    }
    SetSROrbitStatus "Set done."
    return
}

proc CompareCorrVectorWithIndivdualCorr {args} {
    global tolerance
    set plane ""
    set type ""
    set index ""
    APSParseArguments {plane type index}
    set wfDir /home/helios/oagData/sr/orbitControllaw/waveforms
    set vectorFile $wfDir/${plane}corrInfo.sdds
    set PLANE [string toupper $plane]
    set PVname DP:${PLANE}Cor:WF
    
    global ${type}Scroll ${type}ScrollFrame
    #   SetSROrbitStatus "index=$index"
    set tmpFile /tmp/[APSTmpString]
    if [catch {exec sddsprocess $vectorFile $tmpFile \
                 -edit=col,ControlName,DeviceName,ei/:CurrentAO/} result] {
        return -code error "$result"
    }
    if [catch {sdds load $tmpFile corrVec} result] {
        return -code error "$result"
    }
    set corrs [lindex $corrVec(Column.ControlName) 0]
    set corrs [join $corrs ,]
    if [catch {exec cavget -list=$corrs -pend=30} corrValue] {
        return -code error "$corrValue"
    }
    foreach val $corrValue pv $corrs {
        if [string compare $val "?"]==0 {
            SetSROrbitStatus "Error in getting value for $pv." -code error
        }
    }
    set tmp1 /tmp/[APSTmpString]
    APSAddToTmpFileList -ID 1 -fileList "$tmpFile $tmp1"
    if [catch {exec sddswget -PVname=$PVname $tmp1} result] {
        return -code error $result
    }
    set vectorValue [APSGetSDDSColumn -fileName $tmp1 -column Waveform -page 1]
    
    set diffList ""
    set nameList ""
    set waveVaveList ""
    set iocValueList ""
    #SetSROrbitStatus "$tolerance tol"
    set pvList [lindex $corrVec(Column.DeviceName) 0]
    foreach wm $vectorValue corr $corrValue pv $pvList {
        if [string compare $corr "?"]==0 {
            continue
        }
        set val [expr abs($wm-$corr)]
        if {$val > $tolerance} {
            lappend waveValueList $wm
            lappend iocValueList $corr
            lappend nameList $pv
            set val1 [format "%10.4f" $val]
            set corr1 [format "%10.4f" $corr]
            set wm1 [format "%10.4f" $wm]
            append diffList "$pv   $val1   $corr1    $wm1\n"
        }
    }
    
    if [string length $diffList] {
        set out1 /tmp/[APSTmpString].compare
        APSAddToTempFileList -ID Compare $out1
        set errorData(ColumnInfo.Corr) "type SDDS_DOUBLE"
        set errorData(ColumnInfo.Waveform) "type SDDS_DOUBLE"
        set errorData(ColumnInfo.DeviceName) "type SDDS_STRING"
        set errorData(Column.Corr) [list $iocValueList]
        set errorData(Column.Waveform) [list $waveValueList]
        set errorData(Column.DeviceName) [list $nameList]
        set errorData(ColumnNames) [list Corr Waveform DeviceName]
        if [catch {sdds save $out1 errorData} result] {
            return -code error "save1.$result"
        }
        
        set f1 [set ${type}Scroll].f1
        set f2 [set ${type}Scroll].f2
        if [winfo exist $f1] {
            destroy $f1
        }
        if [winfo exist $f2] {
            destroy $f2
        }
        APSFrame .f1 -parent [set ${type}Scroll]
        $f1.frame configure -relief flat -bd 0
        APSFrame .f2 -parent [set ${type}Scroll]
        $f2.frame configure -relief flat -bd 0
        APSLabel .diff1 -parent $f1.frame -text "difference list:\nPV           \
differ       Corrector      Waveform"
	
	APSLabel .diff2 -parent $f2.frame -text $diffList -packOption "-side left"
        .differenceMessage.frame.tn select $index
        tkwait visibility $f2.frame.diff2
        APSScrollAdjust [set ${type}ScrollFrame] -numVisible 10
      
        if [catch {eval exec sddsplot $out1 -title=Different_Corr_${PVname} \
		       -legend -col=DeviceName,Waveform \
		       -graphic=symbol,sca=3  \
		       -col=DeviceName,Corr -graphic=symbol,sub=1,sca=3  &} result] {
            SetSROrbitStatus "$result" -code error
        }
    } else {
	SetSROrbitStatus "No difference greater than $tolerance for $PVname."
    }
}

proc CompareInUseBPMWithVector {args} {
    global dataDir hResponseDir vResponseDir plane Coord coord tolerance
    set config $dataDir/[set ${plane}ResponseDir]/config
    set waveform $dataDir/[set ${plane}ResponseDir]/bpmWaveform
    set tmpRoot /tmp/[APSTmpString]
    SetSROrbitStatus "comparing in-use bpms with vector ..."
    if ![file exist $waveform] {
        set filename /home/helios/oagData/sr/orbitControllaw/waveforms/adjust${Coord}BpmInfo.sdds
        if [catch {exec sddsconvert $filename $tmpRoot.waveform -rename=par,WaveformPV=AdjustWaveformPV \
                     -rename=par,SetpointWaveformPV=WaveformPV } result] {
            return -code error $result
        }
        set waveform $tmpRoot.waveform
        APSAddToTmpFileList -ID compare -fileList $tmpRoot.waveform
    }
    
    APSAddToTmpFileList -ID compare -fileList "$tmpRoot.error $tmpRoot.offset $tmpRoot.setpoint $tmpRoot.sum"
    if [catch {exec sddsprocess $config -pipe=out -edit=col,ControlName,Name,ei/:ms:${coord}:ErrorCC/ \
                 | sddscasr -pipe -save -pend=100 \
                 | sddsprocess -pipe=in $tmpRoot.error -match=col,CAError=n \
                 -scan=col,ErrorCC,ValueString,%f,type=float
        exec sddsprocess $config -pipe=out -edit=col,ControlName,Name,ei/:ms:${coord}:OffsetAO/ \
                 | sddscasr -pipe -save -pend=100 \
                 | sddsprocess -pipe=in $tmpRoot.offset -match=col,CAError=n \
                 -scan=col,Offset,ValueString,%f,type=float
        exec sddsprocess $config -pipe=out -edit=col,ControlName,Name,ei/:ms:${coord}:SetpointAO/ \
                 | sddscasr -pipe -save -pend=100 \
                 | sddsprocess -pipe=in $tmpRoot.setpoint -match=col,CAError=n \
                 -scan=col,Setpoint,ValueString,%f,type=float
        exec sddsxref $tmpRoot.offset $tmpRoot.setpoint -match=Name -take=Setpoint -pipe=out \
                 | sddsprocess -pipe=in $tmpRoot.sum "-define=col,Offset+Setpoint,Offset Setpoint +" } result] {
        return -code error $result
    }
    
    APSAddToTmpFileList -ID compare -fileList "$tmpRoot.errorwave1 $tmpRoot.adjust1 $tmpRoot.adjust2 $tmpRoot.adjust"
    if [catch {exec sddswget $waveform $tmpRoot.errorwave1} result] {
        return -code error $result
    }
    
    if [catch {exec sddsconvert $waveform $tmpRoot.adjust1 -delete=par,WaveformPV -rename=par,AdjustWaveformPV=WaveformPV
        exec sddswget $tmpRoot.adjust1 $tmpRoot.adjust2 } result] {
        return -code error $result
    }
    if [catch {exec sddscombine $tmpRoot.errorwave1 $tmpRoot.errorwave -merge
        exec sddscombine $tmpRoot.adjust2 $tmpRoot.adjust -merge } result] {
        return -code error $result
    }
    
    if [catch {exec sddsxref $tmpRoot.error $tmpRoot.errorwave -match=Name=DeviceName \
                 -take=Waveform -pipe=out -noWarnings  \
                 | sddsprocess -pipe=in $tmpRoot.errorDiff "-define=col,ErrorDiff,Waveform ErrorCC -" \
                 "-filter=col,ErrorDiff,-$tolerance,$tolerance,!" -noWarnings
        exec sddsxref $tmpRoot.sum $tmpRoot.adjust -take=Waveform -pipe=out -noWarnings \
                 -match=Name=DeviceName \
                 | sddsprocess -pipe=in $tmpRoot.adjustDiff "-define=col,AdjustDiff,Waveform Offset+Setpoint -" \
                 "-filter=col,AdjustDiff,-$tolerance,$tolerance,!" -noWarnings } result] {
        return -code error "Error with compare ErrorCC and adjust pv: $result"
    }
    
    set row1 [exec sdds2stream $tmpRoot.errorDiff -rows=bare]
    set row2 [exec sdds2stream $tmpRoot.adjustDiff -rows=bare]
    if !$row1 {
        SetSROrbitStatus "No ErrorCC difference bigger than $tolerance found between the $plane waveform and in using scalar pvs!"
    } else {
        APSAddToTmpFileList -ID comparevector -fileList $tmpRoot.errorPrintout
        SetSROrbitStatus "CheckBpmVectorValues: $result\n\You could do following things:\n\n\(1) If the bpm value (msAve:ErrorCC) is too big, check the Num2Ave value for that bpm, put the correct value and press enter. This will fix the abnomal bpm's msAve:ErrorCC.\n\n\(2) If the waveform value is bigger than the msAve:ErrorCC, the MSI of that bpm could be wrong, check that bpm's MSI from \"BPM Global Feedback Readback\" and press \"reset MSI\" if it is abnormal.\n\n(3) When a lot of P0 and P1s disagree between waveform and scalar values, it is beause datapool got rebooted somehow and the gains waveforms for P0 P1 have reverted to 1's, try \"RestoreDPGainFromFile\" button in \"setup Vector in Selected plane\" tab to restore DP gain for both planes. \n\nIf this does not fix the waveform values, contact Frank LENKSZUS or control group guys."
        exec sddsplot $tmpRoot.errorDiff -legend -col=Name,Waveform -graphic=sym,sub=1 \
          -col=Name,ErrorCC -graphic=sym,sub=2 \
          "-title=ErrorCC value difference between $plane plane waveform and scalar pvs." &
        if [catch {exec sddsprintout $tmpRoot.errorDiff $tmpRoot.errorPrintout \
                     "-title=the ErrorCC differences between $plane plane waveform and in using scalar pvs that bigger than $tolerance\n" \
                     -col=Name -col=Waveform,format=%.3f -col=ErrorCC,format=%.3f -col=ErrorDiff,format=%.3f } result] {
            return -code error $result
            
        }
        APSFileDisplayWindow [APSUniqueName .] -fileName $tmpRoot.errorPrintout \
          -width 80 -printCommand "enscript -r"
    }
    if !$row2 {
        SetSROrbitStatus "No Adjust difference bigger than $tolerance found between the $plane plane waveform and in using scalar pvs!"
    } else {
        APSAddToTmpFileList -ID comparevector -fileList "$tmpRoot.adjustPrintout"
        exec sddsplot $tmpRoot.adjustDiff -legend -col=Name,Waveform -graphic=sym,sub=1 \
          -col=Name,Offset+Setpoint -graphic=sym,sub=2 \
          "-title=Adjust value difference between $plane plane waveform and in using scalar pvs.\nTry \"restoreDPGainFromFile\" button in \"Setup Vector in Selected Plane\" tab" &
        if [catch {exec sddsprintout $tmpRoot.adjustDiff $tmpRoot.adjustPrintout \
                     "-title=the adjust(Setpoint+Offset) differences between $plane plane waveform and in using scalar pvs that bigger than $tolerance" \
                     -col=Name -col=Waveform,format=%.3f  -col=Offset+Setpoint,format=%.3f  -col=AdjustDiff,format=%.3f } result] {
            return -code error $result
            
        }
        APSFileDisplayWindow [APSUniqueName .] -fileName $tmpRoot.adjustPrintout \
          -width 80 -printCommand "enscript -r"
    }
    set tmpfiles [glob -nocomplain /tmp/${tmpRoot}*]
    APSAddToTmpFileList -ID compare -fileList $tmpfiles
    SetSROrbitStatus "done."
}

proc CompareVector {args} {
    global XrayBPMSelection tolerance dataDir hResponseDir vResponseDir
    set planeList {x y x y x y y x y}
    SetSROrbitStatus "Compare waveform with individual PVs..."
    set typeList {idX idY rfX rfY p0X p0Y bm hcorr vcorr}
    set XrayBPMSelection ""
    APSScrolledListWindow .process -name "Xray waveform type selection" \
      -label "Select a waveform type" \
      -itemList $typeList -selectionVar XrayBPMSelection
    while {1} {
        tkwait variable XrayBPMSelection
        CompareVectorWith -bpmSelections $XrayBPMSelection
    }
}

proc CompareVectorWith {args} {
    set bpmSelections ""
    global dataDir hResponseDir vResponseDir tolerance
    APSParseArguments {bpmSelections} 
    set planeList {x y x y x y y x y}
    set typeList {idX idY rfX rfY p0X p0Y bm hcorr vcorr}
    if ![string length $bpmSelections] {
        SetSROrbitStatus "The waveform type was not choosen." -code error
        return
    }
    set waveformDir /home/helios/oagData/sr/orbitControllaw/waveforms
    foreach bpmSelection $bpmSelections {
        set index [lsearch $typeList $bpmSelection]
        set plane [lindex $planeList $index]
        set tmpRoot /tmp/[APSTmpString]
        if [string match *corr* $bpmSelection] {
            APSAddToTmpFileList -ID comparevector -fileList "$tmpRoot.corr $tmpRoot.corrDiff $tmpRoot.corrPrintout"
            set waveformFile $waveformDir/${bpmSelection}Info.sdds
            if [catch {exec sddsconvert $waveformFile $tmpRoot.waveform -rename=par,SetpointWaveformPV=WaveformPV } result] {
                return -code error "CompareVectorWith(Error1): $result"
            }
            if [catch {exec sddswget $tmpRoot.waveform $tmpRoot.corr } result] {
                return -code error "CompareVectorWith(Error2): $result"
            } 
            if [catch {exec sddsprocess $tmpRoot.corr -pipe=out \
                         -edit=col,ControlName,DeviceName,i/SFB:/ei/:CurrentAO/ \
                         | sddscasr -pend=100 -pipe -save \
                         |  sddsprocess -pipe=in -match=col,CAError=n  \
                         -scan=col,${bpmSelection},ValueString,%f,type=float \
                         "-define=col,CorrDiff,Waveform ${bpmSelection} -" \
                         -nowarnings "-filter=col,CorrDiff,-$tolerance,$tolerance,!" \
                         $tmpRoot.corrDiff } result] {
                return -code error "CompareVectorWith(Error3): $result"
            }
            set rows [exec sdds2stream $tmpRoot.corrDiff -rows=bare]
            
            if !$rows {
                SetSROrbitStatus "No difference bigger than $tolerance between waveform and $plane correctors found."
            } else {
                exec sddsplot $tmpRoot.corrDiff -legend -col=DeviceName,Waveform -graphic=sym,sub=1 \
                  -col=DeviceName,${bpmSelection} -graphic=sym,sub=2 &
                if [catch {exec sddsprocess $tmpRoot.corrDiff -pipe=out \
                             -reedit=col,ControlName,%/SFB://%/:CurrentAO/:InUseMBBO/ \
                             | sddscasr -pipe -save -pend=100 \
                             | sddsprintout -pipe=in $tmpRoot.corrPrintout \
                             "-title=difference between waveform and $bpmSelection that bigger than $tolerance:" \
                             -col=DeviceName -col=Waveform,format=%8.2f  -col=${bpmSelection},format=%8.2f \
                             -col=CorrDiff,format=%8.2f -col=ValueString,label=InUse,format=%10s } result] {
                    return -code error "CompareVectorWith(Error4): $result"
                }
                APSFileDisplayWindow [APSUniqueName .] -fileName $tmpRoot.corrPrintout \
                  -width 80 -printCommand "enscript -r"
            }
        } else {
            set waveformFile $waveformDir/${bpmSelection}BpmInfo.sdds
            set bpmStatusFile /home/helios/oagData/sr/BPMStatus/config.sdds
            switch $plane {
                x -
                h {
                    set Plane H
                    set coord x
                }
                y -
                v {
                    set Plane V
                    set coord y
                }
                default {
                    return -code error "No valid plane given: $plane"
                }
            }
            switch $bpmSelection {
                rfX -
                rfY { set filter S*\[AB\]:P\[1-5\] }
                p0X -
                p0Y { set filter S*:P0 }
                idX -
                idY { set filter S*ID*}
                bm { set filter S*BM*}
                default {return -code error "unknow selection: $bpmSelection" }
            }
            if [catch {exec sddsprocess $bpmStatusFile -match=col,DeviceName=$filter \
                         "-filter=col,Nonexistent${Plane},-0.5,0.5" -pipe=out \
                         | sddsconvert -pipe=in -retain=col,DeviceName $tmpRoot.exist} result] {
                return -code error "CompareVectorWith(Error5): $result"
            }
            APSAddToTmpFileList -ID comparevector -fileList "$tmpRoot.exist $tmpRoot.exitError $tmpRoot.existOffset $tmpRoot.existSetpoint $tmpRoot.sum"
            if [catch {exec sddsprocess $tmpRoot.exist -pipe=out \
                         -edit=col,ControlName,DeviceName,ei/:ms:${coord}:ErrorCC/ \
                         | sddscasr -pend=100 -pipe -save \
                         | sddsprocess -pipe=in $tmpRoot.existError \
                         -match=col,CAError=n -scan=col,ErrorCC,ValueString,%f,type=float
                exec sddsprocess $tmpRoot.exist -pipe=out \
                         -edit=col,ControlName,DeviceName,ei/:ms:${coord}:OffsetAO/ \
                         | sddscasr -pend=100 -pipe -save \
                         | sddsprocess -pipe=in $tmpRoot.existOffset \
                         -match=col,CAError=n -scan=col,Offset,ValueString,%f,type=float
                exec sddsprocess $tmpRoot.exist -pipe=out \
                         -edit=col,ControlName,DeviceName,ei/:ms:${coord}:SetpointAO/ \
                         | sddscasr -pend=100 -pipe -save \
                         | sddsprocess -pipe=in $tmpRoot.existSetpoint \
                         -match=col,CAError=n -scan=col,Setpoint,ValueString,%f,type=float
                exec sddsxref $tmpRoot.existOffset $tmpRoot.existSetpoint \
                         -match=DeviceName -take=Setpoint -pipe=out \
                         | sddsprocess -pipe=in $tmpRoot.sum \
                         "-define=col,Offset+Setpoint,Offset Setpoint +" } result] {
                return -code error "CompareVectorWith(Error6): $result"
            }   
            
            APSAddToTmpFileList -ID comparevector -fileList "$tmpRoot.adjust1 $tmpRoot.exist"
            if [catch {exec sddsconvert $waveformFile -delete=par,WaveformPV \
                         -rename=par,AdjustWaveformPV=WaveformPV $tmpRoot.adjust1 } result] {
                return -code error "CompareVectorWith(Error6): $result"
            }
            APSAddToTmpFileList -ID comparevector -fileList $tmpRoot.adjust
            if [catch {exec sddswget $tmpRoot.adjust1 $tmpRoot.adjust
                exec sddswget $waveformFile $tmpRoot.error} result] {
                return -code error "CompareVectorWith(Error7): $result"
            }
            APSAddToTmpFileList -ID comparevector -fileList $tmpRoot.errorDiff
            if [catch {exec sddsxref $tmpRoot.error $tmpRoot.existError -match=DeviceName \
                         -noWarnings -take=ErrorCC -pipe=out \
                         | sddsprocess -pipe=in $tmpRoot.errorDiff \
                         "-define=col,ErrorDiff,Waveform ErrorCC -" \
                         "-filter=col,ErrorDiff,-$tolerance,$tolerance,!" -nowarnings } result] {
                return -code error "CompareVectorWith(Error8): $result"
            }
            set requests ""
            set layout 0
            set print1 ""
            set rows [exec sdds2stream $tmpRoot.errorDiff -rows=bar]
            if !$rows {
                SetSROrbitStatus "No ErrorCC difference bigger than $tolerance found between the $bpmSelection waveform and scalar pvs!"
            } else {
                incr layout
                APSAddToTmpFileList -ID comparevector -fileList $tmpRoot.errorPrintout
                lappend requests "-title=ErrorCC value difference between $bpmSelection waveform and scalar pvs." \
                  -legend -col=DeviceName,Waveform -graphic=sym,sub=1,scale=2,type=1 $tmpRoot.errorDiff \
                  -legend -col=DeviceName,ErrorCC -graphic=sym,sub=4,scale=2,type=2 $tmpRoot.errorDiff
                # exec sddsplot $tmpRoot.errorDiff -legend -col=DeviceName,Waveform -graphic=sym,sub=1 \
                  #   -col=DeviceName,ErrorCC -graphic=sym,sub=2 \
                  #  "-title=ErrorCC value difference between $bpmSelection waveform and scalar pvs." &
                
                if [catch {exec sddsprocess $tmpRoot.errorDiff -pipe=out \
                             -edit=col,ControlName,DeviceName,ei/:ms:$plane:InUseBO/ \
                             | sddscasr -save -pipe -pend=100 \
                             | sddsprintout -pipe=in $tmpRoot.errorPrintout \
                             "-title=the ErrorCC differences between $bpmSelection waveform and scalar pvs that bigger than $tolerance" \
                             -col=DeviceName -col=Waveform,format=%.3f -col=ErrorCC,format=%.3f \
                             -col=ErrorDiff,format=%.3f -col=ValueString,label=InUse,format=%10s } result] {
                    return -code error "CompareVectorWith(Error9): $result"
                    
                }
                set print1 $tmpRoot.errorPrintout
                #  APSFileDisplayWindow [APSUniqueName .] -fileName $tmpRoot.errorPrintout \
                  #  -width 80 -printCommand "enscript -r"
            }
            APSAddToTmpFileList -ID comparevector -fileList "$tmpRoot.offset $tmpRoot.setpoint $tmpRoot.adjustDiff"
            if [catch {exec sddsxref $tmpRoot.adjust $tmpRoot.sum -match=DeviceName \
                         -noWarnings -take=Offset+Setpoint -pipe=out \
                         | sddsprocess -pipe=in $tmpRoot.adjustDiff \
                         "-define=col,AdjustDiff,Waveform Offset+Setpoint -" \
                         "-filter=col,AdjustDiff,-$tolerance,$tolerance,!" -nowarnings } result] {
                return -code error "CompareVectorWith(Error10): $result"
            }
            set rows [exec sdds2stream $tmpRoot.adjustDiff -rows=bar]
            set print2 ""
            if !$rows {
                SetSROrbitStatus "No Adjust difference bigger than $tolerance found between the $bpmSelection waveform and scalar pvs!"
            } else {
                incr layout
                APSAddToTmpFileList -ID comparevector -fileList "$tmpRoot.adjustPrintout"
                lappend requests "-title=Adjust value difference between $bpmSelection waveform and scalar pvs." \
                  -legend -col=DeviceName,Waveform -graphic=sym,sub=1,scale=2,type=1 $tmpRoot.adjustDiff \
                  -legend -col=DeviceName,Offset+Setpoint -graphic=sym,sub=3,scale=2,type=2 $tmpRoot.adjustDiff 
                # exec sddsplot $tmpRoot.adjustDiff -legend -col=DeviceName,Waveform -graphic=sym,sub=1 \
                  #   -col=DeviceName,Offset+Setpoint -graphic=sym,sub=2 \
                  #  "-title=Adjust value difference between $bpmSelection waveform and scalar pvs." &
                if [catch {exec sddsprocess $tmpRoot.adjustDiff -pipe=out \
                             -edit=col,ControlName,DeviceName,ei/:ms:$plane:InUseBO/ \
                             | sddscasr -pipe -save -pend=100 \
                             | sddsprintout -pipe=in $tmpRoot.adjustPrintout \
                             "-title=\n\nthe adjust(Setpoint+Offset) differences between $bpmSelection waveform and scalar pvs that bigger than $tolerance" \
                             -col=DeviceName -col=Waveform,format=%.3f  -col=Offset+Setpoint,format=%.3f  \
                             -col=AdjustDiff,format=%.3f -col=ValueString,label=InUse,format=%10s } result] {
                    return -code error "CompareVectorWith(Error11): $result"
                    
                }
                set print2 $tmpRoot.adjustPrintout
                #  APSFileDisplayWindow [APSUniqueName .] -fileName $tmpRoot.adjustPrintout \
                  #    -width 80 -printCommand "enscript -r"
            }
            set printout ""
            if {[string length $print1] && [string length $print2]} {
                set printout $tmpRoot.printout.$bpmSelection
                APSAddToTmpFileList -ID CompareVector -fileList $printout
                exec cat $print1 $print2 > $printout
            } elseif [string length $print1] {
                set printout $print1
            } elseif [string length $print2] {
                set printout $print2
            }
            if [string length $printout] {
                APSFileDisplayWindow [APSUniqueName .] -fileName $printout \
                  -width 80 -printCommand "enscript -r"
                if {$layout>1} {
                    eval exec sddsplot -layout=1,2 -separate=2 $requests &
                } else {
                    eval exec sddsplot $requests &
                }
            }
        }
    }
}



proc setParameters {args} {
    global interval num2Ave deltaLimit intervalWS
    set intervalMin(plain) 2.5
    set intervalMin(dynamic) 0.5
    set deltaLimitMin(plain) 2.0
    set deltaLimitMin(dynamic) 0.5
    set num2AveMin(plain) 10
    set num2AveMin(dynamic) 5
    set num2AveMin(DP) 10
    set corrType ""
    APSParseArguments {corrType}
    switch $corrType {
        plain - 
        dynamic -
        scalar {
            if {$interval < $intervalMin($corrType)} {
                set interval $intervalMin($corrType)
                set intervalWS $intervalMin($corrType)
            }
            if {$deltaLimit < $deltaLimitMin($corrType)} {
                set deltaLimit $deltaLimitMin($corrType)
            }
            if {$num2Ave > $num2AveMin($corrType)} {
                set num2Ave $num2AveMin($corrType)
            }
        }
        DP -
        vector {
            set num2Ave $num2AveMin(DP)
        }
    }
}

# Note that this procedure also initializes the datapool BPM setpoint vector
# because APSInitializeCorrVector does this internally.
# For unified mode, initializing the BPM setpoint vector does not cause
# any problems, because the BPM setpoint vector is never written to reflective
# memory. So I leave this procedure as is.
proc InitializeCorrVector {args} {
    global Plane corrAOAItolerance corrDacAOtolerance
    set plane ""
    set setpoint 0
    APSParseArguments {plane setpoint}
    if ![string length $plane] {
        set plane $Plane
    }
    #set corr mode to scalar before initialize vector corrector
    
    APSSetCorrMode -corrMode scalar -plane [string toupper $plane]
    #after 5000
    SetSROrbitStatus "Initializing $plane plane correct vector and datapool BPM setpoint vector..."
# Note that this procedure also initializes the datapool BPM setpoint
# vector.  As I wrote above, in unified mode, initializing the BPM setpoint
# vector does not cause any problems by itself.
    if [catch {APSInitializeCorrVector -plane [string tolower $plane] -setpoint $setpoint \
                   -AOAItolerance $corrAOAItolerance -dacAOtolerance $corrDacAOtolerance} result] {
        return -code error "InitializeCorrVector: $result"
    }
    # after 5000
    SetSROrbitStatus "done."
}

proc ZeroFFCorrector {args} {
    global Plane plane
   # set corrVectorFile /home/helios/oagData/sr/orbitControllaw/waveforms/${plane}corrWaveformFFzero.sdds
    set corrFile /home/helios/oagData/sr/orbitControllaw/waveforms/${plane}corrFFzero.sdds
    if [catch {exec sddswput $corrFile -pend=30
        exec sddscasr -restore $corrFile -pend=30 } result] {
        return -code error "Error in zero corrector FF: $result"
    }
    
    SetSROrbitStatus "$plane FF corrector were zeroed."
}


proc SetMSIOn {} {
    set init 1
    set count 1
    set MSIpv ""
    if [catch {exec cavget -list=SRFB:GBL:Hor:CloseLoopBO -pend=30} horState ] {
        SetSROrbitStatus "$horState, MSI setting aborted." -code error
        return
    }
    if [string compare $horState "Close"]==0 {
        SetSROrbitStatus "Horizontal RTFB loop is closed." -code error
        return
    }
    if [catch {exec cavget -list=SRFB:GBL:Vert:CloseLoopBO -pend=30} vertState] {
        SetSROrbitStatus "$vertState, MSI setting aborted. Abort MSI setting" -code error
        return
    }
    if [string compare $vertState "Close"]==0 {
        SetSROrbitStatus "Vertical RTFB loop is closed. Abort MSI setting" -code error
        return
    }
    if [catch {exec cavget -list=S:OrbitControlLawYRC.RUN -pend=30} vert1State] {
        SetSROrbitStatus "$vert1State, MSI setting aborted." -code error
        return
    }
    if {$vert1State == 1} {
        SetSROrbitStatus "Vertical controllaw is running. Abort MSI setting" -code error
        return
    }
    if [catch {exec cavget -list=S:OrbitControlLawXRC.RUN -pend=30} hor1State] {
        SetSROrbitStatus "$hor1State, MSI setting aborted." -code error
        return
    }
    if {$hor1State == 1} {
        SetSROrbitStatus "Horizontal controllaw is running. Abort MSI setting" -code error
        return
    }
    while {$count<41} {
        lappend MSIpv S${init}FB:GB${count}InitMsiSUB.PROC=1
        incr count
        lappend MSIpv S${init}FB:GB${count}InitMsiSUB.PROC=1
        incr count
        set init [expr $init + 2]
    }
    set MSIpv [join $MSIpv ,]
    if {1} {
        if [catch {exec cavput -list=${MSIpv} -pend=30} result] {
            return -code error $result
        }
    }
}

proc CheckBpmVectorValue {} {
    if [catch {CheckBpmVectorValues} result] {
        SetSROrbitStatus "CheckBpmVectorValues: $result\n\You could do following things:\n\n\(1) If the bpm value (msAve:ErrorCC) is too big, check the Num2Ave value for that bpm, put the correct value and press enter. This will fix the abnomal bpm's msAve:ErrorCC.\n\n\(2) If the waveform value is bigger than the msAve:ErrorCC, the MSI of that bpm could be wrong, check that bpm's MSI from \"BPM Global Feedback Readback\" and press \"reset MSI\" if it is abnormal.\n\n(3) When a lot of P0 and P1s disagree between waveform and scalar values, it is beause datapool got rebooted somehow and the gains waveforms for P0 P1 have reverted to 1's, try \"RestoreDPGainFromFile\" button in \"setup Vector in Selected plane\" tab to restore DP gain for both planes. \n\nIf this does not fix the waveform values, contact Frank LENKSZUS or control group guys."
    }
}

proc CheckBpmVectorValues {} {
    global plane coord tolerance hResponseDir vResponseDir dataDir
    set tmpfile /tmp/[APSTmpString]
    # puts [exec date]
    APSAddToTmpFileList -ID 1 -fileList "$tmpfile.bpm"
    set dir $dataDir/[set ${plane}ResponseDir]
    if ![file exist $dir/bpmWaveform] {
        SetSROrbitStatus "bpmWaveform does not exist; The configuration probably is not datapool."
        return 0
    }
    if [catch {exec sddsprocess $dir/config -pipe=out -match=para,NameType=MonitorNames \
                   -filter=col,Flag,1,1 -nowarnings \
                   -edit=col,ControlName,Name,ei/:msAve:${coord}:ErrorCC/  \
                   | sddscasr -pipe -save \
                   | sddsprocess -pipe=in $tmpfile.bpm \
                   -scan=col,BPMValue,ValueString,%lf \
               } result ] {
        APSDeleteTmpFileList -ID 1
        return -code error "CheckBpmVectorValues: $result"
    }
    APSAddToTmpFileList -ID 1 -fileList "$tmpfile.bpm $tmpfile.vector $tmpfile.diff"
    if [catch {exec sddswget $dir/bpmWaveform $tmpfile.vector} result] {
        return -code error "CheckBpmVectorValues: $result"
    }
    if [catch {exec sddsxref $tmpfile.vector $tmpfile.bpm -reuse \
                 -match=DeviceName=Name -nowarnings \
                 -take=BPMValue -pipe=out \
                 | sddsprocess -pipe -noWarning \
                 "-define=col,Difference,BPMValue Waveform - abs" \
                 -reedit=col,DeviceName,ei/:$coord/ \
                 | sddscombine -pipe -merge \
                 | sddsprocess -pipe=in $tmpfile.diff \
                 -filter=col,Difference,0,$tolerance,! -nowarnings } result] {
        return -code error "CheckBpmVectorValues: $result"
    }
    set rows [exec sdds2stream -rows=bare $tmpfile.diff]
    if $rows {
        if [catch {exec sddsprintout $tmpfile.diff $tmpfile.print -col=DeviceName,format=%15s \
                     -col=BPMValue,label=msAve:ErrorCC,format=%15.3f -col=Waveform,format=%15.3f \
                     -col=Difference,format=%15.3f \
                     "-title=The bpms in [set ${plane}ResponseDir]\\, whose ErrorCC difference between waveform and individual bpms are bigger than $tolerance\\, are as following:\n"} result] {
            return -code error "CheckBpmVectorValues: $result"
        }
        APSAddToTmpFileList -ID check -fileList $tmpfile.print
        global returncomm
        set returncomm ""
        set okCommand "set returncomm ok;destroy .bpmcheck"
        set cancelCommand "set returncomm cancel;destroy .bpmcheck"
        APSFileDisplayWindow .bpmcheck -fileName $tmpfile.print -defaultButtons 0 -closeButton 0 -width 80 \
          -okButton 1 -okCommand $okCommand -cancelButton 1 -cancelCommand $cancelCommand -modal 0 -defaultButtons 1
        #return $returncomm
        return -code error "Some bpms' ErrorCC difference between waveform and individual bpms are bigger than $tolerance."
    } else {
        SetSROrbitStatus "For all the bpms in [set ${plane}ResponseDir], their msAve:ErrorCC difference between vector and scalar bpm are within the $tolerance."
    }
    return 0
}


proc GetBPMAndCorrectorType {args} {
    set fileVariable ""
    global hCorrectorType vCorrectorType hBpmType vBpmType intervalWS
    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]
    switch [set ${plane}CorrectorType] {
        plain {
            set intervalWS 2.5
        }
        default {
            set intervalWS 0.5
        }
    }
    setParameters -corrMode [set ${plane}CorrectorType]
    
}

proc MakeConfigFrame {widget args} {
    global hResponseDir vResponseDir tolerance hCorrectorType vCorrectorType hBpmType vBpmType
    global PVSuffix BPMLimit XBPMLimit rangeErrorLimit S35DCCTLimitH S35DCCTLimitV num2Ave filterCoeff
    global plane
    global SensitiveWidgetList
    global dataDir
    APSParseArguments {parent}

    set w $parent$widget.frame
    APSFrame $widget -parent $parent -label "Configuration Options" \
      -contextHelp "Frame to specify additional options, such as the directory of the response file, the type of bpm data, validity ranges for the sddscontrollaw tests file."

    set widgetList [APSTabFrame .planes -parent $parent$widget.frame -label "" \
                      -labelList "Horizontal Vertical" -width 570 -height 100 \
                      -commandList {{setCorrPlane H} {setCorrPlane V}} ]

    pack $parent$widget.frame.planes -side top
    $parent$widget.frame.planes.frame.tn select 0
    lappend SensitiveWidgetList $parent$widget.frame.planes.frame
   # lappend SensitiveWidgetList $parent$widget.frame.planes.frame.tn
    set windex 0

    # Horizontal Response Directory
    set tabwidget [lindex $widgetList $windex]
    incr windex
    APSFrame .dir -parent $tabwidget -label "" \
      -contextHelp "Frame to specify directories in which files related to horizontal plane correction are found."
    set w $tabwidget.dir.frame
    APSLabeledEntry .responseDir -parent $w -label "Configuration" \
      -textVariable hResponseDir -width 40 -contextHelp \
      "Name of the directory for the response file for the HORIZONTAL plane which can be used with sddscontrollaw."
    bind $w.responseDir.entry <Return> "GetBPMAndCorrectorType -fileVariable hResponseDir"
    APSButton .install -parent $w.responseDir \
      -text I -packOption "-side right" \
      -command "InstallFile -link h.default -fileVariable hResponseDir" \
      -contextHelp "Installs the directory selected (must be a simple directory, not a link) as the new horizontal response directory."
    APSButton .dir -parent $w.responseDir \
      -text F -packOption "-side right" \
      -command "findDir -dirVariable hResponseDir -filter h.*;GetBPMAndCorrectorType -fileVariable hResponseDir" \
      -contextHelp "Bring up a directory selection dialog box to choose the directory."
    APSFrame .type -parent $w 
    $w.type configure -relief flat -bd 0
    set w $w.type.frame
    APSLabeledEntry .type1 -parent $w -label "bpm type:" \
      -textVariable hBpmType -width 15 -contextHelp \
      "bpm type: DP or plain." -packOption  "-side left"
    APSLabeledEntry .type2 -parent $w -label "corrector type:" \
      -textVariable hCorrectorType -width 15 -contextHelp \
      "corrector type: DP, plain or dynamic." -packOption "-side left"
    APSButton .get -parent $w \
      -text Get -packOption "-side right" \
      -command "GetBPMAndCorrectorType -fileVariable hResponseDir" \
      -contextHelp "get the bpm and corrector type from the configuration file"


    # Vertical Response Directory
    set tabwidget [lindex $widgetList $windex]
    incr windex
    APSFrame .dir -parent $tabwidget -label ""  \
      -contextHelp "Frame to specify directories in which files related to vertical plane correction are found."

    set w $tabwidget.dir.frame
    APSLabeledEntry .responseDir -parent $w -label "Configuration" \
      -textVariable vResponseDir -width 40 -contextHelp \
      "Name of the directory for the response file for the VERTICAL plane which can be used with sddscontrollaw."
    bind $w.responseDir.entry <Return> "GetBPMAndCorrectorType -fileVariable vResponseDir"
    APSButton .install -parent $w.responseDir \
      -text I -packOption "-side right" \
      -command "InstallFile -link v.default -fileVariable vResponseDir" \
      -contextHelp "Installs the directory selected (must be a simple directory, not a link) as the new vertical response file."
    APSButton .dir -parent $w.responseDir \
      -text F -packOption "-side right" \
      -command "findDir -dirVariable vResponseDir -filter v.*;GetBPMAndCorrectorType -fileVariable vResponseDir" \
      -contextHelp "Bring up a directory selection dialog box to choose the directory."
    APSFrame .type -parent $w 
    $w.type configure -relief flat -bd 0
    set w $w.type.frame
    APSLabeledEntry .type1 -parent $w -label "bpm type:" \
      -textVariable vBpmType -width 15 -contextHelp \
      "bpm type: DP or plain." -packOption  "-side left"
    APSLabeledEntry .type2 -parent $w -label "corrector type:" \
      -textVariable vCorrectorType -width 15 -contextHelp \
      "corrector type: DP, plain or dynamic." -packOption "-side left"
    
    APSButton .get -parent $w \
      -text Get -packOption "-side right" \
      -command "GetBPMAndCorrectorType -fileVariable vResponseDir" \
      -contextHelp "get the bpm and corrector type from the configuration file"
}

proc MakeOptionAndParameterFrame {widget args} {
    global steps gain interval averages averageInterval deltaLimit RCTimeout
    global runControlPV runControlDesc logStats
    global verbose dryrun FFcompensation logActuators datapool pvTest
    global hDespikeNeighbors hDespikeAverage hDespikePasses hDespikeThresholdStart hDespike
    global vDespikeNeighbors vDespikeAverage vDespikePasses vDespikeThresholdStart vDespike
    global hResponseDir vResponseDir tolerance hCorrectorType vCorrectorType hBpmType vBpmType
    global PVSuffix BPMLimit XBPMLimit rangeErrorLimit S35DCCTLimitH S35DCCTLimitV num2Ave filterCoeff
    global plane fromReference
    global SensitiveWidgetList
    global dataDir
    global hDespikeThresholdEnd hDespikeThresholdSteps hDespikeCountLimit
    global vDespikeThresholdEnd vDespikeThresholdSteps vDespikeCountLimit
    global hDespikeThresholdReramp vDespikeThresholdReramp corrAOAItolerance corrDacAOtolerance

    set parent ""
    APSParseArguments {parent}
    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 steps -width 10 \
      -contextHelp "Enter the number of steps to perform."
    APSLabeledEntry .gain -parent $w -label "gain" \
      -textVariable gain -width 10 \
      -contextHelp "Enter the gain (i.e. fraction of correction at each interval)"
    APSLabeledEntry .intervalDP -parent $w -label "interval for datapool (s)" \
      -textVariable intervalDP -width 10 \
      -contextHelp "Enter the interval between correction steps for datapool orbit correction."
    APSLabeledEntry .intervalWS -parent $w -label "interval for workstation (s)" \
      -textVariable intervalWS -width 10 \
      -contextHelp "Enter the interval between correction steps for workstation orbit correction."
    APSLabeledEntry .deltaLimit -parent $w -label "corrector delta limit (A)" \
      -textVariable 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 averages -width 10 \
      -contextHelp "Enter the number of averages of bpms at each iteration."
    APSLabeledEntry .averageInterval -parent $w -label "interval in averaging" \
      -textVariable averages -width 10 \
      -contextHelp "Enter the interval between readbacks for the bpm averaging."
    APSLabeledEntry .timeout -parent $w -label "runControl timeout (s) " \
      -textVariable RCTimeout -width 10 -contextHelp \
      "Enter the run control timeout in seconds."
    
    APSCheckButtonFrame .checkButton -parent $w0 -label "" \
      -buttonList {"Use pvTest " "dry run" "RTDC overlap compensation" "log actuators " "log stats" "log glitch"} \
      -variableList {pvTest dryrun FFcompensation logActuators logStats 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 {hDespikePasses vDespikePasses} -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 {hDespikeNeighbors  vDespikeNeighbors} -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 {hDespikeAverage vDespikeAverage} -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 {hDespikeCountLimit vDespikeCountLimit} -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 {hDespikeThresholdStart vDespikeThresholdStart} -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 {hDespikeThresholdEnd vDespikeThresholdEnd} -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 {hDespikeThresholdSteps vDespikeThresholdSteps} -width 5 -orientation horizontal \
      -contextHelp "Enter the number of correction steps to take in ramping from the initial to the final spike threshold."
    
    
    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 {hDespike vDespike hDespikeThresholdReramp vDespikeThresholdReramp} \
      -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
    APSRadioButtonFrame .pvSuffix -parent $w1 -label "bpm PV type" \
      -variable PVSuffix -valueList {ms msAve mswAve} \
      -buttonList {ms msAve mswAve} -orientation horizontal -contextHelp \
      "Select the memory/scanner PV type (i.e. bpm data type)."
    
    APSLabeledEntry .num2ave  -parent $w1 -label "number to average" \
      -textVariable num2Ave -width 10 \
      -contextHelp "Enter the number of memory/scanner readback for averaging in the ioc at 10 Hz rate. Relevant for msAve and mswAve data."
    APSLabeledEntry .filterCoeff  -parent $w1 -label "filter coefficient" \
      -textVariable filterCoeff -width 10 \
      -contextHelp "Enter the value for the filter coefficient. Relevant for the mswAve data."
    APSLabeledEntry .currLimitH -parent $w1 -label "S35DCCT lower limit (mA) for H plane" \
      -textVariable S35DCCTLimitH -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 S35DCCTLimitV -width 10 \
      -contextHelp "Enter the lower limit of S35DCCT readback below which the sddscontrollaw correction iteration is skipped."
    APSLabeledEntry .bpmLimit -parent $w2 -label "bpm limit (mm)" \
      -textVariable BPMLimit -width 10 \
      -contextHelp "Enter the range of bpm readback outside of which the sddscontrollaw correction iteration is skipped."
    APSLabeledEntry .xbpmLimit -parent $w2 -label "Xray bpm limit (mm)" \
      -textVariable XBPMLimit -width 10 \
      -contextHelp "Enter the range of Xray bpm readback outside of which the sddscontrollaw correction iteration is skipped."
   
    APSLabeledEntry .rangeErrorLimit -parent $w2 -label "Range Error limit (A)" \
      -textVariable rangeErrorLimit -width 10 \
      -contextHelp "Enter the range error limit of corrector setpoints outside of which the sddscontrollaw correction iteration is skipped."
    APSLabeledEntry .tolerance -parent $w2 -label "Compare Tolerance" \
      -textVariable tolerance -width 10 \
      -contextHelp "Enter the tolerance for the difference of bpm's errors obtained through reflective memory (waveforms) and individual bpms"
    APSLabeledEntry .corrtol -parent $w2 -label "Corr. AO-AI Tolerance (A)" \
      -textVariable 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 corrDacAOtolerance -width 20 \
      -contextHelp "The tolerance for  the difference of corrector's DacAI and CurrentAO."
    
    #  APSRadioButtonFrame .from -parent $w0 -label "Transfer DP from: " -buttonList {Reference IOC} \
      #    -valueList {1 0} -variable fromReference -orientation horizontal

    global useCorrRefFile
    APSRadioButtonFrame .corref -parent $w0 -orientation horizontal \
      -label "Use Corrector Reference File for Range Error:" \
      -buttonList {Yes No} -valueList {1 0} -variable useCorrRefFile \
      -contextHelp "if No is selected, corrector reference will be transferred from UBOP; Yes, it will be transferred from the corrector reference file given in the References tab."
    
    global offsetReferenceFile gainReferenceFile setpointReferenceFile correctorReferenceFile
    set w0 [lindex $widgetList $index]
    incr index
    # APSFrame .offset -parent $w0
    # set w $w0.offset.frame
    APSFrameGrid .grid -parent $w0 -yList {y1 y2 y3 y4}
    set w $w0.grid.y1
    APSLabeledEntry .offsetentry -parent $w -label "Offset:   " \
      -textVariable  offsetReferenceFile -width 90 -contextHelp \
      "name of the 20-term offset reference file"
   
    # APSButton .install -parent $w.offsetentry \
      #   -text I -packOption "-side right" \
      #  -command "Restore20Term -type offset -fileVar offsetReferenceFile" \
      #   -contextHelp "Restore the 20-term offset PVs"
    # $w.offsetentry.install.button configure -state disabled
    APSButton .dir -parent $w.offsetentry \
      -text F -packOption "-side right" \
      -command "findFiles -fileVar offsetReferenceFile" \
      -contextHelp "Bring up a file selection dialog box to choose the offset reference file."
    
    # APSFrame .setpoint -parent $w0
    # set w $w0.setpoint.frame
    set w $w0.grid.y2
    APSLabeledEntry .setpointentry -parent $w -label "Setpoint: " \
      -textVariable  setpointReferenceFile -width 90 -contextHelp \
      "name of the 20-term setpoint reference file"
    # APSButton .install -parent $w.setpointentry \
      #   -text I -packOption "-side right" \
      #   -command "Restore20term -type setpoint -fileVar offsetReferenceFile" \
      #   -contextHelp "Restore the 20-term setpoint PVs"
    # $w.setpointentry.install.button configure -state disabled
    APSButton .dir -parent $w.setpointentry \
      -text F -packOption "-side right" \
      -command "findFiles -fileVar setpointReferenceFile" \
      -contextHelp "Bring up a file selection dialog box to choose the setpoint reference file."
    
    # APSFrame .gain -parent $w0
    # set w $w0.gain.frame
    set w $w0.grid.y3
    APSLabeledEntry .gainentry -parent $w -label "Gain:     " \
      -textVariable  gainReferenceFile -width 90 -contextHelp \
      "name of the 20-term gain reference file"
    #  APSButton .install -parent $w.gainentry \
      #    -text I -packOption "-side right" \
      #    -command "Restore20term -type gain -fileVar offsetReferenceFile" \
      #   -contextHelp "Restore the 20-term gain PVs"
    #  $w.gainentry.install.button configure -state disabled
    APSButton .dir -parent $w.gainentry \
      -text F -packOption "-side right" \
      -command "findFiles -fileVar gainReferenceFile" \
      -contextHelp "Bring up a file selection dialog box to choose the gain reference file."

    set w $w0.grid.y4
    APSLabeledEntry .gainentry -parent $w -label "Corrector:" \
      -textVariable  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."
    
    APSButton .dir -parent $w.gainentry \
      -text F -packOption "-side right" \
      -command "findFiles -fileVar correctorReferenceFile" \
      -contextHelp "Bring up a file selection dialog box to choose a different corrector reference file."
    return 0

}

proc StartPVTest {args} {
    global plane dataDir hResponseDir vResponseDir intervalWS intervalDP steps RCTimeout tabFrameWidgetListForLog hBpmType vBpmType
    global Plane
    GetBPMAndCorrectorType -fileVariable hResponseDir
    GetBPMAndCorrectorType -fileVariable vResponseDir
   
    switch $plane {
        h {
            set controlTest DPHtests
            set testpv DP:HOCtestStatus
            set testcontrolpv DP:HOCtestRC
            set tests $dataDir/$hResponseDir/tests
            set control_parent [lindex $tabFrameWidgetListForLog 0]
            set pvtest_parent [lindex $tabFrameWidgetListForLog 2]
            switch $hBpmType {
                DP {
                    set interval $intervalDP
                } 
                default {
                    set interval $intervalWS
                }
            }
        }
        v {
            set controlTest DPVtests
            set testpv DP:VOCtestStatus
            set testcontrolpv DP:VOCtestRC
            set tests $dataDir/$vResponseDir/tests
            set control_parent [lindex $tabFrameWidgetListForLog 1]
            set pvtest_parent [lindex $tabFrameWidgetListForLog 3]
            switch $vBpmType {
                DP {
                    set interval $intervalDP
                } 
                default {
                    set interval $intervalWS
                }
            }
        }
    }
    set time [expr ($interval+3) * $steps ]
    set testInterval [expr $interval/2]
    set pvOptions "-time=$time -interval=$testInterval -runControlPV=string=$testcontrolpv,pingTime=$RCTimeout -runControlDesc=string=runpvtest -pend=[expr $RCTimeout - 5]"
    
    if [catch {exec cavget -list=$testcontrolpv.RUN -printErrors} running] {
        return -code error "Unable to read $testcontrolpv.RUN: $running"
    }
    if $running {
        SetSROrbitStatus "abort pv test..."
        if [catch {AbortPvtest} result] {
            return -code error $result
        }
        # after [expr int(1000 * ${interval})]
        exec cawait -waitfor=$testcontrolpv.RUN,equal=0
    }
    clearRCRecord -PV $testcontrolpv
    SetSROrbitStatus "starting sddspvtest .."
    if [winfo exist ${pvtest_parent}.sr${Plane}PVtest] {
        destroy ${pvtest_parent}.sr${Plane}PVtest
    }
    set dir [file dir $tests]
    if [file exists $dir/corrRangeError.tests] {
        if [catch {exec sddscasr $dir/corrRangeError.tests -restore -pend=60} result] {
            return -code error $result
        }
    }
    if [catch {exec logMessage  -sourceId=steeringAudit\
                 -tag=Instance $testcontrolpv -tag=Action Start \
             } result ] {
        return -code error "AbortPvtest: $result"
    }
    APSExecLog .sr${Plane}PVtest -width 85 -parent $pvtest_parent  -height 30 -lineLimit 2048 \
        -unixCommand "sddspvtest $tests -pvOutput=$testpv $pvOptions -verbose"
    SetSROrbitStatus "$testcontrolpv started."
}

proc RestoreOffsetsAndSetpoints {args} {
    global waveformFileDir setpointReferenceFile offsetReferenceFile
    global coord
    set inputcoord ""
    set datapool 0
    APSParseArguments {inputcoord datapool}
    
    if ![string length $inputcoord] {
        set inputcoord $coord
    }
    SetSROrbitStatus "Restore Offsets and Setpoints in $inputcoord plane ..."
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTmpFileList -ID RestoreDPOffsets -fileList "$tmpRoot.ref1 $tmpRoot.ref2 $tmpRoot.snap.$inputcoord"
    if [catch {exec sddsprocess $offsetReferenceFile $tmpRoot.ref1 \
		"-match=col,ControlName=S*ID:*:OffsetAO,!" \
                 -match=col,ControlName=*:${inputcoord}:OffsetAO \
                 -edit=col,DeviceName,ControlName,%/:ms:${inputcoord}:OffsetAO// \
                 -scan=col,Offset,ValueString,%lf 
        exec sddsprocess $setpointReferenceFile $tmpRoot.ref2 \
		 "-match=col,ControlName=S*ID:*:SetpointAO,!" \
                 -match=col,ControlName=*:${inputcoord}:SetpointAO \
                 -edit=col,DeviceName,ControlName,%/:ms:${inputcoord}:SetpointAO// \
                 -scan=col,Setpoint,ValueString,%lf
        exec sddscombine $tmpRoot.ref1 $tmpRoot.ref2 \
                 -merge $tmpRoot.snap.$inputcoord -overwrite} result] {
        APSDeleteTmpFileList -ID RestoreDPOffsets
        return -code error "RestoreOffsetsAndSetpoints: $result"
    }
    APSAddToTmpFileList -ID RestoreDPOffsets -fileList "$tmpRoot.adjust $tmpRoot.$inputcoord"
    if $datapool {
        set waveformFile ${waveformFileDir}/adjust[string toupper $inputcoord]BpmInfo.sdds
        if [catch {exec sddsxref $tmpRoot.ref1 $tmpRoot.ref2 -pipe=out \
                     -match=DeviceName -take=Setpoint -nowarnings \
                     | sddsprocess -pipe=in "-define=col,Waveform,Offset Setpoint +" $tmpRoot.adjust
            exec sddsxref $waveformFile $tmpRoot.adjust -match=DeviceName -take=Waveform -fillIn \
                     -reuse -nowarnings $tmpRoot.$inputcoord 
            exec sddswput $tmpRoot.$inputcoord } result] {
            return -code error "RestoreOffsetsAndSetpoints: $result"
        }
        SetSROrbitStatus "Restoring $inputcoord plane adjust vector done."
    }
    if [catch {exec sddscasr -restore $tmpRoot.snap.$inputcoord -pend=70 } result] {
        return -code error "RestoreOffsetsAndSetpoints (sddscasr): $result"
    }
    SetSROrbitStatus "Restoration of $inputcoord plane offset and setpoins done!"
}

proc RestoreBpmGains {args} {
    global waveformFileDir setpointReferenceFile gainReferenceFile
    global coord
    set datapool 0
    set inputcoord ""
    APSStrictParseArguments {inputcoord datapool}
    
    if ![string length $inputcoord] {
        set inputcoord $coord
    }
    set configFile /home/helios/oagData/sr/BPMStatus/config.sdds
    SetSROrbitStatus "Restore bpm gains in $inputcoord plane ..."
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTmpFileList -ID RestoreBpmGains -fileList "$tmpRoot.gain.$inputcoord $tmpRoot.$inputcoord"
    if [catch {exec sddsprocess $gainReferenceFile $tmpRoot.gain.$inputcoord \
                   -match=col,ControlName=*${inputcoord}*GainAO \
                   -match=col,ControlName=*ID*,! \
                   -edit=col,DeviceName,ControlName,%/:ms:${inputcoord}:GainAO// \
                   -scan=col,Waveform,ValueString,%lf \
               } result] {
        APSDeleteTmpFileList -ID RestoreBpmGains
        return -code error "RestoreBpmGains1: $result"
    }
    
    if $datapool {
        set waveformFile ${waveformFileDir}/gain[string toupper $inputcoord]BpmInfo.sdds
        set waveformFile ${waveformFileDir}/adjust[string toupper $inputcoord]BpmInfo.sdds
        if [catch {exec sddsxref $waveformFile $tmpRoot.gain.$inputcoord -match=DeviceName -take=Waveform \
                       -reuse -nowarnings -fillIn -pipe=out \
                       | sddsconvert -pipe -del=par,WaveformPV \
                       | sddsconvert -pipe -rename=par,GainWaveformPV=WaveformPV \
                       | sddsxref -pipe -reuse=page $configFile -match=DeviceName -take=ElectronicsType -fillIn -nowarn \
                       | sddsprocess -pipe=in "-redefine=col,Waveform,ElectronicsType \"FPGA\" streq ? 1 : Waveform $ "\
                       $tmpRoot.$inputcoord.vector } result] {
	    return -code error "RestoreBpmGains2: $result"
        }
	if [catch {exec sddswput $tmpRoot.$inputcoord.vector } result] {
            return -code error "RestoreBpmGains3: $result"
        }
        SetSROrbitStatus "restoring bpm gain vector done."
    }
    if [catch {exec sddscasr -restore $tmpRoot.gain.$inputcoord -pend=70 }  result] {
        return -code error "RestoreBpmGains4: $result"
    }
    SetSROrbitStatus "restoring bpm gain done."
}


proc ChangeDPButtonState {value} {
    global DPButtonList vectorButtonsDisabled
    switch $value {
        0 {
            #disable dp buttons
            foreach but $DPButtonList {
                APSDisableButton $but
            }
            set vectorButtonsDisabled 1
        }
        1 {
            #enable dp buttons
            foreach but $DPButtonList {
                APSEnableButton $but
            }
            set vectorButtonsDisabled 0
        }
        2 {
            if $vectorButtonsDisabled {
                ChangeDPButtonState 1
            } else {
                ChangeDPButtonState 0
            }
        }
    }
}

# Note that this procedure also initializes the datapool BPM setpoint vector
# because APSInitializeCorrVector does this internally.
proc InitializeVector {args} {
    global hCorrectorType vCorrectorType hBpmType vBpmType
    global plane Plane coord Coord
    
    #ChangeDPButtonState 0
    
    set inputplane ""
    set setpoint 0
    set unified 0
    APSParseArguments {inputplane setpoint unified} 
    if ![string length $inputplane] {
        set inputplane $plane
    }
    switch $inputplane {
        h {
            set inputcoord x
        }
        v {
            set inputcoord y
        }
    }
    GetBPMAndCorrectorType -fileVariable ${inputplane}ResponseDir
    set corr [set ${inputplane}CorrectorType]
    set bpm [set ${inputplane}BpmType]
    if {[string compare $corr DP]!=0 && [string compare $bpm DP]!=0} {
        return -code error "$plane config is not vector mode"
    }
    SetSROrbitStatus "Initializing vectors ..."
    if [string match $corr DP] {
        #Initialaze corrector vector as well as datapool BPM setpoints for RTFB
        #SetSROrbitStatus "Initializing corrector vector in $inputplane plane..."
        if [catch {InitializeCorrVector -plane $inputplane -setpoint $setpoint} result] {
            return -code error "Error in initializing corrector vectors: $result"
        }
        # after 20000
        if [catch {APSSetCorrMode -corrMode vector \
                       -plane [string toupper $inputplane] \
                       -unified $unified } result] {
            return -code error "$result"
        }
        # after 5000
    }
    if [string match $bpm DP] {
        SetSROrbitStatus "Initializing bpm vector ..."
        SetSROrbitStatus "Restore DP setpoint+offset from file..."
        if [catch {RestoreOffsetsAndSetpoints -datapool 1 -inputcoord $inputcoord} result] {
            return -code error "Error in transferring DP setpoint+offset, $result"
        }
        # after 5000
        SetSROrbitStatus "Restore DP gain from file..."
        if [catch {RestoreBpmGains -datapool 1 -inputcoord $inputcoord} result] {
            return -code error "Error in transferring DP gains, $result"
        }
        # after 5000
    }
    SetSROrbitStatus "Initializing of corrector vector and RTFB BPM setpoint vector done."
    return
}

proc CompareReadbackIOCWithPolynomial {args} {
    global offsetReferenceFile
    set config /home/helios/oagData/sr/BPMStatus/config.sdds
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTmpFileList -ID CompareIOC -fileList  "$tmpRoot.snap $tmpRoot.req $tmpRoot.req1 $tmpRoot.config"
    APSAddToTmpFileList -ID CompareIOC -fileList  "$tmpRoot.snap.total $tmpRoot.req.total $tmpRoot.readback.snap"
    if [catch {exec sddsprocess $config $tmpRoot.config "-match=col,DeviceType=,!,DeviceType=Xray*,!,&" } result] {
        APSDeleteTmpFileList -ID CompareIOC
        return -code error $result
    }
    APSAddToTmpFileList -ID CompareIOC -fileList  "$tmpRoot.readback $tmpRoot.readback.req"
    if [catch {exec sddsprocess \
                 $offsetReferenceFile -pipe=out \
                 "-match=col,ControlName=*OffsetAO,ControlName=*BM*,!,&,ControlName=*ID*,!,&,ControlName=*:P0*,!,&" | \
                 sddsconvert -pipe -rename=col,ControlName=BPMName | \
                 sddsprocess -pipe=in $tmpRoot.req1 \
                 -edit=col,ControlName,BPMName,%/:ms:x:OffsetAO/:ms.XAVE/%/:ms:y:OffsetAO/:ms.YAVE/
        exec sddsprocess $offsetReferenceFile -pipe=out \
                 "-match=col,ControlName=*OffsetAO,ControlName=*BM*,!,&,ControlName=*ID*,!,&,ControlName=*:P0*,!,&" | \
                 sddsconvert -pipe -rename=col,ControlName=BPMName | \
                 sddsprocess -pipe=in -edit=col,ControlName,BPMName,%/:OffsetAO// $tmpRoot.readback.req
        exec sddscombine $tmpRoot.readback.req $tmpRoot.req1 $tmpRoot.req.total -merge
        exec sddscasr $tmpRoot.req.total $tmpRoot.snap.total -save -pend=70
        exec sddsselect $tmpRoot.snap.total $tmpRoot.req1 -match=ControlName $tmpRoot.snap
        exec sddsselect $tmpRoot.snap.total $tmpRoot.readback.req -match=ControlName $tmpRoot.readback.snap } result] {
        APSDeleteTmpFileList -ID CompareIOC
        return -code error $result
    }
    #read the gain
    APSAddToTmpFileList -ID CompareIOC -fileList "$tmpRoot.snap.x $tmpRoot.snap.y $tmpRoot.gain.req $tmpRoot.gain"
    APSAddToTmpFileList -ID CompareIOC -fileList "$tmpRoot.gain1 $tmpRoot.vx $tmpRoot.vy $tmpRoot.vxy"
    if [catch {exec sddsprocess $tmpRoot.snap $tmpRoot.snap.x \
                 -match=col,ControlName=*XAVE -scan=col,Vxk1,ValueString,%lf \
                 -edit=col,DeviceName,ControlName,%/:ms.XAVE//
        exec sddsprocess $tmpRoot.snap $tmpRoot.snap.y \
                 -match=col,ControlName=*YAVE -scan=col,Vyk1,ValueString,%lf  \
                 -edit=col,DeviceName,ControlName,%/:ms.YAVE//
        exec sddsconvert $tmpRoot.snap.x -delete=col,ControlName -pipe=out | \
                 sddsprocess -pipe=in $tmpRoot.gain.req \
                 -edit=col,ControlName,DeviceName,ei/:normal_bi/
        exec sddscasr -save $tmpRoot.gain.req  $tmpRoot.gain -pend=70 } result] {
        APSDeleteTmpFileList -ID CompareIOC
        return -code error $result
    }
    if [catch {exec sddsprocess $tmpRoot.gain $tmpRoot.gain1 \
                 "-edit=col,Value,ValueString,%/\"Hi Gain\"/4/%/\"Lo Gain\"/1/" \
                 -scan=col,gain,Value,%lf "-define=col,Gain,gain 2048 *" \
                 -edit=col,DeviceName,ControlName,%/:normal_bi// 
        exec sddsxref $tmpRoot.snap.x $tmpRoot.gain1 -match=DeviceName -take=Gain -pipe=out | \
                 sddsprocess -pipe=in $tmpRoot.vx "-redefine=col,Vxk1,Vxk1 Gain /"
        exec sddsxref $tmpRoot.snap.y $tmpRoot.gain1 -match=DeviceName -take=Gain -pipe=out | \
                 sddsprocess -pipe=in $tmpRoot.vy "-redefine=col,Vyk1,Vyk1 Gain /"
        exec sddsxref $tmpRoot.vx $tmpRoot.vy -match=DeviceName -take=Vyk1 -pipe=out | \
                 sddsconvert -pipe=in -retain=col,DeviceName,Vxk1,Vyk1 $tmpRoot.vxy } result ] {
        APSDeleteTmpFileList -ID CompareIOC
        return -code error $result
    }
    APSAddToTmpFileList -ID CompareIOC -fileList "$tmpRoot.readback $tmpRoot.readback.x $tmpRoot.readback.y"
    APSAddToTmpFileList -ID CompareIOC -fileList "$tmpRoot.readback.snap $tmpRoot.compare $tmpRoot.bpm"
    if [catch {exec cavget -list=S:bpm1:PolynomialSelectMO -num -pend=30} result] {
        return -code error $result
    }
    if !$result {
        set poly 20
    } else {
        set poly 3
    }
    if [catch {APSCalculatePositionTroughPolynormial -input $tmpRoot.vxy -output $tmpRoot.readback \
                 -bpmType Offset -poly ${poly}} result] {
        return -code error $result
    }
    if [catch {exec sddsconvert $tmpRoot.readback -retain=col,DeviceName,X${poly}Offset -pipe=out \
                 -rename=col,X${poly}Offset=ReadbackPoly | \
                 sddsprocess -pipe=in -edit=col,ControlName,DeviceName,ei/:ms:x/ $tmpRoot.readback.x
        exec sddsconvert $tmpRoot.readback -retain=col,DeviceName,Y${poly}Offset \
                 -rename=col,Y${poly}Offset=ReadbackPoly -pipe=out | \
                 sddsprocess -pipe=in -edit=col,ControlName,DeviceName,ei/:ms:y/ $tmpRoot.readback.y
        exec sddscombine $tmpRoot.readback.x $tmpRoot.readback.y $tmpRoot.poly -merge } result] {
        APSDeleteTmpFileList -ID CompareIOC
        return -code error $result
    }
    APSAddToTmpFileList -ID CompareIOC -fileList "$tmpRoot.readback.snap $tmpRoot.compare $tmpRoot.compare.print"
    APSAddToTmpFileList -ID CompareIOC -fileList "$tmpRoot.ioc $tmpRoot.poly"
    if [catch {exec sddsprocess $tmpRoot.readback.snap $tmpRoot.ioc \
                 -scan=col,ReadbackIOC,ValueString,%lf 
        exec sddsxref $tmpRoot.poly $tmpRoot.ioc -pipe=out -match=ControlName -take=ReadbackIOC -nowarn | \
                 sddsprocess -pipe "-define=col,Diff,ReadbackIOC ReadbackPoly -" \
                 "-filter=col,Diff,-1e-3,1e-3,!" \
                 "-print=par,Title,compare IOC with $poly term polynormial" | \
                 sddsconvert -pipe=in $tmpRoot.compare -retain=col,ControlName,DeviceName,*Readback*,Diff } result] {
        # APSDeleteTmpFileList -ID CompareIOC
        return -code error $result
    }
    if [catch {exec sddsprintout $tmpRoot.compare $tmpRoot.compare.print \
                 -col -par=Title } result] {
        return -code error "$result"
    }
    
    APSFileDisplayWindow .diff -fileName $tmpRoot.compare.print -width 110 -printCommand "enscript -r"
}

proc findFiles {args} {
    set fileVar ""
    APSParseArguments {fileVar}
    global $fileVar
    set file [set $fileVar] 
    if ![string length $file] {
        set dir /home/helios/oagData/SCR/snapshots/
    } else {
        set dir [file dir $file]
    }
    set choosedfile [APSFileSelectDialog .chooseInputFile -listDir $dir -pattern *fer*]
    if [string length $choosedfile] {
        set $fileVar $choosedfile
    }
}        
proc SetCorrectorInUse {args} {
    set type ""
    set plane ""
    APSParseArguments {type plane}
    global Plane hResponseDir vResponseDir

    set planes [string tolower $Plane]
    if [string compare $plane "both"]==0 {
        set planes {h v}
    }
    if [string compare $type none]==0 {
        foreach pl $planes {
            if [catch {APSSetCorrectorInUse -resetUnspecified 1 -plane $pl} result] {
                return -code error $result
            }
        }
    } else {
        foreach pl $planes {
            if [catch {APSSetCorrectorInUse -configDC [set ${pl}ResponseDir] } result] {
                return -code error $result
            }
        }
    }
}

proc CheckCorrectorCurrentDifference {args} { 
    set tolerance 0.001 
    set plane h
    APSParseArguments {tolerance plane}
    
    global ${plane}ResponseDir dataDir
    
    set config $dataDir/[set ${plane}ResponseDir]/config
    set plane [string toupper $plane]
    SetSROrbitStatus "Checking corrector current difference..."
    if [catch {exec sddsprocess $config -pipe=out -nowarnings -match=par,NameType=CorrectorNames \
                 | sdds2stream -pipe -col=Name } corrList] {
        return -code error $corrList
    }
    if [catch {exec cavget -list=[join $corrList ,] -list=:DiffCALC -dryRun } pvList] {
        return -code error $pvList
    }
    if [catch {exec cavget -list=[join $pvList ,] -pend=10} valueList] {
        return -code error $valueList
    }
    set tmpfile /tmp/[APSTmpString].diffcalc
    APSAddToTmpFileList -ID check -fileList "$tmpfile $tmpfile.printout"
    if [catch {exec sddsmakedataset -pipe=out -col=ControlName,type=string -data=[join $pvList ,] \
                 -col=Value,type=double -data=[join $valueList ,] \
                 | sddsprocess -pipe=in -nowarnings \
                 -filter=col,Value,-0.5,0.5,! $tmpfile} result] {
        return -code error $result
    }
    set rows [exec sdds2stream $tmpfile -rows=bare]
    if $rows {
        if [catch {exec sddsprintout $tmpfile $tmpfile.print -col=ControlName -col=Value \
                     "-title=The current difference of following correctors are bigger than 0.5A.\n Please make adjustments before switching to operation mode!"} result] {
            return -code error $result
        }
        global returncomm
        set returncomm ""
        set okCommand "set returncomm ok;destroy .corrcheck"
        set cancelCommand "set returncomm cancel;destroy .corrcheck"
        APSFileDisplayWindow .corrcheck -fileName $tmpfile.print -defaultButtons 0 -closeButton 0 \
          -okButton 1 -okCommand $okCommand -cancelButton 1 -cancelCommand $cancelCommand -modal 1
        return $returncomm
    }
    return 0
}

proc TransferCorrectorReference {args} {
    set plane both
    APSParseArguments {plane}
    global correctorReferenceFile useCorrRefFile
    
    SetSROrbitStatus "transfer $plane plane corrector references..."
    if $useCorrRefFile  {
        SetSROrbitStatus "transfer corr reference from reference file..."
        if [catch {APSMpSRTransferCorrectorReference -plane $plane -SCRFile $correctorReferenceFile } result] {
            return -code error "TransferCorrectorReference: $result"
        }
    } else {
        SetSROrbitStatus "transfer corr reference from UBOP..."
        if [catch {APSMpSRTransferCorrectorReference -plane $plane} result] {
            return -code error "TransferCorrectorReference: $result"
        }
    }
    SetSROrbitStatus "done"
}

proc CheckTests {args} {
    set directory ""
    set Plane ""
    APSParseArguments {directory Plane}
    global dataDir
    set testFile $dataDir/$directory/tests 
    if ![file exists $testFile] {
        SetSROrbitStatus "Test file not found---try using GENERATE first." -code error
        return
    }
    set fileList $testFile
    lappend decList "Tested in sddspvtest"
    set DPtype [lindex [exec sdds2stream -par=PVType $dataDir/$directory/config] 0]
    if [regexp {DP} $DPtype] {
        set dp 1
    } else {
        set dp 0
    }
    
    switch $Plane {
        H -
        V {
        }
        default {
            SetSROrbitStatus "Invalid plane provided for tests, should be H or V!" -code error
            return
        }
    }
    set dpTests $dataDir/$directory/DP${Plane}tests
    if ![file exist $dpTests] {
        SetSROrbitStatus "Test file $dpTests not found---try using GENERATE first." -code error
        return
    }
    lappend fileList $dpTests
    lappend decList "Tested in sddspvtest\\, but out of range PVs are in datapool ioc."
    
    set passed 1
    if $dp {
        #check the datapool ioc errors
        if [catch {exec cavget -list=DP:${Plane}CorrLimErrM.VAL -num -pend=30} error] {
            return -code error "Error in checking datapool corrector limit error: $error"
        }
        if $error {
            set tmpFile /tmp/[APSTmpString]
            if [catch {exec sddsconvert /home/helios/oagData/sr/orbitControllaw/waveforms/[string tolower $Plane]corrInfo.sdds \
                         -rename=par,SetpointWaveformPV=WaveformPV $tmpFile.1 
                exec sddswget $tmpFile.1 $tmpFile.value  -pend=30} result] {
                return -code error "Error in reading DP:${Plane}Cor:WF : $result"
            }
            APSAddToTmpFileList  -ID checkTests -fileList "$tmpFile.1 $tmpFile.value $tmpFile.tests $tmpFile.printout"
            
            if [catch {exec sddsprocess $tmpFile.value $tmpFile.tests "-test=col,Waveform 149.5 >" -nowarnings } result] {
                return -code error "Error in checking the out of limit correctors: $result"
            }
            set rows [exec sdds2stream -rows=bar $tmpFile.tests]
            if $rows {
                set corrList [exec sdds2stream -col=DeviceName $tmpFile.tests]
                set fid [open $tmpFile.printout "w"]
                puts $fid "Datapool IOC error: the $Plane corrector limit error (DP:${Plane}CorrLimErrM.VAL is Err)."
                puts $fid "The is caused by sending 150 A to datapool for these correctors: [join $corrList ,]."
                puts $fid "To fix the problem, follow the instruction in file /home/helios/SR/procedures/HowToSetMissingCorrectors"
                puts $fid "\n"
                close $fid
                APSFileDisplayWindow [APSUniqueName .] -fileName $tmpFile.printout \
                  -deleteOnClose 1 -width 80 -height 40
                SetSROrbitStatus "data pool corrector limit errors for [join $corrList ,]."
            } else {
                set fid [open $tmpFile.printout "w"]
                puts $fid "Datapool IOC shows that the $Plane corrector limit error (DP:${Plane}CorrLimErrM.VAL is Err)."
                puts $fid "However, did not find any correctors in datapool with value greater than 149 A. There might be other problems, please contract control group."
                close $fid
                APSFileDisplayWindow [APSUniqueName .] -fileName $tmpFile.printout \
                  -deleteOnClose 1 -width 80 -height 40
                SetSROrbitStatus "data pool corrector limit errors."
            }
            set passed 0
        }
    }
    foreach testFile $fileList dec $decList {
        set tmpFile /tmp/[APSTmpString]
        APSAddToTmpFileList -ID checkTests -fileList "$tmpFile $tmpFile.printout"
        if [catch {exec sddssnapshot $testFile -pipe=out \
                     | sddsprocess -pipe=in $tmpFile -nowarning \
                     "-test=column,MinimumValue Value > MaximumValue Value < ||" } result] {
            return -code error "Error in reading pv values: $result"
        }
        set rows [exec sdds2stream -rows=bare $tmpFile]
        if {$rows==0} {
            SetSROrbitStatus "All tests for [file tail $testFile] are satisfied."
        } else {
            if [regexp {DP} $testFile] {
                if [catch {exec sddsprintout $tmpFile $tmpFile.printout \
                             "-title=Test values out of range for ${directory}\n${dec}" \
                             -column=ControlName,format=%32s -column=MinimumValue,format=%8.3f -column=Value,format=%8.3f \
                             -column=MaximumValue,format=%8.3f
                    exec sdds2stream -rows=bare $tmpFile} result] {
                    SetSROrbitStatus "Error in printing DP tests file: $result" -code error
                    return
                }
            } else {
                if [catch {exec sddsprocess $tmpFile $tmpFile.current -match=col,ControlName=S35DCCT:currentCC -nowarnings 
                    exec sddsprocess $tmpFile $tmpFile.cor -match=col,ControlName=*CurrentAO -nowarnings
                    exec sddsprocess $tmpFile $tmpFile.range -match=col,ControlName=*RangeErrorCALC -nowarnings
                    exec sddsprocess $tmpFile -pipe=out -match=col,ControlName=*ErrorCC -nowarnings \
                             | sddsprocess -pipe=in $tmpFile.xbpm "-match=col,ControlName=S*ID:*,ControlName=S*BM:*,|" -nowarnings 
                    exec sddsprocess $tmpFile -pipe=out -match=col,ControlName=*ErrorCC -nowarnings  \
                             | sddsprocess -pipe=in $tmpFile.bpm "-match=col,ControlName=S*A:P*,ControlName=S*B:P*,|,ControlName=S*C:P*,|" -nowarnings
                    exec sddscombine $tmpFile.current $tmpFile.cor $tmpFile.range $tmpFile.xbpm $tmpFile.bpm -merge \
                             $tmpFile.tcl 
                    exec sddsselect $tmpFile $tmpFile.tcl $tmpFile.other -invert -match=ControlName} result] {
                    SetSROrbitStatus "Error in checking other tests: $result" -code error
                    return
                }
                set descrList [list "S35DCCT current out of range" \
                                 "$Plane corrector out of range (use corrector management tool to change the limit)" \
                                 "Range Error out of range" \
                                 "Xray bpm out of range" \
                                 "rf bpm out of range" \
                                 " "]
                set printFiles ""
                foreach type {current cor range xbpm bpm other} desc $descrList {
                    set row [exec sdds2stream -rows=bare $tmpFile.$type]
                    if {$row} {
                        if [catch {exec sddsprintout $tmpFile.$type $tmpFile.$type.print\
                                     "-title=Test values out of range for ${directory}\n${dec}: $desc" \
                                     -column=ControlName,format=%32s -column=MinimumValue,format=%8.3f -column=Value,format=%8.3f \
                                     -column=MaximumValue,format=%8.3f } result] {
                            SetSROrbitStatus "Error in testing $type : $result" -code error
                            return
                        }
                        lappend printFiles $tmpFile.$type.print
                    }
                }
                APSAddToTmpFileList -ID checkTests -fileList $printFiles
                if [llength $printFiles]==1 {
                    exec mv $printFiles $tmpFile.printout
                } else {
                    eval exec cat $printFiles > $tmpFile.printout
                }
            }
            set passed 0
            APSFileDisplayWindow [APSUniqueName .] -fileName $tmpFile.printout \
              -sddsExportableFile $tmpFile -deleteOnClose 1 -width 80 -height 40
        }
    }
    
    if {$dp} {
        set waveformTest $dataDir/$directory/waveformTest
        if ![file exist $waveformTest] {
            SetSROrbitStatus "waveformTest file not found---try using GENERATE first." -code error
            return
        }
        set tmpFile  /tmp/[APSTmpString]
        APSAddToTmpFileList -ID checkTests -fileList "$tmpFile.1 $tmpFile.2 $tmpFile $tmpFile.print"
        if [catch {exec sddswget $waveformTest $tmpFile.1} result] {
            SetSROrbitStatus "$result" -code error
            return
        }
        if [catch {exec sddscombine $dataDir/$directory/config $tmpFile.2 -merge -overwrite} result] {
            SetSROrbitStatus "$result" -code error
            return
        }
        switch $Plane {
            H {
                set coord X
            }
            V {
                set coord Y
            }
        }
        if [catch {exec sddsselect $tmpFile.1 $tmpFile.2 -match=DeviceName=Name \
                     -reuse=page -pipe=out -nowarnings \
                     | sddsprocess -pipe \
                     "-edit=para,Description,WaveformPV,%/DP:${Plane}Cor:WF/Corrector out of range/%/DP:xid${coord}:Out:WF/Xbpm out of range/%/DP:p0${coord}:Out:WF/bpm out of range/%/DP:rfbpm${coord}:Out:WF/bpm out of range/" \
                     | sddsprocess -pipe -nowarning \
                     "-test=column,MinimumValue Waveform > MaximumValue Waveform < ||" \
                     | tee $tmpFile \
                     | sddsprintout -pipe=in $tmpFile.print \
                     "-title=Tested in datapool ioc.\nTest values out of range for ${directory}" \
                     -par=WaveformPV \
                     -par=Description \
                     -column=DeviceName,format=%10s -column=MinimumValue \
                     -column=Waveform,label=Value \
                     -column=MaximumValue
            exec sdds2stream -rows=bare $tmpFile} results] {
            SetSROrbitStatus "$results" -code error
            return
        }
        set failed 0
        foreach result $results {
            if {$result} {
                set failed 1
                set passed 0
            }
        }
        if {!$failed} {
            SetSROrbitStatus "All waveform tests passed."
        } else {
            SetSROrbitStatus "Waveform tests failed."
            APSFileDisplayWindow [APSUniqueName .] -fileName $tmpFile.print \
              -sddsExportableFile $tmpFile -deleteOnClose 1 -width 80 -height 40
        }
    }
    if $passed {
        SetSROrbitStatus "All tests for $Plane plane passed."
    } else {
        SetSROrbitStatus "tests for $Plane plane failed."
    }
    return
}

proc CorrectorSanityCheck {args} {
    global plane corrAOAItolerance corrDacAOtolerance
    SetSROrbitStatus "Corrector sanity check -- check corrector AO-AI, DAC-AO difference..."
    if [catch {APSCorrectorSanityCheck -plane $plane -AOAItolerance $corrAOAItolerance -dacAOtolerance $corrDacAOtolerance} result] {
        SetSROrbitStatus "corrector sanity check failed: $result"
        return
    }
    SetSROrbitStatus "Corrector sanity check passed."
}
#temporary
set waveformFileDir /home/helios/oagData/sr/orbitControllaw/waveforms

set defaultSetpointRef /home/helios/oagData/SCR/snapshots/SR/SR-UserBeamPreferred.gz
set defaultGainRef /home/helios/oagData/SCR/snapshots/SBPMs/SBPMs-Preferred.gz
set defaultOffsetRef /home/helios/oagData/SCR/snapshots/SR/SR-BPMOffsetReference.gz
set defaultCorrRef /home/helios/oagData/SCR/snapshots/SR/SR-UserBeamPreferred.gz

set correctorReferenceFile $defaultCorrRef
set setpointReferenceFile  $defaultSetpointRef
set gainReferenceFile      $defaultGainRef
set offsetReferenceFile    $defaultOffsetRef

set useCorrRefFile 0

set ployDir /home/helios/OAG/oagData/sr/bpmCalibration/bpmPolynomials
set DPButtonList ""
set fromReference 1
set vectorInitialized 0
set vectorButtonsDisabled 1
set polynomial standard
set vectorPolyCalculated 0

#set homeDir [pwd]
set steps 300000
set gain 0.4
set intervalDP 0.1
set intervalWS 0.5
set deltaLimit 0.5
set averages 1
set averageInterval 1
set verbose 1
set dryrun 0
set datapool 0
set FFcompensation 1
set PVSuffix msAve
set num2Ave 5
set filterCoeff 0.1
set hResponseDir h.default
set vResponseDir v.default
set hRunControlPV "S:OrbitControlLawXRC"
set hRunControlDesc "SR x-orbit correction"
set vRunControlPV "S:OrbitControlLawYRC"
set vRunControlDesc "SR y-orbit correction"
set S35DCCTLimitH 15
set S35DCCTLimitV 15
set BPMLimit 10
set XBPMLimit 0.5
set rangeErrorLimit 10
set logActuators 1
set logStats 1
set logGlitch 0
set dataDir /home/helios/oagData/sr/orbitControllaw/lattices/default
cd $dataDir
set RCTimeout 30
set pvTest 1
set tolerance 0.02
set corrAOAItolerance 2.0
set corrDacAOtolerance 0.2
set hCorrectorType ""
set hBpmType ""
set vCorrectorType ""
set vBpmType ""
set RunningMode ""
set home $env(HOME)
set oxygenStation 0
set hsimulatorControllawID ""
set hsimulatorControllawInput ""
set vsimulatorControllawID ""
set vsimulatorControllawInput ""
#for testing purpose (remove it when install)
if [string match "*oxygen*" $home] {
    set oxygenStation 1
    #  set env(EPICS_CA_ADDR_LIST) 127.0.0.1
}

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

set brief 0
set unified 0
if [llength $argv] {
    set args $argv
    APSStrictParseArguments {brief hResponseDir vResponseDir unified}
}
if $unified {
    set hResponseDir h.defaultXRDP
    set vResponseDir v.defaultXRDP
    set dataDir /home/helios/oagData/sr/unifiedSteering/lattices/default
    cd $dataDir
}
set SROrbitStatus "Initializing ..."
APSScrolledStatus .status -parent .userFrame -width 60 \
  -textVariable SROrbitStatus -packOption "-fill both -expand true"


GetBPMAndCorrectorType -fileVariable hResponseDir
GetBPMAndCorrectorType -fileVariable vResponseDir

setDespikeDefaults -plane both
set parent ""
if !$brief {
    # tab frame already starts with Horizontal and a call to "setCorrPlane H"
    #MakeOptionFrame .options -parent .userFrame
    #MakeFileFrame .files -parent .userFrame
    MakeConfigFrame .config -parent .userFrame
    MakeOptionAndParameterFrame .options -parent .userFrame
} else {
    MakeBriefPlaneFrame .plane -parent .userFrame
    setCorrPlane H
    set parent .userFrame
}

MakeActionWidget .actions -parent .userFrame
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 pvtest_x pvtest_y]

set tabFrameWidgetListForLog [APSTabFrame .log -parent $parent.execLog.frame \
                                -label "" \
                                -labelList $sectionList \
                                -width 955 -height 600 \
                                -packOption "-expand yes -fill both"]
if !$brief {
  update
  wm geometry .execLog +[expr [winfo rootx .] + 50]+[expr [winfo rooty .] + 300]
}
#ChangeDPButtonState 0
if !$brief {
    wm protocol $parent.execLog WM_DELETE_WINDOW {return} 
}

# Local Variables:
# mode: tcl
# indent-tabs-mode: nil
# End:
