#!/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 args $argv
set doubleSector 1
APSParseArguments {doubleSector}

set env(EPICS_CA_AUTO_ADDR_LIST) YES
set env(EPICS_CA_ADDR_LIST) ""

set BPLDNumber [format %02d $doubleSector]
set sector $doubleSector
set userReset 1
#ID1 S$sector
#ID2 S[expr $sector +1]

set VarList ""
set PVList ""
proc SelectID {args} {
    global BPLD
    set type $BPLD(IDchoice)
    set BPLD(IDbpm.L) $BPLD(${type}L)
}


proc SetDefaultVars {args} {
    global BPLD sector PVList VarList

    set BPLD(IDchoice) ID1
    set BPLD(IDplane) x
    set BPLD(ID1.P0Index1) 8
    set BPLD(ID1.P0Index2) 9
    set BPLD(ID1.P1Index1) 7
    set BPLD(ID1.P1Index2) 10
    set BPLD(ID2.P0Index1) 21
    set BPLD(ID2.P0Index2) 22
    set BPLD(ID2.P1Index1) 20
    set BPLD(ID2.P1Index2) 23

    set BPLD(BPLDNumber) [format %02d $sector]
    set BPLDNumber $BPLD(BPLDNumber)
    set BPLD(sector1) $sector
    set BPLD(sector2) [expr $sector+1]
    set BPLD(ID1L) 5.571
    set BPLD(ID2L) 5.571
    set BPLD(IDbpm.L) $BPLD(ID1L)
    set BPLD(IDbpm.window) 2
    #
    set BPLD(IDbpm.xLimit0) 1.0
    set BPLD(IDbpm.yLimit0) 1.0
    set BPLD(IDbpm.rect.x'Limit) 0.25
    set BPLD(IDbpm.rect.y'Limit) 0.25
    #increase the limit by 5% in order to make the BPLD trip
    set BPLD(IDbpm.xLimit) 1.05
    set BPLD(IDbpm.yLimit) 1.05
    set BPLD(IDbpm.rect.x'Limit) [expr 0.25*1.05]
    set BPLD(IDbpm.rect.y'Limit) [expr 0.25*1.05]
    
    set BMbpmList ""
    set BMbpmVarList ""
    set IDbpmList {8 9 21 22}
    set IDbpmVarList ""
    for {set i 1} {$i<=28} {incr i} {
	#if [lsearch -exact $IDbpmList $i]<0 {
	    lappend BMlabelList  [format %02d $i]
	    lappend BMbpmList $i
	    set BPLD(BM.bpm$i) 0
	    lappend BMbpmVarList BPLD(BM.bpm$i)
	#} else {
	#    set BPLD(BM.bpm$i) 0
	#    lappend IDbpmVarList BPLD(BM.bpm$i)
	#}
    }
    set BPLD(ID.bpmIndexList) $IDbpmList
    set BPLD(BM.bpmList) $BMbpmList
    set BPLD(BM.labelList) $BMlabelList
    set BPLD(BM.bpmVarList) $BMbpmVarList
    #default select 25-28 bpms for BM
    set BPLD(BM.bpm25) 1
    set BPLD(BM.bpm26) 1
    set BPLD(BM.bpm27) 1
    set BPLD(BM.bpm28) 1

    set BPLD(BM.sectorChoiceList) {28-25 24-2 20-17 16-13 12-9 8-5 4-1 1-16}
    set BPLD(BM.sectorOxValueList) {0xf000000 0xe000000 0xd000000 0xc00000 0xb00000 0xa00000 0x100000}
    set BPLD(BM.sectorChoice) 28-25
    set BPLD(BM.sectorValue) 0xf000000
    set BPLD(BM.commandList) [APSReplicateItem -item UpdateBPLDChoisePar -number [llength $BPLD(BM.sectorChoiceList)]]
    set BPLD(BM.sectorList) {25 26 27 28}

    global mainDir logDir
    set mainDir [APSGoToDailyDirectory -subdirectory APSUBPLDValidation]
    set logDir $mainDir

    set stamp [clock format [clock seconds] -format %Y%m%d]
    set BPLD(BMlogFile) $logDir/BM-${stamp}.log
    set BPLD(IDlogFile) $logDir/ID-${stamp}.log

    set BPLDchoice(BM.currentLimit) 25
    set BPLDchoice(ID.currentLimit) 2

    set maxBeamS [exec cavget -list=APSU:MMPS2:MaxSoftBeam-SP -pend=10]
    set maxBeamH [exec cavget -list=APSU:MMPS2:Sim:HWmaxBeam-SP -pend=10]
    if {$maxBeamS<$maxBeamH} {
	set BPLD(allowedBeam) $maxBeamS
    } else {
	set BPLD(alloedBeam) $maxBeamS
    }

    
    #mm, mrad
    set BPLD(ID.xLimit) 1.0 
    set BPLD(ID.x'Limit) 0.25
    set BPLD(ID.yLimit) 1.0
    set BPLD(ID.y'Limit) 0.25
    
    set PVList ""
    set VarList ""
    #pv link userReset S${BPLDNumber}-LMPS:UsrReset-SP
    set BPLD(usrResetPV) S${BPLDNumber}-LMPS:UsrReset-SP
    set BPLD(userReset) 1
    lappend PVList $BPLD(usrResetPV)
    lappend VarList BPLD(userReset)
    
    #this pv sets the enabled BPM bits
    set BPLD(BM.bpmEnablePV) S${BPLDNumber}-LMPS:BPLD:BM_Enable-I
    lappend PVList $BPLD(BM.bpmEnablePV)
    lappend VarList BPLD(BM.bpmEnable)
    
    #this pv is the BPM mask -- after it changes, the bpmEnablePV should have the same value as its
    set BPLD(BM.bpmMaskPV) S${BPLDNumber}-LMPS:BPLD:BpmMask-SP
    lappend PVList $BPLD(BM.bpmMaskPV)
    lappend VarList BPLD(BM.bpmMask)
    
    set BPLD(BM.bpmFaultStatusPV) S${BPLDNumber}-LMPS:BPLD:BM_IL_Status-I
    lappend PVList $BPLD(BM.bpmFaultStatusPV) 
    lappend VarList BPLD(BM.bpmFaultStatus)

    set BPLD(BM.enablePV) S${BPLDNumber}-LMPS:BPLD:BM_Enable-SP
    lappend PVList $BPLD(BM.enablePV)
    lappend VarList BPLD(BM.enable)
    

    set BPLD(simBeamCurrent) 25
    set BPLD(simBeamCurrentPV) APSU:MMPS2:Sim:BeamCurrent-SP
    lappend PVList $BPLD(simBeamCurrentPV) 
    lappend VarList BPLD(simBeamCurrent) 

    set BPLD(ID.currentLimit) 2
    set BPLD(ID.currentLimitPV) APSU:MMPS2:ID:Thold-SP
    lappend PVList $BPLD(ID.currentLimitPV)
    lappend VarList BPLD(ID.currentLimit)

    set BPLD(BM.currentLimit) 2
    set BPLD(BM.currentLimitPV) APSU:MMPS2:BM:Thold-SP
    lappend PVList $BPLD(BM.currentLimitPV)
    lappend VarList BPLD(BM.currentLimit)

    #hardware limit
    set BPLD(hwBeamLimitPV) APSU:MMPS2:Sim:HWmaxBeam-SP
    lappend PVList $BPLD(hwBeamLimitPV)
    lappend VarList BPLD(hwBeamLimit)

    #software limit
    set BPLD(swBeamLimitPV) APSU:MMPS2:MaxSoftBeam-SP
    lappend PVList $BPLD(swBeamLimitPV)
    lappend VarList BPLD(swBeamLimit)

    set BPLD(simBeamCurrent) 0
    set BPLD(simBeamCurrentPV) APSU:MMPS2:Sim:BeamCurrent-SP
    lappend PVList $BPLD(simBeamCurrentPV)
    lappend VarList BPLD(simBeamCurrent)

    set BPLD(simEnable) 0
    set BPLD(simEnablePV) APSU:MMPS2:BeamSim-SP
    lappend PVList $BPLD(simEnablePV)
    lappend VarList BPLD(simEnable)

			 

    set BPLD(P0CountLimit) 100
    set BPLD(P0CountLimitPV) S${BPLDNumber}-LMPS:P0_CntLimit-SP
    lappend PVList $BPLD(P0CountLimitPV)
    lappend VarList BPLD(P0CountLimit)

    set BPLD(latchedFaultPV) S${BPLDNumber}-LMPS:ExtInFaultData1-I
    lappend PVList $BPLD(latchedFaultPV)
    lappend VarList BPLD(latchedFault)
		
    #x/y bpm limits
    foreach plane {x y} {
	#	puts "cavget -list=S${BPLDNumber} -list=-LMPS:BM_[string toupper $plane] \
			     #		       -range=begin=1,end=28 -list=_TH-SP -pend=4"
	if [catch {exec cavget -list=S${BPLDNumber} -list=-LMPS:BM_[string toupper $plane] \
		       -range=begin=1,end=28 -list=_TH-SP -pend=10} xLimitList] {
	    return -code error "Error reading x limits: $xLimitList"
	}
	set limit -1
	for {set i 0} {$i<28} {incr i} {
	    set bpm [expr $i+1]
	    set BPLD(${plane}Limit.$i) [lindex $xLimitList $i]
	    if $BPLD(${plane}Limit.$i)>$limit {
		set limit $BPLD(${plane}Limit.$i)
	    }
	}
	set BPLD(${plane}Limit.max) $limit
    }
    if $BPLD(xLimit.max)>$BPLD(yLimit.max) {
	#test starting from lower limit
	set BPLD(rampStartPlane) y
    } else {
	set BPLD(rampStartPlane) x
    }
    
    #ID bpm limits PVs
    set BPLD(ID1.enablePV) S${BPLDNumber}-LMPS:BPLD:ID1_Enable-SP
    lappend PVList $BPLD(ID1.enablePV)
    lappend VarList BPLD(ID1.enable)
    
    set BPLD(ID2.enablePV) S${BPLDNumber}-LMPS:BPLD:ID2_Enable-SP
    lappend PVList $BPLD(ID2.enablePV)
    lappend VarList BPLD(ID2.enable)
    
    set BPLD(ID.gapSimPV) S${BPLDNumber}-LMPS:ID:GapSim-SP
    lappend PVList $BPLD(ID.gapSimPV)
    lappend VarList BPLD(ID.gapSim)

    set BPLD(ID.gapSimClosePV) S${BPLDNumber}-LMPS:ID:GapSimClose-SP
    lappend PVList $BPLD(ID.gapSimClosePV)
    lappend VarList BPLD(ID.gapSimClose)
    
    set BPLD(ID1.xy1IndexPV) S${BPLDNumber}-LMPS:BPLD:ID1:BPM-XY1_idx-SP
    lappend PVList $BPLD(ID1.xy1IndexPV)
    lappend VarList BPLD(ID1.xy1Index)
    
    set BPLD(ID1.xy2IndexPV) S${BPLDNumber}-LMPS:BPLD:ID1:BPM-XY2_idx-SP
    lappend PVList $BPLD(ID1.xy2IndexPV)
    lappend VarList BPLD(ID1.xy2Index)

    set BPLD(ID2.xy1IndexPV) S${BPLDNumber}-LMPS:BPLD:ID2:BPM-XY1_idx-SP
    lappend PVList $BPLD(ID2.xy1IndexPV)
    lappend VarList BPLD(ID2.xy1Index)
    
    set BPLD(ID2.xy2IndexPV) S${BPLDNumber}-LMPS:BPLD:ID2:BPM-XY2_idx-SP
    lappend PVList $BPLD(ID2.xy2IndexPV)
    lappend VarList BPLD(ID2.xy2Index)
    
    #ID bpm limits, nm, nrad units
    set limit1 1000
    set offset 0
    set angle 200
    set varList ""
    foreach ID {ID1 ID2} {
	foreach nm {H1 H2 V1 V2} bpm {X1 X2 Y1 Y2} {
	    set BPLD($ID.diamond${nm}Limit) $limit1
	    set BPLD($ID.diamond${nm}LimitPV) S${BPLDNumber}-LMPS:BPLD:${ID}:AIOL-${nm}-SP
	    lappend PVList $BPLD($ID.diamond${nm}LimitPV)
	    lappend VarList  BPLD($ID.diamond${nm}Limit)
	    lappend varList BPLD($ID.diamond${nm}Limit)

	    set BPLD($ID.offset${nm}PV) S${BPLDNumber}-LMPS:BPLD:${ID}:AIOR-${nm}-SP
	    lappend PVList $BPLD($ID.offset${nm}PV)
	    lappend VarList  BPLD($ID.offset${nm})
	    
	    set BPLD($ID.raw${nm}PV) S${BPLDNumber}-LMPS:BPLD:${ID}_${bpm}-I
	    lappend PVList $BPLD($ID.raw${nm}PV)
	    lappend VarList BPLD($ID.raw${nm})
	    
	}
	foreach plane {H V} {
	    set BPLD($ID.rect${plane}OffsetLimit) $offset
	    set BPLD($ID.rect${plane}OffsetLimitPV) S${BPLDNumber}-LMPS:BPLD:${ID}:AIOL-${plane}3-SP
	    lappend PVList $BPLD($ID.rect${plane}OffsetLimitPV)
	    lappend VarList BPLD($ID.rect${plane}OffsetLimit)
	    lappend varList BPLD($ID.rect${plane}OffsetLimit)

	    set BPLD($ID.rect${plane}AngleLimit) $angle
	    set BPLD($ID.rect${plane}AgnleLimitPV) S${BPLDNumber}-LMPS:BPLD:ID1:AIAL_${plane}-SP
	    lappend PVList $BPLD($ID.rect${plane}AgnleLimitPV)
	    lappend VarList BPLD($ID.rect${plane}AngleLimit)
	    lappend varList BPLD($ID.rect${plane}AngleLimit)
	}
    }
    set BPLD(IDLimitVarList) $varList
 
}


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


proc LogBMValidationResult {args} {
    set type Ramp
    APSParseArguments {type}
    
    global logDir BPLD
    if ![file exist $BPLD(BMlogFile)] {
	set BPLD(BMlogID) [open $BPLD(BMlogFile) a+]
	puts $BPLD(BMlogID) "SDDS1"
	puts $BPLD(BMlogID) "&column name=StartTime, type=string, &end"
	puts $BPLD(BMlogID) "&column name=EndTime, type=string, &end"
	puts $BPLD(BMlogID) "&column name=ValidationType, type=string &end"
	puts $BPLD(BMlogID) "&column name=BPM, type=string, &end"
	puts $BPLD(BMlogID) "&column name=X_Status, type=string, &end"
	puts $BPLD(BMlogID) "&column name=Y_Status, type=string, &end"
	puts $BPLD(BMlogID) "&column name=Result, type=string, &end"
	puts $BPLD(BMlogID) "&data mode=ascii, no_row_counts=1, &end"
	exec chmod 777 $BPLD(BMlogFile)
    } else {
	set BPLD(BMlogID) [open $BPLD(BMlogFile) a+]
    }
     
    for {set bpm 1} {$bpm<=28} {incr bpm} {
	
	if !$BPLD(BM.bpm$bpm) {
	    continue
	}
	set valList $BPLD(BM.startTime)
	lappend valList $BPLD(BM.endTime)
	lappend valList $type
	lappend valList [format %02d $bpm]
	set pass 1
	if $BPLD(passed.x$bpm) {
	    lappend valList passed
	} else {
	    lappend valList failed
	    set pass 0
	}
	if $BPLD(passed.y$bpm) {
	    lappend valList passed
	} else {
	    lappend valList failed
	    set pass 0
	}
	if $pass {
	    lappend valList passed
	} else {
	    lappend valList failed
	}
	puts $BPLD(BMlogID) "[join $valList]"
    }
    flush $BPLD(BMlogID)
}


proc SelectBMbpm {args} {
    set choice ""
    APSParseArguments {choice}

    global BPLD 
    set IDbpmList $BPLD(ID.bpmIndexList)
    
    set start [lindex [split $choice '-'] 0]
    set end [lindex [split $choice '-'] 1]
    for {set i 1} {$i<=28} {incr i} {
	if [lsearch $i $IDbpmList]<0 {
	    set BPLD(BM.bpm$i) 0
	}
    }
    for {set i $start} {$i<=$end} {incr i} {
	if [lsearch $i $IDbpmList]<0 {
	    set BPLD(BM.bpm$i) 1
	}
    } 
}

proc UpdateBPLDChoisePar {args} {
    global BPLD

    set sectorChoiceList $BPLD(BM.sectorChoiceList)

    set sectorOxValueList $BPLDList(BM.sectorOxValueList)
    
    set index [lsearch $sectorChoiceList $BPLD(BM.sectorChoice)]
    set BPLD(BM.sectorValue) [lindex $sectorOxValueList $index]
    set start [lindex [split $BPLDchoice(sector) "-"] 0]
    set end [lindex [split $BPLDchoice(sector) "-"] 1]
    set BPLDchoice(sectorList) ""
    for {set s $start} {$s<=$end} {incr s} {
	lappend BPLD(BM.sectorList) $s
    }
}

proc CheckBPMIDEnageCurrent {args} {
    global BPLD
    set type BM
    APSParseArguments {type}

    if {$BPLD(${type}.currentLimit)<0 || $BPLD(${type}.currentLimit)>$BPLD(allowedBeam)} {
	SetDPBPLDStatus "Error the $type current limit exceeds the allowed max beam limit, set it to default values."
	switch $type {
	    BM {
		set val 25
	    }
	    ID {
		set val 2
	    }
	}
	set BPLD(${type}.currentLimit) $val
    }
}

proc ComputeBMbpmMaskValue {args} {
    global BPLD
    set sum 0
    foreach bpm $BPLD(BM.bpmList) {
	if $BPLD(BM.bpm$bpm) {
	    set sum [expr $sum + pow(2, $bpm-1)]
	}
    }
    set sum [expr int($sum)]
    set BPLD(BM.maskValue) $sum
    return $sum
}

proc VerifyBMBpmMask {args} {
    global BPLD
    set BPLDNumber $BPLD(BPLDNumber)
    #if [catch {exec cavget -list=S${BPLDNumber}-LMPS:BPLD:BM_Enable-I -pend=10} value] {
    #	return -code error "Error reading BM enable status pv: $value"
    #   }
  #  puts $BPLD(BM.bpmEnablePV)
    pv getw BPLD(BM.bpmEnable)
    update
   # puts $BPLD(BM.bpmEnable)
    set value $BPLD(BM.bpmEnable)
   # puts $value
    set mask [ComputeBMbpmMaskValue]
    if {$value!=$mask} {
	return -code error "Error the BM bpm enable ($value) is different from the BPM mask ($mask), which means that the bpms are not being corrected chosen.!"
    }
    return 

    set binstr [format %b $value]
    set len [string length $binstr]
    set error 0
    for {set i 0} {$i<$len} {incr i} {
	set bpm [expr $len-$i]
	set bit [string index $binstr $i]
	if $bit!=$BPLD(BM.bpm$bpm) {
	    SetDPBPLDStatus "Error: bpm $i enable status is wrong!"
	    incr error
	}
    }
    #high bits should not be enabled
    for {set i [expr $len+1]} {$i<=28} {incr i} {
	if $BPLD(BM.bpm$i) {
	    SetDPBPLDStatus "Error: bpm $i enable status is wrong!"
	    incr error
	}
    }
    if $error {
	return -code error "BM BPM enable status confirmation failed."
    }
}


proc SetBMbpmMask {args} {
    set type SP
    APSParseArguments {type}
    
    global BPLD
    SetDPBPLDStatus "compute mask value..."
    
    set BPLD(BM.bpmMask) 0
    pv putw BPLD(BM.bpmMask)

    set value [ComputeBMbpmMaskValue]
    SetDPBPLDStatus "Set BM bpm mask ..."
    SetDPBPLDStatus "BM mask value: $value  "
    set BPLD(BM.bpmMask) $value
    pv putw BPLD(BM.bpmMask)
    
    set BPLD(BM.enable) 1
  #  puts $BPLD(BM.enablePV)
    pv putw BPLD(BM.enable)
    after 3000
    SetDPBPLDStatus "verify BM bpm enable status..."
    if [catch {VerifyBMBpmMask} result] {
	return -code error "Error: $result"
    }
    SetDPBPLDStatus "done"
}

proc SetupValidation {args} {
    set type BM
    APSParseArguments {type}
    global BPLD 
    
    SetupSimMode
    set BPLDNumber $BPLD(BPLDNumber)
    set BPLD(userReset) 1
    set BPLD(simBeamCurrent) 25
    set BPLD(ID.currentLimit) 2
    set BPLD(simEnable) 0
    set BPLD(P0CountLimit) 100
    set varList {BPLD(simBeamCurrent) BPLD(ID.currentLimit) BPLD(simEnable) BPLD(P0CountLimit) }

 
    pv putw $varList
    pv putw BPLD(userReset)
    
    SetDPBPLDStatus "Step 0: before start validation, check the latched fault, make sure it is zero. if not, fix it first!"
    pv getw BPLD(latchedFault)
    update
    set fault $BPLD(latchedFault)

    if $fault {
	SetDPBPLDStatus "The lock MPS latched fault has to be cleared before starting validation!"
	APSInfoWindow .info -name "Local MPS fault" -infoMessage "The local MPS latched fault needs to be cleared before starting validation!" -modal 1
	return
    }
    SetDPBPLDStatus "To enable BM/ID validation, it needs following conditions 1)the simulated hardware limit should be equal or greater than BM engaged current.\n\
                     2) software limit should be less than the hardware limit but greater than BM/ID engaged current \n\
                     3) MPS arming current should be greater than 0 (normally set to 0.5mA) \n\
                     4) beam simulation current has to be equal or greater than BM/ID engaged current."
    SetDPBPLDStatus "checking hardware limit..."
    
    pv getw BPLD(ID.currentLimit)
    pv getw BPLD(BM.currentLimit)
    pv getw BPLD(simHWmaxBeam)
    pv getw BPLD(hwBeamLimit)
    update
    
    set hwLimit $BPLD(hwBeamLimit)
    set BMengageCurrent $BPLD(BM.currentLimit)
    set IDengageCurrent $BPLD(ID.currentLimit)
    set limit 0
    if {$type=="BM" && $hwLimit<[expr $BMengageCurrent+5]} {
	set limit [expr $BMengageCurrent+20]
    } elseif {$type=="ID" && $hwLimit<[expr $IDengageCurrent+5]} {
	set limit [expr $IDengageCurrent+20]
    }
    if $limit>0 {
	SetDPBPLDStatus "Hardware limit is lower than $type engage current, increase it to $limit"
	#if [catch {exec cavput -list=APSU:MMPS2:Sim:HWmaxBeam-SP=$limit -pend=10} result] {
	#    return -code error "Error seting hardware current limit: $result"
	#}
	set hwLimit $limit
	set BPLD(hwBeamLimit) $limit
	pv putw BPLD(hwBeamLimit)
	
    }
    SetDPBPLDStatus "checking software current limit..."
    #if [catch {exec cavget -list=APSU:MMPS2:MaxSoftBeam-SP -pend=10} swLimit] {
#	return -code error "Error reading software limit: $swLimit"
 #   }
    pv getw BPLD(swBeamLimit)
    update
    set swLimit $BPLD(swBeamLimit)
    
    set limit 0
    if {$swLimit>$hwLimit} {
	SetDPBPLDStatus "software limit is higher than hardward limit, reduce it."
	set limit [expr $hwLimit - 2]
    }
    if {$type=="BM" && $swLimit<$BMengageCurrent} {
	set limit [expr $BMengageCurrent + 1]
	SetDPBPLDStatus "software limit is lower than BM engage current, increase it."
    }
    if {$type=="ID" && $swLimit<$IDengageCurrent} {
	set limit [expr $IDengageCurrent + 1 ]
	SetDPBPLDStatus "software limit is lower than ID engage current, increase it."
    }
    if {$limit>0} {
	#if [catch {exec cavput -list=APSU:MMPS2:MaxSoftBeam-SP=$limit -pend=10} result] {
	#    return -code error "Error setting software limit: $result"
	#}
	set BPLD(swBeamLimit) $limit
	pv putw BPLD(swBeamLimit) 
    }
    SetDPBPLDStatus "checking beam simulation current: it should be equal or greater than BM/ID engaged current. However, I found that it works even if it is zero"
    #if [catch {exec cavget -list=APSU:MMPS2:Sim:BeamCurrent-SP -pend=10} beamCurrent] {
#	retun -code error "Error getting beam current: $beamCurrent"
 #   }
    pv getw BPLD(simBeamCurrent)
    update
    set beamCurrent $BPLD(simBeamCurrent)
 
    SetDPBPLDStatus "enable beam simulator"
    #if [catch {exec cavput -list=APSU:MMPS2:BeamSim-SP=1 -pend=10} result] {
#	return -code error "Error enable beam simulator: $result"
    #}
    set BPLD(simEnable) 1
    pv putw BPLD(simEnable)
   
    if {$type=="BM"} {
	SetDPBPLDStatus "reset and enable BM, disable ID1 and ID2"
	#if [catch {exec cavput -list=S${BPLDNumber}-LMPS:UsrReset-SP=1,S${BPLDNumber}-LMPS:BPLD:BM_Enable-SP=1 -pend=10} result] {
	#    return -code error "Error enable BM: $result"
	#}
	set varList {BPLD(userReset) BPLD(BM.enable) BLID(ID1.enable) BPLD(ID2.enable)}
	set BPLD(userReset) 1
	set BPLD(BM.bpmMaskEnable) 1
	set BPLD(ID1.enable) 0
	set BPLD(ID2.enable) 0
	pv putw $varList
	#disable ID1 and ID2
	
    } else {
	#disable BM, ID1, ID2, enable gap sim, and close gap
	set BPLD(BM.enable) 0
	set BPLD(ID1.enable) 0
	set BPLD(ID2.enable) 0
	set BPLD(ID.gapSim) 1
	#gapSim mode should be checked when open is closed
	set BPLD(ID.gapSimClose) 1
	set BPLD(userReset) 1
	set varList {BPLD(BM.enable) BPLD(ID1.enable) BPLD(ID2.enable) BPLD(ID.gapSim) BPLD(ID.gapSimClose)}
	pv putw $varList
	pv putw BPLD(userReset)
	#disabel BM
	exec caput S${BPLDNumber}-LMPS:BPLD:BM_Enable-SP 0
	SetDPBPLDStatus "reset and enable ID"
	#set S1 and S2 distance
	if [catch {exec cavput -list=S${BPLDNumber}-LMPS:BPLD:ID1:S1-SP=[expr $BPLD(ID1L)/-2.0],S${BPLDNumber}-LMPS:BPLD:ID1:S2-SP=[expr $BPLD(ID1L)/2.0] -pend=10} result] {
	    return -code error "Error setting S1 S2 distance: $result"
	}
	if [catch {exec cavput -list=S${BPLDNumber}-LMPS:BPLD:ID2:S1-SP=[expr $BPLD(ID2L)/-2.0],S${BPLDNumber}-LMPS:BPLD:ID2:S2-SP=[expr $BPLD(ID2L)/2.0] -pend=10} result] {
	    return -code error "Error setting S1 S2 distance: $result"
	}
    }
    
   # return
    #for ID, if change P0 to P1, the S1 and S2 should be changed, and bpm Index should be changed
  
    global p0Index p1Index
    set varList ""
    set pvList [list S${BPLDNumber}-LMPS:BPLD:ID1:BPM-XY1_idx-SP S${BPLDNumber}-LMPS:BPLD:ID1:BPM-XY2_idx-SP \
		    S${BPLDNumber}-LMPS:BPLD:ID2:BPM-XY1_idx-SP S${BPLDNumber}-LMPS:BPLD:ID2:BPM-XY2_idx-SP ]
    switch $BPLD(IDbpm.BPMType) {
	P0 {
	    set indexList $p0Index
	}
	P1 {
	    set indexList $p1Index
	}
    }
    set putList ""
    foreach i $indexList pv $pvList {
	#puts "$i: $BPLD(IDbpm.$i.index)"
	lappend putList $pv=$BPLD(IDbpm.$i.index)
    }
    lappend putList $BPLD(simEnablePV)=1
    if [catch {APScavput -list=[join $putList ,] -pend=10 } result] {
	return -code error "Error setup the ID bpm index: $result"
    }
    
    SetDPBPLDStatus "$type ready for validation."
}

proc ClearBMFaults {args} {
    set resetBMSP 1
    APSParseArguments {resetBMSP}
    
    global BPLD

    set BPLDNumber $BPLD(BPLDNumber)
    set BMbpmList $BPLD(BM.bpmList)
    
    if [catch {exec cavput -list=S${BPLDNumber}-LMPS:BM_ -list=X,Y -range=begin=1,end=28 -list=_Offset-SP=0 -pend=30 } result] {
	return code error "ClearBMFaults1: error setting offsets to 0: $result"
    }
    
    if [catch {exec cavput -list=S${BPLDNumber}-LMPS:BM_ -list=X -range=begin=1,end=28 -list=_TH-SP=2500 -pend=30 
	exec cavput -list=S${BPLDNumber}-LMPS:BM_ -list=Y -range=begin=1,end=28 -list=_TH-SP=1500 -pend=30 } result] {
	return -code error "ClearBMFaults2: error reset bpm limits: $result"
    }
    if [catch {exec cavput -list=S${BPLDNumber}-LMPS:P0_CntLimit-SP=100 -pend=10} result] {
	return -code error "ClearBMFaults3: error reset ramp limit: $result"
    }
    if $resetBMSP {
	if [catch {exec cavput -list=S${BPLDNumber}-LMPS:BPLD:BpmMask-SP=0 -pend=10} result] {
	    return -code error "ClearBMFault4: error reset BM SP: $result"
	}
    }
    set BPLD(userReset) 1
    pv putw BPLD(userReset)
    after 3000
}

#set rampTests {13 14 15 16 25 26 27 28}
#set offsetTests {5 6 23 24}
set rampTests ""
set offsetTests ""
for {set i 1} {$i<=28} {incr i} {
    lappend rampTests $i
    lappend offsetTests $i
}
proc CheckBMbpmFaultStatus {args} {
    set type ramp
    set plane x
    APSParseArguments {type plane}
    
    global BPLD rampTests offsetTests
    set BPLDNumber $BPLD(BPLDNumber)
    
    if [catch {exec cavget -list=S${BPLDNumber}-LMPS:BPLD:BM_IL_Status-I -pend=10 } faultValue] {
	return -code error "error reading BM bpm fault status: $faultValue"
    }
    set testList [set ${type}Tests]
    set bpmList ""
    for {set i 1} {$i<=28} {incr i} {
	if {[lsearch -exact $testList $i]>=0 && $BPLD(BM.bpm$i)} {
	    lappend bpmList $i
	} 
    }
    if ![llength $bpmList] {
	return -code error "No $type  bpms selected!"
    }
    set binStr [format %b $faultValue]
    set len [string length $binStr]
    SetDPBPLDStatus "$faultValue $binStr"

    for {set i 0} {$i<$len} {incr i} {
	set bpm [expr $len-$i]
	set value [string index $binStr $i]
	set index [lsearch -exact $bpmList $bpm]
	if {$index>=0} {
	    if $value {
		set BPLD(passed.$plane$bpm) 1
		SetDPBPLDStatus "$plane $bpm BPM passed."
	    } else {
		set BPLD(passed.$plane$bpm) 0
		SetDPBPLDStatus "$plane $bpm BPM failed."
	    }
	}
    }
    #higher bits are zeros
    for {set $i $len} {$i<28} {incr i} {
	set bpm [expr $i+1]
	set value 0
	set index [lsearch -exact $bpmList $bpm]
	if {$index>=0} {
	    set BPLD(passed.$plane$bpm) 0
	    SetDPBPLDStatus "$plane $bpm BPM failed."
	}
    }
    #check BM flag, the value of this pv is wrong, skip it for now
    #S${BPLDNumber}-LMPS:MLinkTXpkt_FS-I
    if [catch {exec cavget -list=S${BPLDNumber}-LMPS:MLinkTXpkt_FS-I -pend=10} value] {
	return -code error "Error reading: BPM fault status: $result"
    }
    set binstr [format %b $value]
    #the first bit is used as sign -- skip it
    set len [string length $binstr]
    #set set BPLD(passed.${plane}28) 1
    #
}


proc ValidateBMBPMWithRamp {args} {
    set plane ""
    set bpmList ""
    set limit ""
    APSParseArguments {plane bpmList limit}
    set Plane $plane
    global BPLD 
    
    set BPLDNumber $BPLD(BPLDNumber)
    set BMbpmList $BPLD(BM.bpmList)
    
    SetDPBPLDStatus "Set BPM mask...."
    for {set i 1} {$i<=28} {incr i} {
	if [lsearch -exact $bpmList $i]>=0 {
	    set BPLD(BM.bpm$i) 1
	} else {
	    set  BPLD(BM.bpm$i) 0
	}
    }
    if [catch {SetBMbpmMask -type Test } result] {
	return -code error "Error set BM bpm mask: $result"
    }
    SetDPBPLDStatus "setting the ramp limit to $limit, waiting..."
    if [catch {exec cavput -list=S${BPLDNumber}-LMPS:P0_CntLimit-SP=$limit -pend=10} result] {
	return -code error "Error setting ramp limit to $limit : $result"
    }
    after 10000
    SetDPBPLDStatus "Checking the fault status for $plane plane..."
    if [catch {CheckBMbpmFaultStatus -plane $plane -type ramp } result] {
	return -code error "Error checking BM fault status: $result"
    }
    SetDPBPLDStatus "clear the faults"
    if [catch {ClearBMFaults} result] {
	return -code error "Error clearing BM faults: $result"
    }
    if [catch {exec cavget -list=S${BPLDNumber}-LMPS:BPLD:BM_IL_Status-I -pend=10 } faultValue]  {
	return -code error "Error reading BM fault status after clearing faults: $faultValue"
    }
    if $faultValue {
	return -code error "Error: the fault status was not cleared! EXIT validation"
    }
}

proc ValidateBMBPMWithOffset {args} {
    set plane ""
    set bpmList ""
    APSParseArguments {plane bpmList}
    set Plane [string toupper $plane]
    global BPLD
    
    set BPLDNumber $BPLD(BPLDNumber)
    SetDPBPLDStatus "Validation [join $bpmList ,] $Plane BPMs with offset..."
    if [catch {exec cavget -list=S${BPLDNumber}-LMPS:BM_TBT_$Plane -list=[join $bpmList ,] -list=-I -pend=10 -printErrors} posList] {
	return -code error "Error reading bpm position: $posList"
    }
    if [catch {exec cavget -list=S${BPLDNumber}-LMPS:BM_$Plane -list=[join $bpmList ,] -list=_Offset-SP -pend=10 -printErrors} offsetList] {
	return -code error "Error reading bpm offset: $offsetList"
    }
    if [catch {exec cavget -list=S${BPLDNumber}-LMPS:BM_$Plane -list=[join $bpmList ,] -list=_TH-SP -pend=10 -printErrors} limitList] {
	return -code error "Error reading bpm limit: $limitList"
    }
    set putList ""
    foreach pos $posList limit $limitList offset $offsetList bpm $bpmList {
	set offset0 [expr $offset+$pos+$limit]
	lappend putList  S${BPLDNumber}-LMPS:BM_${Plane}${bpm}_Offset-SP=$offset0
    }
    SetDPBPLDStatus "set BPM mask...$bpmList"
    for {set i 1} {$i<=28} {incr i} {
	if [lsearch -exact $bpmList $i]<0 {
	    set BPLD(BM.bpm$i) 0
	} else {
	    set BPLD(BM.bpm$i) 1
	}
    }
    
    if [catch {SetBMbpmMask -type Test} result] {
	return -code error "Error set BM bpm mask: $result"
    }
    SetDPBPLDStatus "change offsets, waiting..."
    puts $putList
    if [catch {exec cavput -pend=10 -list=[join $putList ,] } result] {
	return -code error "Error change offsets: $result"
    }
    after 10000
    SetDPBPLDStatus "Checking the fault status for $plane plane..."
    if [catch {CheckBMbpmFaultStatus -plane $plane -type offset } result] {
	return -code error "Error checking BM fault status: $result"
    }
    SetDPBPLDStatus "clear the faults"
    if [catch {ClearBMFaults} result] {
	return -code error "Error clearing BM faults: $result"
    }
    if [catch {exec cavget -list=S${BPLDNumber}-LMPS:BPLD:BM_IL_Status-I -pend=10 } faultValue]  {
	return -code error "Error reading BM fault status after clearing faults: $faultValue"
    }
    if $faultValue {
	return -code error "Error: the fault status was not cleared! EXIT validation"
    }
}

proc ValidateBMBPMs {args} {
    set type Ramp
    APSParseArguments {type}
    
    global BPLD rampTests offsetTests

    set BPLDNumber $BPLD(BPLDNumber)
    set BMbpmList $BPLD(BM.bpmList)
    
    set BPLD(BM.startTime) [clock format [clock  seconds] -format %Y%m%d-%H:%M:%S]
    SetDPBPLDStatus "Deselect BM bpm mask and reset fault..."
    if [catch {exec cavput -list=S${BPLDNumber}-LMPS:BPLD:BpmMask-SP=0 -pend=10} result] {
	return -code error "Error deselect BM bpms: $result"
    }
    set BPLD(userReset) 1
    pv putw BPLD(userReset)
    after 2000
    if [catch {exec cavget -list=S${BPLDNumber}-LMPS:BPLD:BM_IL_Status-I -pend=10} fault] {
	return -code error "Error reading BM bpm fault status: $fault"
    }
    if $fault {
	SetDPBPLDStatus "There is BM fault now, clear it first..."
	if [catch {ClearBMFaults } result] {
	    return -code error "Error clear BM faults: $result"
	}
	if [catch {exec cavget -list=S${BPLDNumber}-LMPS:BPLD:BM_IL_Status-I -pend=10} fault] {
	    return -code error "Error reading BM bpm fault status: $fault"
	}
	if $fault {
	    APSInfoWindow .info "BM Faults not cleared" -infoMessage "BM bpm faults can not be cleared automatically, please clear it first before starting validating." -modal 1
	    return
	}
    }
    
    SetDPBPLDStatus "Step1: Setup BM validation..."
    if [catch {SetupValidation -type BM} result] {
	return -code error "Error setup validation for BM: $result"
    }
    for {set i 1} {$i<=28} {incr i} {
	set BPLD(passed.x$i) 0
	set BPLD(passed.y$i) 0
    }
    set bpmList ""
    foreach bpm $BMbpmList {
	if $BPLD(BM.bpm$bpm) {
	    lappend bpmList $bpm
	}
    }
    SetDPBPLDStatus "Testing BM bpms: $bpmList"
    if ![llength $bpmList] {
	SetDPBPLDStatus "No bpms selected."
	return
    }
    if {$type=="Ramp"} {
	set startPlane $BPLD(rampStartPlane)
	if $startPlane=="x" {
	    set planeList {x y}
	} else {
	    set planeList {y x}
	}
	foreach plane $planeList {
	    set limit $BPLD(${plane}Limit.max)
	    SetDPBPLDStatus "validating BM $plane plane bpms with ramp..."
	    if [catch {ValidateBMBPMWithRamp -plane $plane -bpmList $bpmList -limit $limit} result] {
		return -code error "Error validation with ramp: $result"
	    }
	}
    } else {
	foreach plane {x y} {
	    SetDPBPLDStatus "Validating BM $plane bpms $bpmList with offset..."
	    if [catch {ValidateBMBPMWithOffset -plane $plane -bpmList $bpmList} result] {
		return -code error "Eror validating with offset: $result"
	    }
	}
    }
    set BPLD(BM.endTime) [clock format [clock seconds] -format %Y%m%d-%H:%M:%S]
    #log result
    LogBMValidationResult -type $type
    set tmpFile /tmp/[APSTmpString]
    if [catch {exec sddsprintout -col $BPLD(BMlogFile) $tmpFile "-title=BM validation result" } result] {
	return -code error "Error printing result: $result"
    }
    APSFileDisplayWindow [APSUniqueName .] -fileName $tmpFile -deleteOnClose 1 -width 150
}



proc CreateBMWidget {args} {
    set parent ""
    APSParseArguments {parent}
    
    #BPM 7,8, 21, and 22 are used for ID
    global BPLD 
    APSLabel .label -parent $parent -fgColor blue -text "Note that BPM 21, 22, 7, and 8 are used for ID"
    APSCheckButtonFrame .sector -parent $parent -label "BM BPMs:" -buttonList $BPLD(BM.labelList) -variableList $BPLD(BM.bpmVarList) \
	-orientation horizontal  -limitPerRow 7 -allNone 1
    
    APSFrameGrid .grid -parent $parent.sector.frame -yList {y1 y2}
    set w1 $parent.sector.frame.grid.y1
    set w2 $parent.sector.frame.grid.y2

    APSButton .b0 -parent $w1 -text "01-16" -command "SelectBMbpm -choice 1-16"
    APSButton .b1 -parent $w1 -text "01-04" -command "SelectBMbpm -choice 1-4"
    APSButton .b2 -parent $w1 -text "05-08" -command "SelectBMbpm -choice 5-7"
    APSButton .b3 -parent $w1 -text "10-12" -command "SelectBMbpm -choice 10-12"
    APSButton .b4 -parent $w2 -text "13-16" -command "SelectBMbpm -choice 13-16"
    APSButton .b5 -parent $w2 -text "17-20" -command "SelectBMbpm -choice 17-20"
    APSButton .b6 -parent $w2 -text "23-24" -command "SelectBMbpm -choice 23-24"
    APSButton .b7 -parent $w2 -text "25-28" -command "SelectBMbpm -choice 25-28"
    
    APSButton .setbpm -parent $parent -text "Set BPM Mask" -command SetBMbpmMask
   # APSButton .start -parent $parent -text "Start BM BPM Validation" -command ValidateBMBPMs
    APSButton .start1 -parent $parent -text "Validate with Ramp" -command "ValidateBMBPMs -type Ramp"
    APSButton .start2 -parent $parent -text "Validate With Offset" -command "ValidateBMBPMs -type Offset"
}


set BPLD(IDplane) x

proc ValidateIDBPMs {args} {
    set type Ramp
    APSParseArguments {type}
    global BPLD IDbpms p0Index p1Index BPLDNumber
    
    SetDPBPLDStatus "Start ID bpm validation with $type..."
    SetDPBPLDStatus "Disable BPM bpms..."
    set BPLD(IDbpm.startTime) [clock format [clock  seconds] -format %Y%m%d-%H:%M:%S]
    if [catch {exec cavput -list=S${BPLDNumber}-LMPS:BPLD:BM_Enable-SP=0 -pend=10 } result] {
	return -code error "Error disable BM status: $result"
    }
    SetDPBPLDStatus "clear faults..."
    if [catch {SetupValidation -type ID} result] {
	return -code error "Error setup ID validation: $result"
    }
    SetDPBPLDStatus "Set BPLD ID BPM window shape..."
    if [catch {exec cavput -list=S${BPLDNumber}-LMPS:BPLD:ID-Shape-SP=$BPLD(IDbpm.window) -pend=10} result] {
	return -code error "Error setting ID bpm window shape..."
    }
    #SetDPBPLDStatus "Set BPLD ID position and angle limits..."
    SetIDWindowPars
    SetDPBPLDStatus "Set beam simulation current to 5..."
    if [catch {exec cavput -list=APSU:MMPS2:Sim:BeamCurrent-SP=5 -pend=10} result] {
	return -code error "Error setting beam simulation current: $result"
    }
    SetDPBPLDStatus "Set gap simulation mode to 1"
    if [catch {exec cavput -list=S${BPLDNumber}-LMPS:ID:GapSim-SP=1 -pend=10} result] {
	return -code error "Error set gap simulation mode: $result"
    }
    SetDPBPLDStatus "Set simulated gap closed..."
    if [catch {exec cavput -list=S${BPLDNumber}-LMPS:ID:GapSimClose-SP=1 -pend=10} result] {
	return -code error "Error set gap close: $result"
    }
    SetDPBPLDStatus "Set ID engaged beam current APSU:MMPS2:ID:Thold-SP – set to threshold current to arm the ID BPM"
    if [catch {exec cavput -list=APSU:MMPS2:ID:Thold-SP=$BPLD(ID.currentLimit) -pend=10} result] {
	return -code error "Error setting ID beam current limit: $result"
    }
    SetupIDTest
    set ID $BPLD(IDchoice)
    if {$ID=="ID1"} {
	set otherID ID2
    } else {
	set otherID ID1
    }
    exec cavput -list=S${BPLDNumber}-LMPS:BPLD: -list=ID1,ID2 -list=_Enable-SP=0
    after 1000
    SetDPBPLDStatus "validating $ID check..."
    SetDPBPLDStatus "enabling $ID..."
    if [catch {exec cavput -list=S${BPLDNumber}-LMPS:BPLD:${ID}_Enable-SP=1,S${BPLDNumber}-LMPS:BPLD:${otherID}_Enable-SP=0 \
		   -pend=10} result] {
	return -code error "Error enable ID check: $result"
    }
    set result0 passed
    
    
    switch $BPLD(IDplane) {
	both {
	    set coordList {x y}
	}
	default {
	    set coordList $BPLD(IDplane)
	}
    }
	
    foreach coord $coordList {
	SetDPBPLDStatus "Validating $coord plane..."
	if [catch {ValidateIDBPMWith$type -ID $ID -coord $coord} result] {
	    SetDPBPLDStatus "Error validing ID bpm: $result"
	    return
	    return -code error "Error validating $ID $coord bpm: $result"
	}
	if {$result=="failed"} {
	    set result0 failed
	}
    }
    set BPLD($ID.result) $result0
    set BPLD(IDbpm.endTime)  [clock format [clock  seconds] -format %Y%m%d-%H:%M:%S]
    SetDPBPLDStatus "clearing faults..."
   # ResetIDBPMLimits
    
    #should change the bpm mode to poly after test; #can not use string values -- because the IOC does not accept string for these pvs
    #if [catch {exec cavput -list=S${sector1}B:P0:ConvertBO.VAL=0,S${sector2}A:P0:ConvertBO.VAL=0,DP:BpmDoPolyC=1 -pend=10} result] {
#	return -code error "Error setting bpm mode: $result"
 #   }
    SetDPBPLDStatus "log result..."
    LogIDValidationResult -type $type
    set tmpFile /tmp/[APSTmpString]
    if [catch {exec sddsprintout -col=StartTime -col=Type,format=%10s -col=BPM,format=%10s -col=WindowShape,format=%15s \
		   -col=X_Status,format=%10s -col=Y_Status,format=%10s -col=Result,format=%10s \
		   $BPLD(IDlogFile) $tmpFile "-title=ID validation result" } result] {
	return -code error "Error printing result: $result"
    }
    APSFileDisplayWindow [APSUniqueName .] -fileName $tmpFile -deleteOnClose 1 -width 100
    
}

proc ValidateIDBPMWithRamp {args} {
    set ID ID1
    set coord x
    APSParseArguments {ID coord}

    global BPLD BPLDNumber
    set window $BPLD(IDbpm.window)
   
    if [catch {ResetIDBPMLimits} resul] {
	return -code error "Error reseting ID bpm limits: $result"
    }
    set putList ""
    switch $coord {
	x {
	    set limit [expr $BPLD(IDbpm.xLimit)*1e6]
	    set limit1 [expr $limit+2000]
	    if {$window==1 || $window==2} {
		#set x limit to actual limit
		lappend putList S${BPLDNumber}-LMPS:BPLD:${ID}:AIOL-H3-SP=$limit
		#set y limit to higher limit
		lappend putList S${BPLDNumber}-LMPS:BPLD:${ID}:AIOL-V3-SP=$limit1
	    }
	    if {$window==0 || $window==2} {
		#set X limit to actual limit
		lappend putList S${BPLDNumber}-LMPS:BPLD:${ID}:AIOL-H1-SP=$limit
		lappend putList S${BPLDNumber}-LMPS:BPLD:${ID}:AIOL-H2-SP=$limit
		#set Y limit to higher limit
		lappend putList S${BPLDNumber}-LMPS:BPLD:${ID}:AIOL-V1-SP=$limit1
		lappend putList S${BPLDNumber}-LMPS:BPLD:${ID}:AIOL-V2-SP=$limit1
	    }
	}
	y {
	    set limit [expr $BPLD(IDbpm.yLimit)*1e6]
	    set limit1 [expr $limit+2000]
	    if {$window==1 || $window==2} {
		#set Y limit to actual limit
		lappend putList S${BPLDNumber}-LMPS:BPLD:${ID}:AIOL-V3-SP=$limit
		#set X limit to higher limit
		lappend putList S${BPLDNumber}-LMPS:BPLD:${ID}:AIOL-H3-SP=$limit1
	    }
	    if {$window==0 || $window==2} {
		#set Y limit to actual limit
		lappend putList S${BPLDNumber}-LMPS:BPLD:${ID}:AIOL-V1-SP=$limit
		lappend putList S${BPLDNumber}-LMPS:BPLD:${ID}:AIOL-V2-SP=$limit
		#set X limit to higher limit
		lappend putList S${BPLDNumber}-LMPS:BPLD:${ID}:AIOL-H1-SP=$limit1
		lappend putList S${BPLDNumber}-LMPS:BPLD:${ID}:AIOL-H2-SP=$limit1
	    }
	}
    }
    SetDPBPLDStatus "Change ID bpm limit..."
    if [catch {exec cavput -list=[join $putList ,] -pend=10 } result] {
	return -code error "Error setting ID bpm limit: $result"
    }
    SetDPBPLDStatus "set ramp limit to $limit..."
    if [catch {exec cavput -list=S${BPLDNumber}-LMPS:P0_CntLimit-SP=$limit -pend=10} result] {
	return -code error "Error reset ramp limit1: $result"
    }
    after 2000
    SetDPBPLDStatus "checking ID bpm fault status..."
    if [catch {exec cavget -list=S${BPLDNumber}-LMPS:MLinkTXpkt_FS-I -pend=10 -printErrors} faultValue] {
	return -code error "Error reading ID fault status: $fault"
    }
    set binStr [format %b $faultValue]
    set len [string length $binStr]
    set result passed
    #only the second bit should be 1, all others should be zero
    for {set i 0} {$i<$len} {incr i} {
	#ID is the second bit
	set val [string index $binStr $i]
	if {$i==[expr $len-2]} {
	    if !$val {
		set result failed
		break
	    }
	} else {
	    if $val {
		set result failed
		break
	    }
	}
    }
    set BPLD($ID.$coord.result) $result
    return $result
}


set AbortIDTest 0
proc ValidateIDBPMWithOffset {args} {
    set ID ID1
    set coord x
    set reset 1
    APSParseArguments {ID coord reset}

    global BPLD BPLDNumber userReset AbortIDTest
    set window $BPLD(IDbpm.window)
   
   # if [catch {ResetIDBPMOffsets} result] {
#	return -code error "Error reset ID bpm offsets: $result"
 #   }
    switch $coord {
	x {
	    set plane H
	}
	y {
	    set plane V
	}
    }
    set Coord [string toupper $coord]
    
    switch $BPLD(IDbpm.window) {
	0 {
	    #diamond
	    set points 12
	    set win diamond
	} 
	1 {
	    #rect
	    set points 4
	    set win rect
	}
	2 {
	    #diamond-rect
	    set points 12
	    set win both
	}
    }
    SetIDWindowPars
    set result0 passed
    set ID $BPLD(IDchoice)
    switch $ID {
	ID1 {
	    set sector1 $BPLD(sector1)
	    set sector2 $BPLD(sector2)
	}
	ID2 {
	    set sector1 $BPLD(sector2)
	    set sector2 [expr $BPLD(sector2)+1]
	}
    }
    
    for {set i 1} {$i<=$points} {incr i} {
	if $AbortIDTest {
	    set AbortIDTest 0
	    SetDPBPLDStatus "ID validation aborted"
	    
	    return -code error "Aborted"
	}
	if !$BPLD(IDpoint.$i) {
	    continue
	}
	SetDPBPLDStatus "working with contour point - $i..."
	exec caput S${BPLDNumber}-LMPS:BPLD:${ID}_Enable-SP 1
	
	set s0 [set BPLD(ID$win.S0.${i}$coord)]
	set s0' [set BPLD(ID$win.S0.${i}${coord}')]
	set s1 [expr 1.0e3 * ($s0 - $BPLD(IDbpm.L)/2.0 * ${s0'})]
	set s2 [expr 1.0e3 * ($s0 + $BPLD(IDbpm.L)/2.0 * ${s0'})]
	#real orbit setpoint changes
	set x1 [expr ($s0 - $BPLD(IDbpm.L)/2.0 * ${s0'})]
	set x2 [expr ($s0 + $BPLD(IDbpm.L)/2.0 * ${s0'})]
	SetDPBPLDStatus "Point $i: s1=$s1,  s2=$s2"
	SetDPBPLDStatus "change offsets..."
	if [catch {exec cavget -list=S${BPLDNumber}-LMPS:BPLD:${ID}_${Coord} -list=1,2 -list=-I -printErrors -pend=10 } result] {
	    return -code error "Error reading current position: $result"
	}
	set offset1 [expr $s1 + [lindex $result 0]]
	set offset2 [expr $s2 + [lindex $result 0]]
	if [catch {exec cavput -list=S${BPLDNumber}-LMPS:BPLD:${ID}:AIOR-${plane}1-SP=$offset1,S${BPLDNumber}-LMPS:BPLD:${ID}:AIOR-${plane}2-SP=$offset2 -pend=10} result] {
	    return -code error "Error setting offset: $result"
	}
	after 3000
	#check the status
	
	set result [CheckIDFaultStatus]
	
	if {$result=="failed"} {
	    set result0 failed
	    SetDPBPLDStatus "ID offset validation at ${i}th point failed."
	    break
	} else {
	    SetDPBPLDStatus "ID offset validation at ${i}th point passed."
	}
	if $BPLD(confirm) {
	    if ![APSYesNoPopUp "Continue to next point?"] {
		SetDPBPLDStatus "ID offset validation aborted."
		return -code error "ID offset validation aborted."
	    }
	}
	SetDPBPLDStatus "reset offsets..."
	
	if [catch {exec cavput -list=S${BPLDNumber}-LMPS:BPLD:${ID}:AIOR-${plane}1-SP=0,S${BPLDNumber}-LMPS:BPLD:${ID}:AIOR-${plane}2-SP=0 -pend=10} result] {
	    return -code error "Error setting offset: $result"
	}
	#	after 3000
	set BPLD(userReset) 1
	pv putw BPLD(userReset)
	if [catch {exec cawait -waitfor=S${BPLDNumber}-LMPS:BPLD:${ID}_IL_RegOut-I,equal=0 -timeLimit=10} result] {
	    return -code error "Error waiting for fault to clear: $result"
	}
	if [catch {exec cavget -list=S${BPLDNumber}-LMPS:BPLD:${ID}_IL_RegOut-I -pend=10 } fault] {
	    return -code error "Error reading fault: $fault"
	}
	if $fault {
	    return -code error "Fault was not cleared after set the offsets to zero!"
	}
	after 2000
    }
    set BPLD($ID.$coord.result) $result0
}

proc CheckIDFaultStatus {args} {
    global BPLD
    set BPLDNumber $BPLD(BPLDNumber)
    SetDPBPLDStatus "checking ID bpm fault status..."
    if [catch {exec cavget -list=S${BPLDNumber}-LMPS:MLinkTXpkt_FS-I -pend=10 -printErrors} faultValue] {
	return -code error "Error reading ID fault status: $fault"
    }
    if !$faultValue {
	return failed
    } else {
	return success
    }
    
    set binStr [format %b $faultValue]
    set len [string length $binStr]
    set result passed
    #only the second bit should be 1, all others should be zero
    for {set i 0} {$i<$len} {incr i} {
	#ID is the second bit
	set val [string index $binStr $i]
	if {$i==[expr $len-2]} {
	    if !$val {
		set result failed
		break
	    }
	} else {
	    if $val {
		set result failed
		break
	    }
	}
    }
    return $result
}


proc ResetIDBPMLimits {args} {
    global BPLD
    pv putw $BPLD(IDLimitVarList)
    set BPLD(userReset) 1
    set BPLD(P0CountLimit) 100
    
    pv putw BPLD(userRest)
    pv putw BPLD(P0CountLimit)
}

proc SetupIDTest {args} {
    SetupValidation -type ID
    SetIDBPMLimits
   # TransferOffset
    SetDPBPLDStatus "Setup ID test done."
}

proc ResetIDBPMOffsets {args} {
    global BPLDNumber BPLD userReset

    set BPLDNumber $BPLD(BPLDNumber)
   # if [catch {exec cavput -list=S${BPLDNumber} -list=-LMPS:BPLD: -list=ID1,ID2 -list=:AIOR- -list=H,V -list=1,2 -list=-SP=0 } result] {
#	return -code error "Error reset ID bpm offsets: $result"
#    }
    if [catch {exec cavput -list=S${BPLDNumber}-LMPS:P0_CntLimit-SP=100 -pend=10} result] {
	return -code error "Error reset ramp limit: $result"
    }
    set BPLD(userReset) 1
    pv putw BPLD(userReset)
}

proc SetBMBPMLimits {args} {
    global BPLD BPLDNumber userReset
    
    
}

proc SetIDBPMLimits {args} {
    global BPLD BPLDNumber userReset
    set index 1
    set window 0
    APSParseArguments {index}
    
    set BPLD(IDbpm.diamond.x'Limit) [expr 2*$BPLD(IDbpm.xLimit)/$BPLD(IDbpm.L)]
    set BPLD(IDbpm.diamond.y'Limit) [expr 2*$BPLD(IDbpm.yLimit)/$BPLD(IDbpm.L)]
    set BPLDNumber [format %02d $BPLDNumber]
    if {$window==0} {
	#diamon shape
	set xAngleLimit [expr $BPLD(IDbpm.diamond.x'Limit)*1.0e6]
	set yAngleLimit [expr $BPLD(IDbpm.diamond.y'Limit)*1.0e6]

	set xAngleLimit 250
	set yAngleLimit 250
    } else {
	#rect or rect-diamond shape
	set xAngleLimit [expr $BPLD(IDbpm.rect.x'Limit)*1.0e6]
	set yAngleLimit [expr $BPLD(IDbpm.rect.y'Limit)*1.0e6]
	set xAngleLimit 250
	set yAngleLimit 250
	
    }
    set xLimit [expr $BPLD(IDbpm.xLimit0)*1.0e3]
    set yLimit [expr $BPLD(IDbpm.yLimit0)*1.0e3]
   
    #set x and y limit for all
    
    if [catch {exec cavput -list=S${BPLDNumber}-LMPS:BPLD: -list=ID1,ID2 -list=:AIOL-H -list=1,2,3 -list=-SP=$xLimit -pend=10} result] {
	return -code error "Error setting ID bpm x limit: $result"
    }
   # if [catch {exec cavput -list=S${BPLDNumber}-LMPS:BPLD: -list=ID1,ID2 -list=:AIOL-H,:AIOL-V -list=3 -list=-SP=0 -pend=10} result] {
#	return -code error "Error setting ID bpm x limit: $result"
 #   }
    if [catch {exec cavput -list=S${BPLDNumber}-LMPS:BPLD: -list=ID1,ID2 -list=:AIOL-V -list=1,2,3 -list=-SP=$yLimit -pend=10 } result] {
	return -code error "Error setting ID bpm y limit: $result"
    }
    #set x and y angle limit
    if [catch {exec cavput -list=S${BPLDNumber}-LMPS:BPLD: -list=ID1,ID2 -list=:AIAL_H-SP=$xAngleLimit,:AIAL_V-SP=$yAngleLimit  -pend=10 } result] {
	return -code error  "Error setting ID bpm x/y angle limit: $result"
    }
    if [catch {exec cavput -list=S${BPLDNumber}-LMPS:P0_CntLimit-SP=100 -pend=10} result] {
	return -code error "Error reset ramp limit: $result"
    }
    #set offsets to 0
    if [catch {exec cavput -list=S${BPLDNumber}-LMPS:BPLD: -list=ID1,ID2 -list=:AIOR- -list=H,V -list=1,2 -list=-SP=0  -pend=10} result] {
	    return -code error "Error setting offset: $result"
	}
    pv putw userReset
    
}

proc UpdateIDBPMSelection {W line variable tmp op} {
    global $variable  BPLD
 
    set count 0
    for {set i 0} {$i<8} {incr i} {
	if $BPLD(IDbpm.$i) {
	    set count [expr $count+1]
	}
    }
    if {$count>4} {
	SetDPBPLDStatus "ID bpms can not exceed 4!"
	set BPLD(IDbpm.$line) 0
	return
    }
    set value $BPLD(IDbpm.$line)
    set wList $BPLD(IDtable.fields.[expr $line+1])
    if $value {
	foreach w $wList {
	    $w configure -bg cyan
	}
    } else {
	foreach w $wList {
	    $w configure -bg grey90
	}
    }   
}

proc CreateIDTable {args} {
    set parent ""
    APSParseArguments {parent}

    global BPLD
    frame $parent.w 
    pack $parent.w
    frame $parent.w.f1 -bg black
    pack $parent.w.f1 -side left
    
    set w $parent.w.f1
   # set w $parent.w
    set r 0
    set content {
	{BPM Index Sector} 
	    {BP1 8 odd_up}
	    {BP0 9 odd_up}
	    {AP0 10 odd_down}
	    {AP1 11 odd_down}
	    {BP1 22 even_up}
	    {BP0 23 even_up}
	    {AP0 24 even_down}
	    {AP1 25 even_down}
    }
    set r 0
    global p0Index p1Index
    foreach row $content {
	set fields {}
	set c 0
	set i [expr $r - 1]
	set p0 0
	if [lsearch -exact $p0Index $i]>=0 {
	    set p0 1
	}
	foreach col $row {
	    if $p0 {
		#lappend fields [label $w.$r/$c -text $col -fg blue]
		lappend fields [label $w.$r/$c -text $col]
	    } else {
		lappend fields [label $w.$r/$c -text $col]
	    }
	    incr c
	}
	
	if {$r>0} {
	    set line [expr $r-1]
	    lappend fields [checkbutton $w.$r/$c -variable BPLD(IDbpm.[expr $r-1])]
	    trace variable BPLD(IDbpm.$line) w "UpdateIDBPMSelection $w.$r/$c $line"
	} else {
	    lappend fields [label $w.$r/$c -text ""]
	}
	eval grid $fields -sticky news -padx 1 -pady 1
	set BPLD(IDtable.fields.$r) $fields
	incr r
    }
    
    frame $parent.w.f2
    pack $parent.w.f2 -side right
    SelectIDBPMs -P0 1
    APSButton .p0 -parent $parent.w.f2 -text "P0" -command "SelectIDBPMs -P0 1"
    APSButton .p1 -parent $parent.w.f2 -text "P1" -command "SelectIDBPMs -P1 1"
    APSButton .none -parent $parent.w.f2 -text "none" -command "SelectIDBPMs -P0 0 -P1 0"
    
}

set p0Index {1 2 5 6}
set p1Index {0 3 4 7}
set IDP0BpmList {9 10 23 24}
set IDP1BpmList {8 11 22 25}

set IDbpms 8
proc SetupIDBPMs {args} {
    global BPLD IDbpms p0Index p1Index BPLDNumber IDP0BPMList IDP1BPMList
    set IDBPMList {8 9 10 11 22 23 24 25}
    
    set indexPVList ""
    set indexVarList ""
    for {set i 0} {$i<$IDbpms} {incr i} {
	set BPLD(IDbpm.$i) 0
	set BPLD(IDbpm.$i.index) [lindex $IDBPMList $i]
	switch $i {
	    0 -
	    3 -
	    4 -
	    7 {
		set BPLD(IDbpm.$i.P0P1) P1
	    }
	    default {
		set BPLD(IDbpm.$i.P0P1) P0
	    }
	}
	if {$i<4} {
	    set BPLD(IDbpm.$i.IDtype) ID1
	    set type ID1
	    set index 1
	} else {
	    set BPLD(IDbpm.$i.IDtype) ID2
	    set type ID2
	    set index 2
	}
	set BPLD(IDbpm.$i.indexPV) S${BPLDNumber}-LMPS:BPLD:${type}:BPM-XY${index}_idx-SP
    }
}

proc SetIDWindowPars {args} {
    global BPLD

    #increase the limit by 10%
    #mm, mrad
    set BPLD(IDbpm.diamond.x'Limit) [format %0.3f [expr 2.0*$BPLD(IDbpm.xLimit)/$BPLD(IDbpm.L)]]
    set BPLD(IDbpm.diamond.y'Limit) $BPLD(IDbpm.diamond.x'Limit)

    #x1 = Xs - L/2 * Xs'
    set BPLD(IDbpm.rect.x1Limit) [expr $BPLD(IDbpm.xLimit) + $BPLD(IDbpm.L)/2 * $BPLD(IDbpm.rect.x'Limit)]
   # puts $BPLD(IDbpm.rect.x1Limit)
    set BPLD(IDbpm.rect.x2Limit) [expr $BPLD(IDbpm.xLimit) + $BPLD(IDbpm.L)/2 * $BPLD(IDbpm.rect.x'Limit)]
   # puts $BPLD(IDbpm.rect.x2Limit)
    set BPLD(IDbpm.rect.y1Limit) $BPLD(IDbpm.rect.x1Limit)
    set BPLD(IDbpm.rect.y2Limit) $BPLD(IDbpm.rect.x2Limit)
    set BPLD(IDbpm.diamond.x1Limit) [expr $BPLD(IDbpm.xLimit) + $BPLD(IDbpm.L)/2 * $BPLD(IDbpm.diamond.x'Limit)]
    set BPLD(IDbpm.diamond.x2Limit) $BPLD(IDbpm.diamond.x1Limit)
    set BPLD(IDbpm.diamond.y1Limit) $BPLD(IDbpm.diamond.x1Limit)
    set BPLD(IDbpm.diamond.y2Limit) $BPLD(IDbpm.diamond.x2Limit)

    #rectangle limits  -- 4 points (-1,-0.25), (-1, 0.25), (1,0.25), (1,-0.25)
    set BPLD(IDrect.S0.1x) [expr -1.0 * $BPLD(IDbpm.xLimit)]
    set BPLD(IDrect.S0.1x') [expr -1.0 * $BPLD(IDbpm.rect.x'Limit)]
    set BPLD(IDrect.S0.2x) [expr -1.0 * $BPLD(IDbpm.xLimit)]
    set BPLD(IDrect.S0.2x') $BPLD(IDbpm.rect.x'Limit)
    set BPLD(IDrect.S0.3x)  $BPLD(IDbpm.xLimit)
    set BPLD(IDrect.S0.3x') $BPLD(IDbpm.rect.x'Limit)
    set BPLD(IDrect.S0.4x) $BPLD(IDbpm.xLimit)
    set BPLD(IDrect.S0.4x') [expr -1.0 * $BPLD(IDbpm.rect.x'Limit)]

    
    #diamond shape  -- 4 points (-1, 0), (0, 0.363), (1, 0), (0,-0.363)
    if {0} {
    set BPLD(IDdiamond.S0.1x) [expr -1.0 * $BPLD(IDbpm.xLimit)]
    set BPLD(IDdiamond.S0.1x') 0
    set BPLD(IDdiamond.S0.2x) $BPLD(IDbpm.diamond.x'Limit)
    set BPLD(IDdiamond.S0.2x') 0
    set BPLD(IDdiamond.S0.3x) $BPLD(IDbpm.xLimit)
    set BPLD(IDdiamond.S0.3x') 0
    set BPLD(IDdiamond.S0.4x) 0
    set BPLD(IDdiamond.S0.4x') [expr -1.0 * $BPLD(IDbpm.diamond.x'Limit)]
    }
    #diamond use 12 points as both window, but 4, 10th point are different
    #both: diamond and rectangle window
    set BPLD(IDboth.S0.1x)  [expr -1.0 * $BPLD(IDbpm.xLimit)]
    set BPLD(IDboth.S0.1x') 0
    set BPLD(IDdiamond.S0.1x) $BPLD(IDboth.S0.1x)
    set BPLD(IDdiamond.S0.1x') $BPLD(IDboth.S0.1x')

    set BPLD(IDboth.S0.2x') [expr $BPLD(IDbpm.rect.x'Limit)/2.0]
    set BPLD(IDboth.S0.2x) [format %0.3f [expr -1.0 * $BPLD(IDbpm.xLimit) + $BPLD(IDboth.S0.2x')/$BPLD(IDbpm.diamond.x'Limit)]]
    set BPLD(IDdiamond.S0.2x) $BPLD(IDboth.S0.2x)
    set BPLD(IDdiamond.S0.2x') $BPLD(IDboth.S0.2x')

    set BPLD(IDboth.S0.3x') $BPLD(IDbpm.rect.x'Limit)
    set BPLD(IDboth.S0.3x) [format %0.3f [expr -1.0 * $BPLD(IDbpm.xLimit) + $BPLD(IDboth.S0.3x')/$BPLD(IDbpm.diamond.x'Limit)]]
    set BPLD(IDdiamond.S0.3x) $BPLD(IDboth.S0.3x)
    set BPLD(IDdiamond.S0.3x') $BPLD(IDboth.S0.3x')
    set BPLD(IDdiamond.S0.4x) 0
    set BPLD(IDdiamond.S0.4x')  $BPLD(IDbpm.diamond.x'Limit)
    
    set BPLD(IDboth.S0.4x') $BPLD(IDbpm.rect.x'Limit)
    set BPLD(IDboth.S0.4x) 0
    set BPLD(IDdiamond.S0.4x) 0
    set BPLD(IDdiamond.S0.4x') $BPLD(IDbpm.diamond.x'Limit)
    
    set BPLD(IDboth.S0.5x') $BPLD(IDboth.S0.3x')
    set BPLD(IDboth.S0.5x) [format %.3f [expr -1.0 * $BPLD(IDboth.S0.3x)]]
    set BPLD(IDdiamond.S0.5x) $BPLD(IDboth.S0.5x)
    set BPLD(IDdiamond.S0.5x') $BPLD(IDboth.S0.5x')
    
    set BPLD(IDboth.S0.6x') $BPLD(IDboth.S0.2x')
    set BPLD(IDboth.S0.6x) [format %0.3f [expr -1.0 * $BPLD(IDboth.S0.2x)]]
    set BPLD(IDdiamond.S0.6x) $BPLD(IDboth.S0.6x)
    set BPLD(IDdiamond.S0.6x') $BPLD(IDboth.S0.6x')
    
    set BPLD(IDboth.S0.7x) [format %0.3f [expr -1.0 * $BPLD(IDboth.S0.1x)]]
    set BPLD(IDboth.S0.7x') 0
    set BPLD(IDdiamond.S0.7x) $BPLD(IDboth.S0.7x)
    set BPLD(IDdiamond.S0.7x') $BPLD(IDboth.S0.7x')
    
    set BPLD(IDboth.S0.8x') [format %.3f [expr -1.0 * $BPLD(IDboth.S0.6x')]]
    set BPLD(IDboth.S0.8x) $BPLD(IDboth.S0.6x)
    set BPLD(IDdiamond.S0.8x) $BPLD(IDboth.S0.8x)
    set BPLD(IDdiamond.S0.8x') $BPLD(IDboth.S0.8x')

    set BPLD(IDboth.S0.9x) $BPLD(IDboth.S0.5x)
    set BPLD(IDboth.S0.9x') [format %0.3f [expr -1.0*$BPLD(IDboth.S0.5x')]]
    set BPLD(IDdiamond.S0.9x) $BPLD(IDboth.S0.9x)
    set BPLD(IDdiamond.S0.9x') $BPLD(IDboth.S0.9x')

    
    set BPLD(IDboth.S0.10x) $BPLD(IDboth.S0.4x)
    set BPLD(IDboth.S0.10x') [format %0.3f [expr -1.0*$BPLD(IDboth.S0.4x')]]
    set BPLD(IDdiamond.S0.10x) 0
    set BPLD(IDdiamond.S0.10x') [format %0.3f [expr -1.0*$BPLD(IDbpm.diamond.x'Limit)]]

    set BPLD(IDboth.S0.11x) $BPLD(IDboth.S0.3x)
    set BPLD(IDboth.S0.11x') [format %0.3f [expr -1.0*$BPLD(IDboth.S0.3x')]]
    
    set BPLD(IDdiamond.S0.11x) $BPLD(IDboth.S0.11x)
    set BPLD(IDdiamond.S0.11x') $BPLD(IDboth.S0.11x')
    
    set BPLD(IDboth.S0.12x) $BPLD(IDboth.S0.2x)
    set BPLD(IDboth.S0.12x') [format %.3f [expr -1.0*$BPLD(IDboth.S0.2x')]]

    set BPLD(IDdiamond.S0.12x) $BPLD(IDboth.S0.12x)
    set BPLD(IDdiamond.S0.12x') $BPLD(IDboth.S0.12x')
    
    set type rect
    puts "rect.."
    for {set i 1} {$i<=4} {incr i} {
	set BPLD(ID$type.S0.${i}y) $BPLD(ID$type.S0.${i}x) 
	set BPLD(ID$type.S0.${i}y') $BPLD(ID$type.S0.${i}x') 
	puts "$i: $BPLD(ID$type.S0.${i}x) $BPLD(ID$type.S0.${i}x')"
    }
    
    set type both
    set win both
    foreach type {diamond both} win {diamond both} {
	#puts "\n$type"
	for {set i 1} {$i<=12} {incr i} {
	    puts "$i: $BPLD(ID$type.S0.${i}x) $BPLD(ID$type.S0.${i}x')"
	    set BPLD(ID$type.S0.${i}y) $BPLD(ID$type.S0.${i}x) 
	    set BPLD(ID$type.S0.${i}y') $BPLD(ID$type.S0.${i}x')
	    set s0 [set BPLD(ID$win.S0.${i}x)]
	    set s0' [set BPLD(ID$win.S0.${i}x')]
          #  puts "point $i: s0: $s0; s0': ${s0'}"
	    set s1 [expr 1.0 * ($s0 - $BPLD(IDbpm.L)/2.0 * ${s0'})]
	    set s2 [expr 1.0 * ($s0 + $BPLD(IDbpm.L)/2.0 * ${s0'})]
	   # puts "$i :  x1 --> $s1   x2--> $s2"
	} 
    }
}


proc SelectIDBPMs {args} {
    global BPLD p0Index p1Index IDbpms
    set P0 0
    set P1 0
    APSParseArguments {P0 P1}
    
    for {set i 0} {$i<$IDbpms} {incr i} {
	set BPLD(IDbpm.$i) 0
    }

    if $P0 {
	foreach i $p0Index {
	    set BPLD(IDbpm.$i) 1
	}
	set BPLD(IDbpm.BPMType) P0
    }
    if $P1 {
	foreach i $p1Index {
	    set BPLD(IDbpm.$i) 1
	}
	set BPLD(IDbpm.BPMType) P1
    }
}

SelectIDBPMs -P0 1

proc SetIDBPMOffset {args} {
    global BPLD  BPLDNumber
    
    set BPLDNumber $BPLD(BPLDNumber)
    
    switch $BPLD(IDbpm.window) {
	0 {
	    #diamond
	    set points 12
	    set win diamond
	} 
	1 {
	    #rect
	    set points 4
	    set win rect
	}
	2 {
	    #diamond-rect
	    set points 12
	    set win both
	}
    }
    SetIDWindowPars
    set ID ID1
    set sector1 $BPLDNumber
    set sector2 [expr $BPLDNumber +1]
    set coord x
    for {set i 1} {$i<=$points} {incr i} {
	if !$BPLD(IDpoint.$i) {
	    continue
	}
	set s0 [set BPLD(ID$win.S0.${i}$coord)]
	set s0' [set BPLD(ID$win.S0.${i}${coord}')]
	set s1 [expr ($s0 - $BPLD(IDbpm.L)/2.0 * ${s0'})]
	set s2 [expr ($s0 + $BPLD(IDbpm.L)/2.0 * ${s0'})]
	#SetDPBPLDStatus "upstream bpm  offset: $s1  downstream bpm offset: $s2"
	#if [catch {exec cavput -list=S${BPLDNumber}-LMPS:BPLD:${ID}:AIOR-${plane}1-SP=$s1,S${BPLDNumber}-LMPS:BPLD:${ID}:AIOR-${plane}2-SP=$s2 -pend=10} result] {
	#    return -code error "Error setting ID bpm offset: $result"
	#}
	SetDPBPLDStatus "change B:P0 and A:P0 setpoints to steer the beam ($s1, $s2)..."
	if [catch {exec cavput -list=S${sector1}B:P0:ms:${coord}:SetpointAO=$s1,S${sector2}A:P0:ms:${coord}:SetpointAO=$s2 -pend=10 } result] {
	    return -code error "Error change setpoints: $result"
	}
    }
}

proc CreateIDWidget {args} {
    set parent ""
    APSParseArguments {parent}
    
    global BPLD AbortIDTest
    
    CreateIDTable -parent $parent
    
    set BPLD(confirm) 0

    APSLabeledEntryFrame .l -parent $parent -width 10 -label "Upstream and downstream bpm distance (m) for ID1/ID2:" \
	-variableList {BPLD(ID1L) BPLD(ID2L)} -orientation horizontal
    APSRadioButtonFrame .id -parent $parent -label "Validate which ID?    " -buttonList {ID1 ID2} -valueList {ID1 ID2}  \
	-variable BPLD(IDchoice) -orientation horizontal \
	-commandList {SelectID SelectID}
    APSRadioButtonFrame .coord -parent $parent -label "Validate which plane?    " -buttonList {H V Both} -valueList {x y both}  \
	-variable BPLD(IDplane) -orientation horizontal
    APSRadioButtonFrame .confirm -parent $parent -label "Confirm at each step?"  -buttonList {Yes No} -valueList {1 0} \
	-variable BPLD(confirm) -orientation horizontal
    APSRadioButtonFrame .win -parent $parent -label "ID BPM window shape:" -buttonList {diamond rectangle both} \
	-valueList {0 1 2} -variable BPLD(IDbpm.window) -orientation horizontal
    
    for {set i 1} {$i<13} {incr i} {
	lappend butList $i
	set BPLD(IDpoint.$i) 1
	lappend varList BPLD(IDpoint.$i)
    }
    APSCheckButtonFrame .points -parent $parent -label "Select contour points:" -buttonList $butList \
	-variableList $varList -orientation horizontal -allNone 1 -limitPerRow 6

    APSButton .start -parent $parent -text "ValidateWithRamp" -command "ValidateIDBPMs -type Ramp"
    APSButton .start1 -parent $parent -text "ValidateWithOffset" -command "ValidateIDBPMs -type Offset"
    APSButton .abort -parent $parent -text "Abort" -command "set AbortIDTest 1"
    APSButton .setup -parent $parent -text "SetupIDtest" -command "SetupIDTest"
  #  APSFrame .f1 -parent $parent -packOption "-side top"
   
 #   APSButton .offset -parent $parent -text "SetOffset" -command "SetIDBPMOffset"
 #   APSButton .offset1 -parent $parent -text "TransferOffset" -command TransferOffset
}

proc TransferOffset {args} {
    global BPLD
    
    set BPLDNumber $BPLD(BPLDNumber)
    set ID $BPLD(IDchoice)
    SetDPBPLDStatus "reading raw data..."
    set BPLD($ID.offsetH1) 0
    set BPLD($ID.offsetH2) 0
    set BPLD($ID.offsetV1) 0
    set BPLD($ID.offsetV2) 0
    set varList [list BPLD($ID.offsetH1) BPLD($ID.offsetH2) BPLD($ID.offsetV1) BPLD($ID.offsetV2)]
    pv putw $varList
    #if [catch {exec cavput -list=S${BPLDNumber}-LMPS:BPLD:${ID}:AIOR- -list=H1,V1,H2,V2 -list=-SP=0 -pend=10} result] {
#	return -code error "Error set the offsets to 0: $result"
   # }
    after 2000
    if [catch {exec cavget -list=S${BPLDNumber} -list=-LMPS:BPLD:${ID}_ -list=X1,X2,Y1,Y2 -list=-I -pend=10 -repeat=number=10,pause=1,average } valList] {
	return -code error "Error reading bpm positions: $valList"
    }
    set val1 [lindex $valList 0]
    set val2 [lindex $valList 1]
    set val3 [lindex $valList 2]
    set val4 [lindex $valList 3]
    
    set BPLD($ID.offsetH1) $val1
    set BPLD($ID.offsetH2) $val2
    set BPLD($ID.offsetV1) $val3
    set BPLD($ID.offsetV2) $val4
    
    set BPLD($ID.offsetH1.ref) $val1
    set BPLD($ID.offsetH2.ref) $val2
    set BPLD($ID.offsetV1.ref) $val3
    set BPLD($ID.offsetV2.ref) $val4
    
    pv putw $varList
    
    SetDPBPLDStatus " done."
    return
}

proc LogIDValidationResult {args} {
    set type Ramp
    APSParseArguments {type}
    
    global logDir BPLD IDBPMs
    if ![file exist $BPLD(IDlogFile)] {
	set BPLD(IDlogID) [open $BPLD(IDlogFile) a+]
	puts $BPLD(IDlogID) "SDDS1"
	puts $BPLD(IDlogID) "&column name=StartTime, type=string, &end"
	puts $BPLD(IDlogID) "&column name=EndTime, type=string, &end"
	puts $BPLD(IDlogID) "&column name=Type, type=string, &end"
	puts $BPLD(IDlogID) "&column name=BPM, type=string &end"
	puts $BPLD(IDlogID) "&column name=WindowShape, type=string, &end"
	puts $BPLD(IDlogID) "&column name=X_Status, type=string, &end"
	puts $BPLD(IDlogID) "&column name=Y_Status, type=string, &end"
	puts $BPLD(IDlogID) "&column name=Result, type=string, &end"
	puts $BPLD(IDlogID) "&data mode=ascii, no_row_counts=1, &end"
	exec chmod 777 $BPLD(IDlogFile)
    } else {
	set BPLD(IDlogID) [open $BPLD(IDlogFile) a+]
    }
    switch $BPLD(IDbpm.window) {
	0 {
	    set shape diamond
	}
	1 {
	    set shape rectangle
	}
	2 {
	    set shape diamond-rect
	}
    }
    set ID $BPLD(IDchoice)
    set valList $BPLD(IDbpm.startTime)
    lappend valList $BPLD(IDbpm.endTime)
    lappend valList $type
    lappend valList "$BPLD(IDbpm.BPMType):$ID"
    lappend valList $shape
    switch $BPLD(IDplane) {
	x {
	    lappend valList $BPLD($ID.x.result)
	    lappend valList "Not_tested"
	}
	y {
	    lappend valList "Not_tested"
	    lappend valList $BPLD($ID.y.result)
	}
	both {
	    lappend valList $BPLD($ID.x.result)
	    lappend valList $BPLD($ID.y.result)
	}
    }
    lappend valList $BPLD($ID.result)
    puts $BPLD(IDlogID) "[join $valList]"
    
    flush $BPLD(IDlogID)
}

proc SetupSimMode {args} {
    if [catch {exec cavput -list=APSU:MMPS2:MaxSoftBeam-SP=50,APSU:MMPS2:BM:Thold-SP=25,APSU:MMPS2:ID:Thold-SP=5,APSU:MMPS2:ID:Thold-SP=0.7,APSU:MMPS2:Sim:BeamCurrent-SP=100 -pend=10 } result] {
	return -code error "Error setup sim currents: $result"
    }
    if [catch {exec cavput -list=APSU:MMPS2:BeamSim-SP=Sim -pend=10 } result] {
	return -code error "Error setup sim mode: $result"
    }
}

SetDefaultVars
pv linkw $VarList $PVList

SetIDWindowPars 

SetupIDBPMs

APSApplication . -name LocalMPS-BM/ID-BPMTestingLab-Sector$doubleSector  \
  -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

#if [catch {SetupValidation } result] {
#    return -code error "Error setup BM validation: $result"
#}

#APSLabeledEntry .bmlimit -parent .userFrame  -label "BM Engage current (mA):" -width 25 -textVariable BPLDchoice(BMCurrentLimit)
#bind .userFrame.bmlimit.entry <Leave> "CheckBPMIDEnageCurrent -type BM"
#APSLabeledEntry .idlimit -parent .userFrame -label "ID Engage current (mA):" -width 25 -textVariable BPLDchoice(IDCurrentLimit)
#bind .userFrame.idlimit.entry <Leave> "CheckBPMIDEnageCurrent -type ID"

set tabList [APSTabFrame .tab -parent .userFrame -width 700 -height 450 -labelList "BM ID" -packOption "-expand true"]

CreateBMWidget -parent [lindex $tabList 0]
CreateIDWidget -parent [lindex $tabList 1]

ResetIDBPMLimits 

#APSButton .start -parent .userFrame -text "Start" -command "StartVerification"
#APSButton .bpm -parent .userFrame -text "Set BM bpm Mask" -command "SetBMbpmMask"
SetupSimMode
