#!/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

APSApplication . -name SRDPBPLDVerificationBrief \
  -overview "SRBPLDVerificationBrief provides convenience controls for BPLD trip limit testing with both datapool and  workstation orbit correction."

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

proc SetDPBPLDStatus {text} {
    global DPBPLDStatus
    set DPBPLDStatus "[exec date] $text"
    update
}

proc BringUpBPLDMedm {args} {
    set sector ""
    APSParseArguments {sector}
    global offsetRead checked
    
    if $checked($sector) {
        set sector1 [expr $sector +1]
        exec medm -x -attach -dg +800+100 -macro "bpm=${sector}B,but=P1,id=$sector,label=upstream" /usr/local/iocapps/adlsys/srbpm/diagApp/dbpldDetail.adl &
        exec medm -x -attach -dg +1350+100 -macro "bpm=${sector1}A,but=P1,id=$sector,label=downstream" /usr/local/iocapps/adlsys/srbpm/diagApp/dbpldDetail.adl &   
        if $offsetRead {
            CheckBPLDSetpoints -sector $sector
        }
    }
}

proc CheckControllaw {args} {
    if [catch {APSCheckControllawRunning -config h.BPLDVerificationDP} hRunningDP] {
        return -code error "Error in check h plane controllaw): $hRunningDP"
    }
    if [catch {APSCheckControllawRunning -config v.BPLDVerificationDP} vRunningDP] {
        return -code error "Error in check v plane controllaw): $vRunningDP"
    }
    set dp 0
    if {$hRunningDP && $vRunningDP} {
        return 1
    }
    if !$dp {
        if [catch {APSCheckControllawRunning -config h.BPLDVerification} hRunning] {
            return -code error "Error in check h plane controllaw): $hRunning"
        }
        if [catch {APSCheckControllawRunning -config v.BPLDVerification} vRunning] {
            return -code error "Error in check v plane controllaw): $vRunning"
        }
        if {$hRunning && $vRunning} {
            return 0
        }
    }
    
    APSInfoWindow .info -name "Start BPPLVerification  orbit correction" -modal 1  \
      -infoMessage "Start DP or workstation BPLDVerification orbit correction for both plane.\nPress ok when it is done."
    while {1} {
        if [catch {APSCheckControllawRunning -config h.BPLDVerificationDP} hRunning] {
            return -code error "Error in check h plane controllaw): $hRunning"
        }
        if [catch {APSCheckControllawRunning -config v.BPLDVerificationDP} vRunning] {
            return -code error "Error in check v plane controllaw): $vRunning"
        }
        if {$hRunning && $vRunning} {
            return 1
        }
        if [catch {APSCheckControllawRunning -config h.BPLDVerification} hRunning] {
            return -code error "Error in check h plane controllaw): $hRunning"
        }
        if [catch {APSCheckControllawRunning -config v.BPLDVerification} vRunning] {
            return -code error "Error in check v plane controllaw): $vRunning"
        }
        if {$hRunning && $vRunning} {
            return 0
        }
        set answer [APSMultipleChoice .info -name "BPLDVerification controllaw not running" \
                      -question "BPLDVerification controllaw not running, pless Check-Again to check again or abort to abort the pem." -labelList {Check-Again Abort} \
                      -returnList {Check Abort} ]
        if {$answer=="Abort"} {
            return -code error "BPLD validation was aborted."
        }
        after 1000
    }
}

proc CheckCPUArming {args} {
    set turnOff 1
    APSParseArguments {turnOff}
    global BPLDArmingTripped logID
    
    if [catch {exec cavget  -list=ID04b:Ready -printErrors -pend=20 } on] {
        return -code error "Error reading CPU status: $on"
    }
    if {!$on} {
        if [catch {exec cavput -list=ID04b:set_H_coil.VAL=0,ID04b:set_V_coil.VAL=0 -pend=30 } result] {
            return -code error "Error seting CPU: $result"
        }
        after 1000
        SetDPBPLDStatus "Turning on CPU..."
        if [catch {exec cavput -list=ID04b:on_off.VAL=On -pend=30} result] {
            return -code error "Error turning on CPU: $result"
        }
        if [catch {exec cawait -waitFor=ID04b:Ready,equalTo=1 -timeLimit=180 } result] {
            return -code error "Error waiting for CPU to turn on: $result"
        }
        if [catch {exec cavget  -list=ID04b:Ready -printErrors -pend=20 } ready] {
            return -code error "Error reading CPU status: $ready"
        }
        if !$ready {
            return -code error "It was not able to turn on CPU."
        }
    }
    after 2000
    SetDPBPLDStatus "Checking IEX arming state..."
    #check arming status
    if [catch {exec cavget -list=S4BPLD: -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} {
        SetDPBPLDStatus "CPU arming validation failed."
        set BPLDArmingTripped(4) 0
        logData "4 0 \"Arming validation failed\""
    } else {
        SetDPBPLDStatus "CPU arming validation success."
        set BPLDArmingTripped(4) 1
        logData "4 1 \"Arming validation passed\""
    }
    if $turnOff {
        if [catch {exec cavput -list=ID04b:set_H_coil.VAL=0,ID04b:set_V_coil.VAL=0 -pend=30 } result] {
            return -code error "Error seting CPU: $result"
        }
       # if [catch {exec cawait -waitFor=ID04b:H_coil.VAL,equalTo=0 -waitFor=ID04b:V_coil.VAL,equalTo=0 -and -timeLimit=100 } result] {
       #     return -code error "Error waiting for H, V coil current to be zero: $result"
       # }
        after 1000
        if [catch {exec cavput -list=ID04b:on_off.VAL=Off -pend=30} result] {
            return -code error "Error turning off CPU: $result"
        }
    }

}

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
        SetDPBPLDStatus "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
    SetDPBPLDStatus "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} {
        SetDPBPLDStatus "IEX arming validation failed."
        set BPLDArmingTripped(29) 0
        logData "29 0 \"Arming validation failed.\""
    } else {
        SetDPBPLDStatus "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 TurnOnSCU {args} {
    set sector ""
    
    APSParseArguments {sector} 

    set sectorf [format %02d $sector]
    if [catch {exec cavget -list=ID${sectorf}ds:MainOn -printErrors -pend=10 } onoff] {
        return -code error "Error reading SCU $sector ds:MainOn: $onoff"
    }
    if {$onoff=="Off"} {
        #set desired current to 0, turn on SCU and check if it is alarmed.
        SetDPBPLDStatus "Set SCU $sector current to 0..."
        if [catch {exec cavput -list=ID${sectorf}ds:MainCurrentSet.VAL=0 -pend=10} result] {
            return -code error "Error setting SCU current to 0: $result"
        }
        SetDPBPLDStatus "Turn on SCU $sector ..."
        if [catch {exec cavput -list=ID${sectorf}ds:Main_OnOff=1 -pend=20} result] {
            return -code error "Error turning on SCU $sector: $result"
        }
        SetDPBPLDStatus "Wait for $sector SCU to turn on..."
        if [catch {exec cawait -waitFor=ID${sectorf}ds:MainOn,equal=1 -timeLimit=180 } result] {
            return -code error "Error waiting for $sector SCU to turn on: $result"
        }
        if [catch {exec cavget -list=ID${sectorf}ds:MainOn -printErrors -num -pend=20} onOff] {
            return -code error "Error reading SCU on/off state: $onOff"
        }
        if {!$onOff} {
            return -code error "$sector SCU is not turned on."
        }
    }
}

proc CheckSCUArming {args} {
    set scuList ""
    APSParseArguments {scuList} 
    global BPLDArmingTripped logID
    
    if ![llength $scuList] {
        return
    }
    set waitList ""
    set fList ""
    foreach sector $scuList {
        lappend fList [format %02d $sector]
    }
    if [catch {exec cavget -list=ID -list=[join $fList ,] -list=ds:MainOn -printErrors -pend=10 } onoffList] {
        return -code error "Error reading SCU $sector ds:MainOn: $onoff"
    }
    #check SCU arming
    foreach sector $scuList fsector $fList onoff $onoffList {
        if {$onoff=="On"} {
            #if it is on, the bpld should be alarmed
        } else {
            #set desired current to 0, turn on SCU and check if it is alarmed.
            SetDPBPLDStatus "Set SCU $sector current to 0..."
            if [catch {exec cavput -list=ID${fsector}ds:MainCurrentSet.VAL=0 -pend=10} result] {
                return -code error "Error setting SCU current to 0: $result"
            }
            SetDPBPLDStatus "Turn on SCU $sector ..."
            if [catch {exec cavput -list=ID[format %02d $sector]ds:Main_OnOff=1 -pend=20} result] {
                return -code error "Error turning on SCU $sector: $result"
            }
            lappend waitList $fsector
        }
    }
    if [llength $waitList] {
        SetDPBPLDStatus "Wait for [join $waitList] SCU to turn on..."
        foreach wait $waitList {
            if [catch {exec cawait -waitFor=ID${wait}ds:MainOn,equal=1 -timeLimit=180 } result] {
                return -code error "Error waiting for ID $wait SCU to turn on: $result"
            }
        }
        if [catch {exec cavget -list=ID -list=[join $waitList ,] -list=ds:MainOn -printErrors -num -pend=20} onList] {
            return -code error "Error reading SCU on/off state: $onList"
        }
        foreach val $onList id $waitList {
            if !$val {
                set on 0
                SetDPBPLDStatus "SCU $id not on yet -- something might be wrong with it."
            }
        }
    }
    SetDPBPLDStatus "Check arming status..."
   
    foreach sector $scuList {
        if [catch {exec cavget -list=S${sector}BPLD:CH -list=1,2 -list=:IDgapBI.VAL -num -printErrors -pend=20 } valList] {
            return -code error "Error reading SCU $sector arming state: $valList"
        }
        set v1 [lindex $valList 0]
        set v2 [lindex $valList 1]
        if {!$v1 || !$v2} {
            SetDPBPLDStatus "Error: SCU $sector not armed, arming validation failed!"
            set BPLDArmingTripped($sector) 0
            logData "$sector 0 \"Arming validation failed.\""
        } else {
            SetDPBPLDStatus "SCU $sector armed, arming validation success."
            set BPLDArmingTripped($sector) 1
            logData "$sector 1 \"Arming validation passed.\""
        }
    }
    SetDPBPLDStatus "Turn off SCU..."
    
    if [catch {exec cavput -list=ID -list=[join $fList ,] -list=ds:MainCurrentSet.VAL=0 -pend=20} result] {
        return -code error "Error setting SCU current to zero : $result"
    }
    after 1000
    if [catch {exec cavput -list=ID -list=[join $fList ,] -list=ds:Main_OnOff=0 -pend=20 } result] {
        return -code error "Error turning off SCU : $result"
    }
    after 2000
}

proc CheckTrip {args} {
    set sector ""
    set stream ""
    set type ""
    APSParseArguments {sector stream type}
    global BPLDLimitsTripped logID
    switch $stream {
        upstream {
            set sector1 $sector
            set bpm B:P1
        }
        downstream {
            set sector1 [expr $sector + 1]
            set bpm A:P1
        }
    }
    if [catch {exec cavget -list=S${sector1}${bpm} -list=:dbpld: -list=x,y -list=${type}BI.VAL -pend=30 -num } valList] {
        return -code error $valList
    }
    set tripped 1
    foreach val $valList plane {x y} {
        set BPLDLimitsTripped($sector.bpm.$plane) S${sector1}${bpm}:$plane
        set BPLDLimitsTripped($sector.$stream.$type.$plane) $val
        if !$val {
            set tripped 0
            logData "$sector 0 \"S${sector1}${bpm} $plane $stream limits validation failed."
        }
    }
    if $tripped {
        logData "$sector 0 \"limits validation passed."
    }
    return $tripped
}

proc ReValidateLimits {args} {
    set sectorList ""
    set percent 15
    set stream ""
    set type ""
    APSParseArguments {sectorList percent stream type}
    
    global rampSteps rampInterval abort dpWaitTime
    
    if ![llength $sectorList] {
        return 
    }
    set putList1 ""
    set pvList ""
    foreach sector $sectorList {
        switch $stream {
            upstream {
                set sector1 $sector
                set bpm S${sector1}B:P1
            }
            downstream {
                set sector1 [expr $sector + 1]
                set bpm S${sector1}A:P1
            }
        }
        global $bpm
        set xDelta [expr [set ${bpm}($stream.$type.xdelta)] * ($percent/100.0 + 1.0)]
        set yDelta [expr [set ${bpm}($stream.$type.ydelta)] * ($percent/100.0 + 1.0)]
        lappend putList1 ${bpm}:ms:x:SetpointAO=[format %.5f $xDelta]
        lappend putList1 ${bpm}:ms:y:SetpointAO=[format %.5f $yDelta]
    }
    
    if [catch {exec cavput -list=[join $putList1 ,] -deltaMode=factor=1 -pend=30} result] {
        return -code error "Error changing setpoints: $result"
    }
    for {set i 0} {$i<5} {incr i} {
        if $abort {
            catch {exec cavput  -list=[join $putList1 ,] -deltaMode=factor=-1 -pend=30 }
            set abort 0
            return -code error "Re-validate was aborted."
        }
        after 1000
        update
    }
    for {set i 0} {$i<$dpWaitTime} {incr i} {
        if $abort {
            catch {exec cavput  -list=[join $putList1 ,] -delta=factor=-1 -pend=30 }
            set abort 0
            return -code error "Re-validate was aborted."
        }
        if [catch {exec cavget -list=S35DCCT:currentCC -pend=10 -printErrors } current] {
            catch {exec cavput  -list=[join $putList1 ,] -delta=factor=-1 -pend=30 }
            return -code error "Error reading current: $current"
        }
        if {$current<20} {
            catch {exec cavput  -list=[join $putList1 ,] -delta=factor=-1 -pend=30 }
            return -code error "The SR current is too low, beam might be lost!"
        }
        
        set tripped 1
        set noTripList ""
        foreach sector $sectorList {
            if [catch {CheckTrip -sector $sector -stream $stream -type $type } trip] {
                catch {exec cavput  -list=[join $putList1 ,] -delta=factor=-1 -pend=30 }
                return -code error "Error reading current: $trip"
            }
            if !$trip {
                set tripped 0
                lappend noTripList $sector
            }
        }
                
        if $tripped {
            break
        } 
    }
    if !$tripped {
        SetDPBPLDStatus "[join $noTripList ,] not tripped at revalidation."
    }
    return $noTripList
}

set waitTime 40
set dpWaitTime 10
set rampSteps 5
set rampInterval 1
proc ValidateBPLDLimits {args} {
    global checked BPLDList downBPM upBPM percent waitTime dpWaitTime abort rampSteps rampInterval
    
    if [catch {CheckControllaw} result] {
        SetDPBPLDStatus "$result"
        return
    }
    if $result {
        set wait $dpWaitTime
    } else {
        set wait $waitTime
    }
    set dp $result
    set bpldList ""
    set Checked 0
    set selectedSectors ""
    foreach sector $BPLDList {
        if $checked($sector) {
            if [catch {CheckBPLDSetpoints -sector $sector -info 0} result] {
                return -code error "Error check BPLD setpoints: $result"
            }
            if $result {
                set answer [APSMultipleChoice [APSUniqueName .] -name Warning \
                              -type warning \
                              -question "ID $sector trip limit pending warning, would you like to continue validate it or skip?" \
                              -returnList {Continue Skip} -labelList {Continue Skip}]
                if {$answer=="Skip"} {
                    SetDPBPLDStatus "ID $sector has trip limit warning, skip valid this sector."
                    continue
                } else {
                    SetDPBPLDStatus "ID $sector has trip limit warning, continue anyway (may cause beam dump!!!)"
                }
            }
            set sector1 [expr $sector +1]
            set bpmList [list S${sector}B:P1 S${sector1}A:P1]
            lappend bpldList S${sector}B:P1
            lappend bpldList S${sector1}A:P1
            foreach bpm $bpmList  stream {upstream downstream} {
                foreach type {hi lo} {
                    # SetDPBPLDStatus "compute $sector $stream $type Limit ..."
                    if [catch {exec cavget -list=$bpm -list=:dbpld: -list=x,y -list=${type}AO,liveAI -pend=20 } valList] {
                        return -code error "Error reading $sector upstream ${type} limit pv values: $valLisst"
                    }
                    set xTarget [lindex $valList 0]
                    set xCurrent [lindex $valList 1]
                    set yTarget [lindex $valList 2]
                    set yCurrent [lindex $valList 3]
                    set xDelta [expr ($xTarget - $xCurrent)*($percent/100.0  + 1.0)]
                    set yDelta [expr ($yTarget - $yCurrent)*($percent/100.0 + 1.0)]
                    global $bpm
                    set ${bpm}($stream.$type.xdelta) [expr $xTarget - $xCurrent]
                    set ${bpm}($stream.$type.ydelta) [expr $yTarget - $yCurrent]
                    lappend putList($stream.$type) ${bpm}:ms:x:SetpointAO=[format %.5f $xDelta]
                    lappend putList($stream.$type) ${bpm}:ms:y:SetpointAO=[format %.5f $yDelta]
                }
            }
            incr Checked
            lappend selectedSectors $sector
        }
    }
   
    if !$Checked {
        SetDPBPLDStatus "No ID selected."
        return
    }
    #$putList(upstream.hi)
    #puts $putList(upstream.lo)
    #puts $putList(downstream.hi)
    #puts $putList(downstream.lo)
    
    if [catch {CreateLogRoot} logRoot] {
        return -code error "Error generating logRoot: $logRoot"
    }
    
    foreach stream {upstream downstream} {
        foreach type {hi lo} {
            if $abort {
                set abort 0
                SetDPBPLDStatus "aborted."
                return
            }
            SetDPBPLDStatus "Valid $stream $type Limit ..."
            SetDPBPLDStatus "setting [join $putList($stream.$type) ,] ..."
            if [catch {exec cavput -list=[join $putList($stream.$type) ,] -delta=factor=1 -ramp=steps=$rampSteps,pause=$rampInterval -pend=30} result] {
                catch {exec cavput -list=[join $putList($stream.$type) ,] -delta=factor=-1  }
                return -code error "Error changing setpoints: $result"
            }
            SetDPBPLDStatus "Waiting for orbit to converge..."
            for {set i 0} {$i<5} {incr i} {
                if $abort {
                    catch {exec cavput  -list=[join $putList($stream.$type) ,] -delta=factor=-1 -pend=30 }
                    set abort 0
                    SetDPBPLDStatus "aborted."
                    return
                }
                after 1000
                update
            }
            for {set i 0} {$i<$wait} {incr i} {
                if $abort {
                    catch {exec cavput  -list=[join $putList($stream.$type) ,] -delta=factor=-1 -pend=30 }
                    set abort 0
                    SetDPBPLDStatus "aborted."
                    return
                }
                if [catch {APScavget -list=S35DCCT:currentCC -pend=10 -printErrors } current] {
                    catch {exec cavput  -list=[join $putList($stream.$type) ,] -delta=factor=-1 -pend=30 }
                    return -code error "Error reading current: $current"
                }
                if {$current<15} {
                    SetDPBPLDStatus "The SR current is too slow, beam might be lost!"
                    return
                }
                
                set tripped 1
                set noTripList ""
                foreach sector $selectedSectors {
                   # set ${stream}${type}($sector) 1
                    if [catch {CheckTrip -sector $sector -stream $stream -type $type } trip] {
                        catch {exec cavput  -list=[join $putList($stream.$type) ,] -delta=factor=-1 -pend=30 }
                        return -code error "Error reading current: $trip"
                    }
                    if !$trip {
                        set tripped 0
                        lappend noTripList $sector
                    }
                }
                
                if $tripped {
                    break
                } 
            }
            SetDPBPLDStatus "restoring setpoint..."
            if [catch {exec cavput -list=[join $putList($stream.$type) ,] -delta=factor=-1  -pend=30} result] {
                return -code error "Error restoring setpoints: $result"
            }
            if $tripped {
                SetDPBPLDStatus "$stream $type tripped."
            } else {
                SetDPBPLDStatus "[join  $noTripList , ]  $stream $type not tripped."
                foreach times {first second} percent0 {5 10} {
                    set percent1 [expr $percent + $percent0]
                    SetDPBPLDStatus "change limit percent to ${percent1}% to revalidate  these no-tripped sectors at $times time."
                    if [catch {ReValidateLimits -sectorList $noTripList -percent $percent1 -stream $stream -type $type } noTripSectors] {
                        SetDPBPLDStatus "Error in revalidate at $times time: $noTripSectors"
                        return
                    }
                    if ![llength $noTripSectors] {
                        SetDPBPLDStatus "All sectors tripped at $times time revalidate."
                        break
                    } else {
                        set noTripList $noTripSectors
                        if {$times=="second"} {
                            SetDPBPLDStatus "[join $noTripSectors ,] $stream $type did not trip after two times try"
                        }
                    }
                }
                
            }
            SetDPBPLDStatus "waiting for orbit to converge..."
            for {set i 0} {$i<$wait} {incr i} {
                if $abort {
                    SetDPBPLDStatus "aborted."
                    set abort 0
                    return
                }
                after 1000
                update
            }
        }
    }
    global BPLDLimitsTripped
    set txtList ""
    set passList ""
    foreach sector $selectedSectors {
        set passed 1
        set text ""
        foreach stream {upstream downstream} st {us ds} {
            foreach type {hi lo} {
                foreach plane {x y} {
                    if {$BPLDLimitsTripped($sector.$stream.$type.$plane)==0 } {
                        set passed 0
                        append text "$BPLDLimitsTripped($sector.bpm.$plane) $type  limit failed;"
                    }
                }
            }
        }
        if $passed {
            set text "BPLD limits validation passed"
        }
        lappend txtList $text
        lappend passList $passed
    }
    if [catch {exec sddsmakedataset  $logRoot.BPLDLimits -col=IDSector,type=long -data=[join $selectedSectors ,] \
                 -col=ValidationResult,type=string "-data=[join $txtList ,]" -col=Passed,type=short -data=[join $passList ,] } result] {
        return -code error "Error creating trip limit result file: $result"
    }
    set printFile /tmp/[APSTmpString].print
    if [catch {exec sddsprintout $logRoot.BPLDLimits $printFile "-title=BPLD limits validation results" \
                 -col=IDSector,format=%03d -col=ValidationResult } result] {
        return -code error "Error printing BPLD limit tests result: $result"
    }
    APSFileDisplayWindow [APSUniqueName .] -height 30  \
	-fileName $printFile  -width 150  -deleteOnClose 1 
    SetDPBPLDStatus "done."
}

set specialSectors {1 6 29}
proc HeartBeatValidation {args} {
    global checked BPLDList downBPM upBPM percent waitTime dpWaitTime abort dsExist usExist scuSectorList 
    
    #need disable SR:DumpRecorder:Inhibit to be able to open gaps
    if [catch {exec cavput -list=SR:DumpRecorder:Inhibit=No -pend=10 } result] {
	return -code error "Error disabling dump recorder inhibit which is needed for opening gaps: $result"
    }
    SetDPBPLDStatus "moving selected gaps to above trip limit.."
    if [catch {MoveGapToBPLDTripLimits } result] {
        return -code error "$result"
    }

    if [catch {CheckControllaw} result] {
        SetDPBPLDStatus "$result"
        return
    }
    if $result {
        set wait $dpWaitTime
    } else {
        set wait $waitTime
    }
    set dp $result
    set sectorList ""
    foreach sector $BPLDList {
        if $checked($sector) {
            lappend sectorList $sector
        }
    }
    set sectors [llength $sectorList]
    set passList ""
    set txtList ""
    if [catch {CreateLogRoot} logRoot] {
        return -code error "Error creating logRoot: $result"
    }
    
    set orderList [shuffle $sectorList]
    
    SetDPBPLDStatus "The heart beat will be done in order: [join $orderList]"
    set index 0
    foreach sector $orderList {
        SetDPBPLDStatus "heart beat test for sector $sector ..."
        if {$sector==35} {
            set limit 68
        } else {
            set limit 56
        }
        set IDList ""
        set sectorf [format %02d $sector]
        if {$dsExist($sector) && $usExist($sector)} {
            set IDList "ID${sectorf}ds ID${sectorf}us"
        } elseif $dsExist($sector) {
            set IDList ID${sectorf}ds
        } elseif $usExist($sector) {
            set IDList ID${sectorf}us
        } else {
            if {$sector==29} {
                #turn on IEX and check arming
                if [catch {CheckIEXArming  -turnOff 0 } result] {
                    return -code error "Error turning on IEX and checking it arming state: $result"
                }
            } else {
                SetDPBPLDStatus "Something wrong with ID $sector, no us or ds gap found." 
                continue
            }
        }
        if [lsearch -exact $sector $scuSectorList]>=0 {
            #turn on scu before do heart beat valication
            if [catch {TurnOnSCU -sector $sector} result] {
                return -code error "Error turning on $sector SCU: $result"
            }
        }
        if {$sector==4} {
            #turn on CPU
            if [catch {CheckCPUArming -turnOff 0} result] {
                return -code error "Error turn on CPU for heart heat validation: $result"
            }
        }
        if [llength $IDList] {
            SetDPBPLDStatus "moving $IDList gap to 48mm..."
            if [catch {exec cavput -list=[join $IDList ,] -list=:GapSet.VAL=48 -pend=30} result] {
                return -code error "Error move $IDList : $result"
            }
            if [catch {exec cavput -list=[join $IDList ,] -list=:Start.VAL=1 -pend=30 } result] {
                return -code error "Error1 move $IDList : $result"
            }
            if [catch {APSMpCheckAndWaitForIDs -deviceList $IDList -tolerance 0.1 } result] {
                return -code error "Error in waiting $IDList : $result"
            }
        }
        
        set bpm S${sector}B:P1
        if [catch {APScavget -list=$bpm -list=:dbpld:x -list=hiAO,liveAI -pend=20 } valList] {
            return -code error "Error reading $sector upstream hi limit pv values: $result"
        }
        set xHi [lindex $valList 0]
        set xCurrent [lindex $valList 1]
        set delta [expr ($xHi - $xCurrent) * ($percent/100.0 + 1.0)]
        SetDPBPLDStatus "move $bpm top left exec cavput -list=$bpm:ms:x:SetpointAO=$delta -pend=20  -delta=factor=1 ..."
        if [catch {exec cavput -list=$bpm:ms:x:SetpointAO=$delta -pend=20  -delta=factor=1 } result] {
            catch {exec cavput -list=$bpm:ms:x:SetpointAO=$delta -pend=20  -delta=factor=-1 }
            return -code error "HeartBeatValidation1: $result"
        }
        SetDPBPLDStatus "wait  for heart beat status to become red..."
       
        for {set i 0} {$i<$wait} {incr i} {
            if $abort {
                set abort 0
                catch {APScavput -list=$bpm:ms:x:SetpointAO=$delta -pend=20  -delta=factor=-1}
                SetDPBPLDStatus "aborted."
                    return
            }
            if [catch {APScavget -list=${bpm}:dbpld:xheartBI.VAL -num -printErrors -pend=10} result] {
                catch {APScavput -list=$bpm:ms:x:SetpointAO=$delta -pend=20  -delta=factor=-1 }
                return -code error "Error reading $bpm heart beat status: $result"
            }
            if {$result==1} {
                break
            }
            after 1000
            update
        }
        
        if [catch {exec cavget -list=${bpm}:dbpld:xheartBI.VAL -num -printErrors -pend=10} result] {
            return -code error "Error reading heart beat status: $result"
        }
        
        if !$result {
            lappend passList 0
            lappend txtList "heart beat validation failed"
            SetDPBPLDStatus "$bpm not tripped at $percent percent."
            logData "$sector 0 \"heart beat validation failed\""
        } else {
            SetDPBPLDStatus "$bpm tripped at $percent percent."
            lappend passList 1
            lappend txtList "heart beat validation passed"
            logData "$sector 1 \"heart beat validation passed\""
        }
        SetDPBPLDStatus "Restore $bpm setpoint  cavput -list=$bpm:ms:x:SetpointAO=$delta -delta=factor=-1.0  ..."
        if [catch {exec cavput -list=$bpm:ms:x:SetpointAO=$delta -delta=factor=-1.0  -pend=20} result] {
            return -code error "Error restoring $bpm setpoint: $result"
        }
        SetDPBPLDStatus "Restore correctors..."
        if [catch {RestoreCorrectors } result] {
            return -code error "$result"
        }
        #stop opening gaps by mpsDump
        set checked($sector) 0
        incr index
        if {$index<$sectors} {
            #do not do it for last sector (since all validation is done)
            SetDPBPLDStatus "Stop opening other gaps and move them back to above trip limits."
            catch {StopOpenGaps -doneSector $sector}
        }
        
        if {$sector==29} {
            #turn off IEX for fill, ready for next one
            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
            if [catch {exec cavput -list=ID29:Main_on_off.VAL=Off -pend=30} result] {
                return -code error "Error turning off IEX: $result"
            }
        }
        if {$sector==4} {
            #turn off CPU for refill, get ready for next one
             if [catch {exec cavput -list=ID04b:set_H_coil.VAL=0,ID04b:set_V_coil.VAL=0 -pend=30 } result] {
                 return -code error "Error seting CPU: $result"
             }
             after 1000
             if [catch {exec cavput -list=ID04b:on_off.VAL=Off -pend=30} result] {
                 return -code error "Error turning off CPU: $result"
             }
        }
        #turn off other SCU
        if [lsearch -exact $sector $scuSectorList]>0 {
            #turn off SCU
            if [catch {exec cavput -list=ID[format %02d $sector]ds:MainCurrentSet.VAL=0 -pend=20} result] {
                return -code error "Error setting SCU current to zero : $result"
            }
            after 1000
            if [catch {exec cavput -list=ID[format %02d $sector]ds:Main_OnOff=0 -pend=20 } result] {
                return -code error "Error turning off SCU : $result"
            }
        }
            
        if {$index<$sectors} {
            while {1} {
                if $abort {
                    set abort 0
                    SetDPBPLDStatus "aborted."
                    return
                }
                if ![APSYesNoPopUp "S$sector heart beat validation done, are you ready to do next sector?"] {
                    after 1000
                } else {
                    break
                }
            }
        }
    }
    if [catch {exec sddsmakedataset  -pipe=out -col=IDSector,type=long -data=[join $orderList ,] \
                 -col=ValidationResult,type=string "-data=[join $txtList ,]" -col=Passed,type=short -data=[join $passList ,] \
        | sddssort -col=IDSector -numericHigh -pipe=in $logRoot.heartbeat } result] {
        return -code error "Error creating trip limit result file: $result"
    }
    set printFile /tmp/[APSTmpString]
    if [catch {exec sddsprintout $logRoot.heartbeat $printFile "-title=Heart beat validation results" \
                 -col=IDSector,format=%03d -col=ValidationResult } result] {
        return -code error "Error printing BPLD limit tests result: $result"
    }
    APSFileDisplayWindow [APSUniqueName .] -height 30  \
	-fileName $printFile  -width 100  -deleteOnClose 1 
    
    SetDPBPLDStatus "done."
}

proc StopOpenGaps {args} {
    set doneSector ""
    set waitTime 10
    APSParseArguments {doneSector waitTime} 
    #stop opening all other gaps except the doneSector
    
    set tmpRoot /tmp/[APSTmpString]
    SetDPBPLDStatus "Stop opening other gaps (except $doneSector)..."
    if [catch {exec sddsprocess /home/helios/oagData/sr/IDs/SetGapToBPLDTripLimits -pipe=out \
                 -filter=col,Sector,[expr $doneSector -0.5],[expr $doneSector + 0.5],!  \
                 | tee $tmpRoot.limit \
                 | sddsprocess -pipe -reedit=col,ControlName,%/GapSet.VAL/Stop.VAL/ -reprint=col,ValueString,1 \
                 | sddscasr -pipe=in -restore -pend=30 } result] {
        return -code error "Error stop gaps moving: $result"
    }
    
    if [catch {exec sddscasr -restore $tmpRoot.limit } result] {
        return -code error "Error restore gap limits: $result"
    }
    SetDPBPLDStatus "Move other gaps to above trip limit..."
    if [catch {MoveGapToBPLDTripLimits } result] {
        return -code error "Error moving gaps to above trip limit: $result"
    }
}

proc MakeSectorsTable {args} {
    global BPLDList
    global xHiAo xLoAO yHiAO yLoAO xHiAI xLoAI yHiAI yLoAI
    global xHiDownLoad xLoDownload yHiDownload yLoDownload LockStatus

    foreach sector $BPLDList {
        set sector1 [expr $sector + 1]
        set Bbpm S${sector}B:P1
        set Abpm S${sector1}A:P1
      #  puts "$sector1 $Bbpm $Abpm"
        if {[pv linkw \
            [list xHiAO(${sector}u) xLoAO(${sector}u) yHiAO(${sector}u) yLoAO(${sector}u) \
            xHiAI(${sector}u) xLoAI(${sector}u) yHiAI(${sector}u) yLoAI(${sector}u) \
            LockStatus(${sector}u) \
            xHiAO(${sector}d) xLoAO(${sector}d) yHiAO(${sector}d) yLoAO(${sector}d) \
            xHiAI(${sector}d) xLoAI(${sector}d) yHiAI(${sector}d) yLoAI(${sector}d) \
            LockStatus(${sector}d)] \
            [list ${Bbpm}:dbpld:xhiAO ${Bbpm}:dbpld:xloAO \
            ${Bbpm}:dbpld:yhiAO ${Bbpm}:dbpld:yloAO \
            ${Bbpm}:dbpld:xhiAI ${Bbpm}:dbpld:xloAI \
            ${Bbpm}:dbpld:yhiAI ${Bbpm}:dbpld:yloAI \
            ${Bbpm}:dbpld:xlockBI \
            ${Abpm}:dbpld:xhiAO ${Abpm}:dbpld:xloAO \
            ${Abpm}:dbpld:yhiAO ${Abpm}:dbpld:yloAO \
            ${Abpm}:dbpld:xhiAI ${Abpm}:dbpld:xloAI \
            ${Abpm}:dbpld:yhiAI ${Abpm}:dbpld:yloAI \
            ${Abpm}:dbpld:xlockBI ]] != 0} {
                APSAlertBox .alert -errorMessage "Problem with connecting with \
                  ${Bbpm}:dbpld:xhiAO ${Bbpm}:dbpld:xloAO \
                  ${Bbpm}:dbpld:yhiAO ${Bbpm}:dbpld:yloAO \
                  ${Bbpm}:dbpld:xlockBI \
                  ${Abpm}:dbpld:xhiAO ${Abpm}:dbpld:xloAO \
                  ${Abpm}:dbpld:yhiAO ${Abpm}:dbpld:yloAO \
                  ${Abpm}:dbpld:xlockBI:$errorCode"
                return 1
        }
        
        foreach channel {u d} {
            if {[pv umon xHiAO($sector$channel)] != 0} {
                APSAlertBox .alert -errorMessage "$errorCode"
                return 1
            }
            if {[pv umon xLoAO($sector$channel)] != 0} {
                APSAlertBox .alert -errorMessage "$errorCode"
                return 1
            }
            if {[pv umon yHiAO($sector$channel)] != 0} {
                APSAlertBox .alert -errorMessage "$errorCode"
                return 1
            }
            if {[pv umon yLoAO($sector$channel)] != 0} {
                APSAlertBox .alert -errorMessage "$errorCode"
                return 1
            }
            if {[pv umon xHiAI($sector$channel)] != 0} {
                APSAlertBox .alert -errorMessage "$errorCode"
                return 1
            }
            if {[pv umon xLoAI($sector$channel)] != 0} {
                APSAlertBox .alert -errorMessage "$errorCode"
                return 1
            }
            if {[pv umon yHiAI($sector$channel)] != 0} {
                APSAlertBox .alert -errorMessage "$errorCode"
                return 1
            }
            if {[pv umon yLoAI($sector$channel)] != 0} {
                APSAlertBox .alert -errorMessage "$errorCode"
                return 1
            }
        }
    }
}

set offsetRefFile  /home/helios/oagData/SCR/snapshots/SR/SR-BPMOffsetReference.gz
set offsetRead 0
proc ReadOffsets0 {args} {
    global offsetRefFile offsetRead xOffset yOffset xGain yGain BPLDList
    if !$offsetRead {
        SetDPBPLDStatus "Calculating trip limits from offsets..."
        # pick out the offsets related to the bpld bpms
        set tmpRoot /tmp/[APSTmpString]
        set gainRefFile /home/helios/oagData/SCR/snapshots/SBPMs/SBPMs-Preferred.gz
        foreach bpm {B:P1 A:P1} channel {u d} {
            foreach plane {x y} {
                if [catch {exec sddsprocess $offsetRefFile -pipe=out \
                             -match=col,ControlName=S*${bpm}:ms:$plane:OffsetAO \
                             | sddsprocess -pipe=in $tmpRoot.$bpm.$plane.offset \
                             -edit=col,DeviceName,ControlName,%/:ms:$plane:OffsetAO// } result] {
                    return -code error "Error1: $result"
                }
                if [catch {exec sddsprocess $gainRefFile -pipe=out \
                             -match=col,ControlName=S*${bpm}:ms:$plane:GainAO \
                             | sddsprocess -pipe=in $tmpRoot.$bpm.$plane.gain \
                             -edit=col,DeviceName,ControlName,%/:ms:$plane:GainAO// } result] {
                    return -code error "Error1: $result"
                }
                switch $channel {
                    u {
                        #downstream, sector 1 upstream bpm is S1B:P1
                        if [catch {exec sddsmakedataset -pipe=out -col=Sector,type=long -data=[join $BPLDList ,] \
                                     | sddsprocess -pipe -print=col,DeviceName,S%ld$bpm,Sector \
                                     | sddsxref -pipe=in $tmpRoot.$bpm.$plane.offset -match=DeviceName -fillIn \
                                     -take=ValueString $tmpRoot.$bpm.$plane.offset1 } result] {
                            return -code error "Error2: $result"
                        }
                        if [catch {exec sddsmakedataset -pipe=out -col=Sector,type=long -data=[join $BPLDList ,] \
                                     | sddsprocess -pipe -print=col,DeviceName,S%ld$bpm,Sector \
                                     | sddsxref -pipe=in $tmpRoot.$bpm.$plane.gain -match=DeviceName -fillIn \
                                     -take=ValueString $tmpRoot.$bpm.$plane.gain1 } result] {
                            return -code error "Error2: $result"
                        }
                    }
                    d {
                        #for downstream, sector 1 downstream bpm is S2A:P1
                        #downstream, sector 1 upstream bpm is S1B:P1
                        if [catch {exec sddsmakedataset -pipe=out -col=Sector,type=long -data=[join $BPLDList ,] \
                                     | sddsprocess -pipe "-redefine=col,Sector1,Sector 1 +,type=long" \
                                     | sddsprocess -pipe -print=col,DeviceName,S%ld$bpm,Sector1 \
                                     | sddsxref -pipe=in $tmpRoot.$bpm.$plane.offset -match=DeviceName -fillIn \
                                     -take=ValueString $tmpRoot.$bpm.$plane.offset1 } result] {
                            return -code error "Error2: $result"
                        }
                        if [catch {exec sddsmakedataset -pipe=out -col=Sector,type=long -data=[join $BPLDList ,] \
                                     | sddsprocess -pipe "-redefine=col,Sector1,Sector 1 +,type=long" \
                                     | sddsprocess -pipe -print=col,DeviceName,S%ld$bpm,Sector1 \
                                     | sddsxref -pipe=in $tmpRoot.$bpm.$plane.gain -match=DeviceName -fillIn \
                                     -take=ValueString $tmpRoot.$bpm.$plane.gain1 } result] {
                            return -code error "Error2: $result"
                        }
                    }
                }
                set sectors [exec sdds2stream -col=Sector $tmpRoot.$bpm.$plane.offset1]
                set offsets [exec sdds2stream -col=ValueString $tmpRoot.$bpm.$plane.offset1]
                
                foreach sector $sectors offset $offsets {
                    set ${plane}Offset(${sector}$channel) $offset
                }
                set sectors [exec sdds2stream -col=Sector $tmpRoot.$bpm.$plane.gain1]
                set gains [exec sdds2stream -col=ValueString $tmpRoot.$bpm.$plane.gain1]
                
                foreach sector $sectors gain $gains {
                    set ${plane}Gain(${sector}$channel) $gain
                }
            }
        }
        set fileList [glob $tmpRoot.*]
        eval file delete -force $fileList
    }
    set offsetRead 1
}

proc ReadOffsets {args} {
    global offsetRefFile offsetRead
    global BPLDList 
    global xLimit yLimit xLimitMax yLimitMax xScale yScale xOffset yOffset xGain yGain
    global xHiDownload xLoDownload yHiDownload yLoDownload 
    global xHiAO xLoAO yHiAO yLoAO xHiDiff xLoDiff yHiDiff yLoDiff

    ReadOffsets0
    # determine average of offset for each bpld bpm pair
    foreach sector $BPLDList {
        set x1Offset $xOffset(${sector}u)
        set x2Offset $xOffset(${sector}d)
        set x1gain $xGain(${sector}u)
        set x2gain $xGain(${sector}d)

        if {$x1gain>$x2gain} {
            set xCalibration $x1gain
        } else {
            set xCalibration $x2gain
        }
      
        set xHiDownload(${sector}u) [expr ($xLimit($sector) + $x1Offset) / $x1gain]
        if [expr $xHiDownload(${sector}u) > $xLimitMax] {
            set xHiDownload(${sector}u) $xLimitMax
        }
        set xLoDownload(${sector}u) [expr ($xLimit($sector) * -1 + $x1Offset) / $x1gain]
        if [expr $xLoDownload(${sector}u) < -$xLimitMax] {
            set xLoDownload(${sector}u) -$xLimitMax
        }
        set xHiDownload(${sector}d) [expr ($xLimit($sector) + $x2Offset) / $x2gain]
        if [expr $xHiDownload(${sector}d) > $xLimitMax] {
            set xHiDownload(${sector}d) $xLimitMax
        }
        set xLoDownload(${sector}d) [expr ($xLimit($sector) * -1 + $x2Offset) / $x2gain]
        if [expr $xLoDownload(${sector}d) < -$xLimitMax] {
            set xLoDownload(${sector}d) -$xLimitMax
        }
        set xHiDiff(${sector}u) [format %.7f [expr [set xHiAO(${sector}u)] - [set xHiDownload(${sector}u)]]]
        set xLoDiff(${sector}u) [format %.7f [expr [set xLoAO(${sector}u)] - [set xLoDownload(${sector}u)]]]
        set xHiDiff(${sector}d) [format %.7f [expr [set xHiAO(${sector}d)] - [set xHiDownload(${sector}d)]]]
        set xLoDiff(${sector}d) [format %.7f [expr [set xLoAO(${sector}d)] - [set xLoDownload(${sector}d)]]]
        
       
        set y1Offset $yOffset(${sector}u)
        set y2Offset $yOffset(${sector}d)
        set y1gain $yGain(${sector}u)
        set y2gain $yGain(${sector}d)
        
        if {$y1gain>$y2gain} {
            set yCalibration $y1gain
        } else {
            set yCalibration $y2gain
        }
        
        set yHiDownload(${sector}u) [expr ($yLimit($sector) + $y1Offset) / $y1gain]
        if [expr $yHiDownload(${sector}u) > $yLimitMax] {
            set yHiDownload(${sector}u) $yLimitMax
        }
        set yLoDownload(${sector}u) [expr ($yLimit($sector) * -1 + $y1Offset) / $y1gain]
        if [expr $yLoDownload(${sector}u) < -$yLimitMax] {
            set yLoDownload(${sector}u) -$yLimitMax
        }
        set yHiDownload(${sector}d) [expr ($yLimit($sector) + $y2Offset) / $y2gain]
        if [expr $yHiDownload(${sector}d) > $yLimitMax] {
            set yHiDownload(${sector}d) $yLimitMax
        }
        set yLoDownload(${sector}d) [expr ($yLimit($sector) * -1 + $y2Offset) / $y2gain]
        if [expr $yLoDownload(${sector}d) < -$yLimitMax] {
            set yLoDownload(${sector}d) -$yLimitMax
        }
        set yHiDiff(${sector}u) [expr [set yHiAO(${sector}u)] - [set yHiDownload(${sector}u)] ]
        set yLoDiff(${sector}u) [expr [set yLoAO(${sector}u)] - [set yLoDownload(${sector}u)] ]
        set yHiDiff(${sector}d) [expr [set yHiAO(${sector}d)] - [set yHiDownload(${sector}d)] ]
        set yLoDiff(${sector}d) [expr [set yLoAO(${sector}d)] - [set yLoDownload(${sector}d)] ]
    }
    foreach sector $BPLDList {
        CheckBPLDSetpoints -sector $sector
    }
    update
    SetDPBPLDStatus "Done."
}

proc CheckBPLDSetpoints {args} {
    global xHiDownload xLoDownload yHiDownload yLoDownload
    global xHiAO xLoAO yHiAO yLoAO
    global xHiAI xLoAI yHiAI yLoAI
    global checkButtonList
    global OffsetRead tolerance
    global xLoDiff xHiDiff yLoDiff yHiDiff BPLDList

    set sector ""
    set info 1
    APSParseArguments {sector info}
    set index [lsearch -exact $BPLDList $sector]
    set button [lindex $checkButtonList $index]
    set highlight 0
    foreach chan {u d} desc {upstream downstream} {
        set sector1 ${sector}$chan
        set outlimit 0
        foreach limit {xHi xLo yLo yHi} {
            set setpoint [subst \$${limit}AO($sector1)]
            set toDownload [subst \$${limit}Download($sector1)]
            set ${limit}Diff($sector) [format %.7f [expr $setpoint - $toDownload]]
            if [info exists ${limit}AI($sector1)] {
                set readback [subst \$${limit}AI($sector1)]
                if {[expr abs( $readback - $toDownload) > $tolerance] } {
                    set highlight 1
                    set outlimit 1
                }
            } 
            if {[expr abs( $setpoint - $toDownload ) > $tolerance] } {
                set highlight 1
                set outlimit 1
            }
        }
        if {$outlimit && $info} {
            APSInfoWindow .info$sector$chan -name "Warning: $sector $desc limit out of range" \
              -infoMessage "ID $sector $desc limit needs to be reload, click ok when reload is done." -modal 1
        }
    }
    
    if $highlight {
        $button configure -highlightbackground red
    } else {
        $button configure -highlightbackground white
    }
    return $highlight    
}

proc MoveGapToBPLDTripLimits {args} {
    set moveTo ""
    set sectorList ""
    APSParseArguments {moveTo sectorList}
    
    global BPLDList checked
    if [llength $sectorList] {
        set selectedSectors $sectorList
    } else {
        set selectedSectors ""
        foreach sector $BPLDList {
            if $checked($sector) {
                lappend selectedSectors $sector
            }
        }
        if ![llength $selectedSectors] {
            # SetDPBPLDStatus "no sectors selected."
            return
        }
    }
    
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddsmakedataset $tmpRoot.sector -col=Sector,type=long -data=[join $selectedSectors ,] } result] {
        return -code error "Error moving gaps1: $result"
    }
    if [catch {exec sddsselect /home/helios/oagData/sr/IDs/SetGapToBPLDTripLimits $tmpRoot.sector -reuse -equate=Sector $tmpRoot.move } result] {
        return -code error "Error moving gaps2: $result"
    }
    set rows [exec sdds2stream -rows=bar $tmpRoot.move]
    if !$rows {
        #no ID gap to move
        return
    }
    if [string length $moveTo] {
        if [catch {exec sddsprocess $tmpRoot.move -nowarnings -reprint=col,ValueString,$moveTo } result] {
            return -code error "Error moving gaps3: $result"
        }
    }
    
    SetDPBPLDStatus "Restore device values"
    set deviceList [exec sdds2stream -col=GapName $tmpRoot.move]
    
    if [catch {exec sddscasr -restore $tmpRoot.move } result] {
        APSMpReturn error "APSMpIDRestoreGapsFromSCR: $result"
    }
    
    after 1000
    if [catch {exec sddsprocess $tmpRoot.move -pipe=out -reedit=col,ControlName,%/:GapSet.VAL/:Start.VAL/ \
                 -reprint=col,ValueString,1 \
                 | sddscasr -pipe=in -restore -pend=30 } result] {
        return -code error "Error1: $result"
    }
    after 1000
    SetDPBPLDStatus "Waiting for ID gaps stop moving. (it may take several minutes, please be patient.)"
    if [catch {APSMpCheckAndWaitForIDs -deviceList $deviceList -timeout 500} results] {
        if {[APSPEMTKDialog .warningDialog -text "Problem1 occurred while waiting restoring ID gaps\n$results"] == 1} {
            return -code error "Error in checking ID gaps: $results"
        }
    }
    
    return
}

proc ValidateBPLDArming {args} {
    global checked BPLDList waitTime dpWaitTime abort dsExist usExist  BPLDArmingTripped
   
 
    SetDPBPLDStatus "moving selected gaps to above trip limit.."
    if [catch {MoveGapToBPLDTripLimits } result] {
        return -code error "$result"
    }
    SetDPBPLDStatus "clear arming..."
    if [catch {exec cavput -list=S -list=[join $BPLDList ,] -list=BPLD:ResetBO.VAL=1 -pend=30} result] {
        return -code error "Error clearning pending arms: $result"
    }
    set dsList ""
    set usList ""
    #set sectorList ""
    set usSectorList ""
    set dsSectorList ""
    set scuList ""
    global BPLDArmingTripped
    set selectedSectors ""
    foreach sector $BPLDList {
        set sectorf [format %02d $sector]
        if $checked($sector) {
            if $dsExist($sector) {
                lappend dsList ID${sectorf}ds
                lappend dsSectorList $sector
            }
            if $usExist($sector) {
                lappend usList ID${sectorf}us
                lappend usSectorList $sector
            }
            #lappend sectorList $sector
            if {$sector==1 || $sector==6 || $sector==7} {
                lappend scuList $sector
            }
            lappend selectorSectors $sector
            set BPLDArmingTripped($sector.ds) 1
            set BPLDArmingTripped($sector.us) 1
        }
    }
    if [llength $scuList] {
        if [catch {CheckSCUArming -scuList $scuList} result] {
            return -code error "Error checking SCU arming: $result"
        }
    }
    if $checked(29) {
        #IEX arming special
        SetDPBPLDStatus "Check IEX arming..."
        if [catch {CheckIEXArming } result] {
            return -code error "Error validate IEX arming: $result"
        }
    }
    if $checked(4) {
        SetDPBPLDStatus "Check CPU arming.."
        if [catch {CheckCPUArming } result] {
            return -code error "Error validate CPU arming: $result"
        }
    }
    if {![llength $dsSectorList] && ![llength $usSectorList]} {
        return
    }
    SetDPBPLDStatus "Start arming validation..."
    if [catch {CreateLogRoot} logRoot] {
        return -code error "Error creating log root: $logRoot"
    }
    foreach stream {ds us} {
        set idList [set ${stream}List]
        set sectorList [set ${stream}SectorList]
        
        SetDPBPLDStatus "moving $stream gaps to 48mm..."
        
        if [catch {MoveGapToBPLDTripLimits -moveTo 48} result] {
            return -code error "$result"
        }
        
        SetDPBPLDStatus "checking arming state..."
        set noTripList ""
        
        foreach sector $sectorList {
            if [catch {exec cavget -list=S${sector}BPLD:CH -list=1,2 -list=:IDgapBI.VAL -num -pend=30 } valList] {
                return -code error "Error reading ID $sector arming state: $valList"
            }
            set val1 [lindex $valList 0]
            set val2 [lindex $valList 1]
            if {$val1==0 || $val2==0} {
                set BPLDArmingTripped($sector.$stream) 0
                SetDPBPLDStatus "S$sector bpld $stream gap arming validation failed."
                lappend noTripList $sector
                logData "$sector 0 \"$stream arming validation failed\""
            } else {
                logData "$sector 1 \"$stream arming validation passed.\""
            }
        }
        if [llength $noTripList] {
            SetDPBPLDStatus "[join $noTripList , ] $stream gap arming validation failed."
        } else {
            SetDPBPLDStatus "[join $sectorList ,] $stream gap arming validation success."
        }
        SetDPBPLDStatus "move gaps to above trip limit..."
        if [catch {MoveGapToBPLDTripLimits } result] {
            return -code error "$result"
        }
        SetDPBPLDStatus "clear arming..."
        if [catch {exec cavput -list=S -list=[join $BPLDList ,] -list=BPLD:ResetBO.VAL=1 -pend=30} result] {
            return -code error "Error clearning pending arms: $result"
        }
    }
    
    set selectedSectors ""
    set txtList ""
    set passList ""

    foreach sector $BPLDList {
        set passed 1
        set text ""
        if $checked($sector) {
            lappend selectedSectors $sector
            if {$sector==29 || $sector==4 || [lsearch $scuList $sector]>=0} {
                if !$BPLDArmingTripped($sector) {
                    set passed 0
                    set text "Arming test failed"
                }
            } else {
                foreach stream {ds us} {
                    if !$BPLDArmingTripped($sector.$stream) {
                        set passed 0
                        append text "$stream "
                    }
                }
                if !$passed {
                    append text "arming validation failed."
                }
            }
            if $passed {
                set text "Arming validation passed."
            }
            lappend txtList $text
            lappend passList $passed
        }
    }
    if [catch {exec sddsmakedataset  $logRoot.BPLDArming -col=IDSector,type=long -data=[join $selectedSectors ,] \
                 -col=ValidationResult,type=string "-data=[join $txtList ,]" -col=Passed,type=short -data=[join $passList ,] } result] {
        return -code error "Error creating trip limit result file: $result"
    }
    set printFile /tmp/[APSTmpString].print
    if [catch {exec sddsprintout $logRoot.BPLDArming $printFile "-title=BPLD arming validation results" \
                 -col=IDSector,format=%03d -col=ValidationResult } result] {
        return -code error "Error printing BPLD limit tests result: $result"
    }
    APSFileDisplayWindow [APSUniqueName .] -height 30  \
	-fileName $printFile  -width 100  -deleteOnClose 1 
    SetDPBPLDStatus "done."
}

proc BringUpSCRDialogBox {args} {
    global BPLDVerification dialogBoxResponse
    
    set w [APSUniqueName .scr]
    APSDialogBox $w -name "Select a SR SCR file" -width 80 \
      -cancelCommand "set dialogBoxResponse cancelled" \
      -okCommand "set dialogBoxResponse ok"
    APSAddSCRDialog .sr -parent $w.userFrame -system SR -arrayName BPLDVerification \
      -defaultFile BPLDVerification(ShortFilename) \
      -label "Choose SCR file."
    tkwait variable dialogBoxResponse
    if {$dialogBoxResponse=="cancelled"} {
        return -code error "select SCR was cancelled."
    }
}

set BPLDVerification(ShortFilename) ""
proc RestoreCorrectors {args} {
    set ramp 0
    APSParseArguments {ramp}
    global BPLDVerification
    
    set BPLDVerification(ShortFilename) ""
    SetDPBPLDStatus "Please select a SCR file to restore correctors..."
    if ![string length $BPLDVerification(ShortFilename)] {
        if [catch {BringUpSCRDialogBox} result] {
            return -code error "RestoreCorrectors1: $result"
        }
    }
    
    if ![string length $BPLDVerification(ShortFilename)] {
        return -code error "RestoreCOrrectors2: SCR file not chosen."
    }
    set snapDir /home/helios/oagData/SCR/snapshots/SR
   
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddsprocess $snapDir/$BPLDVerification(ShortFilename) $tmpRoot.corr  \
                 -match=col,Category=SteeringPS -match=col,ControlName=SFB*CurrentAO  } result] {
        return -code error "RestoreCorrector4: $result"
    }
    if $ramp {
        #ask again 
        set answer [APSMultipleChoice .ramp -question "Do you want to ramp correctors or just restore correctors in one step?" \
                      -labelList {Ramp Restore} -returnList {1 0}]
        set ramp $answer
    }
    
    SetDPBPLDStatus "change corrector to scalar mode..."
    if [catch {APSSetCorrMode -corrMode scalar -plane both } result] {
        return -code error "RestoreCorrectors3: $result"
    }
    SetDPBPLDStatus "Restore correctors ..."
    if !$ramp  {
        if [catch {exec sddscasr -restore $tmpRoot.corr -pend=30 } result] {
            return -code error "RestoreCorrector5: $result"
        }
    } else {
        if [catch {APSRampToSnapshot -initDialog 1 -steps 20 \
                     -logFile $tmpRoot.log -fileName $tmpRoot.corr } result] {
            return -code error "RestoreCorrector6: $result"
        }
    }
    SetDPBPLDStatus "change corrector back to vector mode..."
    if [catch {APSSetCorrMode -corrMode vector -plane both } result] {
        return -code error "RestoreCorrectors6: $result"
    }
    SetDPBPLDStatus "Restore correctors done."
}

proc Info {args} {
    global BPLDList checked
    set sectorList ""
    foreach sector $BPLDList {
        if $checked($sector) {
            lappend sectorList $sector
        }
    }
    if ![llength $sectorList] {
        SetDPBPLDStatus "No sector selected."
    }
    foreach sector $sectorList {
        BringUpBPLDMedm -sector $sector
    }
}

proc TransferOrbit {} {
    SetDPBPLDStatus "Transferring orbit..."
    if [catch {APSSaveMachine -machine SR \
                 -description "Before setpoint transfer, SRBPLDVerificationBriefp"} result] {
        return -code error "SR save): $result"
    }
    if [catch {APSSRTransferBPMSetpoint -plane both} result] {
        return -code error "transfer BPM setpoint failed): $result"
    }
    if [catch {APSSaveMachine -machine SR \
                 -description "Aftersetpoint transfer, SRBPLDVerificationBriefp"} result] {
        return -code error "SR save): $result"
    }
    
    SetDPBPLDStatus "done."
}

proc logData {text} {
    global logID logFile mainDir
    set currDir [clock format [clock seconds] -format %Y-%j-%m%d]
    if ![file exist $mainDir/$currDir] {
        exec mkdir -p $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
}
set mainDir /home/helios/oagData/sr/BPLDs/Validation
set logID ""

set sectorList [exec sdds2stream -col=Sector /home/helios/oagData/sr/IDs/sectors.sdds]
set dsList [exec sdds2stream -col=DownstreamLabel  /home/helios/oagData/sr/IDs/sectors.sdds]
set usList [exec sdds2stream -col=UpstreamLabel  /home/helios/oagData/sr/IDs/sectors.sdds]
foreach sector $sectorList ds $dsList us $usList {
    if [string length $ds] {
        set dsExist($sector) 1
    } else {
        set dsExist($sector) 0
    }
    if [string length $us] {
         set usExist($sector) 1
    } else {
        set usExist($sector) 0
    }
    if {$sector==1 || $sector==6 || $sector==7} {
        #SCU
        set dsExist($sector) 0
    }
  #  puts "$sector $dsExist($sector) $usExist($sector)" 
}
lappend sectorList 28
set dsExist(28) 1
set usExist(28) 1
set dsExist(29) 0
set usExist(29) 0

set BPLDList [exec sdds2stream -col=Sector /home/helios/oagData/sr/BPLDs/sectors.sdds]
set xLimitNormal(P1) 2.25
set yLimitNormal(P1) 1.04
set xLimitMax 3.18
set yLimitMax 3.47
set tolerance 0.1


foreach sector $BPLDList {
    set xLimit($sector) $xLimitNormal(P1)
    set yLimit($sector) $yLimitNormal(P1) 
    if {$sector==4} {
        set L 2.5
        set angle 0.135
        set xLimit($sector) [expr $xLimit($sector) - $angle * 7.0 / 6.3 * $L]
    }
    if ($sector==29) {
        set yLimit($sector) [expr $yLimit($sector) / 2.0]
    }
    if {$sector==2} {
        set xLimit($sector) 1.69
    }
}
set scuSectorList {1 6 7}

set varList ""
set commList ""
set buttonList ""
set defaultList {2 3 4 5 7 8 9 10 11 12 13 14 15}
set defaultList ""
foreach sector $BPLDList {
    if [lsearch -exact $defaultList $sector]>=0 {
        set checked($sector) 1
    } else {
        set checked($sector) 0
    }
    lappend buttonList [format %02d $sector]
    lappend varList checked($sector)
    lappend commList "BringUpBPLDMedm -sector $sector"
}

proc ValidationResults {args} {
    global mainDir selectFile

    cd $mainDir
    
    set files1 [glob -nocomplain ????-???-????/*.BPLDLimits]
    set files2 [glob -nocomplain ????-???-????/*.BPLDArming]
    set files3 [glob -nocomplain ????-???-????/*.heartbeat]
    set files [concat $files1 $files2 $files3]
    if ![llength $files] {
        SetDPBPLDStatus "No validation results 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 extension $selectFile] 1 end] validation result" \
                 -col=IDSector,format=%25d \
                 -col=ValidationResult,format=%50s } result] {
        return -code error "Error print result: $result"
    }
    APSFileDisplayWindow [APSUniqueName .] -height 30  \
      -fileName $tmpRoot.print  -width 100  -deleteOnClose 1 
}

proc CreateLogRoot {args} {
    global  mainDir
    set currDir [clock format [clock seconds] -format %Y-%j-%m%d]
    if ![file exist $mainDir/$currDir] {
        exec mkdir -p $mainDir/$currDir
    }
    set logRoot $mainDir/$currDir/[clock format [clock seconds] -format %Y-%j-%m%d:%H%M%S]
    return $logRoot
}

set percent 10
set checkButtonList [APSCheckButtonFrame .sector -parent .userFrame -buttonList $buttonList -variableList $varList  \
                       -commandList $commList -label "ID sectors:" \
                       -orientation horizontal -limitPerRow 8 -allNone 1]

set abort 0
APSLabeledEntry .percent -label "Limit percentage to be applied to setpoints:" -parent .userFrame \
  -textVariable percent -width 20  \
  -contextHelp "give the percentage of the delta between current bpld and limit bpld to be applied to setpoint."
APSLabeledEntry .dpwait -parent .userFrame -label "Datapool wait time (seconds:)" -width 20 -textVariable dpWaitTime \
  -contextHelp "wait time for orbit converge after changing setpoints."
APSLabeledEntry .wait -parent .userFrame -label "Workstation wait time (seconds:)" -width 20 -textVariable waitTime \
  -contextHelp "wait time for orbit converge after changing setpoints."
APSLabeledEntry .steps -parent .userFrame -label "Ramp setpoint steps:" -width 20 -textVariable rampSteps
APSLabeledEntry .interval -parent .userFrame -label "Ramp interval (seconds):" -width 20 -textVariable rampInterval

APSFrame .f1 -parent .userFrame 
APSFrame .f2 -parent .userFrame
.userFrame.f1.frame configure -bd 0
.userFrame.f2.frame configure -bd 0
set w1 .userFrame.f1.frame
set w2 .userFrame.f2.frame
APSButton .transfer -parent $w1 -text "Transfer Orbit" -command "TransferOrbit"
APSButton .validate -parent $w1 -text "Start BPLDLImit Validation" -command "ValidateBPLDLimits"
APSButton .validate1 -parent $w1 -text "Start BPLDArming Validation" -command "ValidateBPLDArming"
APSButton .heartbeat -parent $w1 -text "Start Heart Beat Validation" -command "HeartBeatValidation"
APSButton .gap -parent $w2 -text "MoveGaptoTripLimits" -command "MoveGapToBPLDTripLimits"
APSButton .abort -parent $w2 -text "Abort" -command "set abort 1"
APSButton .offset -parent $w2 -text "Read Offsets/Recalculate" -command "ReadOffsets"
APSButton .restore -parent $w2 -text "Restore Correctors" -command "RestoreCorrectors -ramp 1"
APSButton .info -parent $w2 -text "Info" -command "Info"
APSButton .result -parent $w2 -text "Validation Results" -command "ValidationResults"
MakeSectorsTable
ReadOffsets
#TransferOrbit
#BringUpSCRDialogBox 
