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

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

proc CheckIDExist {args} {
    global BPLD
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTmpFileList -ID bpld -fileList "$tmpRoot.0 $tmpRoot.1 $tmpRoot.2"
    if [catch {exec sddsprocess /home/helios/oagData/sr/IDs/sectors.sdds $tmpRoot.0 \
		   "-define=col,BPLDSector,Sector 2 mod 0 > ? Sector : Sector 1 + $,type=long" \
		   "-define=col,ID1,Sector 2 mod 0 > ? 0 : 1 $ ,type=short" \
		   "-define=col,ID2,Sector 2 mod 0 > ? 1 : 0 $ ,type=short" \
		   "-define=col,IDexist,Downstream 1 == Upstream 1 == || ? 1 : 0 $ , type=short" } result] {
	return -code error $result
    }
    if [catch {exec sddsprocess $tmpRoot.0 -filter=col,ID1,1,1 $tmpRoot.1
	exec sddsprocess $tmpRoot.0 -filter=col,ID2,1,1 $tmpRoot.2} result] {
	return -code error $result
    }
    set ID1sector [exec sdds2stream -col=BPLDSector $tmpRoot.1]
    set IDsector [exec sdds2stream -col=Sector $tmpRoot.0]
    set IDexist [exec sdds2stream -col=IDexist $tmpRoot.0]
    set ID1exist [exec sdds2stream -col=IDexist $tmpRoot.1]
    set ID2sector [exec sdds2stream -col=BPLDSector $tmpRoot.2]
    set ID2exist [exec sdds2stream -col=IDexist $tmpRoot.2]
    foreach sector $ID1sector exist $ID1exist {
	set BPLD(S[format %02d $sector].ID1exist) $exist
    }
    foreach sector $ID2sector exist $ID2exist {
	set BPLD(S[format %02d $sector].ID2exist) $exist
    }
    set BPLD(missingIDs) ""
    foreach sector $IDsector exist $IDexist {
	if {$sector!=29 && !$exist} {
	    lappend BPLD(missingIDs) ID[format %02d $sector]
	}
    }
}


set sectorList ""
set varList ""

set BPLD(archiveDir) /home/helios/oagData/sr/BPLD/Validation/ID/FastAbort
set BPLD(configDir) /home/helios/oagData/sr/BPLD/BPLD_Config
set BPLD(beam) Real
set sectors 36
set IDList ""
set varList ""
set IDsectorList ""
set BPLD(IDchoice) ""
#set BPLD(missingIDs) {ID33}
for {set sector 1} {$sector<$sectors} {incr sector 1} {
    set sectorf [format %02d $sector]
    lappend IDList ID$sectorf
    lappend IDsectorList $sectorf
    set BPLD(ID$sectorf.var) 0
    lappend varList BPLD(ID$sectorf.var)
    set odd [expr $sector % 2]
    if $odd {
	set s0 $sector
	set BPLD(ID$sectorf.BPLDID) ID2
	lappend BPLD(sectorList) $sectorf
    } else {
	set s0 [expr $sector + 1]
	set BPLD(ID$sectorf.BPLDID) ID1
    }
    set BPLD(ID$sectorf.BPLDsector) $s0
}

set BPLD(IDList) $IDList
set BPLD(IDsectorList) $IDsectorList
set BPLD(simGap) 0
set BPLD(testType) orbit
set BPLD(plane) x
set BPLD(window) both
set BPLD(tolerance) 100
set BPLD(BPM) default

CheckIDExist

proc GetBPLDSectorList {args} {
    global BPLD
    set sectorList ""
    
    foreach ID $BPLD(IDList) {
	set sector [scan $ID ID%ld]
	set sectorf [format %02d $sector]
	set bpldSector $BPLD(ID$sectorf.BPLDsector)
	set BPLD(S$bpldSector.IDList) ""
    }
    foreach ID $BPLD(IDList) {
	set sector [scan $ID ID%ld]
	set sectorf [format %02d $sector]
	set bpldSector $BPLD(ID$sectorf.BPLDsector)
	if $BPLD(ID$sectorf.var) {
	    lappend sectorList $bpldSector
	    lappend BPLD(S$bpldSector.IDList) BPLD(ID$sectorf.BPLDID)
	    lappend BPLD(S$bpldSector.realIDList) $ID
	}
    }
    return [lsort -unique $sectorList]
}

proc MakeIDSelectionWidget {widget args} {
    set parent ""
    APSParseArguments {parent}
    global BPLD
    set w $parent$widget
    APSFrame $widget -parent $parent \
	-label "Fast Abort ID Selection." \
	-contextHelp {IDselection frame}
    APSFrameGrid .grid -parent $w.frame -xList {x1 x2 x3 x4 x5}
    set w1 $w.frame.grid.x1
    set w2 $w.frame.grid.x2
    set w3 $w.frame.grid.x3
    set w4 $w.frame.grid.x4
    set w5 $w.frame.grid.x5
    set j 0
    foreach sectorf $BPLD(IDsectorList) {
	set var BPLD(ID$sectorf.var)
	set sector [scan $sectorf %ld]
	set i [expr $sector%5]
	if {$i==0} {
	    set i 5
	}
	APSFrame .f$j -parent [set w$i] -label ""
	set f [set w$i].f$j.frame
	$f configure  -bd 0 -relief flat
	set button [APSCheckButtonFrame .c$sectorf -parent $f -label "" \
			-buttonList ID$sectorf -packOption "-side left" \
			-variableList $var]
	set BPLD(ID$sectorf.button) $button
	$button configure -bg grey90
	if [lsearch -exact $BPLD(missingIDs) ID$sectorf]>=0 {
	    $button configure -state disabled
	}
	incr j
    }
    APSFrame .fn -parent $parent
    set w $parent.fn.frame
    $w configure -bd 0
    set BPLD(allIDs) 0
    APSRadioButtonFrame .allnone -parent $w -label "" -buttonList {All None} -orientation horizontal \
	-valueList {1 0} -variable BPLD(allIDs) -commandList "SelectAllIDs SelectAllIDs"
}

proc SelectAllIDs {args} {
    global BPLD
    foreach ID $BPLD(IDList) {
	if [lsearch -exact $BPLD(missingIDs) $ID]<0 {
	    set BPLD($ID.var) $BPLD(allIDs)
	}
    }
    update 
}

proc ClearFaults {args} {
    set arm 1
    set BPLDsector ""
    set ID ID1
    APSParseArguments {arm BPLDsector ID}
    
    global BPLD
    if ![string length $BPLDsector] {
	set  sectorList [GetBPLDSectorList]
    } else {
	set sectorList $BPLDsector
    }
    if ![llength $sectorList] {
	SetStatus "No ID chosen!"
	return
    }
    SetStatus "Clear faults..."
    
    if [catch {APScavput -list=S -list=[join $sectorList ,] -list=-LMPS:BPLD:ID -list=1,2 -list=:AIOR- \
		   -list=H,V -list=1,2 -list=-SP=0 -pend=60} result] {
	return -code error "Error set ID bpm offsts to zero: $result"
    }
    
    #clear External inputs faults
    if [catch {APScavput -list=S -list=[join $sectorList ,] -list=-LMPS:CtrlReg0-Cmd=0 -pend=30 } result] {
	return -code error "Error clear ext inputs: $result"
    }
    after 5000
    if [catch {APScavput -list=S -list=[join $sectorList ,]  -list=-LMPS:UsrReset-SP=1 -pend=30 } result] {
	return -code error "Error reset to clear faults: $result"
    }
    SetStatus "done."
}

proc BringUpADT {args} {
    set type adjust
    APSParseArguments {type}
    set oldDir [pwd]
    set dir /home/helios/oagData/ADTFiles/srBpm
    switch $type {
	adjust {
	    set file sr.bpm.lowPass1s.adjusted.pv
	}
	setpoint {
	    set file sr.bpm.setpoint.pv
	}
	error {
	    set file sr.bpm.lowPass1s.error.pv
	}
    }
    if {$type=="adjust"} {
	 exec adt  -geometry +30+0 -f $dir/$file -a $dir -z 3 -d &
    } else {
	exec adt -f $dir/$file -a $dir &
    }
    cd $oldDir
}

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

proc ControllawInfo {args} {
    set plane ""
    APSParseArguments {plane}
    switch $plane {
	h {
	    set runControlPV  "S:RC:OrbitControlLawXC"
	}
	v {
	    set runControlPV "S:RC:OrbitControlLawYC"
	}
    }
    exec medm -x -attach -macro RCPV=$runControlPV \
	/usr/local/iocapps/adlsys/sr/psApp/APSRunControlSingle.adl  &

}

proc LoadDefaultLimits {args} {
    set BPLDsector ""
    APSParseArguments {BPLDsector}
    
    global BPLD  apsSCRSnapDir apsSCRRequestDir
    set scrFile /home/helios/oagData/SCR/snapshots/SRBPLD/SRBPLD-DefaultLimits.gz
    set apsSCRSnapDir /home/helios/oagData/SCR/snapshots
    set apsSCRRequestDir /home/helios/oagData/SCR/requestFiles
    
    set tmpRoot /tmp/[APSTmpString]
    if ![string length $BPLDsector] {
	set sectorList [GetBPLDSectorList]
    } else {
	set sectorList $BPLDsector
    }
    if ![llength $sectorList] {
	SetStatus "No ID chosen!"
	return
    }
    foreach sector $sectorList {
	if [catch {eval exec sddsprocess $scrFile -pipe=out -match=col,Beamline=S$sector \
		       -match=col,Category=ID_BPLD_Limit \
		       | sddscasr -pipe=in -restore } result] {
	    return -code error "Error loading ID BPLD limits from SCR: $result"
	}
	SetStatus "Default SCR ID BPLD limits for double sector S$sector loaded."
    }
}


proc MakeConfigWidget {args} {
    global BPLD
    set plane h
    set parent ""
    
    APSParseArguments {plane parent}
    
    set rootname ${plane}IDOrbit
    global ${rootname}MainDir ${rootname}Lattice 
    set ${rootname}MainDir /home/helios/oagData/sr/orbitControllaw/lattices
    set ${rootname}Lattice default
    global ${rootname}Plane ${rootname}Readdir ${rootname}ReadDescription
    global ${rootname}FilterEnd1 
    set ${rootname}Plane $plane
    set ${rootname}Readdir ${plane}.BPLD-IDs
    set ${rootname}ReadDescription ""
    set ${rootname}FilterEnd1 .*
    
    APSFileSelectWidget .file -parent $parent -variable ${rootname}Readdir -label "Config: " \
      -pathVariableList [list ${rootname}MainDir ${rootname}Lattice] \
      -mode directory -filterVariableList \
      [list ${rootname}Plane ${rootname}FilterEnd1] -width 60 \
      -incrementButtons 1 -contextHelp \
      "Enter the name of the configuration file to read."
	 
    APSLabeledEntry .descrip -parent $parent -label "Description:" -width 60 -packOption "-side top -anchor w" \
      -textVariable ${rootname}ReadDescription -contextHelp \
      "Shows the description of the last-read configuration file."
    
    APSButton .readDesc -parent $parent.descrip -text "Read" -packOption "-side right" \
      -command "ReadDescription  -plane $plane" \
      -contextHelp "Reads the description of the configuration."
    
}

proc ReadDescription {args} {
    global BPLD
    set plane ""
    APSParseArguments {plane}
    set rootname ${plane}IDOrbit
    global ${rootname}Readdir ${rootname}ReadDescription
    set config [subst \$${rootname}Readdir]
     set tmpfile /tmp/[APSTmpString]
    
    # read the configuration
    set baseDir /home/helios/oagData/sr/orbitControllaw
    
    set configDir $baseDir/lattices/default/$config
    if ![file exists $configDir/config] {
	SetStatus "Can't find config file for $configDir/config."
        return
    }
    set ${rootname}ReadDescription [lindex [exec sdds2stream $configDir/config -para=Description] 0]
    SetStatus  "Done."
    return
}

proc GenerateControllawFiles {args} {
    set plane h
    set regenerateFiles 1
    APSParseArguments {plane regenerateFiles}
    set rootname ${plane}IDOrbit
    global BPLD  ${rootname}Plane ${rootname}Readdir ${rootname}ReadDescription
    set mainDir /home/helios/oagData/sr/orbitControllaw/lattices/default
    
    set dir ${plane}.[clock format [clock seconds] -format %Y-%m%d.00]
    set newdir [APSNextGenerationedName -name $dir -separator . -directory $mainDir -newFile 1]
    if [catch {exec mkdir -p $mainDir/$newdir} result] {
	return -code error "Error creating new dir - $newdir: $result"
    }
    SetStatus "Creating new config $newdir..."
    exec chmod 777 $mainDir/$newdir
    exec cp $mainDir/${plane}.BPLD-IDs/config $mainDir/$newdir/.
    set oldDir [pwd]
    cd $mainDir/$newdir
    if [catch {exec sddsprocess config -scan=col,Sector,Name,S%ld,type=long -pipe=out \
		   -match=par,NameType=MonitorNames \
		   | sddsprocess -pipe -filter=col,Sector,1,35 \
		   | sddsprocess -pipe=in config.otherbpm1 "-match=col,Name=*P0,!" "-match=col,Name=*P1,!" } result] {
	return -code error "Error filter config0: $result"
    }
    if [catch {exec sddsprocess config -scan=col,Sector,Name,S%ld,type=long -pipe=out  -match=par,NameType=MonitorNames \
		   | sddsprocess -pipe -filter=col,Sector,36,40 \
		   | sddsprocess -pipe=in config.otherbpm2 "-match=col,Name=S36A:P0,!" "-match=col,Name=S36A:P1,!" \
		   "-match=col,Name=S40B:P1,!" "-match=col,Name=S40B:P0,!" } result] {
	return -code error "Error filter config1: $result"
    }
    
    if [catch {exec sddsprocess config config.corr -match=par,NameType=CorrectorNames } result] {
	return -code error "Error filter config2: $result"
    }
    if {$BPLD(BPM)=="default"} {
	#use default config
	set configFile  $BPLD(configDir)/config.sdds
    } else {
	set configFile $BPLD(configDir)/BPLDConfig-ID$BPLD(BPM).sdds
    }
    if [catch {exec sddsprocess $configFile -pipe=out -filter=col,IDBPM,1,1 \
		   | sdds2stream -pipe=in -col=DeviceName } bpmList] {
	return -code error "Error getting ID bpms: $result"
    }
    set BPLD(bpmList) $bpmList
    if [catch {exec sddsmakedataset -pipe=out -col=Name,type=string -data=[join $bpmList ,] \
	       | sddsprocess -pipe=in config.idbpm "-define=col,Flag,1,type=short" \
		   -define=col,Weight,1.0 -define=col,Despike,1,type=short \
		   -print=col,ElectronicsType,LB+
	exec  sddscombine config.otherbpm1 config.otherbpm2  config.idbpm -merge -pipe=out \
		   | sddsconvert -pipe -del=col,Sector \
		   | sddssort -pipe=in -col=Name -unique config.bpms } result] {
	return -code error "Error create bpm config: $result"
    }
    if [catch {exec sddscombine config.bpms config.corr -pipe=out \
		   | sddsprocess -pipe=in config -nowarn \
		   "-reprint=par,Description,OC config for $BPLD(BPM) ID-BPLD config" } result] {
	return -code error "Error creating OC config for ID-BPLD: $result"
    }
    cd $oldDir
    #update database

    if [catch {APSUpdateConfigDescriptionDatabase -newConfig $newdir\
		   -dataDir $mainDir -booster 0} result] {
	return -code error "APSWriteSRConfig: $result"
    }
    foreach par {NumberOfSingularValuesUsed TikhonovFilterUsed TikhonovSVNNumber TikhonovAlpha TikhonovBeta \
		     ReferenceMatrix } {
	set $par [exec sdds2stream -par=$par $mainDir/${plane}.BPLD-IDs/irm]
    }
    SetStatus "computing irm..."
    if [catch {APSSRGenerateOrbCorrFiles -rootname $rootname -generate 1 \
		   -configFile $mainDir/$newdir/config -plane $plane \
		   -referenceMatrix $ReferenceMatrix \
		   -currLimitH 0.5 \
		   -currLimitV 0.5 \
		   -timeFilter Raw \
		   -outputRoot $mainDir/$newdir -singularValues $NumberOfSingularValuesUsed \
		   -SVDanalysis 0 \
		   -tikhonovFilter $TikhonovFilterUsed\
		   -tikhonovSVN $TikhonovSVNNumber \
		   -tikhonovBeta  $TikhonovBeta \
		   -tikhonovType SVN } result] {
	return -code error "Error computing irm: $result"
    }
    set ${rootname}Readdir $newdir
    ReadDescription  -plane $plane
    SetStatus "Generating controllaw files for $newdir..."
    if [catch {APSSRGenerateControllawFiles -dataDir $mainDir -config $newdir \
		   -currLimitH $BPLD(currLimitH) -currLimitV $BPLD(currLimitV) \
		   -regenerateFiles $regenerateFiles} result] {
        SetStatus "$result"
        return
    }
    SetStatus "done"
}

proc StartControllaw {args} {
    set plane ""
    set regenerateFiles 0
    APSParseArguments {plane regenerateFiles}
    if ![string length $plane] {
        return -code error "Plane for running orbit correction is not given"
    }
    set rootname ${plane}IDOrbit
    global ${rootname}Readdir BPLD
    set config [set ${rootname}Readdir]
    switch $plane {
        h {
            set runControlPV S:RC:OrbitControlLawXC
	    set widget .xcontrollaw
	    set config $hIDOrbitReaddir
        }
        v {
            set runControlPV S:RC:OrbitControlLawYC
	    set widget .ycontrollaw
	    set config $vIDOrbitReaddir
        }
        default {
            return -code error "plane should be h or v!"
        }
    }
    
    set dataDir /home/helios/oagData/sr/orbitControllaw/lattices/default
    if [catch {APSSRGenerateControllawFiles -dataDir $dataDir -config $config \
		   -currLimitH 0.3 -currLimitV 0.5 -timeFilter Raw \
		   -regenerateFiles $regenerateFiles } result] {
        return -code error "$result"
    }
    if [catch {AbortControllaw -plane $plane } result] {
	return -code error "$result"
    }
    set interval 4
    set steps 20000
    if [catch {APSSRPrepareControllawOptions -config $config -steps $BPLD(ocSteps) -interval $BPLD(ocInterval) -deltaLimit 0.5} options] {
	return -code error "Error prepare controllaw option: $options"
    }
  
    if [exec cavget -list=$runControlPV.RUN -pend=30] {
        if [catch {AbortControllaw -plane $plane } result] {
            return -code error "$result"
        }
    }
    
    if {0} {
	if [catch {exec logMessage -sourceId=offsetMeasurement \
                 -tag=Instance $runControlPV -tag=Action Start \
		   } result ] {
	    APSAlertBox .alert -errorMessage "error with logMessage: $result"
	    return -code error "Error!"
	}
    }
    
    global controllawDone
    set controllawDone 0
    set abortComm "AbortControllaw -plane $plane"
    APSExecLog $widget -width 95 \
	-name "SR ${plane}-orbit correction for $plane ID-BPLD validation" \
	-unixCommand "sddscontrollaw  $options" \
	-abortCallback $abortComm \
	-cancelCallback $abortComm
    
}

proc AbortControllaw {args} {
    set plane ""
    APSParseArguments {plane}
    SetStatus "aborting $plane controllaw..."
    switch $plane {
        h -
	x {
            set runControlPV S:RC:OrbitControlLawXC
        }
        v -
	y {
            set runControlPV S:RC:OrbitControlLawYC
        }
        default {
            return -code error "plane should be h or v!"
        }
    }
    
    if [catch {exec cavget -list=${runControlPV}.RUN } running] {
	return -code error "Error readding $plane runControlPV: $result"
    }
    if !$running {
	exec cavput -list=${runControlPV}.CLR=1
	SetStatus "$plane controllaw is not running."
	return
    }
    SetStatus "Aborting $plane controllaw ($runControlPV)..."
    if [catch {exec cavput -list=${runControlPV}.ABRT=1 } result] {
	return -code error "Error abort $plane controllaw: $result"
    }
    exec cawait -waitFor=${runControlPV}.RUN,equalTo=0
    exec cavput -list=${runControlPV}.CLR=1
    SetStatus "$plane controllaw aborted."
    if {0} {
    if [catch {exec logMessage -sourceId=offsetMeasurement \
                 -tag=Instance $runControlPV -tag=Action Abort \
             } result ] {
        APSAlertBox .alert -errorMessage "error with logMessage: $result"
        return -code error "Error!"
    }
    }
}

proc CreateBump {args} {
    set plane ""
    set amp 1
    APSParseArguments {plane amp}
    global BPLD
		
    if ![string length $plane] {
	set plane $BPLD(plane)
    }
    SetStatus "plane: $plane"
    switch $plane {
	h -
	x {
	    set runControlPV S:RC:OrbitControlLawXC 
	    set coord x
	    set plane0 x
	}
	v -
	y {
	    set runControlPV S:RC:OrbitControlLawYC
	    set coord y
	    set plane0 y
	    if {$BPLD(window)=="Both"} {
		#y plane does not have both window shape
		set BPLD(window) Diamond
	    }
	}
	default {
	    return -code error "plane should be h or v!"
	}
    }
    SetStatus "Plane: $plane0"
    	      
    set val [expr abs($amp)*1.0]
    if {$val>0} {
	SetStatus "check if controllaw running..."
	if [catch {exec cavget -list=${runControlPV}.RUN } running] {
	    return -code error "Error readding $plane runControlPV: $result"
	}
	if !$running {
	    return -code error "$plane controllaw is not running."
	}
    } else {
	SetStatus "zero setpoints..."
	set bpmList [GetBPMList]
	if [catch {APScavput -list=[join $bpmList ,] -list=:$coord:SetpointC=0 -pend=10} result] {
	    return -code error "Error zero setpoints: $result"
	}
	return
    }
    set sectors 0
    set direction 1
    set sectorList [GetBPLDSectorList]
			
    if ![llength $sectorList] {
	SetStatus "No ID chosen!"
	return
    }
    
    foreach sectorf $sectorList {
	set sector [scan $sectorf %ld]
	set BPLD(S$sectorf.done) 0
	if [llength $BPLD(S$sectorf.IDList)]==2 {
	    set ID both
	} else {
	    set ID $BPLD(S$sectorf.IDList)
	}
	if [expr $sectors%2] {
	    set direction -1
	} else {
	    set direction 1
	}
	set command "/home/helios/SHANG/oag/apps/src/tcltkapp/oagapp/SRBPLD_ID_Bump -sector $sector -plane $plane -ID $ID -window $BPLD(window) -IDL $BPLD(IDL) -testType orbit-bump -direction $direction -BPMconfig $BPLD(BPM) -beam $BPLD(beam) -ID1exist $BPLD(S$sector.ID1exist) -ID2exist $BPLD(S$sector.ID2exist) -fastAbort 1 -tolerance $BPLD(tolerance)"
	APSExecLog .s$sector -width 80 -lineLimit 1048 -name "Create bump for $BPLD(S$sectorf.realIDList) in $plane plane." \
	    -unixCommand "$command" \
	    -callback "set BPLD(S$sector.done) done;SetStatus \"Limits validation for $BPLD(S$sectorf.realIDList) in $plane plane done.\"" \
	    -abortCallback "set BPLD(S$sector.done) aborted;SetStatus \"Limits validation for $BPLD(S$sectorf.realIDList) in $plane plane aborted.\"" \
	    -cancelCallback "set BPLD(S$sector.done) canceledSetStatus \"Limits validation for $BPLD(S$sectorf.realIDList) in $plane plane  cancelled.\";"
    }
}

proc CreateOCWidget {args} {
    set parent ""
    APSParseArguments {parent}
    global BPLD
    set BPLD(currLimitH) 2
    set BPLD(currLimitV) 2
    set BPLD(ocInterval) 4
    set BPLD(ocSteps) 10000
    
    APSRadioButtonFrame .bpm -parent $parent -label "BPMs:  " -buttonList {"Default Config" "All P0s" "All P1s" "UpP0 DownP1" "UpP1 DownP0"} \
	-orientation horizontal -variable BPLD(BPM) -valueList {default UpP0DownP0 UpP1DownP1 UpP0DownP1 UpP1DownP0}
    APSFrame .f0 -parent $parent -packOption "-side top"
    $parent.f0.frame configure -bd 0
    APSButton .adjust -parent $parent.f0.frame -text "BPM Adjust ADT" -command "BringUpADT -type adjust"
    APSButton .offset -parent $parent.f0.frame -text "BPM Setpoint ADT" -command "BringUpADT -type setpoint"
    APSButton .error -parent $parent.f0.frame -text "BPM Error ADT" -command "BringUpADT -type error"

    #make OC widget
    set wList [APSTabFrame .tab -parent $parent -labelList "Horizontal Vertical" -label "" -height 150 -width 500]
    set w1 [lindex $wList 0]
    set w2 [lindex $wList 1]
    MakeConfigWidget -plane h -parent $w1
    MakeConfigWidget -plane v -parent $w2

    APSLabeledEntry .currlimit -parent $w1 -label "DCCT current limit (mA):" -width 20 -textVariable BPLD(currLimitH)
    APSLabeledEntry .currlimit -parent $w2 -label "DCCT current limit (mA):" -width 20 -textVariable BPLD(currLimitV)
    APSLabeledEntry .interval -parent $w1 -label "Orbit Correction Interval(seconds):" -width 20 -textVariable BPLD(ocInterval)
    APSLabeledEntry .interval -parent $w2 -label "Orbit Correction Interval(seconds):" -width 20 -textVariable BPLD(ocInterval)
    APSLabeledEntry .steps -parent $w1 -label "Orbit Correction Steps:" -width 20 -textVariable BPLD(ocSteps)
    APSLabeledEntry .steps -parent $w2 -label "Orbit Correction Steps:" -width 20 -textVariable BPLD(ocSteps)
    
    
    APSButton .gen -parent $w1 -text "GENERATE" \
      -command "GenerateControllawFiles -plane h -regenerateFiles 1"\
      -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."

    APSButton .start -parent $w1 -text "RUN" \
	-command "StartControllaw -plane h" \
	-contextHelp "Press to start orbit correction using the above correction configuration in h plane."
    APSButton .abort -parent $w1 -text "ABORT" \
	-command "AbortControllaw -plane h" \
	-contextHelp "Press to orbit orbit correction in h plane."
    APSButton .bump -parent $w1 -text "Make Bump" -command "CreateBump -plane h -amp 1"
    APSButton .restore -parent $w1 -text "Zero Bump" -command "CreateBump -plane h -amp 0"
    APSButton .info -parent $w1 -text "Info" -command "ControllawInfo -plane h"
   # APSButton .check -parent $w1 -text "Check Orbit" -command "CheckOrbit -plane h"
    
    APSButton .gen -parent $w2 -text "GENERATE" \
	-command "GenerateControllawFiles -plane v -regenerateFiles 1"\
      -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."
    APSButton .start -parent $w2 -text "RUN" \
      -command "StartControllaw -plane v" \
      -contextHelp "Press to start orbit correction using the above correction configuration in v plane."
    APSButton .abort -parent $w2 -text "ABORT" \
      -command "AbortControllaw -plane v" \
      -contextHelp "Press to orbit orbit correction in v plane"
    APSButton .bump -parent $w2 -text "Make Bump" -command "CreateBump -plane v -amp 1"
    APSButton .zero -parent $w2 -text "Zero Bump" -command "CreateBump -plane v -amp 0"
     APSButton .info -parent $w2 -text "Info" -command "ControllawInfo -plane v"
    #APSButton .check -parent $w2 -text "Check Orbit" -command "CheckOrbit -plane v"
}


proc GetBPMList {args} {
    global BPLD
    if {$BPLD(BPM)=="default"} {
	#use default config
	set configFile  $BPLD(configDir)/IDconfig.sdds
    } else {
	set configFile $BPLD(configDir)/BPLDConfig-ID$BPLD(BPM).sdds
    }
    
    set BPLDsectorList [GetBPLDSectorList]
    if ![llength $BPLDsectorList] {
	SetStatus "No IDs chosen!"
	return
    }
    set BPMList ""
    foreach sectorf $BPLDsectorList {
	set sector [scan $sectorf %ld]
	if [catch {exec sddsprocess $configFile -pipe=out -filter=col,IDBPM,1,1 \
		       -filter=col,BPLDSector,$sector,$sector \
		       | sdds2stream -pipe=in -col=DeviceName } bpmList] {
	    return -code error "Error getting ID bpms: $bpmList"
	}
	set BPMList [concat $BPMList [join $bpmList]]
    }
    SetStatus "$BPMList"
    return $BPMList
}

proc SetArchiveLog {args} {
    global BPLD
    set BPLD(mainDir) $BPLD(archiveDir)
    set BPLD(rootname) [clock format [clock seconds] -format %Y-%m%d]
}

set BPLD(mainDir) [APSGoToDailyDirectory -subdirectory IDBPLDValidation]
set BPLD(rootname) IDValidation
set BPLD(BPM) default
set BPLD(window) Both
set BPLD(plane) x
set BPLD(IDL) 5.571
set L(P0) 2.756
set L(P1) 3.213
set BPLD(IDL.P0) 2.756
set BPLD(IDL.P1) 3.213

APSApplication . -name SRIDBPLDFastAbortTest  \
  -overview "SRIDBPLDFastAbortTest provides convenience controls for ID BPLD fast abort validation."
APSScrolledStatus .status -parent .userFrame -width 80 \
        -textVariable status

set wList [APSTabFrame .tab -parent .userFrame -labelList "FastAbort OC_Setup" -width 700 -height 400]
set f1 [lindex $wList 0]
set f2 [lindex $wList 1]
CreateOCWidget -parent $f2

APSLabeledEntry .dir -parent $f1 -textVariable BPLD(mainDir) -width 65 \
    -label "Log Dir:"
APSButton .archive -parent $f1.dir -packOption "-side right" -text "archive" -size small -command \
    "SetArchiveLog"
APSButton .daily -parent $f1.dir -packOption "-side right" -text "daily" -size small \
    -command "set BPLD(mainDir) [APSGoToDailyDirectory -subdirectory IDBPLDFastAbort]; set BPLD(rootname) IDFastAbort"

MakeIDSelectionWidget .idchoice -parent $f1

APSFrameGrid .grid -parent $f1 -xList {x1 x2}
set w1 $f1.grid.x1
set w2 $f1.grid.x2

APSRadioButtonFrame .plane -parent $w1 -label "Plane: " -buttonList {x y} -valueList {x y} \
    -orientation horizontal -variable BPLD(plane) -commandList {"set BPLD(window) Both" "set BPLD(window) Diamond"}

APSLabeledEntry .tol -parent $w1 -label "Orbit tolerance(um):" -textVariable BPLD(tolerance) -width 15
APSRadioButtonFrame .win -parent $w2 -buttonList {Diamond Rect Both} -valueList {Diamond Rect Both} \
    -orientation horizontal -variable BPLD(window) -label "Window type:"

#APSButton .start -parent $f1 -text "START" -command StartValidation
APSFrame .f1 -parent $f1 
APSFrame .f2 -parent $f1
set w1 $f1.f1.frame
set w2 $f1.f2.frame
$w1 configure -bd 0
$w2 configure -bd 0


#APSButton .val2 -parent $w1 -text "BPLDArming Validation" -command "ValidateBPLDArming"
APSButton .gap -parent $w1 -text "Move Gap to 60mm" -command MoveGapTo60mm
APSButton .val3 -parent $w1 -text "FastAbort Test" -command "FastAbortTest"
APSButton .display -parent $w1 -text "Display Result" -command DisplayResult
APSButton .load -parent $w2 -text "Load Default Limits" -command LoadDefaultLimits
APSButton .clear -parent $w2  -text "Clear Faults" -command ClearFaults
APSButton .bpms -parent $w2 -text "Get BPMs" -command GetBPMList

#APSButton .plot -parent $f1 -text "Plot Archive" -command PlotArchive

proc PlotArchive {args} {
    global BPLD selectFile
    cd $BPLD(archiveDir)
    set files [glob -nocomplain *.sdds]
    if ![llength $files] {
	SetStatus "No data found."
	return
    }
    set selectFile ""
    APSScrolledListWindow .display -height 10 -name "Select File" -itemList $files  -selectionVar selectFile
    tkwait variable selectFile
    destroy .display
    if ![string length $selectFile] {
	SetStatus "No file is chosen."
	continue
    }
    if [file exist $selectFile] {
	DisplayResult -logFile $BPLD(archiveDir)/$selectFile
    }
    
}

proc LoadIDBPLDConfig {args} {
   
    global BPLD lab L
    if {$BPLD(BPM)=="default"} {
	#use default config
	set configFile  $BPLD(configDir)/IDconfig.sdds
    } else {
	set configFile $BPLD(configDir)/BPLDConfig-ID$BPLD(BPM).sdds
    }
  
    set tmpRoot /tmp/[APSTmpString]
    
    set pvList ""
    set valList ""
    APSAddToTmpFileList -ID bpld -fileList "$tmpRoot.1 $tmpRoot.load"
    foreach sectorf $BPLD(sectorList) {
	set sector [scan $sectorf %d]
	if [catch {exec sddsprocess $configFile -filter=col,BPLDSector,$sector,$sector -filter=col,IDBPM,0.5,1.5 $tmpRoot.1 } result] {
	    return -code error "Error process data for sector $sector: $result"
	}
	set bpmList [exec sdds2stream -col=DeviceName $tmpRoot.1]
	set indexList [exec sdds2stream -col=BPLDIndex $tmpRoot.1]
	for {set i 1} {$i<=4} {incr i} {
	    set bpm$i [lindex $bpmList [expr $i-1]]
	    set index$i [lindex $indexList [expr $i-1]]
	}

	lappend pvList S${sectorf}-LMPS:BPLD:ID1:BPM-XY1_idx-SP
	lappend valList $index1
	lappend pvList S${sectorf}-LMPS:BPLD:ID1:BPM-XY2_idx-SP
	lappend valList $index2
	lappend pvList S${sectorf}-LMPS:BPLD:ID2:BPM-XY1_idx-SP
	lappend valList $index3
	lappend pvList S${sectorf}-LMPS:BPLD:ID2:BPM-XY2_idx-SP
	lappend valList $index4

	lappend pvList S${sectorf}-LMPS:BPLD:ID1:S1-SP
	if [regexp {P0} $bpm1] {
	    lappend valList -$L(P0)
	} elseif [regexp {P1} $bpm1] {
	    lappend valList -$L(P1)
	} else {
	    return -code error "invalid bpm - $bpm1 found!"
	}
	lappend pvList S${sectorf}-LMPS:BPLD:ID1:S2-SP
	if [regexp {P0} $bpm2] {
	    lappend valList $L(P0)
	} elseif [regexp {P1} $bpm2] {
	    lappend valList $L(P1)
	} else {
	    return -code error "invalid bpm - $bpm2 found!"
	}
	
	lappend pvList S${sectorf}-LMPS:BPLD:ID2:S1-SP
	if [regexp {P0} $bpm3] {
	    lappend valList -$L(P0)
	} elseif [regexp {P1} $bpm3] {
	    lappend valList -$L(P1)
	} else {
	    return -code error "invalid bpm - $bpm3 found!"
	}
	lappend pvList S${sectorf}-LMPS:BPLD:ID2:S2-SP
	if [regexp {P0} $bpm4] {
	    lappend valList $L(P0)
	} elseif [regexp {P1} $bpm4] {
	    lappend valList $L(P1)
	} else {
	    return -code error "invalid bpm - $bpm4 found!"
	}
    }
   # puts $tmpRoot.load
    if [catch {exec sddsmakedataset -col=ControlName,type=string -data=[join $pvList ,] \
		   -col=ValueString,type=string -data=[join $valList ,] $tmpRoot.load } result] {
	return -code error "Error creating load file: $result"
    }
    
    if [catch {exec sddscasr -restore $tmpRoot.load} result] {
	return -code error "Error writing config to firmware: $result"
    }
    SetStatus "write InUse PVs..."
    if [catch {exec sddsconvert $configFile -pipe=out -del=col,ControlName \
		   | sddsprocess -pipe "-match=col,DeviceName=*P1,DeviceName=*P0,|" \
		   "-match=col,DeviceName=*C:P0,!" \
		   -edit=col,ControlName,DeviceName,ei/:MPS:idBPLD:InUse.RVAL/ -reprint=col,ValueString,0 \
		   | sddscasr -pipe=in -restore } result] {
	return -code error "Error writing inUse PVs1: $result"
    }
    if [catch {exec  sddsconvert $configFile -pipe=out -del=col,ControlName \
		   | sddsprocess -pipe \
		   "-match=col,DeviceName=*C:P0,!" \
		   -filter=col,IDBPM,0.5,1.5 \
		   -edit=col,ControlName,DeviceName,ei/:MPS:idBPLD:InUse.RVAL/ -reprint=col,ValueString,1 \
		   | sddscasr -pipe=in -restore } result] {
	return -code error "Error writing inUse PVs2: $result"
    }
    
    SetStatus "Current BPM configuration $BPLD(BPM) is loaded to firmware."
}

proc MoveGapTo60mm {args} {
    global BPLD
    set moved 0
    foreach ID $BPLD(IDList) {
	if !$BPLD($ID.var) {
	    continue
	}
	set sector [scan $ID ID%d]
	set sectorf [format %02d $sector]
	SetStatus "Moving $ID gaps to 60mn..."
	if [catch {exec cavput -list=S${sector}ID: -list=US,DS -list=ID:GapSetC=60 -blunder -pend=5 } result] {

	}
	after 1000
	if [catch {exec cavput -list=S${sector}ID: -list=US,DS -list=ID:StartC=1 -blunder -pend=5 } result] {
	    
	}
	set moved 1
    }
    if $moved {
	SetStatus "gaps are being moving to 60mm, it may take a while. "
    } else {
	SetStatus "No IDs chosen."
    }
}

proc MoveGapToBPLDTripLimits {args} {
    set moveTo ""
    set sector ""
    set timeout 300
    APSParseArguments {moveTo sector timeout}
    global BPLD env
    
    if {$sector==29}  {
	if {[string length $moveTo] && $moveTo<=48} {
	    set turnOff 0
	    set onoff on
	} else {
	    set turnOff 1
	    set onoff off
	}
	SetStatus "Turn $onoff IEX..."
	if [catch {TurnOnOffIEX -turnOff $turnOff } result] {
	    return -code error "Error turn $onoff IEX: $result"
	}
	return
    }
    if [catch {exec sddsprocess /home/helios/oagData/sr/IDs/devices.sdds -pipe=out -filter=col,Sector,$sector,$sector \
		   | sdds2stream -pipe -col=DeviceName } deviceList] {
	return -code error "Error getting ID devices: $deviceList"
    }
    set sectorf [format %02d $sector]
    SetStatus "ID$sectorf deviceList: $deviceList"
    
    if [catch {exec cavget -list=[join $deviceList ,] -list=:MotorDriveStatusM -printErrors -pend=10} valList] {
	return -code error "Error reading device status: $valList"
    }
    set moveList ""
    foreach device $deviceList val $valList {
	if $val {
	    lappend moveList $device
	}
    }
    if ![llength $moveList] {
	return -code error "Error: no device can be moved for ID$sectorf!"
    }
    if [catch {exec cavget -list=[join $moveList ,] -list=:AccessSecurityC -pend=10} valList] {
	return -code error "Error reading security mode: $valList"
    }
    foreach ID $moveList val $valList {
	if [string compare $val "System Manager"]==0 {
	    return -code error "$ID is in System Managet Mode, can not move it!"
	}
    }
    SetStatus "Moving $moveList gaps to $moveTo mm..."
    
    if [catch {exec cavput -list=[join $moveList ,] -list=:GapSetC=$moveTo -pend=10} result] {
	   return -code error "Error setting $moveList gap setpoint: $result"
    }
    if [catch {exec cavput -list=[join $moveList ,] -list=:StartC=1 -pend=10} result] {
	return -code error "Error moving gaps $moveList: $result"
    }
    
    APSInfoWindow .info -name "waiting for gap" -infoMessage "waiting for gap to stop moving! click OK when it is done." -width 50 \
	-modal 1
    SetStatus "Check gap status..."
    set gapList [regsub -all "ID:" $moveList "-LMPS:"]
    set timeout [expr $timeout + [clock seconds]]
    if {$moveTo>48} {
	set gapOpen 1
    } else {
	set gapOpen 0
    }
    while {[clock seconds]<$timeout} {
	set done 1
	if [catch {exec cavget -list=[join $gapList ,] -list=-GapStatus -num } valList] {
	    return -code error "Error reading gap status: $valList"
	}
	foreach val $valList {
	    if {$val!=$gapOpen} {
		set done 0
	    } 
	}
	if $done {
	    break
	}
	after 1000
    }
    if !$done {
	return -code error "[join $moveList] gaps did not reach target."
    } else {
	SetStatus "moving gaps done."	
    }
    return $moveList
}

proc WriteLogFileHeader {args} {
    set logFile ""
    APSStrictParseArguments {logFile}
    global BPLD
    
    if ![file exist $logFile] {
	#write header of logFile
	set BPLD(logID) [open $logFile a+]
	puts $BPLD(logID) "SDDS1"
	puts $BPLD(logID) "&column name=StartTime, type=string, &end"
	puts $BPLD(logID) "&column name=EndTime, type=string, &end"
	puts $BPLD(logID) "&column name=DoubleSector, type=long, &end"
	puts $BPLD(logID) "&column name=ID, type=string, &end"
	puts $BPLD(logID) "&column name=BPM, type=string &end"
	puts $BPLD(logID) "&column name=WindowShape, type=string, &end"
	puts $BPLD(logID) "&column name=Plane, type=string, &end"
	puts $BPLD(logID) "&column name=Result, type=string, &end"
	puts $BPLD(logID) "&data mode=ascii, no_row_counts=1, &end"
	exec chmod 777 $BPLD(logFile)
	flush $BPLD(logID)
    } else {
	set BPLD(logID) [open $logFile a+]
    }
}

proc FastAbortTest {args} {
    global BPLD env
    set sectorList [GetBPLDSectorList]
    if ![llength $sectorList] {
	SetStatus "No IDs chosen!"
	return
    }
    if [catch {CheckLinkError} result] {
	SetStatus "Error, $result found!"
	return
    }
    
    set logFile $BPLD(mainDir)/FastAbort.sdds
    set BPLD(logFile) $logFile
    WriteLogFileHeader -logFile $logFile
    #fastabort only run with offset
    if {$BPLD(window)=="Both" && $BPLD(plane)=="y"} {
	SetStatus "Either rectangular or diamond is valid window shape for y plane."
	return
    }

    if [catch {PrepareValidation} result] {
	return -code error "Error start OC for fast abort test: $result"
    }
    foreach ID $BPLD(IDList) {
	if !$BPLD($ID.var) {
	    continue
	}
	APSInfoWindow .info -name "Start" -infoMessage "Start fast abort test for $ID now?" \
	    -modal 1
	set sector [scan $ID ID%ld]
	SetStatus "Move ID gaps to BPLD trip limits..."
	
	if [catch {MoveGapToBPLDTripLimits -moveTo 48 -sector $sector} moveList] {
	    return -code error "Error moving ID gaps: $moveList"
	}
	SetStatus "running fast abort test for $ID ..."
	set sector1 [expr $sector+1]
	if {$sector==1} {
	    set sector0 40
	} else {
	    set sector0 [expr $sector-1]
	}
	if [expr $sector % 2] {
	    set ID0 ID2
	    set bpldSector $sector
	    set bpmList [list S[format %02d $sector]A:P0 S[format %02d $sector1]B:P0]
	} else {
	    set ID0 ID1
	    set bpldSector [expr $sector+1]
	    set bpmList [list S[format %02d $sector0]B:P0 S[format %02d $sector]A:P0]
	}
	set starttime [exec date]
	set command "/home/oxygen/SHANG/oag/apps/src/tcltkapp/oagapp/SRBPLD_ID_Bump -sector $bpldSector -plane $BPLD(plane) -ID $ID0 -bpmConfig $BPLD(BPM) -window $BPLD(window) -IDL $BPLD(IDL) -testType orbit -fastAbort 1 -beam real -tolerance $BPLD(tolerance)"
	set BPLD($ID.done) 0
	APSExecLog .s$sector -width 80 -lineLimit 1048 -name "Test $ID $BPLD(plane) plane Fast Abort" \
		   -unixCommand "$command" \
		   -callback "set BPLD($ID.done) done;SetStatus \"Fast Abort for $ID done\"" \
		   -abortCallback "set BPLD($ID.done) aborted;SetStatus \"Fast Abort for $ID aborted\"" \
		   -cancelCallback "set BPLD(S$sector.done) canceled;SetStatus \"Fast Abort for $ID cancelled\""
	tkwait variable BPLD($ID.done)
	
	set endtime [exec date]
	if [catch {APScavget -list=S-DCCT:CurrentM -pend=10 -printError} srCurrent] {
	    return -code error "Error reading SR current: $srCurrent"
	}
	if {$srCurrent<0.05} {
	    set result passed
	    SetStatus "$ID fast abort test passed"
	    $BPLD($ID.button) configure -bg green
	} else {
	    SetStatus "$ID fast abort test failed!"
	    set result failed
	    $BPLD($ID.button) configure -bg red
	}
	puts $BPLD(logID) "\"$starttime\" \"$endtime\" $bpldSector $ID \"[join $bpmList]\" $BPLD(window) $BPLD(plane) $result"
	set BPLD($ID.var) 0
	flush $BPLD(logID)
	if [catch {MoveGapToBPLDTripLimits -moveTo 140 -sector $sector} result] {
	    SetStatus "Error opening gaps: $result"
	}
    }
}

proc PrepareValidation {args} {
    global BPLD
    SetStatus "Load BPM configuration..."
    if [catch {LoadIDBPLDConfig} result] {
	return -code error "Error loading current ID-BPLD configuration: $result"
    }
    SetStatus "config loaded."
    switch $BPLD(plane) {
	x -
	h {
	    set plane h
	}
	y -
	v {
	    set plane v
	}
    }
    if {$BPLD(beam)=="Sim"} {
	return
    }
    if {1} {
	if {0} {
	    SetStatus "Generating controllaw files for $BPLD(plane) plane..."
	    if [catch {GenerateControllawFiles -plane $plane} result] {
		return -code error "Error generating controllaw files: $result"
	    }
	}
	SetStatus "Start $BPLD(plane) orbit correction..."
	if [catch {StartControllaw -plane $plane } result] {
	    return -code error "Error starting orbit correction: $result"
	}
    }
    
    APSInfoWindow .info -name "Inject Beam" -infoMessage "Please start controllaw and  inject the beam above 2mA, press OK when it is done!" \
	-modal 1
    SetStatus "check beam current..."
    if [catch {exec cavget -list=S-DCCT:CurrentM -pend=10 -printErrors} beam] {
	return -code error "Error reading beam current: $beam"
    }
    if {$beam<2} {
	#comment it out temporarily, should check it in real system with beam
	if ![APSYesNoPopUp "Beam current is less than 2mA, do you still want to continue?"] {
	    return -code error "beam current ($beam) is less than 2mA, ID-BPLD validation is prevented."
	}
    }
    
}

proc CreateLogRoot {args} {
    global BPLD
   
    set logRoot $BPLD(mainDir)/[clock format [clock seconds] -format %Y-%j-%m%d:%H%M%S]
    set BPLD(logRoot) $logRoot
    return $logRoot
}

proc TurnOnOffIEX {args} {
    set turnOff 1
    APSParseArguments {turnOff}
    if [catch {exec cavget  -list=S29ID:feedbackM.VAL -printErrors -pend=20 } msg] {
        return -code error "Error reading IEX status: $msg"
    }
    if {[string compare $msg "Ready"]!=0} {
        return -code error "Error: IEX is not Read!"
    }
    if [catch {exec cavget -list=S29ID:Main_on_offC.VAL -printErrors -pend=30} onoff] {
        return -code error "Error reading IEX state: $onoff"
    }
    if {$onoff=="Off"} {
	if $turnOff {
	    return
	}
        if [catch {exec cavput -list=S29ID:EnergySetC.VAL=3.8,S29ID:BxSetC.VAL=0,S29ID:BySetC.VAL=0 -pend=30 } result] {
            return -code error "Error seting IEX: $result"
        }
        after 1000
        SetStatus "Turning on IEX..."
        if [catch {exec cavput -list=S29ID:Main_on_offC.VAL=On -pend=30} result] {
            return -code error "Error turning on IEX: $result"
        }
        if [catch {exec cawait -waitFor=S29ID:feedbackM.VAL,sameas=Ready -timeLimit=180 } result] {
            return -code error "Error waiting for IEX to turn on : $result"
        }
        if [catch {exec cavget -list=S29ID:feedbackM.VAL -printErrors -pend=30} msg] {
            return -code error "Error reading ID29:feedback.VAL : $msg"
        }
        if {[string compare $msg "Ready"]!=0} {
            return -code error "IEX was not able to turn on!"
        }
    } else {
	if $turnOff {
	    if [catch {exec cavput -list=S29ID:EnergySetC.VAL=3.8,S29ID:BxSetC.VAL=0,S29ID:BySetC.VAL=0  -pend=30 } result] {
		return -code error "Error seting IEX: $result"
	    }
	    if [catch {exec cawait -waitFor=S29ID:EnergyM.VAL,lowerlimit=3.6,upperlimit=3.9 \
			   -waitFor=S29ID:BxRdbkM.VAL,lowerlimit=0,upperlimit=1 \
			   -waitFor=S29ID:ByRdbkM.VAL,lowerlimit=0,upperlimit=1 -and -and -timeLimit=180 } result] {
		return -code error "Error waiting for IEX energy to go down: $result"
	    }
	    after 1000
	    if [catch {exec cavput -list=S29ID:Main_on_offC.VAL=Off -pend=30} result] {
		return -code error "Error turning off IEX: $result"
	    }
	}
	return
    }
}

proc CheckIEXArming {args} {
    set turnOff 1
    APSParseArguments {turnOff}
    
    global BPLDArmingTripped logID
    
    if [catch {exec cavget  -list=ID29:feedback.VAL -printErrors -pend=20 } msg] {
        return -code error "Error reading IEX status: $msg"
    }
    if {[string compare $msg "Ready"]!=0} {
        return -code error "Error: IEX is not Read!"
    }
    if [catch {exec cavget -list=ID29:Main_on_off.VAL -printErrors -pend=30} onoff] {
        return -code error "Error reading IEX state: $onoff"
    }
    if {$onoff=="Off"} {
        if [catch {exec cavput -list=ID29:EnergySet.VAL=3.8,ID29:BxSet.VAL=0,ID29:BySet.VAL=0 -pend=30 } result] {
            return -code error "Error seting IEX: $result"
        }
        after 1000
        SetStatus "Turning on IEX..."
        if [catch {exec cavput -list=ID29:Main_on_off.VAL=On -pend=30} result] {
            return -code error "Error turning on IEX: $result"
        }
        if [catch {exec cawait -waitFor=ID29:feedback.VAL,sameas=Ready -timeLimit=180 } result] {
            return -code error "Error waiting for IEX to turn on : $result"
        }
        if [catch {exec cavget -list=ID29:feedback.VAL -printErrors -pend=30} msg] {
            return -code error "Error reading ID29:feedback.VAL : $msg"
        }
        if {[string compare $msg "Ready"]!=0} {
            return -code error "IEX was not able to turn on!"
        }
    }
    after 2000
    SetStatus "Checking IEX arming state..."
    #check arming status
    if [catch {exec cavget -list=S29BPLD: -list=CH1,CH2 -list=:IDgapBI.VAL -printErrors -num -pend=20 } valList] {
        return -code error "Error reading IEX arming state: $valList"
    }
    set v1 [lindex $valList 0]
    set v2 [lindex $valList 1]
    if {$v1==0 || $v2==0} {
        SetStatus "IEX arming validation failed."
        set BPLDArmingTripped(29) 0
        logData "29 0 \"Arming validation failed.\""
    } else {
        SetStatus "IEX arming validation success."
        set BPLDArmingTripped(29) 1
        logData "29 0 \"Arming validation passed.\""
    }
    if $turnOff {
        if [catch {exec cavput -list=ID29:EnergySet.VAL=3.8,ID29:BxSet.VAL=0,ID29:BySet.VAL=0 -pend=30 } result] {
            return -code error "Error seting IEX: $result"
        }
        if [catch {exec cawait -waitFor=ID29:Energy.VAL,lowerlimit=3.6,upperlimit=3.9 \
                     -waitFor=ID29:BxRdbk.VAL,lowerlimit=0,upperlimit=1 \
                     -waitFor=ID29:ByRdbk.VAL,lowerlimit=0,upperlimit=1 -and -and -timeLimit=180 } result] {
            return -code error "Error waiting for IEX energy to go down: $result"
        }
        after 1000
        if [catch {exec cavput -list=ID29:Main_on_off.VAL=Off -pend=30} result] {
            return -code error "Error turning off IEX: $result"
        }
    }
}

proc logData {text} {
    global logID logFile BPLD

    set mainDir $BPLD(archiveDir)
    set currDir [clock format [clock seconds] -format %Y-%j-%m%d]
    if ![file exist $mainDir/currDir] {
        exec mkdir -p $mainDir/currDir
	exec chmod 777 $mainDir/currDir
        set logFile $mainDir/currDir/[clock format [clock seconds] -format %Y-%j-%m%d:%H%M%S].log
        if [string length $logID] {
            close $logID
        }
        set logID [open $logFile a+]
    }
    if ![string length $logID] {
        set logFile $mainDir/currDir/[clock format [clock seconds] -format %Y-%j-%m%d:%H%M%S].log
        set logID [open $logFile a+]
    }
    puts $logID "[clock format [clock seconds] -format %H:%M%:S] $text"
    flush $logID
}


proc DisplayResult {args} {
    set logFile ""
    APSStrictParseArguments {logFile}
    global BPLD selectFile
    set logFile $BPLD(mainDir)/FastAbort.sdds
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddstimeconvert $logFile -pipe=out \
		    "-dateToTime=col,Time,StartTime,format=%a %b %d %H:%M:%S %Z %Y" \
		   | sddssort -pipe -col=Time,decreasing  \
		   | sddsprintout -pipe=in $tmpRoot.print "-title=Fast Abort Test Results:\n" \
		   -col=StartTime,format=%30s \
		   -col=DoubleSector,format=%02d -col=ID,format=%6s \
		   -col=BPM,format=%15s -col=WindowShape,format=%10s \
		   -col=Plane,format=%5s  -col=WindowShape,format=%10s \
		   -col=Result,format=%10s  } result] {
	return -code error "Error printing result: $result"
    }
    APSFileDisplayWindow [APSUniqueName .] -height 30  \
	-fileName $tmpRoot.print  -width 160  -deleteOnClose 1 
    return
}


proc CheckLinkError {args} {
    if [catch {exec cavget -num -list=S-MPS:MMPS:ReadyM -pend=5 -printError} mpsReady] {
	return -code error "Error reading MPS status : $mpsReady"
    }
    if $mpsReady {
	#ok, no need to check others
	return
    }
    if [catch {exec cavget -list=APSU:MMPS2:SysStatus_S16-Sts.BC,APSU:MMPS2:SysStatus_S16-Sts.BD,APSU:MMPS2:SysStatus_S0-Sts.BF,APSU:MMPS2:SysStatus_S0-Sts.BC -pend=10 } valList] {
	return -code error "Error reading Aurora link fault status: $valList"
    }
    set dcctLink [lindex $valList 0]
    set localM1Link [lindex $valList 1]
    set M1M2Link [lindex $valList 2]
    set BPMLink [lindex $valList 3]
    set errorList ""
    foreach name {dcct localM1 M1M2 BPM} {
	if [set ${name}Link] {
	    lappend errorList $name
	}
    }
    if [llength $errorList] {
	return -code error "[join $errorList ,] link fault"
    }
}

SetArchiveLog

