#!/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 env(EPICS_CA_AUTO_ADDR_LIST) YES
set env(EPICS_CA_ADDR_LIST) ""
#wm geometry . +8+8

proc BringUpGlobalStatus {args} {
    set dir /home/helios/MLS/C2/iocs/mps/B1/mpsApp/op/adl
    exec medm -x  $dir/GlobalBM_Trip_Pending_X.adl &
    exec medm -x  $dir/GlobalBM_Trip_Pending_Y.adl &
}

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

set bmBPMConfigStatus "ready."

proc GetBadList {args} {
    global BPLD
    set statusFile /home/helios/oagData/sr/BPMStatus/config.sdds
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddsxref $BPLD(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 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 SaveGeneralLimits {args} {
    set configFile ""
    APSParseArguments {configFile}
    global BPLD description

    set BPLD(C:P0.xLimit) $BPLD(B:P0.xLimit)
    set BPLD(C:P0.yLimit) $BPLD(B:P0.yLimit)
    
    if ![APSYesNoPopUp "Save general limit will overwrite the individual sector limits, are you sure to continue?"] {
	return
    }
    if ![string length $configFile] {
	set filename BPLDConfig-[clock format [clock seconds] -format %Y-%j-%m%d:%H%M%S]
    } else {
	set filename $configFile
    }
    set deviceList [exec sdds2stream -col=DeviceName $BPLD(configDir)/config.sdds]
    set xLimit [exec sdds2stream -col=xBMLimit  $BPLD(configDir)/config.sdds]
    set yLimit [exec sdds2stream -col=yBMLimit  $BPLD(configDir)/config.sdds]
    
    set xCol ""
    set yCol ""
    foreach plane {x y} {
	foreach device $deviceList {
	    set type [string range $device 3 end]
	    lappend ${plane}Col [expr 1000 * $BPLD(${type}.${plane}Limit)]
	}
    }
    set tmpRoot /tmp/[APSTmpString]
   
    if [catch {exec sddsmakedataset $tmpRoot.1 -col=DeviceName,type=string -data=[join $deviceList ,] \
		   -col=xBMLimit,type=double -data=[join $xCol ,] \
		   -col=yBMLimit,type=double -data=[join $yCol ,] } result] {
	return -code error "Error save config1: $result"
    }
    if [catch {exec sddsconvert $BPLD(configDir)/config.sdds -pipe=out -del=col,xBMLimit,yBMLimit \
		   | sddsprocess -pipe "-reprint=par,Description,[APSMakeSafeQualifierString $BPLD(description)]" \
		   | sddsxref -pipe=in $tmpRoot.1 $BPLD(configDir)/$filename -match=DeviceName -take=xBMLimit,yBMLimit } result] {
	return -code error "Error save config2: $result"
    }
    set oldDir [pwd]
    catch {exec rm $BPLD(configDir)/config.sdds}
    cd $BPLD(configDir)
    exec ln -s $filename config.sdds
    cd $oldDir
    SetStatus "genral limits are saved to $filename"
    SetStatus "Loading limits to ioc for selected bpms..."
    if [catch {LoadLimits -configFile $BPLD(configDir)/config.sdds } result] {
	return -code error "Error loading limits for selected bpms: $result"
    }
    APSAddToTmpFileList -ID bmbpld -fileList $tmpRoot.1
    SetStatus "done."
}

proc DeleteConfig {args} {
    set widget ""
    APSParseArguments {widget}
    global BPLD
    set parent $widget.userFrame.sl.listbox
    set chosenList [$parent curselection]
    if ![llength $chosenList] {
	return -code error "No files are chosen"
    }
    set index0 0
    foreach index $chosenList {
	set files $BPLD(dispList)
	set file [lindex $BPLD(dispList) [expr $index-$index0]]
	if [APSYesNoPopUp "Are you sure to delete $file?"] {
	    set file0 [lindex [split $file " "] 0]
	    SetStatus "deleting $file0..."
	    file delete -force $BPLD(configDir)/$file0
	    set index [expr $index - $index0]
	    $parent delete $index $index
	    set BPLD(dispList) [lreplace $files $index $index]
	    incr index0
	}
    }
}

proc SaveConfig {args} {
    set configFile ""
    APSParseArguments {configFile}
    global BPLD  lab

    if ![string length $BPLD(description)] {
	SetStatus "Please provide description for saving config!"
	return
    }
    if ![string length $configFile] {
	set filename BPLDConfig-[clock format [clock seconds] -format %Y-%j-%m%d:%H%M%S]
    } else {
	set filename $configFile
    }

    set deviceList [exec sdds2stream -col=DeviceName $BPLD(configDir)/config.sdds]
    set xLimit [exec sdds2stream -col=xBMLimit  $BPLD(configDir)/config.sdds]
    set yLimit [exec sdds2stream -col=yBMLimit  $BPLD(configDir)/config.sdds]
    set rootList [exec sdds2stream -col=MPSRootname $BPLD(configDir)/config.sdds]
    set bpldSector [exec sdds2stream -col=BPLDSector $BPLD(configDir)/config.sdds]
    
    set BMCol ""
   
    set bpmList [GetBPMs]
    set index 0
   # puts $bpmList
    foreach device $deviceList root $rootList bsector $bpldSector {
	if [lsearch -exact $bpmList $device]>=0 {
	    lappend BMCol 1
	    set BPLD($device.inusevar) 1
	    foreach plane {x y} {
		if [info exist BPLD($device.${plane}Limit)] {
		    set ${plane}Limit [lreplace [set ${plane}Limit] $index $index $BPLD($device.${plane}Limit)]
		} else {
		    set type [string range $device 3 end]
		    set ${plane}Limit [lreplace [set ${plane}Limit] $index $index $BPLD($type.${plane}Limit)]
		}
	    }
	} else {
	    lappend BMCol 0
	    set BPLD($device.inusevar) 0
	}
	incr index
    }
    set tmpRoot /tmp/[APSTmpString]
   
    if [catch {exec sddsmakedataset $tmpRoot.1 -col=DeviceName,type=string -data=[join $deviceList ,] \
		   -col=BMBPM,type=short -data=[join $BMCol ,] \
		   -col=xBMLimit,type=double -data=[join $xLimit ,] \
		   -col=yBMLimit,type=double -data=[join $yLimit ,] } result] {
	return -code error "Error save config1: $result"
    }
    if [catch {exec sddsconvert $BPLD(configDir)/config.sdds -pipe=out -del=col,BMBPM,xBMLimit,yBMLimit \
		   | sddsprocess -pipe "-reprint=par,Description,[APSMakeSafeQualifierString $BPLD(description)]" \
		   | sddsxref -pipe=in $tmpRoot.1 $BPLD(configDir)/$filename -match=DeviceName -take=BMBPM,xBMLimit,yBMLimit } result] {
	return -code error "Error save config2: $result"
    }
    # puts $filename
    	SetStatus "config saved to $filename"
    APSAddToTmpFileList -ID bmbpld -fileList $tmpRoot.1
    if [APSYesNoPopUp "saving the new config as default config?"] {
	set oldDir [pwd]
	catch {exec rm $BPLD(configDir)/config.sdds}
	cd $BPLD(configDir)
	exec ln -s $filename config.sdds
	cd $oldDir
	SetStatus "Set BM BPLD in use pvs..."
   
	if [catch {exec sddsconvert  $BPLD(configDir)/$filename -pipe=out -del=col,ControlName  \
		       | sddsprocess -pipe "-macth=col,DeviceName=*C:P0,!"\
		       -edit=col,ControlName,DeviceName,ei/:MPS:bmBPLD:InUse/  -reprint=col,ValueString,%d,BMBPM \
		       | sddscasr -pipe=in -restore } result] {
	    return -code error "Error setting inuse BPLD: $result"
	}       
	
	SetStatus "Set BM BPLD masks..."
	if [catch {SetBMBPLDMasks} result] {
	    return -code error "Error setting BM BPLD masks: $result"
	}
	
	SetStatus "done."
    }
}

proc ConfigOptions {args} {
    set option load
    APSParseArguments {option}
    global BPLD
    set oldDir [pwd]
    cd $BPLD(configDir)
    set files [lsort -decreasing [glob BPLDConfig-????-???-*]]
    set tmpFile /tmp/[APSTmpString]
    set BPLD(selectConfig) ""
    if [catch {eval exec sddscombine $files -pipe=out \
		   | sddscollapse -pipe \
		   | sddssort -pipe=in $tmpFile -col=Filename,decr } result] {
	return -code error "Error searching for setup files: $result"
    }
    set linkFile [file readlink config.sdds]
    cd $oldDir
    APSAddToTmpFileList -ID bpld -fileList $tmpFile
   
    set fileList [exec sdds2stream -col=Filename $tmpFile]
    set descList [exec sdds2stream -col=Description $tmpFile]
    set displList ""
    set file config.sdds
    set desc "default config"
    lappend dispList "$file $desc"
    foreach file  $fileList desc $descList {
	lappend dispList "$file $desc"
    }
    global selectFile 
    set selectFile ""
    set BPLD(dispList) $dispList
    APSScrolledListWindow .select -height 10 -name "Select A file" -itemList $dispList \
	-selectionVar selectFile
    APSDialogBoxAddButton .delete -parent .select -text "Delete" -command "DeleteConfig -widget .select"
    
    tkwait variable selectFile
    if ![string length $selectFile] {
	SetStatus "No file is chosen!"
	return
    }
    set file [lindex [split $selectFile " "] 0]
    set file [regsub {\{} $file ""]
    set desc [regsub "$file" $selectFile ""]
    set desc [regsub {\{} $desc ""]
    set desc [regsub {\}} $desc ""]
    set oldDir [pwd]
    SetStatus "$file $desc"
    switch $option {
	load {
	    if [catch {LoadConfig0 -filename $file -confirm 1 -description $desc} result] {
		return -code error "Error loading config $file: $result"
	    }
	}
	makeDefault {
	    if {$file=="config.sdds"} {
		SetStatus "config.sdds is chosen, nothing changed."
		return
	    }
	    SetStatus "making $file as default config."
	    cd $BPLD(configDir)
	    exec rm config.sdds
	    exec ln -s $file config.sdds
	    cd $oldDir
	}
    }
    SetStatus "done."
    #APSMakeSDDSListbox $tmpFile .restore -title "Choose a config" \
    #	-page 0 -labelmaker MakeLBoxTextLine  -packOption "-side top -expand true -fill y" \
    #    -callback $command  Description Filename
}

#read ID BPM index to find the ID BPLD BPMs, these BPMs should be disabled for BM configuration
#set BPLD(configDir) /home/oxygen/DIAG/apsu/BPLD/BPLD_Config
set firstLoad 1
proc LoadIDBMConfig {args} {
    global BPLD misingList bmBPMCBWidget firstLoad lab
    set oldDir [pwd]
    cd $BPLD(configDir)
    set files [lsort -decreasing [glob BPLDConfig-????-???-*]]
  
    set tmpFile /tmp/[APSTmpString]
    set BPLD(selectConfig) ""
    if [catch {eval exec sddscombine $files -pipe=out \
		   | sddscollapse -pipe \
		   | sddssort -pipe=in $tmpFile -col=Filename,decr } result] {
	return -code error "Error searching for setup files: $result"
    }
    cd $oldDir
    APSAddToTmpFileList -ID bpld -fileList $tmpFile
    APSMakeSDDSListbox $tmpFile .restore -title "Choose a config" \
	-page 0 -labelmaker MakeLBoxTextLine  -packOption "-side top -expand true -fill y" \
        -callback LoadConfig0  Description Filename
  
}
proc MakeLBoxTextLine {data width} {
    set description [lindex $data 0]
    set wd [lindex $width 0]
    set filename [lindex $data 1]
    set timestamp [string range $filename 11 end]
    set wt [string length $timestamp]
    set wf [lindex $width 1]
    set rootname [file rootname $filename]
    if [file exists $rootname.preferred] {
        set suffix " *"
    } else {
        set suffix "  "
    }
    
    set sform [format "%%%lds    %%%lds$suffix" $wt $wd]
    return [format $sform $timestamp $description]
}
proc LoadDefaultConfig {args} {
    global BPLD
    LoadConfig0 -filename config.sdds -confirm 0
}

proc LoadConfig0 {args} {
    set confirm 1
    set filename ""
    set description ""
    APSParseArguments {confirm filename description}
    global BPLD bmBPMCBWidget
    
    APSSetSRSectorButtons -mode all-off -rootname bmBPM  -itemList $BPLD(itemList) -sectorList $BPLD(sectorList)
    
    #set configFile $BPLD(configDir)/config.sdds
    set configFile $BPLD(configDir)/$filename
    SetStatus "Loading $description ..."
    if [catch {exec sddsprocess $configFile -pipe=out -filter=col,BMBPM,1,1 -nowarn \
		   | sdds2stream -pipe=in -col=DeviceName  } bmList] {
	return -code error "Error reading ID bpm list: $bmList"
    }
    if ![llength $bmList] {
	SetStatus "NO bpms for is found for BM BPLD."
	#return
    }
    set deviceList [exec sdds2stream -col=DeviceName $configFile]
    set xLimit [exec sdds2stream -col=xBMLimit $configFile]
    set yLimit [exec sdds2stream -col=yBMLimit $configFile]
    
    set bsectorList [exec sdds2stream -col=BPLDSector $configFile]
    set bindexList [exec sdds2stream -col=BPLDIndex $configFile]
    set linkPVList ""
    set linkVarList ""
    
    set BPLD(BMbpm) [join $bmList]
    
    foreach sector $BPLD(sectorList) {
	foreach item $BPLD(itemList) {
	    set nm $sector$item
	    set name bmBPM$sector$nm
	    set bpm $BPLD($nm.bpm)
	    global $name
	    set index [lsearch -exact $bmList $bpm]
	    if $index>=0 {
		if [info exist bmBPMCBWidget($sector$item)] {
		    $bmBPMCBWidget($sector$item) invoke
		}
		set $name 1
	    } else {
		set $name 0
	    }
	}
    }
    
    foreach device $deviceList x $xLimit y $yLimit sector $bsectorList index $bindexList {
	set sector0 [scan $device S%d]
	if {$sector0==40 && $sector==1} {
	    set stream :us
	} elseif {$sector==[expr $sector0 +1]} {
	    set stream :us
	} elseif {$sector==$sector0} {
	    set stream ""
	} elseif {$sector==[expr $sector0 - 1]} {
	    set stream :ds
	}
	set inusePV  $device:MPS:bmBPLD:InUse
	set BPLD($device.inusePV) $inusePV
	set BPLD($device.inusevar) 0

	set BPLD($device.xLimit) [format %.0f $x]
	set BPLD($device.yLimit) [format %.0f $y]
	set BPLD($device.bpldSector) $sector
	set BPLD($device.bpldIndex) $index
	set BPLD($device.xLimitPV) S[format %02d $sector]-LMPS:BM_X${index}_TH-SP
	set BPLD($device.yLimitPV) S[format %02d $sector]-LMPS:BM_Y${index}_TH-SP
	set BPLD($device.xRawPV) S[format %02d $sector]-LMPS:BM_TBT_X${index}-I 
	set BPLD($device.yRawPV) S[format %02d $sector]-LMPS:BM_TBT_Y${index}-I
	
	set BPLD($device.xStatus) ok
	set BPLD($device.yStatus) ok
	if [lsearch -exact $BPLD(existSectors) $sector]<0 {
	    continue
	}
	lappend linkPVList $inusePV
	lappend linkVarList BPLD($device.inusevar)
	foreach plane {x y} {
	    foreach name {Raw Limit} {
		lappend linkPVList $BPLD($device.${plane}${name}PV)
		lappend linkVarList BPLD($device.${plane}$name)
	    }
	}
	
    }
  #  puts $linkPVList
    pv unlinkw $linkVarList
    #looks like cannot linkw too many pvs at one time
   
    set bpmList [GetBPMs]
    set BPLD(linkPVList) $linkPVList
    set BPLD(linkVarList) $linkVarList
    global errorCode
    if {0} {
    if [pv linkw $linkVarList $linkPVList] {
	SetStatus "Error link PVs: $errorCode "
	SetStatus "$linkPVList"
    }
    set errorCode ""
    
    if [pv getw $linkVarList 30] {
	SetStatus "Error reading PV values: $errorCode"
    }
    SetStatus "PV link created."
    foreach plane {x y} {
	foreach bpm $bpmList {
	    pv umon BPLD($bpm.${plane}Raw) "UpdateBPLDStatus -plane $plane -bpm $bpm"
	    pv umon BPLD($bpm.${plane}Limit)  "UpdateBPLDStatus -plane $plane -bpm $bpm"
	}
    }
    }
    SetStatus "config loaded."
    if {[APSYesNoPopUp "Writing config into firmware?"]} {
	SetStatus "Write inuse PVs..."
	if [catch {exec sddsconvert  $BPLD(configDir)/$filename -pipe=out -del=col,ControlName \
		       | sddsprocess -pipe "-match=col,DeviceName=*C:P0,!" \
		       -edit=col,ControlName,DeviceName,ei/:MPS:bmBPLD:InUse/  -reprint=col,ValueString,%d,BMBPM \
		       | sddscasr -pipe=in -restore } result] {
	    return -code error "Error setting inuse BPLD in lab: $result"
	}       
	
	SetStatus "Set BM BPLD masks..."
	if [catch {SetBMBPLDMasks -config $filename} result] {
	    return -code error "Error setting BM BPLD masks: $result"
	}
	SetStatus "done."
    }
    #create status widget
     # .userFrame.tab.frame.tn select 2
    # CreateBPLDStatusWidget -plane x -parent $BPLD(xStatusW)
    
    #.userFrame.tab.frame.tn select 3
    #CreateBPLDStatusWidget -plane y -parent $BPLD(yStatusW)
    
    
   # .userFrame.tab.frame.tn select 0
    #SetStatus "status window created."
    
    set firstLoad 0
}

proc ApplyLimitOffsetByBPM {args} {
    set bpm ""
    set plane ""
    set type both
    APSParseArguments {bpm plane type}
    global BPLD
    switch $type {
	offset {
	    SetStatus "BPLD offsets are not allowed to change!"
	    return
	    if [catch {exec cavput -list=$BPLD($bpm.${plane}OffsetPV)=$BPLD($bpm.${plane}Offset) } result] {
		return -code error "Error apply new offset to $plane $bpm: $result"
	    }
	}
	limit {
	    if [catch {exec cavput -list=$BPLD($bpm.${plane}LimitPV)=$BPLD($bpm.${plane}Limit) } result] {
		return -code error "Error apply new limit to $plane $bpm: $result"
	    }
	}
	default {
	    if [catch {exec cavput -list=$BPLD($bpm.${plane}LimitPV)=$BPLD($bpm.${plane}Limit) } result] {
		return -code error "Error apply new limit to $plane  $bpm: $result"
	    }
	}
    }
}

proc UpdateBPLDStatus {args} {
    set bpm ""
    set plane ""
    APSParseArguments {bpm plane}
    global BPLD
    #pv getw $BPLD(linkVarList)
    set color grey
    if [info exist BPLD($bpm.${plane}Status)] {
	set status0 $BPLD($bpm.${plane}Status)
    } else {
	set status0 ""
    }
    pv getw $BPLD($bpm.${plane}Raw)
    pv getw $BPLD($bpm.${plane}Limit)
    update
		 
    set status ok
    if [expr abs($BPLD($bpm.${plane}Raw))]>$BPLD($bpm.${plane}Limit) {
	set color red
	set status trip
    } else {
	set delta [expr abs(abs($BPLD($bpm.${plane}Raw)) - $BPLD($bpm.${plane}Limit))]
	#/$BPLD($bpm.${plane}Limit)]
	set delta [expr $delta/$BPLD($bpm.${plane}Limit)]
	#puts "$bpm $delta $plane $BPLD($bpm.${plane}Raw) $BPLD($bpm.${plane}Limit) "
	set color grey
	if $delta<0.1 {
	    set color red
	    set status major
	} elseif {$delta<0.3} {
	    set color yellow
	    set status minor
	}
    }
    set BPLD($bpm.${plane}Status) $status
  #  puts "$status0 $status"
    if [string compare $status0 $status]!=0 {
	if [info exist BPLD($bpm.${plane}StatusW)] {
	    #puts "$status0 $status $color"
	    $BPLD($bpm.${plane}StatusW) configure -background $color -readonlybackground $color
	}
    }
}
    
proc GetBPMs {args} {
    global BPLD
    set bpmList ""
    foreach sector $BPLD(sectorList) {
	foreach item $BPLD(itemList) {
	    set name bmBPM$sector$item
	    global $name
	    if [set $name] {
		lappend bpmList $BPLD($sector$item.bpm)
	    }
	}
    }
    return $bpmList
}

proc LoadLimits {args} {
    set configFile ""
    APSStrictParseArguments {configFile}
    global BPLD lab
    
    set tmpRoot /tmp/[APSTmpString]
    set bpmList [GetBPMs]
    if ![llength $bpmList] {
	SetStatus "No bpms selected for loading limits."
	continue
    }
    if ![string length $configFile] {
	return -code error "Config file not provided."
    }
    
    if [catch {exec sddsmakedataset -col=DeviceName,type=string -data=[join $bpmList ,] $tmpRoot.bpm } result] {
	return -code error "LoadLimits1: $result"
    }
    APSAddToTmpFileList -ID bmbpld -fileList $tmpRoot.bpm
    
    
    foreach plane {x y} {
	if [catch {exec sddsxref $tmpRoot.bpm $BPLD(configDir)/config.sdds -pipe=out -match=DeviceName \
		       -take=BPLDSector,BPLDIndex,${plane}BMLimit  \
		       | sddsprocess -pipe=in $tmpRoot.$plane.limit \
		       -print=col,ControlName,S%02d-LMPS:BM_[string toupper $plane]%d_TH-SP,BPLDSector,BPLDIndex \
		       -print=col,ValueString,%lf,${plane}BMLimit } result] {
	    return -code error "Error getting $plane BM bpld limits: $result"
	}
	if [catch {eval exec sddsprocess $tmpRoot.$plane.limit $BPLD(filterOpt) -nowarn } result] {
	    return -code error "Error filter bpms for lab: $result"
	}
	
	if [catch {exec sddscasr -restore $tmpRoot.$plane.limit -pend=10} result] {
	    return -code error "Error loading $plane BM BPLD limits: $result"
	}
	APSAddToTmpFileList -ID bmbpld -fileList "$tmpRoot.bpm $tmpRoot.$plane.limit"
	SetStatus "$plane plane BM bpld limits loaded."
    }
    
}

proc SetBMBPLDMasks {args} {
    global BPLD
    set config ""
    APSParseArguments {config}
    
    set tmpRoot /tmp/[APSTmpString]
    set valList ""
    set pvList ""
    set putList ""
    set enablePV ""
    if ![string length $config] {
	set config config.sdds
    }
    foreach sector $BPLD(existSectors) {
	if [catch {exec sddsprocess $BPLD(configDir)/$config $tmpRoot.$sector -filter=col,BPLDSector,$sector,$sector \
		   -filter=col,BMBPM,0.5,1.5 -nowarnings} result] {
	    return -code error "Error getting sector data: $result"
	}
	APSAddToTmpFileList -ID BMbpld -fileList $tmpRoot.$sector
	set bpmList [exec sdds2stream -col=DeviceName $tmpRoot.$sector]
	set indexList [exec sdds2stream -col=BPLDIndex $tmpRoot.$sector]
	lappend pvList S[format %02d $sector]-LMPS:BPLD:BpmMask-SP
	lappend enablePV S[format %02d $sector]-LMPS:BPLD:BM_Enable-SP=1
	set value 0
	if [llength $bpmList] {
	    foreach index $indexList {
		set value [expr $value + pow(2, $index-1)]
	    }
	}
	set value [expr int($value)]
	lappend valList $value
	lappend putList S[format %02d $sector]-LMPS:BPLD:BpmMask-SP=$value
    }
    if [catch {exec cavput -list=[join $putList ,] -pend=10 } result] {
	return -code error "Error setting BM mask: $result"
    }
    if [catch {exec cavput -list=[join $enablePV ,]  -pend=10} result] {
	return -code error "Error enabling BM BPLD: $result"
    }
    SetStatus "read BM mask to confirm..."
    if [catch {exec cavget -list=[join $pvList ,] -pend=10} maskList] {
	return -code error "Error reading BM masks: $result"
    }
    foreach sector $BPLD(existSectors) pv $pvList mask $maskList val $valList {
	if {$mask!=$val} {
	    SetStatus "Error Sector $sector BM mask do not agree."
	}
    }
    SetStatus "done."
}

proc CreateBPLDStatusWidget {args} {
    set parent ""
    set plane ""
    APSParseArguments {parent plane}

    puts $parent
    return
    global BPLD lastWidget
    set bpmList [GetBPMs]
    return
    if ![llength $bpmList] {
	#	SetStatus "No bpms for $plane plane."
	return
    }
    SetStatus "Creating $plane plane BPLD status window..."
    APSFrame .status$plane -parent $parent -label "$plane BM BPLD values and status." -width 80
    set w $parent.status$plane.frame
    APSLabel .label -parent $w -text "BPM Name  BPLDsector       readbacks (um)    limits (um)     BPLDstatus    "
    return
    set BPLD(${plane}scroll) [APSScroll .scroll -parent $w -contextHelp "BM BPLD limits for each sector"]
    set width 15
    puts $BPLD(${plane}scroll)
    return
    foreach bpm $bpmList {
	set sector [scan $bpm S%d]
	if [lsearch -exact $BPLD(existSectors) $BPLD($bpm.bpldSector)]<0 {
	    continue
	}
	APSFrame .s$bpm -parent $BPLD(${plane}scroll) -packOption "-side top"
	set sectorframe $BPLD(${plane}scroll).s$bpm.frame 
	$sectorframe configure -relief flat -bd 0
	label $sectorframe.label -text "$bpm" -width 8 -pady 2
        pack  $sectorframe.label -side left -fill x
	APSLabeledOutput .s -parent $sectorframe -label "" -packOption {-padx 0 -pady 0 -side left} -width $width -textVariable BPLD($bpm.bpldSector)
	APSLabeledOutput .raw -parent $sectorframe -label "" -packOption {-padx 0 -pady 0 -side left} -width $width -textVariable BPLD($bpm.${plane}Raw) 
	APSLabeledEntry .limits -parent $sectorframe -label "" -packOption {-padx 0 -pady 0 -side left} -width $width -textVariable BPLD($bpm.${plane}Limit)
	bind $sectorframe.limits.entry <Return> "ApplyLimitOffsetByBPM -bpm $bpm -plane $plane -type limit"
	APSLabeledOutput .status -parent $sectorframe -label "" -packOption {-padx 0 -pady 0 -side left} -width $width -textVariable BPLD($bpm.${plane}Status)
	set BPLD($bpm.${plane}StatusW) $sectorframe.status.entry
	switch $BPLD($bpm.${plane}Status) {
	    ok {
		set color grey
	    }
	    minor {
		set color yellow
	    }
	    major {
		set color red
	    }
	    default {
		set color red
	    }
	}
	$sectorframe.status.entry configure -background $color -readonlybackground $color
	APSButton .apply -parent $sectorframe -text "Apply" -size small -command "ApplyLimitOffsetByBPM -bpm $bpm -plane $plane"
	
	set lastWidget $sectorframe
    }
    tkwait visibility $lastWidget 
    APSScrollAdjust  $w.scroll -numVisible 25
}

proc ZeroOffsets {args} {
    global BPLD lab
    set bpmList [GetBPMs]
    set varList ""
    foreach bpm $bpmList {
	foreach plane {x y} {
	    set BPLD($bpm.${plane}Offset) 0
	    if [lsearch -exact  $BPLD(existSectors) $BPLD($bpm.bpldSector)]<0 {
		continue
	    }
	    lappend varList BPLD($bpm.${plane}Offset)
	}
    }
    update
    if [llength $varList] {
	pv putw $varList
    }
}

proc MakeLimitsWidget {args} {
    set parent ""
    APSParseArguments {parent}
    global BPLD

    APSFrame .f0 -parent $parent
    $parent.f0.frame configure -bd 0
    APSButton .load0 -parent $parent.f0.frame -text "Load Beta Limits from database" -command "LoadBMLimits" \
	-contextHelp "Load BM beta limits from database to GUI display."
    APSFrame .limits1 -parent $parent -label "General BM BPLD Limits"
    set w $parent.limits1.frame
    $w configure -bd 0 -relief flat
   
    APSFrameGrid .grid -parent $w -xList {x1 x2}
    set w1 $w.grid.x1
    set w2 $w.grid.x2
    APSLabeledEntryFrame .l11 -parent $w1 -label "BM BPLD A:P0 H/V limit(mm):" -width 15 -variableList {BPLD(A:P0.xLimit) BPLD(A:P0.yLimit)} \
	-orientation horizontal
    APSLabeledEntryFrame .l12 -parent $w1 -label "BM BPLD A:P1 H/V limit(mm):" -width 15 -variableList {BPLD(A:P1.xLimit) BPLD(A:P1.yLimit)} \
	-orientation horizontal
    
    APSLabeledEntryFrame .l1 -parent $w1 -label "BM BPLD A:P2 H/V limit(mm):" -width 15 -variableList {BPLD(A:P2.xLimit) BPLD(A:P2.yLimit)} \
	-orientation horizontal
    APSLabeledEntryFrame .l2 -parent $w1 -label "BM BPLD A:P3 H/V limit(mm):" -width 15 -variableList {BPLD(A:P3.xLimit) BPLD(A:P3.yLimit)} \
	-orientation horizontal
    APSLabeledEntryFrame .l3 -parent $w1 -label "BM BPLD A:P4 H/V limit(mm):" -width 15 -variableList {BPLD(A:P4.xLimit) BPLD(A:P4.yLimit)} \
	-orientation horizontal
    APSLabeledEntryFrame .l4 -parent $w1 -label "BM BPLD A:P5 H/V limit(mm):" -width 15 -variableList {BPLD(A:P5.xLimit) BPLD(A:P5.yLimit)} \
	-orientation horizontal
    APSLabeledEntryFrame .l5 -parent $w1 -label "BM BPLD A:P6 H/V limit(mm):" -width 15 -variableList {BPLD(A:P6.xLimit) BPLD(A:P6.yLimit)} \
	-orientation horizontal
    
    
    APSLabeledEntryFrame .l11 -parent $w2 -label "BM BPLD B:P0 H/V limit(mm):" -width 15 -variableList {BPLD(B:P0.xLimit) BPLD(B:P0.yLimit)} \
	-orientation horizontal
    APSLabeledEntryFrame .l12 -parent $w2 -label "BM BPLD B:P1 H/V limit(mm):" -width 15 -variableList {BPLD(B:P1.xLimit) BPLD(B:P1.yLimit)} \
	-orientation horizontal
    
    APSLabeledEntryFrame .l1 -parent $w2 -label "BM BPLD B:P2 H/V limit(mm):" -width 15 -variableList {BPLD(B:P2.xLimit) BPLD(B:P2.yLimit)} \
	-orientation horizontal
    APSLabeledEntryFrame .l2 -parent $w2 -label "BM BPLD B:P3 H/V limit(mm):" -width 15 -variableList {BPLD(B:P3.xLimit) BPLD(B:P3.yLimit)} \
	-orientation horizontal
    APSLabeledEntryFrame .l3 -parent $w2 -label "BM BPLD B:P4 H/V limit(mm):" -width 15 -variableList {BPLD(B:P4.xLimit) BPLD(B:P4.yLimit)} \
	-orientation horizontal
    APSLabeledEntryFrame .l4 -parent $w2 -label "BM BPLD B:P5 H/V limit(mm):" -width 15 -variableList {BPLD(B:P5.xLimit) BPLD(B:P5.yLimit)} \
	-orientation horizontal
    APSLabeledEntryFrame .l5 -parent $w2 -label "BM BPLD B:P6 H/V limit(mm):" -width 15 -variableList {BPLD(B:P6.xLimit) BPLD(B:P6.yLimit)} \
	-orientation horizontal

    
    
    APSButton .load -parent $w -text "Write Limits"  -command SaveGeneralLimits -contextHelp "overwrite the BM bpld limits by the ggeneral limits in above."



    APSFrame .f1 -parent $parent
    $parent.f1.frame configure -bd 0
    set BPLD(AllLimit.x) 1.0
    set BPLD(AllLimit.y) 1.5
    
    APSLabeledEntry .all1 -parent $parent.f1.frame -width 20 -label "Limits for all BPM in x plane (mm):" -textVariable BPLD(AllLimit.x)
    APSLabeledEntry .all2 -parent $parent.f1.frame -width 20 -label "Limits for all BPM in y plane (mm):" -textVariable BPLD(AllLimit.y)
    APSButton .setall -parent $parent.f1.frame -text "Write Common Limit" -command "SetAllLimit" \
	-contextHelp "set all BM-BPLD limits with the same value."
}

proc SetAllLimit {args} {
    global BPLD
    foreach nm {A B} {
	for {set n 0} {$n<=6} {incr n} {
	    set bpm ${nm}:P$n
	    set BPLD($bpm.xLimit) $BPLD(AllLimit.x)
	    set BPLD($bpm.yLimit) $BPLD(AllLimit.y)
	}
    }
    update
    SaveGeneralLimits
}

proc LoadBMLimits {args} {
    global BPLD
    set configFile /home/helios/oagData/sr/BPLD/BPLD_Config/BMLimits.sdds
    set nameList [exec sdds2stream -col=Name $configFile]
    set xLimit [exec sdds2stream -col=xLimit $configFile]
    set yLimit [exec sdds2stream -col=yLimit $configFile]
    foreach name $nameList x $xLimit y $yLimit {
	set BPLD($name.xLimit) [format %0.2f $x]
	set BPLD($name.yLimit) [format %0.2f $y]
    }
}

proc LoadSCROffset {args} {
    set all 1
    APSParseArguments {all}
    global BPLD
    set BPLD(ShortFilename) ""
    set dialogBoxResponse 0

    APSDialogBox .diag  -cancelCommand "set dialogBoxResponse cancel" \
      -okCommand "set dialogBoxResponse ok"  -name "Select SCR"
    APSAddSCRDialog .scr -parent .diag.userFrame -system SR \
      -label "Choose SCR file for viewing" \
      -arrayName BPLD \
      -defaultFile $BPLD(ShortFilename)
    tkwait window .diag
    if ![string length $BPLD(ShortFilename)] {
	SetStatus "SCR was not choosen."
	return
    }
    set tmpRoot /tmp/[APSTmpString]
    set filterOpt ""
    foreach sector $BPLD(existSectors) {
	if ![string length $filterOpt] {
	    set filterOpt -filter=col,BPLDSector,$sector,$sector
	} else {
	    append filterOpt ",BPLDSector,$sector,$sector,|"
	}
    }
    set matchOpt ""
    if !$all {
	set bpms [GetBPMs]
	foreach bpm $bpms {
	    if [string length $matchOpt] {
		append matchOpt ",DeviceName=$bpm,|"
	    } else {
		set matchOpt -match=col,DeviceName=$bpm
	    }
	}
    }
    APSAddToTmpFileList -ID bpld -fileList "$tmpRoot.bpld $tmpRoot.x $tmpRoot.y $tmpRoot.x.set $tmpRoot.y.set"
    if [catch {eval exec sddsprocess $BPLD(configDir)/config.sdds $filterOpt  $tmpRoot.bpld $matchOpt } result] {
	return -code error "Error processing BPLD1: $result"
    }
    set scrDir /home/helios/oagData/SCR/snapshots/SR
    foreach coord {x y} {
	if [catch {exec sddsprocess $scrDir/$BPLD(ShortFilename)  -pipe=out \
		       -match=col,ControlName=*$coord:Offset* \
		       | sddsprocess -pipe=in $tmpRoot.$coord \
		       -reedit=col,ControlName,%/S1A/S01A/%/S2A/S02A/%/S3A/S03A/%/S4A/S04A/%/S5A/S05A/%/S6A/S06A/%/S7A/S07A/%/S8A/S08A/%/S9A/S09A/ \
		       -reedit=col,ControlName,%/S1B/S01B/%/S2B/S02B/%/S3B/S03B/%/S4B/S04B/%/S5B/S05B/%/S6B/S06B/%/S7B/S07B/%/S8B/S08B/%/S9B/S09B/ \
		       -edit=col,DeviceName,ControlName,7fD30 } result] {
	    return -code error "Error process SCR offset: $result"
	}
	if [catch {exec sddsxref $tmpRoot.bpld $tmpRoot.$coord -match=DeviceName -take=ValueString -nowarn -pipe=out \
		       | sddsprocess -pipe -scan=col,Value,ValueString,%lf \
		       | sddsprocess -pipe "-redefine=col,Value,Value 1000 *" \
		       | sddsprocess -pipe "-reprint=col,ValueString,%lf,Value" \
		       | sddsconvert -pipe -del=col,ControlName \
		       | sddsprocess -pipe=in $tmpRoot.$coord.set \
		       -print=col,ControlName,S%02d-LMPS:BM_[string toupper $coord]%d_Offset-SP,BPLDSector,BPLDIndex } result] {
	    return -code error "Error process bpld offset: $result"
	}
    }
    if [catch {exec sddscombine $tmpRoot.x.set $tmpRoot.y.set -merge -pipe=out \
		   | sddscasr -pipe=in -restore } result] {
	return -code error "Error loading BPLD offset: $result"
    }
    SetStatus "BPLD offset was loaded from SCR: $BPLD(ShortFilename)."
}

proc ZeroAllOffsets {args} {
    set all 1
    APSParseArguments {all}
    global BPLD
    set tmpRoot /tmp/[APSTmpString]
    set filterOpt ""
    foreach sector $BPLD(existSectors) {
	if ![string length $filterOpt] {
	    set filterOpt -filter=col,BPLDSector,$sector,$sector
	} else {
	    append filterOpt ",BPLDSector,$sector,$sector,|"
	}
    }
    set matchOpt ""
    if !$all {
	set bpms [GetBPMs]
	foreach bpm $bpms {
	    if [string length $matchOpt] {
		append matchOpt ",DeviceName=$bpm,|"
	    } else {
		set matchOpt -match=col,DeviceName=$bpm
	    }
	}
    }
    foreach coord {x y} {
	if [catch {eval exec sddsprocess $BPLD(configDir)/config.sdds $filterOpt $matchOpt -pipe=out \
		      | sddsprocess -pipe -reprint=col,ValueString,0 \
		       -reprint=col,ControlName,S%02d-LMPS:BM_[string toupper $coord]%d_Offset-SP,BPLDSector,BPLDIndex \
		       | tee tt.$coord \
		       | sddscasr -pipe=in -restore } result] {
	    return -code "Error zero BPLD offsets: $result"
	}
    }
    SetStatus "Zero Offsets done."
}

set lab 0
set args $argv
APSParseArguments {lab}

#########################following are GUI code#####################
set name  SRBMBPLDConfigAndLimits 
if $lab {
    set name ${name}-Lab
}

APSApplication . -name $name -version 1 \
  -overview {.}


APSScrolledStatus .scrolled -parent .userFrame \
    -textVariable bmBPMConfigStatus \
    -width 85 -height 10 -lineLimit 1000 -label ""

if $lab {
    set BPLD(configDir) /home/oxygen/DIAG/apsu/BPLD/BPLD_Config
    set BPLD(existSectors) {1 3 5}
} else {
    set BPLD(configDir) /home/helios/oagData/sr/BPLD/BPLD_Config
    set BPLD(existSectors) [exec sdds2stream -col=Sector /home/helios/oagData/sr/BPLD/doubleSectors.sdds]
}

set opt -filter=col,BPLDSector,
set first 1
foreach sector $BPLD(existSectors) {
    if $first {
	append opt $sector,$sector
    } else {
	append opt ,BPLDSector,$sector,$sector,|
    }
    set first 0
}
#puts $opt
set BPLD(filterOpt) $opt

for {set i 1} {$i<41} {incr i 2} {
    lappend sectorList S[format %02d $i]
}


set itemLabelList {n-1AP5 n-1AP6 n-1BP6 n-1BP5 n-1BP4 n-1BP3 n-1BP2 n-1BP1 n-1BP0 \
		       nAP0 nAP1 nAP2 nAP3 nAP4 nAP5 nAP6 nBP6 nBP5 nBP4 nBP3 nBP2 nBP1 nBP0 \
		       n+1AP0 n+1AP1 n+1AP2 n+1AP3 n+1AP4}

set itemList {n-1A:P5 n-1A:P6 n-1B:P6 n-1B:P5 n-1B:P4 n-1B:P3 n-1B:P2 n-1B:P1 n-1B:P0 \
		       nA:P0 nA:P1 nA:P2 nA:P3 nA:P4 nA:P5 nA:P6 nB:P6 nB:P5 nB:P4 nB:P3 nB:P2 nB:P1 nB:P0 \
		       n+1A:P0 n+1A:P1 n+1A:P2 n+1A:P3 n+1A:P4}
set BPLD(sectorList) $sectorList
set BPLD(itemList) $itemList
foreach sector $sectorList {
    set s [scan $sector S%ld]
    foreach item $itemList {
	set nm $sector$item
	set str [string range $item 0 2]
	switch $str {
	    "n-1" {
		if {$s==1} {
		    set ns 40
		} else {
		    set ns [expr $s -1]
		}
		set bpm [string range $item 3 end]
	    }
	    "n+1" {
		set ns [expr $s +1]
		set bpm [string range $item 3 end]
	    }
	    default {
		set ns $s
		set bpm [string range $item 1 end]
		if {$s==39 && $bpm=="B:P0"} {
		    set bpm C:P0
		} elseif {$s==39 && $bpm=="B:P1"} {
		    set bpm B:P0
		}
	    }
	}
	#for S39, S39B:P1 is replaced by S39B:P0, and S39B:P0 is replaced by S39C:P0
	#need treat S39 specially
	set BPLD($nm.bpm) S[format %02d $ns]$bpm
	#puts "$nm $BPLD($nm.bpm)"
    }
}



#puts $missingList
set missingList [GetBadList]

set wList [APSTabFrame .tab -parent .userFrame -labelList {BM_Selection BM_Limits} -width 800 -height 550]
set w1 [lindex $wList 0]
set w2 [lindex $wList 1]
#set w3 [lindex $wList 2]
#set w4 [lindex $wList 3]
#set BPLD(xStatusW) $w3
#set BPLD(yStatusW) $w4

APSSRSectorButtons .bpm -parent $w1 -rootname bmBPM -allButtons 1 \
    -label "BPLD BM BPM Configuration"  -sectorList $sectorList -orientation horizontal \
    -itemList $itemList -itemLabelList $itemList -description "BPLD BM BPM Config" -colorDesc 0 \
    -sectorControl 1 -packOption "-side top" -globalButtons 1 -missingList $missingList 

APSSetSRSectorButtons -mode all-off -rootname bmBPM  -itemList $itemList -sectorList $sectorList

set description ""
LoadBMLimits
MakeLimitsWidget -parent $w2
#LoadIDBMConfig
#CreateBPLDStatusWidget -plane x -parent $w3
#CreateBPLDStatusWidget -plane y -parent $w4

APSLabeledEntry .desc -parent .userFrame -label "Config Description: " -width 100 -textVariable BPLD(description)


#set hide 1
#APSRadioButtonFrame .hide -parent $w1 -orientation horizontal -label "Hide general limits save button?" -buttonList {Yes No} \
\#    -valueList {1 0} -commandList {"APSDisableButton .userFrame.save1.button" "APSEnableButton .userFrame.save1.button"} -variable hide

APSFrame .f0 -parent .userFrame -packOption "-side top"
set w0 .userFrame.f0.frame
$w0 configure -relief flat -bd 0

APSButton .read -parent $w0 -text "Load Config" -command "ConfigOptions -option load"
APSButton .default -parent $w0 -text "Make Default Config" -command "ConfigOptions -option makeDefault"
APSButton .read1 -parent $w0 -text "Load Default Config" -command "LoadDefaultConfig"
APSButton .save -parent $w0  -text "Save Config" -command SaveConfig
APSButton .medm -parent $w0 -text "Global H/V BM BPLD Status" -command BringUpGlobalStatus

APSFrame .f1 -parent .userFrame -packOption "-side top"
set w .userFrame.f1.frame
$w configure -relief flat -bd 0
#APSButton .offset1 -parent $w -text "Load SCR Offset for selected BPMs" -command "LoadSCROffset -all 0"
#APSButton .offset -parent $w  -text "Load SCR Offsets for All" -command "LoadSCROffset -all 1" \
#    -contextHelp "loading SR BPM offsets to BPLD offset from selected SCR."
#APSButton .zero1 -parent $w -text "Zero Offsets for selected BPMs" -command "ZeroAllOffsets -all 0"
#APSButton .zero -parent $w -text "Zero All Offsets" -command "ZeroAllOffsets" \
#    -contextHelp "set BPLD offsets to zero for all BPMs."

#LoadDefaultConfig
