proc GetBMBPMs {args} {
    set gui 1
    set all 0
    APSParseArguments {gui all}
    global BMBPLD
    set tmpRoot /tmp/[APSTmpString]
    if $gui {
	#get bpms from GUI
	set bpmList0 ""
	set nbpmsList ""
	set indexList ""
	foreach sector BMBPLD(sectorList) {
	    set bpmList ""
	    set index 1
	    set maskValue 0
	    foreach item $BMBPLD(itemList) {
		set name bmBPM$sector$item
		global $name
		if [set $name] {
		    lappend bpmList $BMBPLD($sector$item.bpm)
		    lappend bpmList0 $BMBPLD($sector$item.bpm)
		    set num [expr $index+3]
		    set Bit [format %X $num]
		    set maskValue [format %.0f [expr $maskValue + pow(2, $index-1)]]
		    lappend indexList $index
		}
		incr index
	    }
	    set BMBPLD($sector.mask) $maskValue
	    set BMBPLD($sector.bpmList) $bpmList
	    set BMBPLD($sector.bpmIndexList) $indexList
	    set BMBPLD($sector.bpms) [llength $bpmList]
	    lappend nbpmsList [llength $bpmList]
	}
	set nbpmsList [lsort -unique -integer $nbpmsList]
	set BMBPLD(nbpmsList) $nbpmsList
    }  else {
	#get bpms from config files
	set statusFile /home/helios/oagData/sr/BPMStatus/config.sdds
	set configFile /home/helios/oagData/sr/BPLD/BPLD_Config/config.sdds
	set tmpRoot /tmp/[APSTmpString]
	if $all {
	    if [catch {exec sddsprocess $statusFile $tmpRoot.0 \
			    "-filter=col,NonexistentH,0,0,NonexistentV,0,0,|" \
			   "-filter=col,OkForBMBPLDH,1,1,OkForBMBPLDV,1,1,|" } result] {
		return -code error "Error obtaining BM BPLD bpms2: $result"
	    }
	} else {
	    if [catch {exec sddsprocess $configFile -filter=col,BMBPM,1,1 $tmpRoot.0} result] {
		return -code error "Error obtaining BM BPLD BPMs1: $result"
	    }
	}
	APSAddToTmpFileList -ID bm -fileList "$tmpRoot.0 $tmpRoot.1"
	set nbpmsList ""
	for {set sector0 1} {$sector0<40} {incr sector0 2} {
	    set sector [format %02d $sector0]
	    if [catch {exec sddsprocess $configFile -pipe=out -filter=col,BPLDSector,$sector0,$sector0 \
			   | sddsxref -pipe $tmpRoot.0 -match=DeviceName -nowarn \
			   | tee $tmpRoot.1 \
			   | sdds2stream -pipe=in -col=BPLDIndex } bpmList] {
		return -code error "Error obtaining S$sector BM BPLD bpms: $bpmList"
	    }
	    set BMBPLD(S$sector.bpmIndexList) [join $bpmList]
	    set BMBPLD(S$sector.bpmList) [exec sdds2stream -col=DeviceName $tmpRoot.1]
	    set BMBPLD(S$sector.bpms) [llength $BMBPLD(S$sector.bpmList)]
	    lappend nbpmsList [llength $BMBPLD(S$sector.bpmList)]
	    set maskValue 0
	    foreach bpm $bpmList {
		set num [expr $bpm+3]
		set Bit [format %X $num]
		set maskValue [format %.0f [expr $maskValue + pow(2, $bpm-1)]]
	    }
	    set BMBPLD(S$sector.mask) $maskValue
	}
	set BMBPLD(nbpmsList) [lsort -unique -integer $nbpmsList]
    }
}

proc GetBadBMBPMs {args} {
    global BMBPLD
    set statusFile /home/helios/oagData/sr/BPMStatus/config.sdds
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddsxref $BMBPLD(configDir)/config.sdds $statusFile -match=DeviceName \
		   -take=Nonexist*,OkForBMBPLD* -pipe=out \
		   | tee $tmpRoot.0 \
		   | sddsprocess  -pipe=in $tmpRoot.1 -nowarn  \
		   "-filter=col,NonexistentH,1,1,NonexistentV,1,1,|" }  result] {
	return -code error "Error obtaining nonExistList: $result"
    }
    if [catch {exec sddsprocess $tmpRoot.0 $tmpRoot.2 -nowarn \
		   "-filter=col,OkForBMBPLDH,0,0,OkForBMBPLDV,0,0,|" } result] {
	return -code error "Error obtaining notOkList: $result"
    }
    if [catch {exec sddscombine $tmpRoot.1 $tmpRoot.2 $tmpRoot.3 -merge -over } result] {
	return -code error "Error combining bad list: $result"
    }
    
    APSAddToTmpFileList -ID bpld -fileList "$tmpRoot.0 $tmpRoot.1 $tmpRoot.2 $tmpRoot.3"
    global itemList sectorList
    set badList [exec sdds2stream -col=DeviceName $tmpRoot.3]
    set badSectors [exec sdds2stream -col=BPLDSector $tmpRoot.3]
    set indexList [exec sdds2stream -col=BPLDIndex $tmpRoot.3]

    set itemList $BMBPLD(itemList)
    set missingList ""
    foreach device $badList sector $badSectors index $indexList {
	set item [lindex $itemList [expr $index -1]]
	lappend missingList S[format %02d $sector]$item
    }
    return $missingList
}

proc LoadDefaultBPLDLimits {args} {
    set type BM
    set sectorList ""
    set statusCallback ""
    APSParseArguments {type sectorList statusCallback}
    global apsSCRSnapDir apsSCRRequestDir
    
    set scrFile /home/helios/oagData/SCR/snapshots/SRBPLD/SRBPLD-DefaultBetaLimits.gz
    set apsSCRSnapDir /home/helios/oagData/SCR/snapshots
    set apsSCRRequestDir /home/helios/oagData/SCR/requestFiles
    set opt ""
    if ![llength $sectorList] {
	for {set sector 1} {$sector<40} {incr sector 2} {
	    lappend sectorList S[format %02d $sector]
	}
    }
    foreach sector $sectorList {
	if ![string length $opt] {
	    set opt -match=col,Beamline=$sector
	} else {
	    append opt ",Beamline=$sector,|"
	}
    }
    if [catch {eval exec sddsprocess $scrFile -pipe=out -match=col,Category=${type}_BPLD_Limit $opt \
		   | sddscasr -pipe=in -restore } result] {
	return -code error "Error loading BM BPLD limits from SCR: $result"
    }
    if [string length $statusCallback] {
	SetStatus "Default SCR $type BPLD limits for double sector [join $sectorList] loaded."
    }
}

proc ReadBMBPLDConfig {args} {
    set configFile ""
    APSParseArguments {configFile}

    global BMBPLD IDBPLD bmBPMCBWidget
    
    set tmpFile /tmp/[APSTmpString]
    APSAddToTmpFileList -ID bmbpld -fileList $tmpFile
    set rootname bmBPM
    APSSetSRSectorButtons -mode all-off -rootname bmBPM  -itemList $BMBPLD(itemList) \
	-sectorList $BMBPLD(sectorList)
    set sectorList $BMBPLD(sectorList)
    set itemList $BMBPLD(itemList)
    
    foreach sector $sectorList {
	set sector0 [scan $sector S%d]
	 if [catch {exec sddsprocess $configFile $tmpFile -filter=col,${type}BPM,0.5,1.5 \
			-filter=col,BPLDSector,$sector0,$sector0 } result] {
	    #no bpms for $sector0
	    continue
	}
	set indexList [exec sdds2stream -col=BPLDIndex $tmpFile]
	set deviceList [exec sdds2stream -col=DeviceName $tmpFile]
	foreach index $indexList device $deviceList {
	    set item [lindex $itemList [expr $index -1]]
	    set name $rootname$sector$item
	    set ${type}BPLD($sector$item.bpm) $device
	    global $name
	    [set ${rootname}CBWidget($sector$item)] invoke
	}
    }
}

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

proc MoveGapToBPLDTripLimits {args} {
    set moveTo ""
    set sectorList ""
    set statusCallback ""
    set wait 1
    set bothIDs 0
    APSParseArguments {moveTo sectorList statusCallback wait bothIDs}

    if ![llength $sectorList] {
	for {set sector 1} {$sector<=35} {incr sector 2} {
	    lappend sectorList $sector
	}
    }
    
    if {$moveTo>50} {
	set closeGap 0
    } else {
	set closeGap 1
    }
    set IDList ""
    foreach sector $sectorList {
	set sector0 [scan $sector %d]
	if {$sector!=29} {
	    lappend IDList [format %02d $sector0]
	}
	if {$bothIDs && $sector0>1 && [expr $sector0 % 2]} {
	    #for MPS double sector which moves both ID1 and ID2
	    lappend IDList [format %02d [expr $sector0 -1]]
	}
    }
    if [lsearch -exact "29" $sectorList]>=0 {
	#IEX
	if {$moveTo<50} {
	    #turn on IEX
	    set onoff on
	} else {
	    #turn off IEX
	    set onoff off
	}
	if [string length $statusCallback] {
	    eval $statusCallback {"turn $onoff IEX..."}
	}
	if [catch {TurnOnOffIEX -turnonoff $onoff} result] {
	    return -code error "MoveGapToBPLDTripLimits1a: error turn on/off IEX: $result"
	}
    }
    set IDList [lsort -unique  $IDList]
    if ![llength $IDList] {
	return
    }
    set badList [APSIDGetBadDeviceList -closeGap $closeGap]
    set deviceList ""
    foreach ID $IDList {
	set id1 S${ID}ID:USID
	set id2 S${ID}ID:DSID
	if [lsearch -exact $badList $id1]<0 {
	    lappend deviceList $id1
	}
	if [lsearch -exact $badList $id2]<0 {
	    lappend deviceList $id2
	}
	
    }
    if ![llength $deviceList] {
	return -code error "MoveGapToBPLDTripLimits1: No given IDs can be moved (MotorDriveStatusM is not ready)!"
    }
    set deviceList [lsort $deviceList]
     if [string length $statusCallback] {
	 eval $statusCallback {"moving [join $deviceList] gaps to $moveTo mm...."}
    }
    if [catch {exec cavput -list=[join $deviceList ,] -list=:GapSetC=$moveTo -pend=10} result] {
	return -code error "MoveGapToBPLDTripLimits2: Error setting gaps to $moveTo: $result"
    }
    after 1000
    if [catch {exec cavput -list=[join $deviceList ,] -list=:StartC=1 -pend=10} result] {
	return -code error "MoveGapToBPLDTripLimits3: error starting move gaps: $result"
    }
    if [string length $statusCallback] {
	eval $statusCallback {"Waiting for ID gaps ([join $deviceList]) stop moving. (it may take several minutes, please be patient.)"}
    }
    if [catch { APSIDsGoAndWait -IDList $deviceList -tolerance 0.5} result] {
	return -code error "Error moving ID gaps: $result"
    }
    
    return $deviceList
}

proc WriteBMValidationLogFileHeader {args} {
    set logFile ""
    APSStrictParseArguments {logFile}
    set logID ""
    if ![file exist $logFile] {
	set logID [open $logFile w]
	puts $logID "SDDS1"
	puts $logID "&column name=StartTime, type=string, &end"
	puts $logID "&column name=EndTime, type=string, &end"
	puts $logID "&column name=Sector, type=string, &end"
	puts $logID "&column name=BPM, type=string &end"
	puts $logID "&column name=Plane, type=string, &end"
	puts $logID "&column name=Limit, type=string, &end"
	puts $logID "&column name=Result, type=string, &end"
	puts $logID "&column name=ValidationType, type=string,&end"
	puts $logID "&column name=FaultDesc, type=string, &end"
	puts $logID "&data mode=ascii, no_row_counts=1, &end"
	exec chmod 777 $logFile
	flush $logID
    } else {
	set logID [open $logFile a+]
    }
    return $logID
}

proc ClearBPLDFaults {args} {
    set type BM
    set sectorList ""
    set statusCallback ""
    APSParseArguments {type sectorList statusCallback}
    
    if ![llength $sectorList] {
	return -code error "No sectors provided!"
    }
    if [string length $statusCallback] {
	eval $statusCallback {"zero offsets [join $sectorList ,]..."}
    }
    foreach sector $sectorList {
	set s0 [scan $sector %d]
	lappend sectorList0 [format %02d $s0]
    }
    
    if [catch {exec cavput -list=S-MPS:AccessType=0 -pend=5} result] {
	return -code error "Error changing MPS access mode to MPS test: $result"
    }
    switch $type {
	BM {
	    #set offsets to zero
	    if [catch {exec cavput -list=S -list=[join $sectorList0 ,] \
			   -list=-LMPS:BM_ -list=X,Y -range=begin=1,end=28 -list=_Offset-SP=0 -pend=60} result] {
		return -code error "ClearBPLDFaults1: Error set BM bpm offsets to zero: $result"
	    }
	}
	ID {
	    if [catch {exec cavput -list=S -list=[join $sectorList0 ,] \
			   -list=-LMPS:BPLD:ID -list=1,2 -list=:AIOR- \
			   -list=H,V -list=1,2 -list=-SP=0 -pend=60} result] {
		return -code error "ClearBPLDFaults2: Error set ID bpm offsts to zero: $result"
	    }
	}
    }
   
    #clearn external input faults
    if [catch {exec cavput -list=S -list=[join $sectorList0 ,] -list=-LMPS:CtrlReg0-Cmd=0 -pend=30 } result] {
	return -code error "ClearBPLDFaults3: Error clear ext inputs: $result"
    }
    if [catch {exec cavput -list=S-MPS:AccessType=1 -pend=5} result] {
	return -code error "Error change MPS access type to operation: $result"
    }
    after 3000
    if [string length $statusCallback] {
	eval $statusCallback {"reset BPLD..."}
    }
    if [catch {APScavput -list=S -list=[join $sectorList0 ,]  -list=-LMPS:UsrReset-SP=1 -pend=30 } result] {
	return -code error "Error reset to clear faults: $result"
    }
    if [string length $statusCallback] {
	eval $statusCallback {"done."}
    }
}

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

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

proc WriteIDBPLDValidationLogFileHeader {args} {
    set logFile ""
    APSStrictParseArguments {logFile}
    if ![file exist $logFile] {
	#write header of logFile
	set logID [open $logFile w]
	puts $logID "SDDS1"
	puts $logID "&column name=StartTime, type=string, &end"
	puts $logID "&column name=EndTime, type=string, &end"
	puts $logID "&column name=Sector, type=string, &end"
	puts $logID "&column name=ID, type=string, &end"
	puts $logID "&column name=BPM, type=string &end"
	puts $logID "&column name=WindowShape, type=string, &end"
	puts $logID "&column name=Plane, type=string, &end"
	puts $logID "&column name=ValidationType, type=string, &end"
	puts $logID "&column name=Result, type=string, &end"
	puts $logID "&column name=FaultDesc, type=string, &end"
	puts $logID "&data mode=ascii, no_row_counts=1, &end"
	exec chmod 777 $logFile
	flush $logID
    } else {
	set logID [open $logFile a+]
    }
    return $logID
}

proc WriteIDBPLDConfig {args} {
    set lab 0
    set statusCallback ""
    set LP0 2.756
    set LP1 3.213
    set bpmConfig default
    APSStrictParseArguments {lab statusCallback LP0 LP1 bpmConfig}
    if $lab {
	set configDir /home/oxygen/DIAG/apsu/BPLD/BPLD_Config
    } else {
	set configDir /home/helios/oagData/sr/BPLD/BPLD_Config
    }
    if {$bpmConfig=="default"} {
	#use default config
	set configFile  $configDir/IDconfig.sdds
    } else {
	set configFile $configDir/BPLDConfig-ID${bpmConfig}.sdds
    }
    if ![file exist $configFile] {
	return -code error "WriteIDBPLDConfig1: configFile - $configFile does not exist!"
    }
  
    if $lab {
	set sectorList {1 3 5}
    } else {
	for {set sector 1} {$sector<=35} {incr sector 2} {
	    lappend sectorList $sector
	}
    }
    set tmpRoot /tmp/[APSTmpString] 
    
    set pvList ""
    set valList ""
    APSAddToTmpFileList -ID bpld -fileList "$tmpRoot.1 $tmpRoot.load"
    foreach sector $sectorList {
	set sectorf [format %02d $sector]
	if [catch {exec sddsprocess $configFile -filter=col,BPLDSector,$sector,$sector -filter=col,IDBPM,0.5,1.5 $tmpRoot.$sector } result] {
	    return -code error "WriteIDBPLDConfig2: Error process data for sector $sector: $result"
	}
	APSAddToTmpFileList -ID bpld -fileList $tmpRoot.$sector
	set bpmList [exec sdds2stream -col=DeviceName $tmpRoot.$sector]
	set indexList [exec sdds2stream -col=BPLDIndex $tmpRoot.$sector]
	for {set i 1} {$i<=4} {incr i} {
	    set bpm$i [lindex $bpmList [expr $i-1]]
	    set index$i [lindex $indexList [expr $i-1]]
	}
	lappend pvList S${sectorf}-LMPS:BPLD:ID1:BPM-XY1_idx-SP
	lappend valList $index1
	lappend pvList S${sectorf}-LMPS:BPLD:ID1:BPM-XY2_idx-SP
	lappend valList $index2
	lappend pvList S${sectorf}-LMPS:BPLD:ID2:BPM-XY1_idx-SP
	lappend valList $index3
	lappend pvList S${sectorf}-LMPS:BPLD:ID2:BPM-XY2_idx-SP
	lappend valList $index4

	lappend pvList S${sectorf}-LMPS:BPLD:ID1:S1-SP
	if [regexp {P0} $bpm1] {
	    lappend valList -$LP0
	} elseif [regexp {P1} $bpm1] {
	    lappend valList -$LP1
	} else {
	    return -code error "WriteIDBPLDConfig3: invalid bpm - $bpm1 found!"
	}
	lappend pvList S${sectorf}-LMPS:BPLD:ID1:S2-SP
	if [regexp {P0} $bpm2] {
	    lappend valList $LP0
	} elseif [regexp {P1} $bpm2] {
	    lappend valList $LP1
	} else {
	    return -code error "WriteIDBPLDConfig4: invalid bpm - $bpm2 found!"
	}
	
	lappend pvList S${sectorf}-LMPS:BPLD:ID2:S1-SP
	if [regexp {P0} $bpm3] {
	    lappend valList -$LP0
	} elseif [regexp {P1} $bpm3] {
	    lappend valList -$LP1
	} else {
	    return -code error "WriteIDBPLDConfig5: invalid bpm - $bpm3 found!"
	}
	   lappend pvList S${sectorf}-LMPS:BPLD:ID2:S2-SP
	if [regexp {P0} $bpm4] {
	    lappend valList $LP0
	} elseif [regexp {P1} $bpm4] {
	    lappend valList $LP1
	} else {
	    return -code error "WriteIDBPLDConfig6: invalid bpm - $bpm4 found!"
	}
    }
    if [catch {exec sddsmakedataset -col=ControlName,type=string -data=[join $pvList ,] \
		   -col=ValueString,type=string -data=[join $valList ,] $tmpRoot.load } result] {
	return -code error "Error creating load file: $result"
    }
    if [catch {exec sddscasr -restore $tmpRoot.load} result] {
	return -code error "Error writing config to LMPS: $result"
    }
    if !$lab {
	if [catch {exec sddsconvert $configFile -pipe=out -del=col,ControlName \
		       | sddsprocess -pipe "-match=col,DeviceName=*P1,DeviceName=*P0,|" \
		       "-match=col,DeviceName=*C:P0,!" \
		       -edit=col,ControlName,DeviceName,ei/:MPS:idBPLD:InUse/ \
		       -reprint=col,ValueString,0 \
		       | sddscasr -pipe=in -restore } result] {
	    return -code error "Error writing inUse PVs1: $result"
	}
	if [catch {exec  sddsconvert $configFile -pipe=out -del=col,ControlName \
		       | sddsprocess -pipe \
		       "-match=col,DeviceName=*C:P0,!" \
		       -filter=col,IDBPM,0.5,1.5 \
		       -edit=col,ControlName,DeviceName,ei/:MPS:idBPLD:InUse/ \
		       -reprint=col,ValueString,1 \
		       | sddscasr -pipe=in -restore } result] {
	    return -code error "Error writing inUse PVs2: $result"
	}
    }
    if [string length $statusCallback] {
	eval $statusCallback {"Configuration - $configFile is loaded into LMPS."}
    }
}

proc SetupValidation {args} {
    set type BM
    set statusCallback ""
    set tripInhibit 1
    set SimBeam 0
    APSParseArguments {type statusCallback tripInhibit SimBeam}
    global BMBPLD IDBPLD
    switch $type {
	BM {
	    set sectorList [set ${type}BPLD(sectorList)]
	}
	ID {
	    foreach sector $IDBPLD(sectorList) {
		set sector0 [scan $sector %d]
		if [expr $sector0 % 2] {
		    lappend sectorLit [format %02d $sector0]
		} else {
		    lappend sectorList [format %02d [expr $sector0 -1]]
		}
	    }
	    set sectorList [lsort -unique $sectorList]
	}
    }
    
    if $tripInhibit {
	if [string length $statusCallback] {
	    eval $statusCallback  {"enabling trip inhibitor..."}
	}
	APSInfoWindow .info -width 20 -infoMessage "Please enable the trip inhibitor." -modal 1
	
	if [catch {exec cavget -list=APSU:MMPS2:CtrlReg0-Cmd.BC -pend=5 -printErrors} trip] {
	    return -code error "Error reading trip inhibitor: $trip"
	}
	if !$trip {
	    return -code error "Trip inhibitor is not enabled."
	}
    }
    
    if [catch {ClearBPLDFaults -type $type -sectorList $sectorList -statusCallback $statusCallback} result] {
	return -code error "Error clearing faults: $result"
    }
    if [string length $statusCallback] {
	eval $statusCallback {"To enable BM/ID validation, it needs following conditions"}
	eval $statusCallback {"1)the simulated hardware limit should be equal or greater than BM engaged current."}
	$statusCallback {"2) MPS arming current should be greater than 0 (normally set to 0.5mA)"}
	$statusCallback {"3) beam current has to be equal or greater than BM/ID engaged current."}
	$statusCallback {"checking hardware limit..."}
    }
    if [catch {exec cavget -list=APSU:MMPS2:Sim:BeamCurrent-SP,APSU:MMPS2:ID:Thold-SP,APSU:MMPS2:BM:Thold-SP,APSU:MMPS2:Sim:HWmaxBeam-SP,APSU:MMPS2:MaxSoftBeam-SP -pend=10} valList] {
	return -code error "Error reading sim current and current limit: $valList"
    }
    set simCurrent [lindex $valList 0]
    set IDcurrent [lindex $valList 1]
    set BMcurrent [lindex $valList 2]
    set hwLimit [lindex $valList 3]
    set swLimit [lindex $valList 4]
    set armingCurrent [set ${type}current]
    if {$hwLimit<[expr $armingCurrent+5]} {
	set limit [expr $armingCurrent  + 20]
	$statusCallback "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 increase hardward limit: $result"
	}
	set hwLimit $limit
    }
    set limit 0
    if {$swLimit<$armingCurrent} {
	set limit [expr $armingCurrent + 1 ]
	puts "software limit is lower than $type engage current, increase it."
    }
    if {$limit>0} {
	if [catch {exec cavput -list=APSU:MMPS2:MaxSoftBeam-SP=$limit -pend=10} result] {
	    return -code error "Error change software current limit to $limit: $result"
	}
    }
    $statusCallback "check beam current: it should be equal or greater than BM engaged current"
    if $SimBeam {
	if [catch {exec cavget -list=APSU:MMPS2:Sim:BeamCurrent-SP -pend=10} current] {
	    return -code error "Error reading simulated current: $current"
	}
	if {$current<$armingCurrent} {
	    set limit [expr $armingCurrent+1]
	    $statusCallback "Increase simulated current to $limit.."
	    if [catch {exec cavput -list=APSU:MMPS2:Sim:BeamCurrent-SP=$limit -pend=10} result] {
		return -code error "Error setting simulated current: $result"
	    }
	}
    } else {
	if [catch {exec cavget -list=APSU:MMPS2:BeamCurrent-I -pend=10} current] {
	    return -code error "Error reading beam current: $current"
	}
	set limit [expr $armingCurrent+1]
	if {$current<$armingCurrent} {
	    APSInfoWindow .info -width 20 -infoMessage "The beam current is less than $type engage current, please increase the beam current to $limit mA." -modal 1
	}
    }
    if [string length $statusCallback] {
	eval $statusCallback {"Reset BPLD..."}
    }
    if [catch {APScavput -list=S -list=[join $sectorList ,]  -list=-LMPS:UsrReset-SP=1 -pend=30 } result] {
	return -code error "Error reset to clear faults: $result"
    }
    if [string length $statusCallback] {
	 eval $statusCallback {"BPLD validation setup done."}
    }
    return
}
