#!/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
set CVSRevisionAuthor "\$Revision: 1.0 $ \$Author: shang $"

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

set varList ""
set pvList ""
set sectorList ""
set badDevices [APSIDGetBadDeviceList -closeGap 1]

for {set sector 1} {$sector<36} {incr sector 1} {
    set sectorf [format %02d $sector]
    lappend IDBPLD(sectorList) $sectorf
    lappend IDBPLD(labelList) ID$sectorf
    #ID-BPLD double sector
    if [expr $sector % 2]==0 {
	set dsector [expr $sector+1]
	set ID ID1
    } else {
	set dsector $sector
	set ID ID2
    }
    set IDBPLD(S$sectorf.ID) $ID
    set IDBPLD(S$sectorf.dsector) [format %02d $dsector]
    set IDBPLD(S$sectorf.IDarmingPV) S[format %02d $dsector]-LMPS:SysStatus-I.B0
    set IDBPLD(S$sectorf.IDarming) 0
    lappend varList IDBPLD(S$sectorf.IDarming)
    lappend pvList S[format %02d $dsector]-LMPS:SysStatus-I.B0

  
    set IDBPLD(S$sectorf.arm) 0
    lappend varList IDBPLD(S$sectorf.arm)
    switch $ID {
	ID1 {
	    lappend pvList S[format %02d $dsector]-LMPS:SysStatus-I.B2
	}
	ID2 {
	    lappend pvList S[format %02d $dsector]-LMPS:SysStatus-I.B3
	}
    }
    #us gap and ds gap
    set IDBPLD(S$sectorf.usGap) Open
    set IDBPLD(S$sectorf.dsGap) Open
    lappend pvList  S${sectorf}-LMPS:USID-GapStatus
    lappend varList   IDBPLD(S$sectorf.usGap) 
    lappend pvList  S${sectorf}-LMPS:DSID-GapStatus
    lappend varList  IDBPLD(S$sectorf.dsGap)
    
    set usgap S${sectorf}ID:USID
    set dsgap S${sectorf}ID:DSID
    if {[lsearch -exact $badDevices $usgap]>=0 && [lsearch -exact $badDevices $dsgap]>=0} {
	set IDBPLD(S$sectorf.bad) 1
    } else {
	set IDBPLD(S$sectorf.bad) 0
    }
    set IDBPLD(S$sectorf.ID) $ID
}

proc MoveGaps {args} {
    global IDBPLD
    set moveTo 48
    set all 0
    APSStrictParseArguments {moveTo all}

    set sectorList ""
    for {set sector 1} {$sector<36} {incr sector} {
	set sectorf [format %02d $sector]
	if $all {
	    lappend sectorList $sectorf
	} else {
	    if $IDBPLD(S$sectorf.TripPending) {
		lappend sectorList $sectorf
	    }
	}
    }
    if ![llength $sectorList] {
	SetStatus "No IDs chosen."
	return
    }
    SetStatus "Moving gaps to $moveTo mm..."
    if [catch {exec cavput -list=S -list=[join $sectorList ,] -list=ID: -list=US,DS -list=ID:GapSetC=$moveTo \
		   -pend=5 -blunder } result] {
    }
    after 1000
    if [catch {exec cavput -list=S -list=[join $sectorList ,] -list=ID: -list=US,DS -list=ID:StartC=1 \
		   -pend=5 -blunder } result] {
    }
    if [lsearch -exact 29 $sectorList]>=0 {
	if {$moveTo<50} {
	    #turn on IEX
	    SetStatus "Turn on IEX..."
	    if [catch {TurnOnOffIEX  -turnonoff on} result] {
		return -code error "Error turn on IEX: $result"
	    }
	} else {
	    #turn off IEX
	    SetStatus "Turn off IEX..."
	    if [catch {TurnOnOffIEX  -turnonoff off} result] {
		return -code error "Error turn off IEX: $result"
	    }
	}
    }
    SetStatus "Moving gaps, it may take several minutes."
    return
    set sectorList [GetSectorList]
    if ![llength $sectorList] {
	SetStatus "No IDs are chosen to move."
	return
    }
    SetStatus "Moving gaps to $moveTo..."
    if [catch {MoveGapToBPLDTripLimits -moveTo $moveTo -sectorList $sectorList -statusCallback SetStatus} result] {
	return -code error "Error moving ID gaps: $result"
    }
    SetStatus "done."
}

set IDBPLD(armingVarList) $varList

if [pv linkw [join $varList] [join $pvList] 30] {
    puts stderr "Error link PVs: $errorCode"
    exit 1
}
pv getw $varList
update

set IDBPLD(IDchoice) Both
set IDBPLD(window) Both
set IDBPLD(plane) x
set IDBPLD(IDL) 5.571
set IDBPLD(tolerance) 100

proc KillExecWindows {args} {
    global execList
    foreach win $execList {
	if [winfo exist $win] {
	    destroy $win
	}
    }
    set execList ""
}

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

proc UpdateArmingState {args} {
    set sector ""
    set type arm
    APSParseArguments {sector type}
    global IDBPLD
    switch $type {
	arm {
	    if $IDBPLD(S$sector.$type) {
		set color red
	    } else {
		set color green
	    }
	}
	ds -
	us {
	    if {$IDBPLD(S$sector.${type}Gap)=="Open"} {
		set color green
	    } else {
		set color red
	    }
	}
    }
    $IDBPLD(S$sector.${type}but) configure -selectcolor $color
}

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

    global IDBPLD

    APSFrame $widget -parent $parent -label "ID arming states (red: armed, gap closed; green: not armed, gap open)" -packOption "-side top"
    set parent0 $parent 
    set parent $parent0$widget.frame
    
    frame $parent.f1
    set f1 $parent.f1
    pack $parent.f1 -side left 
    
    frame $f1.labels
    pack $f1.labels -side left
    label $f1.labels.l1 -text "Arm Status"
    pack $f1.labels.l1 -side bottom  -pady 1 -padx 1
    label $f1.labels.l2 -text "DS Gap" 
    pack $f1.labels.l2 -side bottom  -pady 1 -padx 1
    label $f1.labels.l3 -text "US Gap"
    pack $f1.labels.l3 -side bottom   -pady 1 -padx 1
    label $f1.labels.l4 -text "ID Sector"
    pack $f1.labels.l4 -side bottom  -pady 1 -padx 1

    foreach sector $IDBPLD(sectorList) {
	frame $parent.f1.s$sector
	set fn $parent.f1.s$sector
	pack $fn -side left
	
	checkbutton $fn.sum -text "" -width 0 -height 0 -relief flat 
	pack $fn.sum -side bottom -pady 0 -padx 0
	if $IDBPLD(S$sector.arm) {
	    set color red
	} else {
	    set color green
	}
	$fn.sum configure -selectcolor $color
	set IDBPLD(S$sector.armbut)  $fn.sum
	checkbutton $fn.id2 -text "" -width 0 -height 0 -relief flat 
	pack $fn.id2 -side bottom -pady 0 -padx 0
	switch $IDBPLD(S$sector.dsGap) {
	    Closed {
		set color red
	    }
	    Open {
		set color green
	    }
	}
	$fn.id2 configure -selectcolor $color
	set IDBPLD(S$sector.dsbut)  $fn.id2
	
	checkbutton $fn.id1 -text "" -width 1 -height 1 -relief flat 
	pack $fn.id1 -side bottom -pady 0 -padx 0
	switch  $IDBPLD(S$sector.usGap) {
	    Closed {
		set color red
	    }
	    Open {
		set color green
		}
	}
	$fn.id1 configure -selectcolor $color
	set IDBPLD(S$sector.usbut)  $fn.id1
	
	label $fn.label -text $sector -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
	pack $fn.label  -side bottom
    }
    
    
    APSFrame .but -parent $parent0 -packOption "-side top"
    APSButton .start -parent $parent0.but.frame -text "Start Arming Test" -command StartArmingTest
    APSButton .display -parent $parent0.but.frame -text "Display Result" -command "PrintArmingTestResult"
}

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

    global IDBPLD

    set IDBPLD(bpmConfig) default
    set IDBPLD(useLimit) high
    set IDBPLD(plane) x
    
    APSFrame $widget -parent $parent -label "" -packOption "-side top"
    set f0 $parent$widget.frame
    $f0 configure -bd 0
    set varList ""
    foreach sector $IDBPLD(sectorList) {
	set IDBPLD(S$sector.TripPending) 0
	lappend varList IDBPLD(S$sector.TripPending)
    }
    
    MakeIDSelectionWidget .idsector -parent $f0 -type TripPending
    APSRadioButtonFrame .bpm -parent $f0 -label "BPM Config: " \
	-buttonList {"Default Config" "All P0s" "All P1s" "UpP0 DownP1" "UpP1 DownP0"} \
	-valueList {default UpP0DownP0 UpP1DownP1 UpP0DownP1 UpP1DownP0} \
	-orientation horizonal -variable IDBPLD(bpmConfig) -contextHelp "select BPM config for ID-BPLD."
    APSRadioButtonFrame .plane -parent $f0 -label "Plane:      " -orientation horizontal -buttonList {x y} \
	-valueList {x y} -variable IDBPLD(plane) \
	-commandList {"set IDBPLD(window) Both" "set IDBPLD(window) Diamond"}
    set IDBPLD(window) Both
    APSRadioButtonFrame .win -parent $f0 -buttonList {Diamond Rect Both} \
	-valueList {Diamond Rect Both} \
	-orientation horizontal -variable IDBPLD(window) -label "Window type:"
    
    APSButton .start -parent $f0 -text "Start Trip Pending Test" -command StartTripPendingTest
    APSButton .display -parent $f0 -text "Display Result" -command "DisplayTripPendingResult"
    APSButton .clea -parent $f0 -text "Clear Faults" -command "ClearFaults"
    APSButton .load -parent $f0 -text "Load Default Limits" -command LoadLimits
    APSButton .kill -parent $f0 -text "Kill ExecLog Windows" -command  KillExecWindows
    APSFrame .f1 -parent $parent
    set f1 $parent.f1.frame
    APSButton .open -parent $f1 -text "Open All Gaps" -command "MoveGaps -moveTo 140 -all 1"
    APSButton .close1 -parent $f1 -text "Move All Gaps To 70mm" -command "MoveGaps -moveTo 70 -all 1"
    APSButton .close2 -parent $f1 -text "Move Selected Gaps to 48mm" -command "MoveGaps -moveTo 48 -all 0"
}

proc SelectFastAbortID {args} {
    set sector ""
    APSParseArguments {sector}
    global IDBPLD
    foreach s0 $IDBPLD(sectorList) {
	set IDBPLD(S$s0.FastAbort) 0
    }
    set IDBPLD(S$sector.FastAbort) 1
    set IDBPLD(fastAbortSector) $sector
}

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

    global IDBPLD
   
    APSFrame $widget -parent $parent -label "" -packOption "-side top"
    set f0 $parent$widget.frame
    $f0 configure -bd 0
    set IDBPLD(fastAbortSector) ""
    MakeIDSelectionWidget .idsector -parent $f0 -type FastAbort
   # APSRadioButtonFrame .sector -parent $f0 -label "Select ID-BPLD Sector:" -orientation horizontal -buttonList $IDBPLD(labelList) \
#	-valueList $IDBPLD(sectorList) \
#	-variable IDBPLD(fastAbortSector) -limitPerRow 7
    
    set IDBPLD(plane) x
    APSRadioButtonFrame .bpm -parent $f0 -label "BPM Config: " \
	-buttonList {"Default Config" "All P0s" "All P1s" "UpP0 DownP1" "UpP1 DownP0"} \
	-valueList {default UpP0DownP0 UpP1DownP1 UpP0DownP1 UpP1DownP0} \
	-orientation horizonal -variable IDBPLD(bpmConfig) -contextHelp "select BPM config for ID-BPLD."
    APSRadioButtonFrame .plane -parent $f0 -label "Plane:      " -orientation horizontal -buttonList {x y} \
	-valueList {x y} -variable IDBPLD(plane) \
	-commandList {"set IDBPLD(window) Both" "set IDBPLD(window) Diamond"}
    
    APSRadioButtonFrame .win -parent $f0 -buttonList {Diamond Rect Both} \
	-valueList {Diamond Rect Both} \
	-orientation horizontal -variable IDBPLD(window) -label "Window type:"
    
    APSButton .start -parent $f0 -text "Start Fast Abort Test" -command StartFastAbortTest
    APSButton .display -parent $f0 -text "Display Result" -command "DisplayFastAbortResult"
    APSButton .clea -parent $f0 -text "Clear Faults" -command "ClearFaults"
    APSButton .load -parent $f0 -text "Load Default Limits" -command LoadLimits

    APSFrame .f1 -parent $parent -label "ADTs"
    set w $parent.f1.frame
    APSButton .adjust -parent $w -text "BPM Adjust ADT" -command "BringUpADT -type adjust"
    APSButton .offset -parent $w -text "BPM Setpoint ADT" -command "BringUpADT -type setpoint"
    APSButton .error -parent $w -text "BPM Error ADT" -command "BringUpADT -type error"
    APSButton .info -parent $w -text "OC Info" -command ControllawInfo
}

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"
    }
    
    global IDBPLD
    switch $plane {
        h -
	x {
            set runControlPV S:RC:OrbitControlLawXC
	    set widget .xcontrollaw
	    set config h.BPLD-IDs
        }
        v -
	y {
            set runControlPV S:RC:OrbitControlLawYC
	    set widget .ycontrollaw
	    set config v.BPLD-IDs
        }
        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 \
		   -regenerateFiles $regenerateFiles } result] {
        return -code error "$result"
    }
    set interval 4
    set steps 20000
    if [catch {APSSRPrepareControllawOptions -config $config -steps $steps -interval $interval -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"
        }
    }
    
    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 {
	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."
}

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
}

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 StartFastAbortTest {args} {
    global IDBPLD
    set timestr  [clock format [clock seconds] -format %Y-%m%d:%H%M%S]
    set IDBPLD(startTime) $timestr
    set IDBPLD(fastAbortLogFile) $IDBPLD(archiveDir)/FastAbort/FastAbort.sdds
    set IDBPLD(fastAbortLogID) [WriteIDBPLDValidationLogFileHeader -logFile $IDBPLD(fastAbortLogFile)]
    
    set sector $IDBPLD(fastAbortSector)
    if ![string length $sector] {
	SetStatus "Please select one ID for fast abort test!"
	return
    }
    if {$IDBPLD(plane)=="y" && $IDBPLD(window)!="Diamond"} {
	SetStatus "Only diamond is valid window shape for y plane."
	return
    }
    if [catch {PrepareValidation -type FastAbort -sectorList $IDBPLD(fastAbortSector) -tripInhibit 0 } result] {
	return -code error "Error prepare validation for fast abort test: $result"
    }
    APSInfoWindow .info -name "Start" -infoMessage "Start fast abort test for ID$sector now?" \
	-modal 1
    SetStatus "Move ID gaps to BPLD trip limits..."
    if [catch {MoveGapToBPLDTripLimits -moveTo 48 -sectorList [scan $sector %ld] -statusCallback SetStatus} moveList] {
	return -code error "Error moving ID gaps: $moveList"
    }
    SetStatus "running fast abort test for ID$sector ..."
    set sector1 [scan $sector %d]
    if {$sector1==1} {
	set sector0 40
    } else {
	set sector0 [expr $sector1-1]
    }
    set sector2 [expr $sector1+1]
    set bpldSector $IDBPLD(S$sector.dsector)
    if [expr $sector1 % 2] {
	set bpmList [list S[format %02d $sector1]A:P0 S[format %02d $sector2]B:P0]
    } else {
	set bpmList [list S[format %02d $sector0]B:P0 S[format %02d $sector1]A:P0]
    }
    set starttime [exec date]
    SetStatus "start orbit correction for fast abort..."
    StartControllaw -plane x
    StartControllaw -plane y
    
    set command "/home/oxygen/SHANG/oag/apps/src/tcltkapp/oagapp/SRBPLD_ID_Bump -sector [scan $bpldSector %d] -plane $IDBPLD(plane) -ID $IDBPLD(S$sector.ID) -bpmConfig $IDBPLD(bpmConfig) -window $IDBPLD(window) -IDL $IDBPLD(IDL) -testType orbit -fastAbort 1 -tolerance $IDBPLD(tolerance)"
    set IDBPLD(S$sector.fastAbortDone) 0
    APSExecLog .s$sector -width 80 -lineLimit 1048 -name "Test ID$sector $IDBPLD(plane) plane Fast Abort" \
	-unixCommand "$command" \
	-callback "set IDBPLD(S$sector.fastAbortDone) done;SetStatus \"Fast Abort for ID$sector done\"" \
	-abortCallback "set IDBPLD(S$sector.fastAbortDone) aborted;SetStatus \"Fast Abort for ID$sector aborted\"" \
	-cancelCallback "set IDBPLD(S$sector.fastAbortDone) canceled;SetStatus \"Fast Abort for ID$sector cancelled\""
    tkwait variable IDBPLD(S$sector.fastAbortDone)
    set endtime [exec date]
    SetStatus "check beam current..."
    set tries 1
    while {$tries<3} {
	if [catch {exec cavget -list=S-DCCT:CurrentM  } current] {
	    return -code error "Error reading SR current: $current"
	}
	if {$current<0.5} {
	    break
	}
	after 3000
	incr tries
    }
    if [catch {exec cavget -list=S-DCCT:CurrentM  } current] {
	return -code error "Error reading SR current: $current"
    }
    if {$current<0.5} {
	SetStatus "Fast Abort test for ID$sector passed."
	set result passed
	set IDBPLD(S$sector.fastAbortResult) passed
    } else {
	SetStatus "Fast Abort test for ID$sector failed."
	set result failed
    }
    
    puts $IDBPLD(fastAbortLogID) "\"$starttime\" \"$endtime\" $bpldSector ID$sector \"[join $bpmList]\" $IDBPLD(window) $IDBPLD(plane) $result orbit-bump \"\""
    set IDBPLD(S$sector.fastAbort) 0
    $IDBPLD(S$sector.buttonFastAbort) configure -bg green
    
    flush $IDBPLD(fastAbortLogID)
    #SetStatus "opening gaps..."
    #if [catch {MoveGapToBPLDTripLimits -moveTo 140 -sector $sector} result] {
	#SetStatus "Error opening gaps: $result"
    #}
    SetStatus "done."
}

proc ClearFaults {args} {
    global IDBPLD
    if [catch {ClearBPLDFaults -type BM -sectorList $IDBPLD(sectorList) -statusCallback SetStatus} result] {
	return -code error "Error clear faults: $result"
    }
}

proc LoadLimits {args} {
    if [catch {LoadDefaultBPLDLimits -type BM -statusCallback SetStatus } result] {
	return -code error "Error loading limits: $result"
    }
}
proc WriteArmingLogFileHeader {args} {
    global  IDBPLD
    set logDir IDBPLD(archiveDir)/Arming
    if ![file exist $logDir] {
	exec mkdir $logDir
	exec chmod 777 $logDir
    }
    set logFile $logDir/$IDBPLD(armingRootname).sdds
    set IDBPLD(armingLogFile) $logFile
    if ![file exist $armingLogFile] {
	set IDBPLD(arminglogID) [open $IDBPLD(armingLogFile) a+]
	puts $IDBPLD(arminglogID) "SDDS1"
	puts $IDBPLD(arminglogID) "&column name=StartTime, type=string, &end"
	puts $IDBPLD(arminglogID) "&column name=EndTime, type=string, &end"
	puts $IDBPLD(arminglogID) "&column name=Sector, type=string, &end"
	puts $IDBPLD(arminglogID) "&column name=Result, type=string, &end"
	puts $IDBPLD(arminglogID) "&column name=FaultDesc, type=string, &end"
	puts $IDBPLD(arminglogID) "&data mode=ascii, no_row_counts=1, &end"
	exec chmod 777 $IDBPLD(armingLogFile)
	flush $IDBPLD(arminglogID)
    }
}

proc WriteArmingLogFile {args} {
    global IDBPLD
    set sectorList $IDBPLD(sectorList)
    foreach sector $sectorList {
	set valList ""
	lappend valList $IDBPLD(startTime)
	lappend valList $IDBPLD(endTime)
	lappend valList ID$sector
	lappend valList $IDBPLD(S$sector.armResult)
	lappend valList \"$IDBPLD(S$sector.armDesc)\"
	puts $IDBPLD(arminglogID) "[join $valList]"
    }
    flush $IDBPLD(arminglogID)
}

proc SetBMMask {args} {
    global IDBPLD
    set type Arming
    set sectorList ""
    APSParseArguments {type sectorList}
    
    SetStatus "Get BPMs..."
    if ![llength $sectorList] {
	set sectorList $IDBPLD(sectorList)
    }
    set gui 0
    set all 0
    switch $type {
	Arming {
	    set all 1
	}
	TripPending {
	    if {$IDBPLD(bpmConfig)=="all"} {
		set all 1
	    }
	}
	FastAbort {
	    set all 0
	}
    }
    if [catch {GetBPMs  -gui $gui -all $all} result] {
	return -code error "Error getting BM BPLD BPMs: $result"
    }
    set putList ""
    foreach sector $sectorList {
	lappend putList  S${sector}-LMPS:BPLD:BpmMask-SP=$IDBPLD(S$sector.mask)
    }
    SetStatus "Set BM masks for $sectorList..."
    if [catch {exec cavput -list=[join $putList ,] -pend=10} result] {
	return -code error "Error setting mask: $result"
    }
    SetStatus "done."
}

proc PrepareValidation {args} {
    set type Arming
    set tripInhibit 1
    set statusCallback SetStatus
    set sectorList ""
    APSParseArguments {type tripInhibit statusCallback sectorList}
    global IDBPLD

    #change the MPS access mode back to MPS testing mode
    if [catch {exec cavput -list=S-MPS:AccessType=0 -pend=5} result] {
	return -code error "Error changing MPS access mode to MPS testing: $result"
    }
    if [catch {SetupValidation -type ID -tripInhibit $tripInhibit -statusCallback $statusCallback -SimBeam 0} result] {
	return -code error "Error setup BPLD: $result"
    }
    if [catch {APScavget -list=APSU:MMPS2:ID:Thold-SP -pend=10} IDarming] {
	   return -code error "Error reading BM arming current: $IDarming"
    }
    APSInfoWindow .info -width 20 -infoMessage "Please inject beam to greater than $IDarming mA." -modal 1
    if [catch {exec cavget -list=S-DCCT:CurrentM  } current] {
	return -code error "Error reading SR current: $current"
    }
    if {$current<$IDarming && !$IDBPLD(scriptTest) } {
	return -code error "The SR current is $current, less than the ID arming current. can not arm BM-BPLD."
    }
    if [catch {APScavget -num -list=APSU:MMPS2:Beam_ID_Th-Sts -pend=10} armed] {
	return -code error "Error reading ID arming state: $armed"
    }
    if {!$armed  && !$IDBPLD(scriptTest) } {
	return -code error "ID arming test failed: the ID current is not armed!"
    }
    set dsectorList ""
    foreach sector $sectorList {
	set sector0 [scan $sector %d]
	if [expr $sector0 % 2] {
	    lappend dsectorList [format %02d $sector0]
	} else {
	    lappend dsectorList [format %02d [expr $sector0 - 1]]
	}
    }
    set dsectorList [lsort -unique $dsectorList]
    SetStatus "Enable ID-BPLD..."
    if [catch {APScavput -list=S -list=[join $dsectorList ,] -list=-LMPS:BPLD: -list=ID1,ID2 -list=_Enable-SP=1 -pend=10} result] {
	return -code error "Error enabling BM BPLD: $result"
    }
    #change the MPS Access Mode to "MPS testing" so that users can write to offset PVs
    if [catch {exec cavput -list=S-MPS:AccessType=0 -pend=5} result] {
	return -code error "Error changing MPS access mode: $result"
    }
    if [catch {exec cavput -list=S -list=[join $dsectorList ,] -list=-LMPS:BPLD: -list=ID1,ID2 -list=:AIOR- -list=H1,H2,V1,V2 \
		   -list=-SP=0 -pend=10 } result] {
	APSInfoWindow .info -width 20 -infoMessage "$result.\nPlease change the write permission of ID-BPLD BPM offsets." -modal 1
    }
    #check link error
    SetStatus "Check MPS link error..."
    if [catch {CheckMPSLinkError} result] {
	return -code error "Error check MPS link error: $result"
    }
}
    

proc StartArmingTest {args} {
    global IDBPLD
    foreach sector  $IDBPLD(sectorList) {
	if !$IDBPLD(S$sector.bad) {
	    lappend sectorList $sector
	} else {
	    SetStatus "ID$sector devices can not be closed, arming test is not available for it."
	}
    }
    set timestr  [clock format [clock seconds] -format %Y-%m%d:%H%M%S]
    set IDBPLD(armingRootname) BMArming-$timestr
    set IDBPLD(startTime) $timestr

    if [catch {PrepareValidation -type Arming -sectorList $IDBPLD(sectorList) } result] {
	return -code error "Error prepare validation for arming test: $result"
    }
    after 3000
    SetStatus "close gaps to 48mm..."
    if [catch {MoveGapToBPLDTripLimits -moveTo 48 -sectorList $IDBPLD(sectorList) -statusCallback SetStatus } result] {
	return -code error "Error closing ID gaps: $result"
    }
    
    after 3000
    #check arming state
    if [catch { CheckIDArming } result] {
	return -code error "ID arming test failed: $result"
    }
    set timestr  [clock format [clock seconds] -format %Y-%m%d:%H%M%S]
    set IDBPLD(endTime) $timestr
    WriteArmingLogFileHeader
    WriteArmingLogFile
    APSInfoWindow .info -width 20 -infoMessage "Please disable the trip inhibitor after arming test." -modal 1
    SetStatus "ID arming test done."
    SetStatus "Open gaps..."
    if [catch {MoveGapToBPLDTripLimits -moveTo 140 -sectorList $IDBPLD(sectorList) } result] {
	return -code error "Error closing ID gaps: $result"
    }
    set tmpRoot  /tmp/[APSTmpString]
    if [catch {exec sddsprintout $IDBPLD(armingLogFile) $tmpRoot.print -col=StartTime,format=%20s -col=EndTime,format=%20s \
		   -col=Sector,format=%6s -col=Result,format=%10s -col=FaultDesc,format=%30s } result] {
	return -code error "Error printing result: $result"
    }
    APSFileDisplayWindow [APSUniqueName .] -fileName $tmpRoot.print -height 30 -width 150 -deleteOnClose 1
}

proc CheckIDArming {args} {
    global IDBPLD
    set sectorList $IDBPLD(sectorList)
    SetStatus "check BM amring..."
    
    if [catch {APScavget -num -list=APSU:MMPS2:Beam_ID_Th-Sts -pend=10} armed] {
	return -code error "Error reading ID arming state: $armed"
    }
    if !$armed {
	SetStatus "ID current is not armed."
	return -code error "ID current is not armed."
    }
    pv getw $IDBPLD(armingVarList)
    update
    foreach sector $sectorList {
	if !$IDBPLD(S$sector.arm) {
	    SetStatus "S$sector ID is not armed."
	    set IDBPLD(S$sector.armResult) failed
	    set IDBPLD(S$sector.armDesc) "not armed"
	} else {
	    set IDBPLD(S$sector.armResult) passed
	    SetStatus "S$sector ID is armed."
	}
    }
}

proc PrintAmingTestResult {args} {
    global IDBPLD SelectFile
    cd $IDBPLD(archiveDir)/Arming
    set files [glob -nocomplain *Arming*.sdds]
    if ![llength $files] {
	SetStatus "No arming test files found."
	return
    }
    set files [lsort -decreasing $files]
    set SelectFile ""
    APSScrolledListWindow .process -name "Select a file" \
      -label "Select a file" \
      -itemList $files -selectionVar SelectFile
    tkwait variable SelectFile
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddsprintout $SelectFile $tmpRoot.print \
		   "-title=[string range [file root [file tail $SelectFile]] 0 7]  result" \
		   -col=StartTime,format=%20s \
		   -col=EndTime,format=%20s \
		   -col=Sector,format=%6s -col=Result,format=%10s -col=FaultDesc,format=%30s  } result] {
	return -code error "Error print result: $result"
    }
    APSFileDisplayWindow [APSUniqueName .] -height 30  \
	-fileName $tmpRoot.print  -width 140  -deleteOnClose 1
}

proc DisplayTripPendingResult {args} {
    global IDBPLD SelectFile
    cd $IDBPLD(archiveDir)/TripPending
    set files [glob -nocomplain *.tripPending]
    if ![llength $files] {
	SetStatus "No arming test files found."
	return
    }
    set files [lsort -decreasing $files]
    set SelectFile ""
    APSScrolledListWindow .process -name "Select a file" \
      -label "Select a file" \
      -itemList $files -selectionVar SelectFile
    tkwait variable SelectFile
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddsprintout $SelectFile $tmpRoot.print \
		   "-title=ID-BPLD trip pending test  result: $SelectFile" \
		   -col=Sector,format=%4s \
		   -col=ID,format=%10s \
		   -col=BPM,format=%35s \
		   -col=Plane,format=%2s \
		   -col=WindowShape,format=%15s \
		   -col=ValidationType,format=%6s \
		   -col=Result,format=%10s -col=FaultDesc,format=%30s  } result] {
	return -code error "Error print result: $result"
    }
    APSFileDisplayWindow [APSUniqueName .] -height 30  \
	-fileName $tmpRoot.print  -width 160  -deleteOnClose 1
}

proc DisplayFastAbortResult {args} {
    global IDBPLD
    set logFile $IDBPLD(archiveDir)/FastAbort/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=Sector,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
}

proc GetSectorList {args} {
    global IDBPLD
    set sectorList ""
    foreach sector $IDBPLD(sectorList) {
	if $IDBPLD(S$sector.TripPending) {
	    lappend sectorList $sector
	}
    }
    return $sectorList
}

proc ChangeBPMOffsets {args} {
    set sectorList ""
    APSParseArguments {sectorList}

    global IDBPLD
    set coord [string toupper $IDBPLD(plane)]
    
    #set offset to 0
    if [catch {exec cavput -list=S -list=[join $sectorList ,] -list=-LMPS:BM_ -list=X,Y -range=begin=1,end=28 -list=_Offset-SP=0 } result] {
	return -code error "Error clear offsets(ChangeBPMOffsets1): $result"
    }
    set type $IDBPLD(useLimit)
    foreach sector $sectorList {
	SetStatus "Changing S$sector $coord BPM offsets..."
	if [catch {exec cavget -list=S${sector}-LMPS:BM_TBT_${coord} -range=begin=1,end=28 -list=-I -pend=5 -printErrors} rawList] {
	    return -code error "Error reading BPM raw readings(ChangeBPMOffset2): $rawList"
	}
	if [catch {exec cavget -list=S${sector}-LMPS:BM_${coord} -range=begin=1,end=28 -list=_TH-SP -pend=5 -printErrors} limitList] {
	    return -code error "Error reading BPM limits(ChangeBPMOffset2): $limitList"
	}
	set putList ""
	set index 1
	foreach raw $rawList limit $limitList {
	    switch $type {
		high {
		    set s0 [expr $limit - $raw]
		}
		low {
		    set s0 [expr -1.0*$limit - $raw]
		}
	    }
	    set offset [expr -1.10*$s0]
	    lappend putList S${sector}-LMPS:BM_${coord}${index}_Offset-SP=$offset
	    incr index
	}
	if [catch {exec cavput -list=[join $putList ,] -pend=10 } result] {
	    return -code "Error changing BPM offsets (ChangeBPMOffset3): $result"
	}
    }
}

proc SelectAllIDs {args} {
    set type ""
    APSParseArguments {type}
    global IDBPLD
    foreach sector $IDBPLD(sectorList) {
	if !$IDBPLD(S$sector.bad) {
	    set IDBPLD(S$sector.$type) $IDBPLD(allIDs.$type)
	}
    }
}

proc MakeIDSelectionWidget {widget args} {
    set parent ""
    set type ""
    APSParseArguments {parent type}
    global IDBPLD
    switch $type {
	TripPending {
	    set text "Trip Pening Test ID Selection"
	}
	FastAbort {
	    set text "Fast Abort Test ID Selection"
	}
    }
    set w $parent$widget
    APSFrame $widget -parent $parent \
	-label "$text" \
	-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 $IDBPLD(sectorList) {
	set var IDBPLD(S$sectorf.$type)
	set $var 0
	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
	if {$type=="FastAbort"} {
	    set button [APSCheckButtonFrame .c$sectorf -parent $f -label "" \
			    -buttonList ID$sectorf -packOption "-side left" \
			    -variableList $var -commandList [list "SelectFastAbortID -sector $sectorf"] ]
	} else {
	    set button [APSCheckButtonFrame .c$sectorf -parent $f -label "" \
			    -buttonList ID$sectorf -packOption "-side left" \
			    -variableList $var]
	}
	set IDBPLD(S$sectorf.button$type) $button
	$button configure -bg grey90
	if $IDBPLD(S$sectorf.bad) {
	    $button configure -state disabled
	}
	incr j
    }
    if {$type=="TripPending"} {
	APSFrame .fn -parent $parent
	set w $parent.fn.frame
	$w configure -bd 0
	set IDBPLD(allIDs.$type) 0
	APSRadioButtonFrame .allnone -parent $w -label "" -buttonList {All None} -orientation horizontal \
	    -valueList {1 0} -variable IDBPLD(allIDs.$type) -commandList [list "SelectAllIDs -type $type" "SelectAllIDs -type $type"]
    }
}

proc StartTripPendingTest {args} {
    global IDBPLD
    set timestr  [clock format [clock seconds] -format %Y-%m%d:%H%M%S]
    set IDBPLD(startTime) $timestr
    set IDBPLD(tripPendingLogFile) $IDBPLD(archiveDir)/TripPending/${timestr}.tripPending
    set sectorList [GetSectorList]
    if ![llength $sectorList] {
	SetStatus "No IDs are chosen for trip pending test."
	return
    }
    set IDBPLD(logID) [WriteIDBPLDValidationLogFileHeader -logFile $IDBPLD(tripPendingLogFile)]
    if {$IDBPLD(window)!="Diamond" && $IDBPLD(plane)=="y"} {
	SetStatus "Only diamond is valid window shape for y plane."
	return
    }
    
    if [catch {PrepareValidation -type TripPending -sectorList $sectorList -tripInhibit 1 } result] {
	return -code error "Error prepare validation for trip pending: $result"
    }
    SetStatus "close gaps..."
    if [catch {MoveGapToBPLDTripLimits -moveTo 48 -sectorList $sectorList -statusCallback SetStatus} result] {
	return -code error "Error closing ID gaps: $result"
    }
    after 3000
    set doList ""
    set dsectorList ""
    for {set sector 1} {$sector<=35} {incr sector 2} {
	set sectorf [format %02d $sector]
	set IDchoice($sectorf.ID1) 0
	set IDchoice($sectorf.ID2) 0
    }
    foreach sector $sectorList {
	set sector0 [scan $sector %d]
	if [expr $sector0 % 2] {
	    set dsector [format %02d $sector0]
	    set IDchoice($dsector.ID2) 1
	} else {
	    set dsector [format %02d [expr $sector0+1]]
	    set IDchoice($dsector.ID1) 1
	}
	lappend dsectorList $dsector
    }
    global execList
    set execList ""
    set dsectorList [lsort -unique  $dsectorList]
    SetStatus "Starting trip-pending test..."
    foreach sectorf $dsectorList {
	set sector [scan $sectorf %d]
	set ID1 ID[format %02d [expr $sector -1]]
	set ID2 ID[format %02d $sector]
	if {$IDchoice($sectorf.ID1) && $IDchoice($sectorf.ID2)} {
	    set ID Both
	    set IDlabel "$ID1 $ID2"
	} elseif $IDchoice($sectorf.ID1) {
	    set ID ID1
	    set IDlabel $ID1
	} elseif $IDchoice($sectorf.ID2) {
	    set ID ID2
	    set IDlabel $ID2
	} else {
	    SetStatus "No ID (ID1/ID2) are available for sector $sector."
	    continue
	}
	set IDBPLD(S$sectorf.done) 0
	set command "/home/oxygen/SHANG/oag/apps/src/tcltkapp/oagapp/SRBPLD_ID_Bump -sector $sector -plane $IDBPLD(plane) -ID $ID  -BPMconfig $IDBPLD(bpmConfig) -window $IDBPLD(window) -logFile $IDBPLD(tripPendingLogFile) -testType offset -fastAbort 0 -direction 1  -tolerance $IDBPLD(tolerance)"
	APSExecLog .s$sector -width 80 -lineLimit 1048 -name "Test S$sectorf $IDBPLD(plane) $IDlabel" \
	    -unixCommand "$command" \
	    -callback "set IDBPLD(S$sectorf.done) done;SetStatus \"Trip-pending validation for S$sectorf $IDlabel done.\"" \
	    -abortCallback "set IDBPLD(S$sectorf.done) aborted;SetStatus \"Trip-pending validation for S$sector $IDlabel aborted.\"" \
	    -cancelCallback "set IDBPLD(S$sectorf.done) canceledSetStatus \"Trip-pending validation for S$sector $IDlabel cancelled.\";"
	lappend execList .s$sector
    }
    foreach sectorf $dsectorList {
	tkwait variable IDBPLD(S$sectorf.done)
    }
    
    set IDBPLD(endTime) [clock format [clock seconds] -format %Y-%m%d:%H%M%S]
    
    #change the MPS access mode back to operation mode
    if [catch {exec cavput -list=S-MPS:AccessType=1 -pend=5} result] {
	return -code error "Error changing MPS access mode to operation after trip pending test: $result"
    }
    SetStatus "pending trip test done."
}

proc WriteFastAbortTestLogFile {args} {
    global IDBPLD
    set logFile $IDBPLD(archiveDir)/FastAbort/FastAbort.sdds
    if [catch {WriteBMValidationLogFileHeader -logFile $IDBPLD(tripPendingLogFile) } logID] {
	return -code error "Error writing log file header for BM fast abort: $logID"
    }
    set sector $IDBPLD(fastAbortSector)
    
    set valList ""
    lappend valList $IDBPLD(startTime)
    lappend valList $IDBPLD(endTime)
    lappend valList S$sector
    lappend valList \"[join $IDBPLD(S$sector.bpmList)]\"
    lappend valList $IDBPLD(useLimit)
    lappend valList $IDBPLD(S$sector.fastAbortResult)
    lappend valList offset
    lappend valList \"$IDBPLD(S$sector.pendingMsg)\"
    puts $logID "[join $valList]"
    flush $logID
    close $logID
}

set IDBPLD(configDir) /home/helios/oagData/sr/BPLD/BPLD_Config
set IDBPLD(archiveDir) /home/helios/oagData/sr/BPLD/Validation/ID


APSApplication . -name "SRIDBPLDValidationNew" -version $CVSRevisionAuthor \
  -overview "SR BM BPLD arming, trip-pending and fast abort test" \
  -contextHelp "SR BM BPLD arming, trip pending and fast abort test ."
set status ""
set IDBPLD(SimBeam) 0

APSScrolledStatus .ss -parent .userFrame -textVariable status \
  -packOption "-side top -fill x" -height 10 -width 60 \
  -contextHelp "Provides execution status and operation hints."
SetStatus "Working..."
set dataDir [APSGoToDailyDirectory -subdirectory IDBPLD]
set IDBPLD(scriptTest) 0
APSLabeledEntry .dir -parent .userFrame -width 70 -textVariable IDBPLD(archiveDir) -label "Data directory:"
APSRadioButtonFrame .test -parent .userFrame -label "Script Test Only?" -buttonList {Yes No} \
    -valueList {1 0} -variable IDBPLD(scriptTest) -orientation horizontal

set wList [APSTabFrame .tab -parent .userFrame -labelList "Arming TripPending FastAbort" -width 1300 -height 400]
set w0 [lindex $wList 0]
set w1 [lindex $wList 1]
set w2 [lindex $wList 2]


MakeArmingWidget .arming -parent $w0
MakeTripPendingWidget .pending -parent $w1
MakeFastAbortWidget .abort -parent $w2


#monitor arming state
pv getw $varList
update

foreach sector $IDBPLD(sectorList) {
    if [pv umon IDBPLD(S$sector.arm) "UpdateArmingState -sector $sector -type arm"]!=0 {
	puts stderr "Error monitor arming status: $erroCode"
    }
    if [pv umon IDBPLD(S$sector.usGap) "UpdateArmingState -sector $sector -type us"]!=0 {
	puts stderr "Error monitor us gap  status: $erroCode"
    }
    if [pv umon IDBPLD(S$sector.dsGap) "UpdateArmingState -sector $sector -type ds"]!=0 {
	puts stderr "Error monitor ds gap  status: $erroCode"
    }
}

SetStatus "Note that these devices can not be closed: $badDevices"
foreach sector $IDBPLD(sectorList) {
    if $IDBPLD(S$sector.bad) {
	SetStatus "ID$sector validation can not be perform because the gaps can not be closed."
    }
}
