#!/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 CUsectorList {02 06 11 12 13 15 16 21 22 23 24 25 28 31 32 34}
set XBPMTests(CUsectorList) $CUsectorList
set XBPMTests(BMFEsectorList) {01 02 05 06 07 08 09 10 11 12 13 14 16 17 19 20 23 33 35}

proc CreateSectorWidget {args} {
    set type ""
    set parent ""
    set varRoot ""
    APSParseArguments {type parent varRoot}
    global XBPMTests
    
    if ![string length $varRoot] {
	set varRoot $type
    }
    switch $type {
	TetrAMM {
	    set itemList {CM1ds CM2ds CM3ds CM1us CM2us CM3us}
	    set name TetrAMM
	    set labelList $itemList
	}
	Init {
	    set name ID-XBPM
	    set itemList {P1us P1ds}
	    set labelList $itemList
	}
	BMFE {
	    set itemList {CM1}
	    set name TetrAMM
	    set labelList $itemList
	}
	IDXBPM2 {
	    set itemList {CM4us CM4ds}
	    set name TetrAMM
	    set labelList $itemList
	}
	GapScan {
	    set itemList {P1us P1ds}
	    set name ID-XBPM
	    set labelList {US DS}
	    set name ID
	}
	XYScan {
	    set itemList {P1us P1ds}
	    set name ID-XBPM
	    set labelList {US DS}
	    set name ID
	}
	SaveRestore {
	    set itemList {P1us P1ds P2us P2ds BMCM1}
	    set name ID-XBPM
	    set labelList $itemList
	}
    }
    APSFrame .sector -parent $parent
    set w1 $parent.sector.frame
    $w1 configure -bd 0
    APSLabel .label1 -parent $w1  -packOption "-side top" -font bold \
	-text "            ----------------------------------------------------------- Sector---------------------------------------------------"
    frame $w1.f1
    pack $w1.f1 -side left
    frame $w1.f1.labels
    pack $w1.f1.labels -side left -fill y -expand 1
    set w2 $w1.f1.labels
    set items [llength $itemList]
    for {set i 0} {$i<$items} {incr i} {
	set item [lindex $itemList [expr $items-$i-1]]
	set label [lindex $labelList [expr $items-$i-1]]
	label $w2.item$item -text "   $label   " -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
	pack $w2.item$item -side bottom
    }
    label $w2.item1 -text " $name " -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
    pack $w2.item1 -side bottom

    for {set sector 1} {$sector<=35} {incr sector} {
	frame $w1.sector$sector
	set w2 $w1.sector$sector
	pack $w2 -side left
	set sectorf [format %02d $sector]
	for {set i 0} {$i<$items} {incr i} {
	    set item [lindex $itemList [expr $items-$i-1]]
	    set XBPMTests($varRoot.S${sectorf}$item) 0
	    if {[regexp "MotorScan" $varRoot]} {
		checkbutton $w2.${sector}$item -text "" -variable XBPMTests($varRoot.S${sectorf}$item) -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -command "SelectBMFEMotorScan -sector $sector"
	    } elseif [regexp "InitCal" $varRoot] {
		checkbutton $w2.${sector}$item -text "" -variable XBPMTests($varRoot.S${sectorf}$item) -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -command "SelectInitCalItem -item S${sectorf}$item"
	    } else {
		checkbutton $w2.${sector}$item -text "" -variable XBPMTests($varRoot.S${sectorf}$item) -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
	    }
	    if {$type=="BMFE"} {
		if [lsearch -exact $XBPMTests(BMFEsectorList) $sectorf]<0 {
		    $w2.$sector$item configure -state disabled
		}
	    } else {
		if {$type=="GapScan" || $type=="XYScan"} {
		    if {([regexp "us" $item] && [lsearch -exact $XBPMTests(badusList) $sector]>=0) || \
			    ([regexp "ds" $item] && [lsearch -exact $XBPMTests(baddsList) $sector]>=0)} {
			$w2.$sector$item configure -state disabled
		    }
		} else {
		    if {[regexp "us" $item] && [lsearch -exact $XBPMTests(CUsectorList) $sectorf]<0} {
			$w2.$sector$item configure -state disabled
		    }
		    if {[regexp "BMCM1" $item] && [lsearch -exact $XBPMTests(BMFEsectorList) $sectorf]<0} {
			$w2.$sector$item configure -state disabled
		    }
		}
	    }
	    pack $w2.$sector$item -side bottom
	}
	label $w2.label -text $sectorf  -padx 0 -pady 0 -highlightthickness 0

	pack $w2.label -side bottom
    }
    if {$varRoot=="InitCal"} {
	return
    }
    frame $w1.all
    set w2 $w1.all
    pack $w2 -side left
    for {set i 0} {$i<$items} {incr i} {
	set item [lindex $itemList [expr $items-$i-1]]
	set XBPMTests($varRoot.$item.sector) 0
	checkbutton $w2.check$item -text "" -variable XBPMTests($varRoot.$item.sector) \
	    -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -command "SectorControlButton -wtype $type -varRoot $varRoot -item $item"
	pack $w2.check$item -side bottom
    }
    
    label $w2.label -text "All"  -padx 0 -pady 0 -highlightthickness 0
    pack $w2.label -side bottom
}

proc SelectAll {args} {
    set wtype ""
    set varRoot ""
    set all 1
    set IDtype ""
    APSParseArguments {wtype varRoot all IDtype}
    
    global XBPMTests
    if ![string length $varRoot] {
	set varRoot $wtype
    }
    
    switch $wtype {
	TetrAMM {
	    set itemList {CM1ds CM2ds CM3ds CM1us CM2us CM3us}
	}
	BMFE {
	    set itemList {CM1}
	}
	IDXBPM2 {
	    set itemList {CM4us CM4ds}
	}
	GapScan {
	    set itemList {P1us P1ds}
	}
	XYScan {
	    set itemList {P1us P1ds}
	}
	SaveRestore {
	    set itemList {P1us P1ds P2us P2ds BMCM1}
	}
	Init {
	    set itemList {P1us P1ds}
	}
    }
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	set FE $XBPMTests(S$sectorf.FE)
	foreach item $itemList {
	    if {$wtype=="BMFE" && [lsearch -exact $XBPMTests(BMFEsectorList) $sectorf]<0 } {
		continue
	    } elseif {$wtype=="GapScan" || $wtype=="XYScan"} {
		if {([regexp "us" $item] && [lsearch -exact $XBPMTests(badusList) $sector]>=0 ) || \
			([regexp "ds" $item] && [lsearch -exact $XBPMTests(baddsList) $sector]>=0)} {
		    continue
		}
	    } elseif {[regexp "us" $item] && [lsearch -exact $XBPMTests(CUsectorList) $sectorf]<0} {
		continue
	    }
	    set XBPMTests($varRoot.S${sectorf}$item) $all
	    if {[string length $IDtype] && [string compare $IDtype $FE]!=0} {
		set XBPMTests($varRoot.S${sectorf}$item) 0
	    }
	}
    }
    return
}

proc SectorControlButton {args} {
    set wtype ""
    set USDS ""
    set item ""
    set varRoot ""
    APSParseArguments {wtype USDS item varRoot}
    global XBPMTests
    if {$varRoot=="BMFE.motorScan"} {
	SetMainStatus "BMFE motor scan can only select one item."
	return
    }
    if ![string length $varRoot] {
	set varRoot $wtype
    }
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	if {$wtype=="BMFE" && [lsearch -exact $XBPMTests(BMFEsectorList) $sectorf]<0 } {
	    continue
	} elseif {$wtype=="GapScan" || $wtype=="XYScan"} {
	    if {([regexp "us" $item] && [lsearch -exact $XBPMTests(badusList) $sector]>=00) || \
		    ([regexp "ds" $item] && [lsearch -exact $XBPMTests(baddsList) $sector]>=0)} {
		continue
	    }
	} elseif {[regexp "us" $item] && [lsearch -exact $XBPMTests(CUsectorList) $sectorf]<0} {
	    continue
	} elseif {[regexp "BMCM1" $item] && [lsearch -exact $XBPMTests(BMFEsectorList) $sectorf]<0} {
	    continue
	}
	set XBPMTests($varRoot.S${sectorf}$item) $XBPMTests($varRoot.$item.sector)
    }
    return
}

proc TetrAMMSectorButton {args} {
    set sector ""
    set USDS ""
    APSParseArguments {sector USDS}

    global XBPMTests
    set itemList {CM1 CM2 CM3}
    set name0 S[format %02d $sector].TetrAMM
    if {$USDS=="us" && [lsearch -exact $XBPMTests(CUsectorList) [format %02d $sector]]<0} {
	return
    }
    foreach item $itemList {
	set name S[format %02d $sector]$item
	
	set XBPMTests(TetrAMM.$name$USDS) $XBPMTests(TetrAMM.$name0.$USDS)
    }
    update
}

proc CreateDarkCurrentWidgets {widget args} {
    set parent ""
    set label ""
    set wtype TetrAMM
    set sectorControl 0
    APSParseArguments {parent TetrAMM sectorControl label wtype}
    
    global XBPMTests
    
    APSFrame $widget -parent $parent -label $label \
      -packOption "-side top"
   
    
    frame $parent$widget.frame.top
    set topFrame $parent$widget.frame.top
    pack $topFrame -side top
    CreateSectorWidget -type TetrAMM -parent $topFrame
    
    set XBPMTests($wtype.all) 1
    set commandList [list "SelectAll -wtype TetrAMM -all 1" "SelectAll -wtype TetrAMM -all 0"]
    APSRadioButtonFrame .all -parent $parent$widget.frame -packOption "-side left" -orientation horizontal \
	-buttonList {All None} -valueList {1 0} -label "" -variable XBPMTests($wtype.all)  \
	-commandList $commandList
    APSButton .cfe -parent $parent$widget.frame -packOption "-side left" -text "CFE" -command "SelectAll -wtype $wtype -IDtype CFE -all 1"
     APSButton .hhlfe -parent $parent$widget.frame -packOption "-side left" -text "HHLFE" -command "SelectAll -wtype $wtype -IDtype HHLFE -all 1"
    APSButton .default -parent $parent$widget.frame -packOption "-side left" -text "Default" \
	-command "SetDefaultButtonsAndPars -type $wtype"
    APSButton .savedefault -parent $parent$widget.frame -packOption "-side left" -text "Save Default" \
	-command "SaveDefaultButtonsAndPars -type $wtype"
    
    if {$wtype=="TetrAMM"} {
	global verbose
	set verbose 0
	APSRadioButtonFrame .verbose -parent $parent$widget.frame -packOption "-side right" -label "Verbose:" \
	    -buttonList {0 1} -valueList {0 1 2 3} -variable verbose -orientation horizontal
    }
    
    
    
    APSFrame .bot -parent $parent
    
    set wf $parent.bot.frame
    if {$wtype=="TetrAMM"} {
	set XBPMTests($wtype.refType) range0
	set XBPMTests($wtype.refType) default
	APSRadioButtonFrame .range -parent $wf -label "Reference file:" -buttonList {range0 range1 default} \
	    -valueList {range0 range1 default} -orientation horizontal -variable XBPMTests($wtype.refType) \
	    -contextHelp "when default is chosen, Rang1 files for CMXds in HHLFE, and Range0 files for CMXus and CMxds in CFE are being used where x=1,2,3"
	APSButton .setup -parent $wf -text "Setup TetrAMM" -command "SetupIDTetrAMM -type TetrAMM"
	APSButton .meas -parent $wf -text "Measure Dark Current/Noise" -command "MeasureDarkCurrentNoiseWidget -type TetrAMM"
	#APSButton .setup -parent $wf -text "Measurement Setup" -command "DarkCurrentNoiseSetup"
	APSButton .ref -parent $wf -text "Select Reference File" -command "MakeDarkCurrentReference -type TetrAMM"
	APSButton .proc -parent $wf -text "Process Reference Data" -command "ProcessDarkCurrentReference -type TetrAMM"
	#APSButton .procAll -parent $wf -text "Reprocess All" -command "ReprocessDarkCurrentAll"
	APSFrame .bot1 -parent $parent
	set w1 $parent.bot1.frame
	APSButton .plot -parent $w1 -text "Plot Measurement Data" -command "DarkCurrentDisplayWidget -type TetrAMM"
	APSButton .review -parent $w1 -text "Review Reference Data" -command "ReviewDarkCurrent -type TetrAMM"
	
	APSButton .load -parent $w1 -text "Load Reference Offset to IOC" -command "LoadOffsetToIOC -type TetrAMM"
	APSFrame .f -parent $parent  -label "XBPM DAQ Info" -packOption "-side top"
	set w $parent.f.frame
	APSButton .net -parent $w -text "Check Network Connection" -command "CheckNetwork -xbpm IDXBPM1"
	APSButton .froze -parent $w -text "Detect Frozen IOC" -command "DetectFrozenTetra -xbpm IDXBPM1" 
	APSButton .tetra -parent $w -text "TetrAMM Health Monitor" -command "exec /home/helios/oagData/apsu/XbpmSetup/scripts/srTetraHealthMonitor &"
	APSButton .ip -parent $w -text "Verify IP address" -command "exec /home/helios/oagData/apsu/XbpmSetup/scripts/srTetraNetLinkTest &"
	APSButton .help -parent $w -text "Help" -command "PrintHelpInfo -xbpm IDXBPM1"
	
	return
    } elseif {$wtype=="SaveRestore"} {
	set XBPMTests(SaveRestore.desc) ""
	APSLabeledEntry .desc -parent $wf -width 70 -label "Description"  -textVariable XBPMTests(SaveRestore.desc)
	APSButton .save -parent $wf -text "Save IOC Setup Data" -command "SaveSetupData -all 1"
	APSButton .load -parent $wf -text "Load Setup Data to Selected IOC" -command "LoadSetupData -all 0"
	#	APSButton .load1 -parent $wf -text "Load Selected BPMs to IOC" -command "LoadSetupData -all 0"
	APSButton .compare -parent $wf -text "Compare Current IOC with Saved Data File" -command "CompareIOCSetupWithFile"
	APSFrame .fn -parent $parent
	set wf $parent.fn.frame
	#APSButton .load1 -parent $wf -text "Load XBPM IOC Defaults" -command "LoadXbpmIOCDefaults"
	APSButton .start -parent $wf -text "Start All XBPM IOCs" -command "StartAllXBPMIOCs"
    }
}

proc GenerateDefaultXBPM1Calibration {args} {
    global XBPMTests
    if ![string length $XBPMTests(InitCal.choice)] {
	SetMainStatus "No bpm is chosen!"
	return
    }
    set item $XBPMTests(InitCal.choice)
    set sector [scan $item S%ld]
    set st [string range $item end-1 end]
    set sectorf [format %02d $sector]
    

}

proc CreateInitWidgets {widget args} {
    set parent ""
    set label ""
    APSParseArguments {parent label}
    global XBPMTests
    APSFrame $widget -parent $parent -label $label \
	-packOption "-side top"
    set w0 $parent$widget.frame
    APSFrame .top -parent $w0 -label "Normalization and Default Calibration of XBPM1s" -packOption "-side top"
    APSFrame .f1 -parent $w0.top.frame -label ""
    APSFrame .f2 -parent $w0.top.frame -label ""
    APSFrame .f3 -parent $w0.top.frame -label ""
    APSFrame .f4 -parent $w0.top.frame -label ""
    
    set f1 $w0.top.frame.f1.frame
    set f2 $w0.top.frame.f2.frame
    set f3 $w0.top.frame.f3.frame
    set f4 $w0.top.frame.f4.frame
    #APSFrame .f2 -parent $w0 -label "" -packOption "-side top"
   # APSFrame .f3 -parent $w0 -label "" -packOption "-side top"
    #$w0.f2.frame configure -bd 0
    #$w0.f3.frame configure -bd 0
    $f1 configure -bd 0
    $f2 configure -bd 0
    $f3 configure -bd 0
    $f4 configure -bd 0
    CreateSectorWidget -type Init -label "" -parent $f1 -varRoot InitNorm
    
    set XBPMTests(InitNorm.all) 1
    set commandList [list "SelectAll -wtype Init -varRoot InitNorm -all 1" "SelectAll -wtype Init -varRoot InitNorm -all 0"]
    
    APSRadioButtonFrame .all -parent $f2 -packOption "-side left" -orientation horizontal \
	-buttonList {All None} -valueList {1 0} -label "" -variable XBPMTests(InitNorm.all)  \
	-commandList $commandList
    APSButton .default -parent $f2 -packOption "-side left" -text "Default" \
	-command "SetDefaultButtonsAndPars -type InitNorm"
    APSButton .savedefault -parent $f2 -packOption "-side left" -text "Save Default" \
	-command "SaveDefaultButtonsAndPars -type InitNorm"

    
    APSButton .initbpm -parent $f3 -text "Initialize XBPM" -command "InitializeXBPM1"
    APSButton .review -parent $f3 -text "Review/Print Normalization Factors" -command "LoadNormalizationFactors -dryRun 1"
    APSButton .load -parent $f3 -text "Load Normalization Factors" -command "LoadNormalizationFactors -dryRun 0"
    APSButton .kill -parent $f3 -text "Kill Printout Windows" -command "CloseDisplayWidgets"

    APSButton .load1 -parent $f4 -text "Load Default Calibration to Selected XBPM1s" -command "LoadDefaultCalibrationsToXBPM1"
    
    #create calibration frame
    APSFrame .initCal -parent $w0 -label "Calibration of A Single BPM" \
	-packOption "-side top" 
    APSFrame .f1 -parent $w0.initCal.frame -label ""
    APSFrame .f2 -parent $w0.initCal.frame -label ""
    
    set f1 $w0.initCal.frame.f1.frame
    set f2 $w0.initCal.frame.f2.frame
    $f1 configure -bd 0
    $f2 configure -bd 0
    CreateSectorWidget -type Init -varRoot InitCal -parent $f1
    
    APSLabeledEntry .file -parent $f2 -label "Calibration file:" -width 90 -textVariable \
		    XBPMTests(InitCalFile) -commandButton 1
    set XBPMTests(BMbackgroundFile) /home/helios/oagData/apsu/XbpmSetup/inputFiles/XYCal/BmBackground-Summary.sdds
    APSLabeledEntry .file1 -parent $f2 -label "BM Background Info:" -width 90 -textVariable \
	XBPMTests(BMbackgroundFile) -commandButton 1
    APSButton .gen -parent $f2.file -text "Default" -size small -command "SelectInitCalItem"

    APSFrameGrid .grid -parent $f2 -yList {y1 y2}
    set w1 $f2.grid.y1
    set w2 $f2.grid.y2
    APSButton .setup -parent $w1 -text "Setup XBPM1 default" -command "SetupXBPM1Default"
  #  APSButton .copy -parent $w1 -text "Copy Default CalFactors/Offsets" -command "CopyDefaultCalFactorOffset -copy 1 -plot 0"
    APSButton .plot -parent $w1 -text "Plot/Print CalFactors/Offsets" -command  "CopyDefaultCalFactorOffset -copy 0 -plot 1"
    APSButton .weight -parent $w1 -text "Update Weight Functions" -command "UpdateWeightFunctions"
    APSButton .load -parent $w2 -text "Load CalFactors/Offsets" -command "LoadIDXBPM1Calibration"
    APSButton .loadbm -parent $w2 -text "Load BM Background Data" -command "LoadBMbackgroundData"
    APSFrame .but -parent $w0 -label ""
    $w0.but.frame configure -bd 0
    APSButton .scr -parent $w0.but.frame -text "Save-Compare-Restore" -command "exec SaveCompareRestore -system SRXrayBPM &"
    
}

proc PickBMFEScanTemplate {args} {
    global XBPMTests
    set dir /home/helios/oagData/apsu/XbpmSetup/inputFiles/ExpFile
    set oldDir [pwd]
    cd $dir
    set datestr [clock format [clock seconds] -format %Y-%m%d]
    switch $XBPMTests(BMFE.scanMode) {
	Beam {
	    set files [glob *BeamScan*.exp]
	}
	Motor {
	    set files [glob *MotorScan*.exp]
	}
    }
    cd $oldDir
    set datestr [clock format [clock seconds] -format %Y%m%d-%H%M]
   
    if {[llength $files]==1} {
	set XBPMTests(BMFE.scantemplate) $dir/$files
    } else {
	global templateFile
	set templateFile ""
	APSScrolledListWindow .bmscan -height 10 -name "Select A File" -itemList $files \
	    -selectionVar templateFile
	tkwait variable templateFile
	if ![string length $templateFile] {
	    return -code error "No file chosen!"
	}
	set XBPMTests(BMFE.scantemplate) $dir/$templateFile
    }
    if ![regexp {y.*} [file root [file tail $XBPMTests(BMFE.scantemplate)]] b] {
	SetMainStatus "Error format found in $XBPMTests(BMFE.scantemplate)"
	return
    }
    set XBPMTests(BMFE.scanRootname) ${datestr}-$b
}

proc SetDefaultBMFEScanRootname {args} {
    global XBPMTests
    set dir /home/helios/oagData/apsu/XbpmSetup/inputFiles
    
    set scanValue $XBPMTests(BMFE.scan$XBPMTests(BMFE.scanMode))
    set XBPMTests(BMFE.scanValue) $scanValue
    set datestr [clock format [clock seconds] -format %Y%m%d-%H%M]
    switch $XBPMTests(BMFE.scanMode) {
	Beam {
	    set unit ur
	}
	Motor {
	    set unit mm
	    #deselect all selection, only keep one
	    set choseSector ""
	    for {set sector 1} {$sector<=35} {incr sector} {
		if $XBPMTests(BMFE.S[format %02d $sector]CM1) {
		    set choseSector $sector
		    set XBPMTests(BMFE.S[format %02d $sector]CM1) 0
		}
	    }
	    if [string length $choseSector] {
		set XBPMTests(BMFE.S[format %02d $choseSector]CM1) 1
	    }
	}
    }
    set XBPMTests(BMFE.scantemplate) $dir/ExpFile/S00BMFE-XBPM-y$XBPMTests(BMFE.scanMode)Scan.exp
    set XBPMTests(BMFE.scanRootname) XBPM$XBPMTests(BMFE.xbpm)-${datestr}-y$XBPMTests(BMFE.scanMode)Scan-${scanValue}$unit
    
}

proc RunBMCalibrationScanOne {args} {
    set sector ""
    APSParseArguments {sector}
    global XBPMTests

    set sectorf [format %02d $sector]
   
    set monTemplate /home/helios/oagData/apsu/XbpmSetup/inputFiles/MonFile/S00BMFE-XBPM-y$XBPMTests(BMFE.scanMode)Scan.mon
    set dir  /home/helios/oagData/apsu/XbpmSetup/data/S${sectorf}BM/daily
    if ![file exist $dir] {
	exec mkdir -p $dir
	exec chmod 777 $dir
    }
    SetDefaultBMFEScanRootname
    SetMainStatus "Generating monitor file for S$sectorf..."
    
    set s0 [format %02d $sector]
    set s1 [format %02d [expr $sector+1]]
    set upBPM S${s0}B:P1
    set dowBPM S${s1}A:P1
    
    set monFile $dir/S${sectorf}BMFE-$XBPMTests(BMFE.scanRootname).mon
    if [catch {exec replaceText $monTemplate $monFile \
		   -orig=S00,S01,<motorCart>,<UpstreamBPM>,<DownstreamBPM>,<SXDRV0> \
		   -repl=S$s0,S$s1,$XBPMTests(BMFE.motorCart),$upBPM,$downBPM,XDRV:$XBPMTests(BMFE.motorCart) } result] {
	return -code error "Error creating  BM monitor file: $result"
    }
    set expFile $dir/S${sectorf}BMFE-$XBPMTests(BMFE.scanRootname).exp
    SetMainStatus "Generating exp file for S$sectorf..."
  
    #compute scan value (setpoint) from urad to um
    set scanValue $XBPMTests(BMFE.scanValue)
    if [catch {exec replaceText $XBPMTests(BMFE.scantemplate) $expFile \
		   -orig=S00,<motorCart>,<monFile>,<scanRange>,<UpstreamBPM>,<DownstreamBPM>,<sectorf>,<scanAngle> \
		   -repl=S$sectorf,$XBPMTests(BMFE.motorCart),$monFile,$scanValue,$upBPM,$downBPM,$sectorf,$XBPMTests(BMFE.scanValue) } result] {
	return -code error "Error generating BM exp file: $result"
    }
    set dataFile $dir/S${sectorf}BMFE-$XBPMTests(BMFE.scanRootname).sdds
    SetMainStatus "Starting sccan for S$sectorf..."
    set XBPMTests(BMFE.S${sectorf}scandone) 0
    if $XBPMTests(BMFE.dryRun) {
	set command "sddsexperiment $expFile $dataFile -verbose -dryrun"
    } else {
	set command "sddsexperiment $expFile $dataFile -verbose"
	if [catch {exec pvinfo S${sectorf}BM-Steering:Yp} result] {
	    return -code error "S${sectorf}BM steering server not started, please start it first!"
	}
	if [catch {exec caput -list=S${sectorf}BM-Steering:Yp_SetValueC 0
	    return -code error "Error change S$sectorf BM steering: $result"
	}
    }
    APSExecLog .s$sector -name "S$sector BM $XBPMTests(BMFE.scanMode) calibration scan" -lineLimit 1024 \
	-unixCommand "$command"\
	-abortCallback "set XBPMTests(BMFE.S${sectorf}scandone) aborted;SetMainStatus \"S$sector BM scan aborted.\"" \
	-callback "set XBPMTests(BMFE.S${sectorf}scandone) done;SetMainStatus \"S$sector BM scan done\""

}
proc RunBMCalibrationScan {args} {
    global XBPMTests

    SetDefaultBMFEScanRootname
    set doList ""
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	if $XBPMTests(BMFE.S${sectorf}CM1) {
	    RunBMCalibrationScanOne -sector $sector
	    lappend doList S$sectorf
	}
    }
    if ![llength $doList] {
	SetMainStatus "No item chosen!"
	return
    }
    if {$XBPMTests(BMFE.scanMode)=="Motor"} {
	SetMainStatus "Can only can one BM for motor scan!"
	set doList [lrange $doList 0 0]
    }
    SetMainStatus "Waiting for scan done..."
    foreach ID $doList {
	tkwait variable  XBPMTests(BMFE.${ID}scandone) 
    }
    SetMainStatus "done."
}

proc ProcessBMCalibrationData {args} {
    global XBPMTests
    
    
}

proc UpdateWeightFunctions {args} {
    global XBPMTests

    if ![string length $XBPMTests(InitCal.choice)] {
	SetMainStatus "No item is chosen!"
	return
    }
    set sector [scan $XBPMTests(InitCal.choice) S%ld]
    set sectorf [format %02d $sector]
    set bpm [string range  $XBPMTests(InitCal.choice) 3 end]
    set st  [string range  $XBPMTests(InitCal.choice) end-1 end]
    set period  $XBPMTests(S${sectorf}.$st.period)
    set FE $XBPMTests(S${sectorf}.FE)
    SetMainStatus "Updating weight functions for  $XBPMTests(InitCal.choice) ..."
    if [catch {exec /home/helios/oagData/apsu/XbpmSetup/scripts/updateXbpmCalibration \
		   -inputFile $XBPMTests(InitCalFile) -updateWeight 1 \
		   -outputFile $XBPMTests(InitCalFile) -beamline S${sectorf}ID \
		   -undulator [string toupper $st]ID -undulatorPeriod $period \
		   -frontEnd $FE -xbpm $bpm } result] {
	SetMainStatus "Error updating weight functions: $result"
	return
    }
    SetMainStatus "done."
}

proc LoadBMbackgroundData {args} {
    global XBPMTests

    if ![string length $XBPMTests(InitCal.choice)] {
	SetMainStatus "No item is chosen!"
	return
    }
    set sector [scan $XBPMTests(InitCal.choice) S%ld]
    set sectorf [format %02d $sector]
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddsprocess $XBPMTests(BMbackgroundFile) -pip=out -match=col,ControlName=S${sectorf}* \
		   | sddsprocess -pipe=in -reprint=col,ValueString,%lf,Value $tmpRoot.$sector} result] {
	return -code error "LoadBMbackgroundData1: $result"
    }
    APSAddToTmpFileList -ID xbpm -fileList $tmpRoot.$sector
    SetMainStatus "Loading BM background for chosing sectors..."
    if [catch {exec sddscasr $tmpRoot.$sector -restore } result] {
	return -code error "LoadBMbackgroundData2 (error loading BM background): $result"
    }
    SetMainStatus "done."
}

proc CreateBMFEWidgets {widget args} {
    set parent ""
    set label ""
    APSParseArguments {parent label}
    global XBPMTests
    APSFrame $widget -parent $parent -label $label \
	-packOption "-side top"
    set w0 $parent$widget.frame
    APSFrame .f1 -parent $w0
    set w1 $w0.f1.frame
    CreateSectorWidget -type BMFE -parent $w1
    
    APSFrame .f4 -parent $parent$widget.frame -label "Dark Current (DC Offset)" -packOption "-side top -fill x"
    set w0 $parent$widget.frame.f4.frame
    APSFrame .f1 -parent $w0
    set wf $w0.f1.frame
    $wf configure -bd 0
    set XBPMTests(BMFE.refType) range1
    APSRadioButtonFrame .range -parent $wf -label "Reference file:" -buttonList {range0 range1} \
			-valueList {range0 range1} -orientation horizontal -variable XBPMTests(BMFE.refType)
    APSButton .setup -parent $wf -text "Setup TetrAMM" -command "SetupBMTetrAMM"
    APSButton .meas -parent $wf -text "Measure Dark Current/Noise" -command "MeasureDarkCurrentNoiseWidget -type BMFE"
    #APSButton .setup -parent $wf -text "Measurement Setup" -command "DarkCurrentNoiseSetup"
    APSButton .ref -parent $wf -text "Select Reference File" -command "MakeDarkCurrentReference -type BMFE"
    APSButton .proc -parent $wf -text "Process Reference Data" -command "ProcessDarkCurrentReference -type BMFE"
    #APSButton .procAll -parent $wf -text "Reprocess All" -command "ReprocessDarkCurrentAll -type BMFE"
    APSFrame .bot1 -parent $w0 -packOption "-side top"
    set w1 $w0.bot1.frame
    $w1 configure -bd 0
    APSButton .plot -parent $w1 -text "Plot Measurement Data" -command "DarkCurrentDisplayWidget -type BMFE"
    APSButton .review -parent $w1 -text "Review Reference Data" -command "ReviewDarkCurrent -type BMFE"
    APSButton .load -parent $w1 -text "Load Reference Offset to IOC" -command "LoadOffsetToIOC -type BMFE"

    APSButton .check -parent $w1 -text "XBPM DAQ Info" -command "XbpmDAQInfo -xbpm BMFE"
    
    APSFrame .init -parent $parent$widget.frame -label "Initialization"
    set w0 $parent$widget.frame.init.frame
    set XBPMTests(BMFEcalibrationFile) /home/helios/oagData/apsu/XbpmSetup/inputFiles/BMFE-XBPM-Calibration.sdds

    APSLabeledEntry .dir -parent $w0 -label "Calibration file:" -width 90 \
	-textVariable XBPMTests(BMFEcalibrationFile) -commandButton 1
    APSButton .default -parent $w0.dir -packOption "-side right" -command "SetDefaultBMFEFile" -size small -text "default"
    APSButton .setup -parent $w0 -text "Setup TetrAMM" -command "SetupBMTetrAMM"
    #APSButton .load1 -parent $w0 -text "Load XBPM IOC defaults" -command "LoadBMFEIOCDefaults"
    APSButton .load2 -parent $w0 -text "Load XBPM Calibration" -command "LoadXBPMCalibration -xbpm BM"

    APSFrame .scan -parent $parent$widget.frame -label "Calibration Scan"
    set w0 $parent$widget.frame.scan.frame
    set XBPMTests(BMFE.xbpm) 1
    set XBPMTests(BMFE.scanMode) Motor
    set XBPMTests(BMFE.motorCart) 1
    APSFrameGrid .grid1 -parent $w0 -xList {x1 x2}
    APSRadioButtonFrame .r1 -parent $w0.grid1.x1 -label "XBPM:" -buttonList {P1 P2} \
	-orientation horizontal -valueList {1 2} -variable XBPMTests(BMFE.xbpm) 
    APSRadioButtonFrame .r2 -parent $w0.grid1.x1 -label "ScanMode:" -buttonList {Beam Motor} \
	-valueList {Beam Motor} -orientation horizontal -variable XBPMTests(BMFE.scanMode) \
	-commandList { SetDefaultBMFEScanRootname  SetDefaultBMFEScanRootname}
    APSComboboxFrame .com -parent $w0.grid1.x2 -label "MotorCart:" -width 5  \
	-textVariable XBPMTests(BMFE.motorCart) \
	-itemList {1 2 3 4 5 6}
    set XBPMTests(BMFE.scanBeam) 20
    set XBPMTests(BMFE.scanMotor) 0.4
    set XBPMTests(BMFE.dryRun) 1
    set XBPMTests(BMFE.dwellTime) 3
    APSRadioButtonFrame .dryRun -parent $w0.grid1.x1 -label "Dry Run?" -buttonList {Yes No} \
	-valueList {1 0} -variable XBPMTests(BMFE.dryRun) -orientation 0
    APSLabeledEntry .dwell -parent $w0.grid1.x2 -label "Dwell Time per point (seconds):" \
	-width 25 -textVariable XBPMTests(BMFE.dwellTime)
    APSLabeledEntry .val1 -parent $w0.grid1.x1 -label "Beam Scan Setpoint Change(um):" \
	-width 25 -textVariable XBPMTests(BMFE.scanBeam)
    APSComboboxFrame .val1 -parent $w0.grid1.x2 -label "Motor Scan Range(mm):" \
	-width 25 -textVariable XBPMTests(BMFE.scanMotor) -itemList {0.3 0.4 0.5 0.6 0.7 0.8}

    set XBPMTests(BMFE.scantemplate) ""
    APSLabeledEntry .scan -parent $w0 -label "Scan Template:" -width 85 \
	-textVariable XBPMTests(BMFE.scantemplate) -commandButton 1
    #APSButton .pick -parent $w0.scan -packOption "-side right" -text "pick" -size small \
     #	-command "PickBMFEScanTemplate"
    set XBPMTests(BMFE.scanRootname) ""
    APSLabeledEntry .root -parent $w0 -label "Data scan rootname:" -width 85 \
	-textVariable XBPMTests(BMFE.scanRootname)
    APSButton .default -parent $w0.root -text "default" -size small -command "SetDefaultBMFEScanRootname" \
	-packOption "-side right"

    APSButton .run -parent $w0 -text "Run Calibration Scan" -command "RunBMCalibrationScan" 
    APSButton .plot -parent $w0 -text "Process Scan Data" -command ProcessBMCalibrationData 
    
    APSButton .steer1 -parent $w0 -text "Steer Beam To XBPM Center" -command "SteerBMBPM" -packOption "-side right"
    
}

proc SetDefaultTimeStamp {args} {
    set type ""
    APSParseArguments {type}
    global XBPMTests
    set XBPMTests($type.timestamp) S[clock format [clock seconds] -format %Y%m%d-%H%M]
}

proc UpdateXYScanRange {args} {
    set type Wide
    set plane x
    APSParseArguments {type plane}
    global XBPMTests
    set Wide(xstart) -40
    set Wide(xstop) 40
    set Wide(xstep) 2.5
    set Medium(xstart) -30
    set Medium(xstop) 30
    set Medium(xstep) 2.5
    set Narrow(xstart) -20
    set Narrow(xstop) 20
    set Narrow(xstep) 2.5
    set Narrow1(xstart) -10
    set Narrow1(xstop) 10
    set Narrow1(xstep) 2
    
    set Wide(ystart) -40
    set Wide(ystop) 40
    set Wide(ystep) 2.5
    set Medium(ystart) -30
    set Medium(ystop) 30
    set Medium(ystep) 2.5
    set Narrow(ystart) -20
    set Narrow(ystop) 20
    set Narrow(ystep) 2.5
    set Narrow1(ystart) -10
    set Narrow1(ystop) 10
    set Narrow1(ystep) 2

    foreach name {start stop step} {
	set XBPMTests(XYScan.${plane}$name) [set ${type}(${plane}$name)]
    }
}

proc GetRefGapValue {args} {
    set ID ""
    set gap alignment {ID gap}

    switch $gap {
	alignment {
	    set gapPar xbpmAlignmentGap
	}
	softlimit {
	    set gapPar softGapLimit
	}
	gap1 {
	    set gapPar GapNo1
	}
	gap2 {
	    set gapPar GapNo2
	}
	default {
	    return -code error "Invalid gap parameter - $gap provided!"
	}
    }
    set IDinfo /home/helios/oagData/apsu/XbpmSetup/inputFiles/APSU-IDInfo.sdds
    set tmpRoot /tmp/[APSTmpString]
    set sector [scan $ID S%ld]
    if [regexp {US} $ID] {
	set st us
    } elseif [regexp {DS} $ID] {
	set st ds
    } else {
	return -code error "Invalid ID - $ID provided!"
    }
    if [catch {exec sddsprocess $IDinfo -pipe=out \
		   -filter=col,Sector,$sector,$sector \
		   | sdds2stream -pipe=in -col=${st}IDPeriod } period] {
	return -code error "Error obtaining S$sectorf period: $period"
    }
    if [catch {exec sddsprocess $dataFile -pipe=out \
		   -filter=par,undulatorPeriod,[expr $period-0.1],[expr $period+0.1] \
		   | sdds2stream -pipe=in -par=$gapPar } gap] {
	return -code error "Error reading $gapPar gap for S$sectorf: $gap"
    }
    if ![string length $gap] {
	return -code error "Error getting gap value!"
    }
    return $gap
}

proc SetUndulatorAlignmentGap {args} {
    set type XYScan
    set gap alignment
    APSParseArguments {type gap}
    global XBPMTests
    set dir /home/helios/oagData/apsu/XbpmSetup/inputFiles
    set dataFile $dir/GapScan-GapListInfo.sdds
    set IDinfo /home/helios/oagData/apsu/XbpmSetup/inputFiles/APSU-IDInfo.sdds
    set tmpRoot /tmp/[APSTmpString]
    switch $gap {
	alignment {
	    set gapPar xbpmAlignmentGap
	}
	softlimit {
	    set gapPar softGapLimit
	}
	gap1 {
	    set gapPar GapNo1
	}
	gap2 {
	    set gapPar GapNo2
	}
	default {
	    return -code error "Invalid gap parameter - $gap provided!"
	}
    }
    set IDList ""
    set valList ""
    set deviceList ""
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	foreach st {us ds} {
	    if $XBPMTests($type.S${sectorf}P1$st) {
		if [catch {exec sddsprocess $IDinfo -pipe=out \
			       -filter=col,Sector,$sector,$sector \
			       | sdds2stream -pipe=in -col=${st}IDPeriod } period] {
		    return -code error "Error obtaining S$sectorf period: $period"
		}
		if [catch {exec sddsprocess $dataFile -pipe=out \
			       -filter=par,undulatorPeriod,[expr $period-0.1],[expr $period+0.1] \
			       | sdds2stream -pipe=in -par=$gapPar } gap] {
		    return -code "Error reading $gapPar gap for S$sectorf: $gap"
		}
		if ![string length $gap] {
		    SetMainStatus "Error, no gap values found for $ID, skip"
		    continue
		}
		set ID S${sectorf}:[string toupper $st]ID
		lappend deviceList $ID
		lappend IDList $ID:GapSetC
		lappend valList [format %.2f $gap]
	    }
	}
    }
    if ![llength $IDList] {
	return -code error "No item chosen!"
    }
    if [catch {exec sddsmakedataset -col=ControlName,type=string -data=[join $IDList ,] \
		   -col=ValueString,type=string -data=[join $valList ,] $tmpRoot.gap} result] {
	return -code error "Error creating gap file: $result"
    }
    if [catch {exec sddsprocess $tmpRoot.gap $tmpRoot.start -reedit=col,ControlName,%/GapSetC/StartC/ \
		   -reprint=col,ValueString,1 } result] {
	return -code error "Error creating gap start file: $result"
    }
    APSAddToTmpFileList -ID xbpm -fileList "$tmpRoot.gap $tmpRoot.start"
    if [catch {exec sddsprintout $tmpRoot.gap $tmpRoot.print -col=ControlName,format=%20s \
		   -col=ValueString,format=%8s,label=MoveTo \
	       "-title=Following gaps will be moved to MoveTo values\\,\n press OK to continue or cancel to abort" } result] {
	return -code error "Error printing alignment gap: $result"
    }
    global moveGaps
    set moveGaps 0
    APSFileDisplayWindow .gap -fileName $tmpRoot.print -width 80 -modal 1 \
	-closeButton 0 -okButton 1 -cancelButton 1 -okCommand "set moveGaps 1;destroy .gap" \
	-cancelCommand "set moveGaps 0;destroy .gap"
    
    if !$moveGaps {
	SetMainStatus "Moving gaps to alignment was canceled!"
	return
    }
    if $XBPMTests(dryRun) {
	SetMainStatus "Do not move gaps in dryRun mode!"
	return
    }
    SetMainStatus "Moving gaps to alignment gap..."
    
    if [catch {exec sddscasr -restore $tmpRoot.gap} result] {
	return -code error "Error change gap setpoints: $result"
    }
    
    after 1000
    if [catch {exec sddscasr -restore $tmpRoot.start} result] {
	return -code error "Error moving gaps: $result"
    }
    SetMainStatus "gaps are moving, please wait patiently."
    if [catch {APSIDsGoAndWait -IDList $deviceList} result] {
	return -code error "MoveGaps6: $result"
    }
    SetMainStatus "done."
}

proc SaveBeamPosition {args} {
    global XBPMTests
    #XY scan beam position
    set tmpRoot /tmp/[APSTmpString]
    set outDir /home/helios/oagData/apsu/XbpmSetup/data/xbpmCenter
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	set bpm1 S[format %02d $sector]B:P1
	set bpm2 S[format %02d [expr $sector+1]]A:P1
	foreach item {P1us P1ds} {
	    set pvList ""
	    set st [string toupper [string range $item end-1 end]]
	    if $XBPMTests(XYScan.S${sectorf}$item) {
		lappend pvList ${bpm1}:x:SetpointC
		lappend pvList ${bpm1}:y:SetpointC
		lappend pvList ${bpm2}:x:SetpointC
		lappend pvList ${bpm2}:y:SetpointC
	    }
	    if [llength $pvList] {
		set filename $outDir/S${sectorf}${item}-$XBPMTests(XYScan.xcenterMonitor)-$XBPMTests(XYScan.ycenterMonitor)-Center.sdds
		if [catch {exec sddsmakedataset -pipe=out -col=ControlName,type=string -data=[join $pvList ,] \
			       | sddssort -pipe -col=ControlName -unique \
			       | sddscasr -pipe=in -save $filename } result] {
		    return -code error "Error save beam position for $item: $result"
		}
		SetMainStatus "beam position saved for $item."
	    }
	}
    }
}

proc MoveBeamPosition {args} {
    global XBPMTests
    set outDir /home/helios/oagData/apsu/XbpmSetup/data/xbpmCenter
    for {set sector 1} {$sector<=35} {incr sector} {
	 set sectorf [format %02d $sector]
	foreach item {P1us P1ds} {
	    if $XBPMTests(XYScan.S${sectorf}$item) {
		set filename $outDir/S${sectorf}${item}-$XBPMTests(XYScan.xcenterMonitor)-$XBPMTests(XYScan.ycenterMonitor)-Center.sdds
		if ![file exist $filename] {
		    SetMainStatus "beam center file $filename does not exist, ignore."
		    continue
		}
		if $XBPMTests(dryRun) {
		    SetMainStatus "Pretending moving beam position..." 
		} else {
		    if [catch {exec sddscasr -restore $filename} result] {
			return -code error "Error restoring beam position: $result"
		    }
		}
		SetMainStatus "beam position moved for S$sectorf$item."
	    }
	 }
     }
}

proc CenterXBPM1 {args} {
    set plane x
    APSParseArguments {plane}
    global XBPMTests
    set badList ""
    set centerMonitor $XBPMTests(XYScan.${plane}centerMonitor)
    set Plane [string toupper $plane]
    if [regexp {ds} $centerMonitor] {
	set st ds
    } else {
	set st us
    }
    set suffix1 P1${st}:${Plane}Ratio1M
    set suffix2 P1${st}:${Plane}Ratio2M
    set waitTime [expr int($XBPMTests(XYScan.${plane}beamPause))]
    
    set steps [expr int(2*$XBPMTests(XYScan.${plane}beamRange)/$XBPMTests(XYScan.${plane}beamStep)+0.5)]
    set stepsize [expr 2*$XBPMTests(XYScan.${plane}beamRange)*1.0/$steps]
    #P1 bpm distance from ID 3.23m
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	set bpm1 S${sectorf}B:P1:${plane}
	set bpm2 S[format %02d [expr $sector+1]]A:P1:${plane}
	if $XBPMTests(XYScan.beamCenterSearchStop) {
	    SetMainStatus "Center beam search was manually stopped."
	    set XBPMTests(XYScan.beamCenterSearchStop) 0
	    return
	}
	foreach item {P1us P1ds} {
	    if $XBPMTests(XYScan.S${sectorf}$item) {
		if {$XBPMTests(S$sectorf.FE)=="HHLFE" && [regexp {us} $centerMonitor]} {
		    SetMainStatus "Error: us not avalible for FFLFE (S$sectorf), skip"
		    continue
		}	    		  
		SetMainStatus "scanning S$sector beam angle in x plane..."
	
		set found 0
		SetMainStatus "Scanning S${sectorf} beam angle..."
		set rootPV S${sectorf}IDFE-XBPM:
		for {set i 0} {$i<$steps} {incr i} {
		    if $XBPMTests(XYScan.beamCenterSearchStop) {
			SetMainStatus "Center beam search was manually stopped."
			set XBPMTests(XYScan.beamCenterSearchStop) 0
			return
		    }
		    set value1 [expr -1.0 * $XBPMTests(XYScan.${plane}beamRange) + $i*$stepsize]
		    set value1 [expr $value1*$XBPMTests(P1L)]
		    set value2 [expr -1.0* $value1]
		    if $XBPMTests(dryRun) {
			SetMainStatus "Pretending setting $bpm1:SetpointC to $value1, $bpm2:SetpointC to $value2 ..."
		    } else {
			SetMainStatus "setting $bpm1:SetpointC to $value1, $bpm2:SetpointC to $value2 ..."
			if [catch {exec cavput -list=$bpm1:SetpointC=$value1,$bpm2:SetpointC=$value2 -pend=10 } result] {
			    return -code error "Error change beam angle: $result"
			}
			SetMainStatus "waiting for orbit to converge..."
			exec cawait -timeLimit=300 -waitfor=$bpm1:LowPass1sErrorM,lowerlimit=-100,upperlimit=100 \
			    -waitfor=$bpm2:LowPass1sErrorM,lowerlimit=-100,upperlimit=100 -and
		    }
		    APSWaitWithUpdate -waitSeconds $waitTime
		    if [catch {exec cavget -list=$rootPV -list=$suffix1,$suffix2 -repeat=number=5,pause=0.5 \
				   -pend=5 -printErrors} valList] {
			return -code error "Error reading target value: $valList"
		    }
		    set val1 [lindex $valList 0]
		    set val2 [lindex $valList 1]
		    switch $centerMonitor {
			x1ds -
			y1ds -
			x1us -
			y1us {
			    set target $val1
			}
			x2ds -
			y2ds -
			x2us -
			y2us {
			    set target $val2
			}
			default {
			    set target [expr ($val1+$val2)/2.0]
			}
		    }
		    SetMainStatus "Reading target: S${sectorf}IDFE-XBPM:$suffix1=$val1, S${sectorf}IDFE-XBPM:$suffix2=$val2, target=$target"
		    if {[expr abs($target)]<=$XBPMTests(XYScan.${plane}beamTarget)} {
			set found 1
			SetMainStatus "S$sectorf$item $plane beam scan reached target."
			break
		    }
		}
		if !$found {
		    bell bell bell
		    SetMainStatus "Warning: S$sectorf$item $plane beam scan did not reach target!"
		    lappend badList S$sectorf$item
		}
	    }
	}
    }
    if [llength $badList] {
	APSInfoWindow [APSUniqueName .] -name Message -width 30 -infoMessage "Warning, [join $badList ,] $plane beam scan did not reach the target." -modal 1
    }
}

proc MoveXBPMBeamAngle {args} {
    set sign ""
    set plane ""
    APSParseArguments {sign plane}
    global XBPMTests
    if {$sign==1} {
	set value1 [expr $XBPMTests(XYScan.${plane}beamStep) * -1.0]
	set value2 $XBPMTests(XYScan.${plane}beamStep)
    } else {
	set value1  $XBPMTests(XYScan.${plane}beamStep)
	set value2 [expr $XBPMTests(XYScan.${plane}beamStep) * -1.0]
    }
    
    set value1 [expr $value1*$XBPMTests(P1L)]
    set value2 [expr $value2*$XBPMTests(P1L)]
    #use P0
    
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	set bpm1 S${sectorf}B:P1:${plane}
	set bpm2 S[format %02d [expr $sector+1]]A:P1:${plane}
	if {$XBPMTests(XYScan.S${sectorf}P1ds) || $XBPMTests(XYScan.S${sectorf}P1ds)} {
	    if $XBPMTests(dryRun) {
		SetMainStatus "pretending change $bpm1:SetpointC by $value1 and $bpm2:SetpointC by $value2 (in delta mode)..."
	    } else {
		if [catch {exec cavput -list=$bpm1:SetpointC=$value1,$bpm2:SetpointC=$valu2 -delta } result] {
		    return -code error "Error changing $bpm1:OffsetC by $value1 and $bpm2:OffsetC by $value2: $result"
		}
	    }
	}
    }
    
}

proc MakeXYScanFrame {args} {
    set parent ""
    set plane ""
    APSParseArguments {parent plane}
    global XBPMTests
    
    APSFrame .scan -parent $parent -label "Gap Grid for XY-Cal Scan"
    APSFrame .center -parent $parent -label "Center Orbit Positions"
    set f1 $parent.scan.frame
    set f2 $parent.center.frame
    global XBPMTests
    set XBPMTests(XYScan.${plane}scanType) SingleGap
    UpdateXYScanRange -type Narrow1 -plane $plane

    set XBPMTests(XYScan.singleGap) 30
    APSRadioButtonFrame .scan0 -parent $f1 -label "Gap Grid:" \
	-buttonList {ExtraLong Long Medium Short ExtraShort BM SingleGap} \
	-orientation horizontal -valueList {ExtraLONG LONG MEDIUM SHORT EXTRASHORT BM SingleGap} -variable XBPMTests(XYScan.${plane}scanType)
    APSLabeledEntry .single -parent $f1.scan0 -packOption "-side right" \
	-label "Single Gap (mm):" -width 10 -textVariable  XBPMTests(XYScan.singleGap)
    APSLabeledEntryFrame .scan -parent $f1 -label "${plane}p-steer range (start/stop/step):" -width 15 \
	-variableList [list XBPMTests(XYScan.${plane}start) XBPMTests(XYScan.${plane}stop) XBPMTests(XYScan.${plane}step)] -orientation horizontal
    APSButton .short -parent $f1.scan -text "40" -size small -command "UpdateXYScanRange -type Wide -plane $plane" -packOption "-side right"
    APSButton .medi -parent $f1.scan -text "30" -size small -command "UpdateXYScanRange -type Medium -plane $plane" -packOption "-side right"
    APSButton .long -parent $f1.scan -text "20" -size small -command "UpdateXYScanRange -type Narrow -plane $plane" -packOption "-side right"
    APSButton .short1 -parent $f1.scan -text "10" -size small -command "UpdateXYScanRange -type Narrow1 -plane $plane" -packOption "-side right"

    set XBPMTests(XYScan.yoffset0) 1
    set XBPMTests(XYScan.xoffset0) 1
    foreach nm {5 10 20 30} {
	set XBPMTests(XYScan.yoffset$nm) 0
	set XBPMTests(XYScan.xoffset$nm) 0
    }
    switch $plane {
	x {
	    set other y
	}
	y {
	    set other x
	}
    }
    APSCheckButtonFrame .offset -parent $f1 -label "${other} steer (urad):" -buttonList {0 +/-5 +/-10 +/-15 +/-20 +/-30} \
	-orientation horizontal -allNone 1 \
	-variableList [list XBPMTests(XYScan.${other}offset0) XBPMTests(XYScan.${other}offset5) XBPMTests(XYScan.${other}offset10) XBPMTests(XYScan.${other}offset15) XBPMTests(XYScan.${other}offset20) XBPMTests(XYScan.${other}offset30)]

    APSFrameGrid .grid -parent $f1 -xList {x1 x2}
    set w1 $f1.grid.x1
    set w2 $f1.grid.x2
    set XBPMTests(XYScan.timestamp) ""
    APSLabeledEntry .timestr -parent $w1 -label "Time Stamp:" -width 40 -textVariable XBPMTests(XYScan.timestamp)
    APSButton .default -parent $w1.timestr -text "default" -command "SetDefaultTimeStamp -type XYScan"
    APSLabeledEntry .dwell -parent $w2 -label "Dwell time (seconds):" -width 40 -textVariable XBPMTests(XYScan.dwellTime)
    APSButton .show -parent $f1 -text "Show XBPM signals" -command "ShowXBPMSignals -plane $plane"
    APSButton .run -parent $f1 -text "Run $plane Beam Scans" -command "RunXYBeamScans -plane $plane"
    APSButton .plot -parent $f1 -text "Plot Raw Data" -command "PlotXYScanRawData -plane $plane"
    set XBPMTests(XYScan.xbeamScanButton) $f1.run.button
    
    
    set XBPMTests(XYScan.${plane}beamRange) 80
    set XBPMTests(XYScan.${plane}beamStep) 2.0
    set XBPMTests(XYScan.${plane}beamTarget) 0.01
    set XBPMTests(XYScan.${plane}beamPause) 2
    set XBPMTests(XYScan.${plane}centerMonitor) x12ds

    APSRadioButtonFrame .mon -parent $f2 -label "Center monitor:" -buttonList [list ${plane}Qds ${plane}1ds ${plane}2ds ${plane}Qus ${plane}1us ${plane}2us] \
    -valueList [list ${plane}12ds ${plane}1ds ${plane}2ds ${plane}12us ${plane}1us ${plane}2us] \
	-variable XBPMTests(XYScan.xcenterMonitor) -orientation horizontal
    APSLabeledEntryFrame .center1 -parent $f2 -label "Center search range (urad)/pause(seconds):" -width 15 \
	-variableList [list XBPMTests(XYScan.${plane}beamRange) XBPMTests(XYScan.${plane}beamPause)] -orientation horizontal
    APSLabeledEntryFrame .center2 -parent $f2 -label "Center search stepsize(urad) and XBPM ratio tolerance:"  -width 15 -variableList [list XBPMTests(XYScan.${plane}beamStep) XBPMTests(XYScan.${plane}beamTarget)] -orientation horizontal
    APSButton .down -parent $f2.center2 -packOption "-side right" -text Down -command "MoveXBPMBeamAngle -sign -1 -plane $plane"
    APSButton .up -parent $f2.center2 -packOption "-side right" -text Up -command "MoveXBPMBeamAngle -sign 1 -plane $plane"

    set  XBPMTests(XYScan.beamCenterSearchStop) 0
    APSButton .move -parent $f2 -text "Set Undulator Gap for Alignment" -command SetUndulatorAlignmentGap
    APSButton .center -parent $f2 -text "Center Beam in XBPM-$plane" -command "CenterXBPM1 -plane $plane"
    APSButton .stop -parent $f2 -text "Stop Moving Beam" -command "set XBPMTests(XYScan.beamCenterSearchStop) 1"
    APSButton .saveorbit -parent $f2 -text "Save Orbit" -command "SaveBeamPosition -plane $plane"
    APSButton .restore -parent $f2 -text "Restore Saved Orbit" -command "MoveBeamPosition -plane $plane"
    
    
}

proc PlotXYScanRawData {args} {
    set plane x
    APSParseArguments {plane}

    

}

proc CreateXYScanWidgets {widget args} {
    set parent ""
    APSParseArguments {parent}
    
    global XBPMTests
    APSFrame $widget -parent $parent -label "" \
	-packOption "-side top"
    set w0 $parent$widget.frame
    APSFrame .f1 -parent $w0 -label "" -packOption "-side top"
    APSFrame .f2 -parent $w0 -label "" -packOption "-side top"
    set f1 $w0.f1.frame
    set f2 $w0.f2.frame
    CreateSectorWidget -type XYScan -parent $f1

    APSFrameGrid .grid -parent $f2 -xList {x1 x2}
    set w1 $f2.grid.x1
    set w2 $f2.grid.x2
    APSRadioButtonFrame .undulator -parent $w1 -label "Undulators In:" -buttonList {All HHLFE CFE None} \
	-orientation horizontal -valueList {all HHLFE CFE none} -variable XBPMTests(XT=YScan.undulatorType) \
	-commandList [list "SelectUndulators -wtype XYScan -undulatorType all" \
			  "SelectUndulators -wtype XYScan -undulatorType HHLFE" \
			  "SelectUndulators -wtype XYScan -undulatorType CFE" \
			  "SelectUndulators -wtype XYScan -undulatorType none" ]
    
    set XBPMTests(dryRun) 1
    APSRadioButtonFrame .dryRun -parent $w2 -label "Dry Run?" -buttonList {Yes No} \
	-valueList {1 0} -variable XBPMTests(dryRun) -orientation horizontal \
	-commandList {"set XBPMTests(XYScan.dwellTime) 3" "set XBPMTests(XYScan.dwellTime) 20" }
    
    set XBPMTests(XYScan.dwellTime) 5
   # APSLabeledEntry .dwell -parent $w1 -label "Dwell time (seconds):" -width 25 -textVariable XBPMTests(XYScan.dwellTime)
    
    
    set XBPMTests(XYScan.gapGridListFile) /home/helios/oagData/apsu/XbpmSetup/inputFiles/XYScan-GapListInfo.sdds
    
    set wList [APSTabFrame .tab -parent $w0 -labelList "Horizontal Vertical" -width 700 -height 350]
    set xframe0 [lindex $wList 0]
    set yframe0 [lindex $wList 1]
    MakeXYScanFrame -parent $xframe0 -plane x
    MakeXYScanFrame -parent $yframe0 -plane y
    return
}

proc ShowXBPMSignals {args} {
    set type XYScan
    APSParseArguments {type}
    
    global XBPMTests

    set tmpRoot /tmp/[APSTmpString]
    set fd [open $tmpRoot.print w]
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	if {$XBPMTests($type.S${sectorf}P1us) || $XBPMTests($type.S${sectorf}P1ds) }  {
	    puts $fd "Sector $sectorf"
	    set us 0
	    if {$XBPMTests(S$sectorf.usExist) && $XBPMTests(S$sectorf.FE)=="CFE"} {
		set us 1
		if [catch {exec cavget -list=S${sectorf}ID:USID: -list=DeviceM,GapM -pend=10} valList] {
		    return -code error "Error reading S$sectorf US device:$vaList"
		}
		puts $fd "  USID = [lindex $valList 0]    Gap = [format %0.3f [lindex $valList 1]]"
		if [catch {exec cavget -list=S${sectorf}IDFE-XBPM: -list=CM1,CM2,CM3,CM4 -list=us -list=:Current \
			       -list=1,2,3,4 -list=:MeanValue_RBV -pend=10 -printErrors } usvalList1] {
		    return -code error "Error reading S$sectorf tetraAMM1: $usvalList1"
		}
		if [catch {exec cavget -list=S${sectorf}IDFE-XBPM: -list=CM1,CM2,CM3 -list=us -list=:Current \
			       -list=1,2,3,4 -list=:MeanValue_NormM -pend=10 -printErrors } usvalList2] {
		    return -code error "Error reading S$sectorf tetraAMM1: $usvalList2"
		}
		if [catch {exec cavget -list=S${sectorf}IDFE-XBPM:P1us: -list=X1M,X2M,x -printErrors -pend=10 } xusList] {
		    return -code error "Error reading x bpm pos: $xusList"
		}
		if [catch {exec cavget -list=S${sectorf}IDFE-XBPM:P1us: -list=Y1M,Y2M,y -printErrors -pend=10 } yusList] {
		    return -code error "Error reading x bpm pos: $x=yusList"
		}
		#ratio
		if [catch {exec cavget -list=S${sectorf}IDFE-XBPM:P1us:X -list=Ratio1M,Ratio2M,MixFractionM \
			       -printErrors -pend=10} xusRatioList] {
		    return -code erorr "Error reading x ratio: $xusRatioList"
		}
		if [catch {exec cavget -list=S${sectorf}IDFE-XBPM:P1us:Y -list=Ratio1M,Ratio2M,MixFractionM \
			       -printErrors -pend=10} yusRatioList] {
		    return -code erorr "Error reading y ratio: $yusRatioList"
		}
	    }
	    if [catch {exec cavget -list=S${sectorf}ID:DSID: -list=DeviceM,GapM -printErrors -pend=10} valList] {
		return -code error "Error reading S$sectorf DS device:$vaList"
	    }
	    puts $fd "  DSID = [lindex $valList 0]    Gap = [format %0.3f [lindex $valList 1]] (mm)"
	    puts $fd "   "
	    puts $fd "XBPM = P1us/P1ds Raw Input Signal"
	    puts $fd "  TetrAMM    Chan.1     Chan.2      Chan.3       Chan.4"
	    if [catch {exec cavget -list=S${sectorf}IDFE-XBPM: -list=CM1,CM2,CM3,CM4 -list=ds \
			   -list=:Current  -list=1,2,3,4 -list=:MeanValue_RBV -pend=10 -printErrors} dsvalList1] {
		return -code error "Error reading S$sectorf tetraAMM1: $dsvalList1"
	    }
	    if [catch {exec cavget -list=S${sectorf}IDFE-XBPM: -list=CM1,CM2,CM3 -list=ds \
			   -list=:Current  -list=1,2,3,4 -list=:MeanValue_NormM -pend=10 -printErrors} dsvalList2] {
		return -code error "Error reading S$sectorf tetraAMM1: $dsvalList2"
	    }
	    if $us {
		set i 0
		foreach cm {1 2 3 4} {
		    set val1 [format %7.3f [lindex $usvalList1 $i]]
		    set val2 [format %7.3f [lindex $usvalList1 [expr $i+1]]]
		    set val3 [format %7.3f [lindex $usvalList1 [expr $i+2]]]
		    set val4 [format %7.3f [lindex $usvalList1 [expr $i+3]]]
		    set i [expr $i+4]
		    puts $fd "   CM${cm}us   $val1     $val2     $val3    $val4 "
		}
	    }
	    set i 0
	    foreach cm {1 2 3 4} {
		set val1 [format %7.3f [lindex $dsvalList1 $i]]
		set val2 [format %7.3f [lindex $dsvalList1 [expr $i+1]]]
		set val3 [format %7.3f [lindex $dsvalList1 [expr $i+2]]]
		set val4 [format %7.3f [lindex $dsvalList1 [expr $i+3]]]
		set i [expr $i+4]
		puts $fd "   CM${cm}ds   $val1     $val2     $val3    $val4 "
	    }
	    puts $fd "   "
	    puts $fd "XBPM = P1us/P1ds Normalized Signal"
	    puts $fd "  TetrAMM    Chan.1     Chan.2      Chan.3      Chan.4"
	    if $us {
		set i 0
		foreach cm {1 2 3} {
		    set val1 [format %7.3f [lindex $usvalList2 $i]]
		    set val2 [format %7.3f [lindex $usvalList2 [expr $i+1]]]
		    set val3 [format %7.3f [lindex $usvalList2 [expr $i+2]]]
		    set val4 [format %7.3f [lindex $usvalList2 [expr $i+3]]]
		    set i [expr $i+4]
		    puts $fd "   CM${cm}us   $val1     $val2     $val3    $val4 "
		}
	    }
	    set i 0
	    foreach cm {1 2 3} {
		set val1 [format %7.3f [lindex $dsvalList2 $i]]
		set val2 [format %7.3f [lindex $dsvalList2 [expr $i+1]]]
		set val3 [format %7.3f [lindex $dsvalList2 [expr $i+2]]]
		set val4 [format %7.3f [lindex $dsvalList2 [expr $i+3]]]
		set i [expr $i+4]
		puts $fd "   CM${cm}ds   $val1     $val2     $val3    $val4 "
	    }
	    if [catch {exec cavget -list=S${sectorf}IDFE-XBPM:P1ds: -list=X1M,X2M,x -printErrors -pend=10 } xdsList] {
		return -code error "Error reading x bpm pos: $xdsList"
	    }
	    if [catch {exec cavget -list=S${sectorf}IDFE-XBPM:P1ds: -list=Y1M,Y2M,y -printErrors -pend=10 } ydsList] {
		return -code error "Error reading x bpm pos: $ydsList"
	    }
	    if [catch {exec cavget -list=S${sectorf}IDFE-XBPM:P1ds:X -list=Ratio1M,Ratio2M,MixFractionM \
			   -printErrors -pend=10} xdsRatioList] {
		    return -code erorr "Error reading x ratio: $xdsRatioList"
	    }
	    if [catch {exec cavget -list=S${sectorf}IDFE-XBPM:P1ds:Y -list=Ratio1M,Ratio2M,MixFractionM \
			   -printErrors -pend=10} ydsRatioList] {
		return -code erorr "Error reading y ratio: $ydsRatioList"
	    }
	    puts $fd "  "
	    puts $fd "XBPM = P1us/P1ds XBPM Target Functions"
	    puts $fd "  XBPM    Position       Target       ||  XBPM     Position      Target"
	    if $us {
		set x1 [lindex $xusList 0]
		set x2 [lindex $xusList 1]
		set xq [lindex $xusList 2]
		set xr1 [lindex $xusRatioList 0]
		set xr2 [lindex $xusRatioList 1]
		set xmix [lindex $xusRatioList 2]
		set y1 [lindex $yusList 0]
		set y2 [lindex $yusList 1]
		set yq [lindex $yusList 2]
		set yr1 [lindex $yusRatioList 0]
		set yr2 [lindex $yusRatioList 1]
		set ymix [lindex $yusRatioList 2]
		set xt [expr $xr1 + $xmix*($xr2-$xr1)]
		set yt [expr $yr1 + $ymix *($yr2-$yr1)]
		 puts $fd "  X1ds   [format %10.3f $x1]   [format %10.3f $xr1]      ||  Y1ds   [format %10.3f $y1]   [format %10.3f $yr1]"
		puts $fd "  X2ds   [format %10.3f $x2]   [format %10.3f $xr2]      ||  Y2ds   [format %10.3f $y2]   [format %10.3f $yr2]"
		puts $fd "  XQds   [format %10.3f $xq]   [format %10.3f $xt]      ||  YQds   [format %10.3f $y2]   [format %10.3f $yt]"
	    }
	    set x1 [lindex $xdsList 0]
	    set x2 [lindex $xdsList 1]
	    set xq [lindex $xdsList 2]
	    set xr1 [lindex $xdsRatioList 0]
	    set xr2 [lindex $xdsRatioList 1]
	    set xmix [lindex $xdsRatioList 2]
	    set y1 [lindex $ydsList 0]
	    set y2 [lindex $ydsList 1]
	    set yq [lindex $ydsList 2]
	    set yr1 [lindex $ydsRatioList 0]
	    set yr2 [lindex $ydsRatioList 1]
	    set ymix [lindex $ydsRatioList 2]
	    set xt [expr $xr1 + $xmix*($xr2-$xr1)]
	    set yt [expr $yr1 + $ymix *($yr2-$yr1)]
	    puts $fd "  X1ds   [format %10.3f $x1]   [format %10.3f $xr1]      ||  Y1ds   [format %10.3f $y1]   [format %10.3f $yr1]"
	    puts $fd "  X2ds   [format %10.3f $x2]   [format %10.3f $xr2]      ||  Y2ds   [format %10.3f $y2]   [format %10.3f $yr2]"
	    puts $fd "  XQds   [format %10.3f $xq]   [format %10.3f $xt]      ||  YQds   [format %10.3f $y2]   [format %10.3f $yt]"
	    
	    puts $fd "\nVacuum # root1 = S00IDFE:IPC1  root2 = S00IDFE:IPC2"
	    if [catch {exec cavget -list=S${sectorf}IDFE:IPC1:IP -list=1,3,5 -list=:PressureM -printErrors -pend=10 } vacList1] {
		return -code error "Error reading S$sectorf vaccum1" $vacList1"
	    }
	    if [catch {exec cavget -list=S${sectorf}IDFE:IPC2:IP -list=2,4,6 -list=:PressureM -printErrors -pend=10 } vacList2] {
		return -code error "Error reading S$sectorf vaccum2" $vacList1"
	    }
	    puts $fd "IP1 = [format %5.1e [lindex $vacList1 0]] ||  IP2 = [format %5.1e [lindex $vacList2 0]]  ||  IP3 = [format %5.1e [lindex $vacList1 1]]"
	    puts $fd "IP4 = [format %5.1e [lindex $vacList2 1]] ||  IP5 = [format %5.1e [lindex $vacList1 2]]  ||  IP6 = [format %5.1e [lindex $vacList2 2]]"
	    puts $fd "==============================================================================="
	    puts $fd "   "
	}
    }
    flush $fd
    close $fd
    if [file exist $tmpRoot.print] {
	APSFileDisplayWindow [APSUniqueName .]  -fileName $tmpRoot.print -width 80 
    } else {
	SetMainStatus "No bpm is chosen!"
    }
}

proc RunXYBeamScanWithSingleGap {args} {
    set plane x
    set useSteering 1
    APSParseArguments {plane useSteering}
    global XBPMTests

    set gap $XBPMTests(XYScan.singleGap)
    switch $plane {
	x {
	    set otherPlane y
	}
	y {
	    set otherPlane x
	}
    }
    if ![info exist XBPMTests(XYScan.${plane}start)] {
	SetMainStatus "$plane scan range not provided!"
	return
    }
    foreach nm {start stop step} {
	set $nm $XBPMTests(XYScan.${plane}$nm)
    }
    set steps [expr int(($stop-$start)/($step*1.0)+1)]

    if {![info exist XBPMTests(XYScan.timestamp)] || ![string length $XBPMTests(XYScan.timestamp)]} {
	set XBPMTests(XYScan.timestamp) S[clock format [clock seconds] -format %Y%m%d-%H%M]
    }
    set timestr $XBPMTests(XYScan.timestamp)
    set root ${timestr}
    set offsetList ""

    foreach offset {0 5 10 15 20 30} {
	if $XBPMTests(XYScan.${otherPlane}offset$offset)  {
	    lappend offsetList $offset
	    if $offset>0 {
		lappend offsetList [expr int(-1*$offset)]
	    }
	}
    }
   
    set type $XBPMTests(XYScan.${plane}scanType)
    foreach offset $offsetList {
	SetMainStatus "doing $plane single gap beam scan with $otherPlane offset = $offset urad..."
	#set root1 ${root}-${otherPlane}Offset$offset
	set doList ""
	for {set sector 1} {$sector<=35} {incr sector} {
	    set sectorf [format %02d $sector]
	    set s1 [format %02d [expr $sector+1]]
	    set outDir /home/helios/oagData/apsu/XbpmSetup/data/S${sectorf}ID/daily
	    set IDList ""
	    foreach item {P1us P1ds} {
		set st [string range $item end-1 end]
		set ID S${sectorf}ID:[string toupper $st]ID
		set usds ""
		if $XBPMTests(XYScan.S${sectorf}$item) {
		    append usds $st
		    lappend IDList $ID
		}
	    }
	    if ![llength $IDList] {
		continue
	    }
	    set XBPMTests(XYScan.S$sectorf.done) 0
	    set rootname ${root}-S${sectorf}ID-${usds}XYScan-SingleGap[format %.1f $gap]mm-${otherPlane}Offset$offset.$plane
	    
	    #create parameter file
	    set IDtype $XBPMTests(S$sectorf.FE)
	    if [catch {exec replaceText /home/helios/oagData/apsu/XbpmSetup/inputFiles/MonFile/S00IDFE-XBPM-BeamScan-${IDtype}.par \
			   $outDir/$rootname.par -orig=<sectorf>,<sector1f> -repl=$sectorf,$s1 } result] {
		return -code error "Error generating parameter file for XYScan: $result"
	    }
	    set template   /home/helios/oagData/apsu/XbpmSetup/inputFiles/MonFile/S00IDFE-XBPM-BeamScan-${IDtype}.mon
	    set ustemplate /home/helios/oagData/apsu/XbpmSetup/inputFiles/MonFile/S00IDFE-XBPM-BeamScan-USID.mon
	    set monFile $outDir/$rootname.mon
	    puts $template
	    puts $ustemplate
	    puts "$sectorf $s1"
	    set tmpRoot /tmp/[APSTmpString]
	    if $XBPMTests(S[format %02d $sector].usExist) {
		#if us exist, add us gap monitor
		if [catch {exec replaceText $template $tmpRoot.ds.$sectorf -orig=<sectorf>,<sector1f> -repl=$sectorf,$s1
		    exec replaceText $ustemplate $tmpRoot.us.$sectorf -orig=<sectorf>,<sector1f> -repl=$sectorf,$s1
		    exec sddscombine $tmpRoot.ds.$sectorf $tmpRoot.us.$sectorf -merge $monFile -over } result] {
		    return -code error "Error generating mon file for S$sectorf: $result"
		}
		APSAddToTmpFileList -ID xbpm -fileList "$tmpRoot.ds.$sectorf $tmpRoot.us.$sectorf"
	    } else {
		#the monitor file is multiple pages
		if [catch {exec replaceText $template  $tmpRoot.mon1.$sectorf \
			       -orig=<sectorf>,<sector1f> -repl=$sectorf,$s1 } result] {
		    return -code error "Error generating mon file: $result"
		}
		if [catch {exec sddscombine $tmpRoot.mon1.$sectorf $monFile -merge -over} result] {
		    return -code error "Error generating mon file1: $result"
		}
		APSAddToTmpFileList -ID xbpm -fileList "$tmpRoot.mon1.$sectorf"
	    }
	    set fileList ""
	    if $useSteering {
		if [catch {exec replaceText /home/helios/oagData/apsu/XbpmSetup/inputFiles/ExpFile/xyBeamScan.steer.template1a.exp \
			       $tmpRoot.mon1.$sectorf -orig=<sectorf>,<Coord>,<start>,<stop>,<xysteps> \
			       -repl=$sectorf,[string toupper $plane],$start,$stop,$steps } result] {
		    return -code error "Error creating gap scan exp file2: $result"
		}
	    } else {
		set bpm1 S[format %02d $sector]B:P0
		set bpm2 S[format %02d [expr $sector+1]]A:P0
		set start [expr $start*$XBPMTests(P0L)]
		set stop [expr $stop*$XBPMTests(P0L)]
		set start1 [expr -1.0*$start]
		set stop1 [expr -1.0*$stop]
		set offset [expr $offset * $XBPMTests(P0L)]
		set offset1 [expr -1.0*$offset]
		if [catch {exec replaceText /home/helios/oagData/apsu/XbpmSetup/inputFiles/ExpFile/xyBeamScan.template1.exp \
			       $tmpRoot.mon1.$sectorf -orig=<bpm1>,<bpm2>,<coord>,<start>,<stop>,<xysteps>,<start1>,<stop1> \
			       -repl=$bpm1,$bpm2,$plane,$start,$stop,$steps,$start1,$stop1 } result] {
		    return -code error "Error creating gap scan exp file2: $result"
		}
	    }
	    APSAddToTmpFileList -ID xbpm -fileList $tmpRoot.mon1.$sectorf
	    lappend fileList $tmpRoot.mon1.$sectorf
	    if !$XBPMTests(dryRun) {
		SetMainStatus "moving ID gaps ([join $IDList]) to $gap mm..."
		if [catch {exec cavput -list=[join $IDList ,] -list=:GapSetC=$gap -pend=10} result] {
		    return -code error "Error changing gap setpoint to $gap: $result"
		}
		if [catch {exec cavput -list=[join $IDList ,] -list=:StartC=1 -pend=10} result] {
		    return -code error "Error moving gaps; $result"
		}
		APSInfoWindow .moveGap -width 30 -infoMessage "Waiting for [join $IDList] gap stop moving, click ok when done." -modal 1
	    }
	    set rampsteps [expr int(abs($start)/1.0+1)]
	    set ramppause 6.0
	    if $useSteering {
		if [catch {exec replaceText /home/helios/oagData/apsu/XbpmSetup/inputFiles/ExpFile/xyBeamScan.steer.template2.exp \
			       $tmpRoot.mon2.$sectorf -orig=<monFile>,<sectorf>,<otherCoord>,<offset>,<pause>,<ramp_steps>,<ramp_pause> \
			       -repl=$monFile,$sectorf,[string toupper $otherPlane],$offset,$XBPMTests(XYScan.dwellTime),$rampsteps,$ramppause } result] {
		    return -code error "Error creating gap scan exp file2: $result"
		}
	    } else {
		if [catch {exec replaceText /home/helios/oagData/apsu/XbpmSetup/inputFiles/ExpFile/xyBeamScan.template2.exp \
			       $tmpRoot.mon2.$sectorf -orig=<monFile>,<bpm1>,<bpm2>,<value1>,<value2>,<coord1>,<pause>,<ramp_steps>,<ramp_pause> \
			       -repl=$monFile,$bpm1,$bpm2,$offset,$offset1,$otherPlane,$XBPMTests(XYScan.dwellTime),$rampsteps,$ramppause } result] {
		    return -code error "Error creating gap scan exp file2: $result"
		}
	    }
	    APSAddToTmpFileList -ID xbpm -fileList $tmpRoot.mon2.$sectorf
	    lappend fileList $tmpRoot.mon2.$sectorf
	    catch {exec rm $outDir/$rootname.exp}
	    if [catch {eval exec cat $fileList > $outDir/$rootname.exp } result] {
		return -code error "Error creating xyscan exp file: $result"
	    }
	    set XBPMTests(XYScan.S${sectorf}.done) 0
	    if $XBPMTests(dryRun) {
		set command  "/home/oxygen8/SHANG/epics/extensions/src/SDDSepics/SDDSepics/O.linux-x86_64/sddsexperiment $outDir/$rootname.exp -scalars=$outDir/$rootname.par -dryrun  $outDir/$rootname.sdds -verbose"
	    } else {
		set command  "/home/oxygen8/SHANG/epics/extensions/src/SDDSepics/SDDSepics/O.linux-x86_64/sddsexperiment $outDir/$rootname.exp -scalars=$outDir/$rootname.par  $outDir/$rootname.sdds -verbose"
		if $useSteering {
		    if [catch {exec pvinfo S${sectorf}ID-Steering:[string toupper $plane]p } result] {
			return -code error "Error S${sectorf}ID [string toupper $plane]p server not started yet: $result"
		    }
		    if [catch {exec cavput -list=S${sectorf}ID-Steering: -list=X,Y -list=p_SetValueC=0 } result] {
			return -code error "Error change the steering angle for S$sector to 0: $result"
		    }
		    SetMainStatus "steer $otherPlane to $offset..."
		    
		    if [catch {exec cavput -list=S${sectorf}ID-Steering:[string toupper $otherPlane]p_SetValueC=$offset -pend=5} result] {
			return -code error "Error steering the other plane by $offset urad: $result"
		    }
		}
	    }
		
	    APSExecLog .s$sector -name "S$sector ID XY scan" -lineLimit 1024 \
		-unixCommand "$command"\
		-abortCallback "set XBPMTests(XYScan.S${sectorf}.done) aborted;SetMainStatus \"S$sector XY beam scan aborted.\"" \
		-callback "set XBPMTests(XYScan.S${sectorf}.done) done;catch {exec sddsprocess $outDir/$rootname.sdds -nowarn -define=par,OtherPlaneOffset,$offset};SetMainStatus \"S$sector ID XY scan done\"" \
		-cancelCallback "set XBPMTests(XYScan.S${sectorf}.done) cancelled;SetMainStatus \"S$sector ID XY beam scan cancelled\"" 
	    
	    lappend doList S$sectorf
	}
	if ![llength $doList] {
	    SetMainStatus "No item is chosen for XY beam scan."
	    return
	}
	foreach job $doList {
	    tkwait variable XBPMTests(XYScan.$job.done)
	}
    }
    if !$XBPMTests(dryRun) {
	SetMainStatus "Restore the steering in other plane..."
	if [catch {exec cavput -list=[join $doList ,] -list=ID-Steering:[string toupper $otherPlane]p_SetValueC=0 -pend=5} result] {
	    return -code error "Error steering the other plane by $offset urad: $result"
	}
    }
    SetMainStatus "$plane single gap beam scan done."
    
}

proc RunXYBeamScans {args} {
    set plane x
    set useSteering 1
    APSParseArguments {plane useSteering}
    global XBPMTests

    if {$XBPMTests(XYScan.${plane}scanType)=="SingleGap"} {
	RunXYBeamScanWithSingleGap -plane $plane -useSteering $useSteering
	return
    }
    switch $plane {
	x {
	    set otherPlane y
	}
	y {
	    set otherPlane x
	}
    }
    set Coord [string toupper $plane]
    set otherCoord [string toupper $otherPlane]
    if ![info exist XBPMTests(XYScan.${plane}start)] {
	SetMainStatus "$plane scan range not provided!"
	return
    }
    foreach nm {start stop step} {
	set $nm $XBPMTests(XYScan.${plane}$nm)
    }
    set steps [expr int(($stop-$start)/($step*1.0)+1)]
    
    if {![info exist XBPMTests(XYScan.timestamp)] || ![string length $XBPMTests(XYScan.timestamp)]} {
	set XBPMTests(XYScan.timestamp) S[clock format [clock seconds] -format %Y%m%d-%H%M]
    }
    set timestr $XBPMTests(XYScan.timestamp)
    set root $timestr
    set offsetList ""
    #P1 distance from ID
    foreach offset {0 5 10 15 20 30} {
	if $XBPMTests(XYScan.${otherPlane}offset$offset)  {
	    lappend offsetList $offset
	    if $offset>0 {
		lappend offsetList [expr int(-1*$offset)]
	    }
	}
    }
    
    set type $XBPMTests(XYScan.${plane}scanType)
    foreach offset $offsetList {
	SetMainStatus "doing $plane beam scan with $otherPlane offset = $offset urad..."
	#set root1 ${root}-${otherPlane}Offset$offset
	set doList ""
	for {set sector 1} {$sector<=35} {incr sector} {
	    set sectorf [format %02d $sector]
	    set s1 [format %02d [expr $sector+1]]
	    set outDir /home/helios/oagData/apsu/XbpmSetup/data/S${sectorf}ID/daily
	    set IDList ""
	    foreach item {P1us P1ds} {
		set st [string range $item end-1 end]
		set ID S${sectorf}ID:[string toupper $st]ID
		set usds ""
		if $XBPMTests(XYScan.S${sectorf}$item) {
		    append usds $st
		    lappend IDList $ID
		}
	    }
	    if ![llength $IDList] {
		continue
	    }
	    set XBPMTests(XYScan.S$sectorf.done) 0
	    set rootname ${root}-S${sectorf}ID-${usds}XYScan-${type}-${otherPlane}Offset$offset.$plane
	    
	    set tmpRoot /tmp/[APSTmpString]
	    #create parameter file
	    set IDtype $XBPMTests(S$sectorf.FE)
	    if [catch {exec replaceText /home/helios/oagData/apsu/XbpmSetup/inputFiles/MonFile/S00IDFE-XBPM-BeamScan-${IDtype}.par \
			   $outDir/$rootname.par -orig=<sectorf>,<sector1f> -repl=$sectorf,$s1 } result] {
		return -code error "Error generating parameter file for XYScan: $result"
	    }
	    set template   /home/helios/oagData/apsu/XbpmSetup/inputFiles/MonFile/S00IDFE-XBPM-BeamScan-${IDtype}.mon
	    set ustemplate /home/helios/oagData/apsu/XbpmSetup/inputFiles/MonFile/S00IDFE-XBPM-BeamScan-USID.mon
	    set monFile $outDir/$rootname.mon
	    if $XBPMTests(S[format %02d $sector].usExist) {
		#if us exist, add us gap monitor
		if [catch {exec replaceText $template $tmpRoot.ds -orig=<sectorf>,<sector1f> -repl=$sectorf,$s1
		    exec replaceText $ustemplate $tmpRoot.us -orig=<sectorf>,<sector1f> -repl=$sectorf,$s1
		    exec sddscombine $tmpRoot.ds $tmpRoot.us -merge $monFile -over } result] {
		    return -code error "Error generating mon file for S$sectorf: $result"
		}
		APSAddToTmpFileList -ID xbpm -fileList "$tmpRoot.ds.$sectorf $tmpRoot.us.$sectorf"
	    } else {
		#the monitor file is multiple pages
		if [catch {exec replaceText $template  $tmpRoot.mon1 -orig=<sectorf>,<sector1f> -repl=$sectorf,$s1 } result] {
		    return -code error "Error generating mon file: $result"
		}
		if [catch {exec sddscombine $tmpRoot.mon1 $monFile -merge -over} result] {
		    return -code error "Error generating mon file1: $result"
		}
		APSAddToTmpFileList -ID xbpm -fileList "$tmpRoot.mon1"
	    }
	    set fileList ""
	    set rampsteps [expr int(abs($start)/2.0+1)]
	    set ramppause 6.0
	    if [catch {exec replaceText /home/helios/oagData/apsu/XbpmSetup/inputFiles/ExpFile/xyBeamScan.steer.template1a.exp \
			   $tmpRoot.mon1 -orig=<sectorf>,<Coord>,<start>,<stop>,<xysteps> \
			   -repl=$sectorf,[string toupper $plane],$start,$stop,$steps } result] {
		return -code error "Error creating gap scan exp file2: $result"
	    }
	    APSAddToTmpFileList -ID xbpm -fileList $tmpRoot.mon1
	    
	    lappend fileList $tmpRoot.mon1
	    foreach ID $IDList {
		if [catch {GetGapFile -ID $ID -scanType $XBPMTests(XYScan.${plane}scanType) -type XYScan } gapFile] {
		    return -code "Error in geting gap file: $gapFile"
		}
		if [catch {exec replaceText /home/helios/oagData/apsu/XbpmSetup/inputFiles/ExpFile/IDGapXYScan.template.exp \
			       $tmpRoot.$ID.var -orig=<ID>,<valuesFile> -repl=$ID,$gapFile } result] {
		    return -code error "Error creating gap scan exp file1: $result"
		}
		lappend fileList $tmpRoot.$ID.var
		APSAddToTmpFileList -ID xbpm -fileList $tmpRoot.$ID.var
	    }
	    if $useSteering {
		if [catch {exec replaceText /home/helios/oagData/apsu/XbpmSetup/inputFiles/ExpFile/xyBeamScan.steer.template2.exp \
			       $tmpRoot.mon2 -orig=<monFile>,<sectorf>,<offset>,<otherCoord>,<pause>,<ramp_steps>,<ramp_pause> \
			       -repl=$monFile,$sectorf,$offset,[string toupper $otherPlane],$XBPMTests(XYScan.dwellTime),$rampsteps,$ramppause } result] {
		    return -code error "Error creating gap scan exp file2: $result"
		}
	    } else {
		if [catch {exec replaceText /home/helios/oagData/apsu/XbpmSetup/inputFiles/ExpFile/xyBeamScan.template2.exp \
			       $tmpRoot.mon2 -orig=<monFile>,<bpm1>,<bpm2>,<value1>,<value2>,<coord1>,<pause> \
			       -repl=$monFile,$bpm1,$bpm2,$offset,$offset1,$otherPlane,$XBPMTests(XYScan.dwellTime) } result] {
		    return -code error "Error creating gap scan exp file2: $result"
		}
	    }
	    APSAddToTmpFileList -ID xbpm -fileList $tmpRoot.mon2
	    lappend fileList $tmpRoot.mon2
	    
	    catch {exec rm $outDir/$rootname.exp}
	    if [catch {eval exec cat $fileList > $outDir/$rootname.exp } result] {
		return -code error "Error creating xyscan exp file: $result"
	    }
	    set XBPMTests(XYScan.S${sectorf}.done) 0
	    if $XBPMTests(dryRun) {
		set command  "/home/oxygen8/SHANG/epics/extensions/src/SDDSepics/SDDSepics/O.linux-x86_64/sddsexperiment $outDir/$rootname.exp -scalars=$outDir/$rootname.par -dryrun  $outDir/$rootname.sdds -verbose"
	    } else {
		set command  "/home/oxygen8/SHANG/epics/extensions/src/SDDSepics/SDDSepics/O.linux-x86_64/sddsexperiment $outDir/$rootname.exp -scalars=$outDir/$rootname.par  $outDir/$rootname.sdds -verbose"
		if $useSteering {
		    if [catch {exec pvinfo S${sectorf}ID-Steering:[string toupper $plane]p } result] {
			return -code error "Error S${sectorf}ID-Steering:[string toupper $plane]p steering server not started: $result"
		    }
		    if [catch {exec cavput -list=S${sectorf}ID-Steering: -list=Xp,Yp -list=_SetValueC=0 } result] {
			return -code error "Error change the steer angle for S$sector to 0: $result"
		    }
		    SetMainStatus "Steer [string toupper $otherPlane]p by $offset urad.."
		    if [catch {exec cavput -list=S${sectorf}ID-Steering:[string toupper $otherPlane]p_SetValueC=$offset -pend=5} result] {
			return -code error "Error steering the other plane by $offset urad: $result"
		    }
		}
	    }
	    
	    APSExecLog .s$sector -name "S$sector ID XY scan" -lineLimit 1024 \
		-unixCommand "$command"\
		-abortCallback "set XBPMTests(XYScan.S${sectorf}.done) aborted;SetMainStatus \"S$sector XY beam scan aborted.\"" \
		-callback "set XBPMTests(XYScan.S${sectorf}.done) done;catch {exec sddsprocess $outDir/$rootname.sdds -nowarn -define=par,OtherPlaneOffset,$offset};SetMainStatus \"S$sector ID XY scan done\"" \
		-cancelCallback "set XBPMTests(XYScan.S${sectorf}.done) cancelled;SetMainStatus \"S$sector ID XY beam scan cancelled\"" 
	    
	    lappend doList S$sectorf
	}
	if ![llength $doList] {
	    SetMainStatus "No item is chosen for XY beam scan."
	    return
	}
	foreach job $doList {
	    tkwait variable XBPMTests(XYScan.$job.done)
	}

    }
    if !$XBPMTests(dryRun) {
	SetMainStatus "Restore the steering in other plane..."
	if [catch {exec cavput -list=[join $doList ,] -list=ID-Steering:[string toupper $otherPlane]p_SetValueC=0 -pend=5} result] {
	    return -code error "Error steering the other plane by $offset urad: $result"
	}
    }
    SetMainStatus "$plane beam scan done."
}

proc UpdateGapScanFiles {args} {
    global XBPMTests
    set dir /home/helios/oagData/apsu/XbpmSetup/inputFiles
    set  XBPMTests(GapScan.gapInputFile) $dir/IDgapScan-$XBPMTests(GapScan.gapScanType).sdds
    
}

proc GetGapFile {args} {
    set ID ""
    set scanType SHORT
    set type GapScan
    APSParseArguments {ID scanType type}
    
    set IDinfo /home/helios/oagData/apsu/XbpmSetup/inputFiles/APSU-IDInfo.sdds
   
    set tmpRoot /tmp/[APSTmpString]
    set sector [scan $ID S%ld]
    set sectorf [format %02d $sector]
    set st [string tolower [string range $ID end-3 end-2]]
    set dataDir /home/helios/oagData/apsu/XbpmSetup/data/S${sectorf}ID/inputFiles/$type
    
    if [catch {exec sddsprocess $IDinfo -pipe=out \
		   -filter=col,Sector,$sector,$sector \
		   | sdds2stream -pipe=in -col=${st}IDPeriod } period] {
	return -code error "Error obtaining $ID period: $period"
    }
    set gapFile $dataDir/S${sectorf}ID${st}-U[format %0.1f $period]mm-${scanType}GapScan-GapList.sdds
    if ![file exist $gapFile] {
	return -code error "Gap file $gapFile does not exist, please run /home/helios/oagData/apsu/XbpmSetup/scripts/makeGapScanInputFiles -type $type to generate it first!"
    }
    return $gapFile
}

proc GetGapScanList {args} {
    global XBPMTests
    set gapScanList ""
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	foreach item {P1us P1ds} {
	    if $XBPMTests(GapScan.S${sectorf}$item) {
		lappend gapScanList S${sectorf}$item
	    }
	}
    }
    return $gapScanList
}

proc MoveGaps {args} {
    global XBPMTests
    set gapScanList [GetGapScanList]
    if ![llength $gapScanList] {
	return -code error "No item is chosen."
    }
    if $XBPMTests(dryRun) {
	SetMainStatus "Do not move gaps in dryRun mode!"
	return
    }
    set IDList ""
    set valList ""
    foreach item $gapScanList {
	set sector [scan $item S%ld]
	set st [string range $item end-1 end]
	set ID S[format %02d $sector]ID:[string toupper $st]ID
	lappend IDList $ID
    }
    set IDs [llength $IDList]
    if [catch {exec cavget -list=[join $IDList ,] -list=:DeviceLimitM -pend=10 } minList] {
	return -code error "Error reading minimum gaps: $minList"
    }
    switch $XBPMTests(GapScan.gapTarget) {
	custom {
	    set valueList [APSReplicateItem -item $XBPMTests(GapScan.customGap) -number $IDs]
	}
	limit {
	    foreach val $minList {
		lappend valueList [expr $val+0.05]
	    }
	}
	default {
	    if [catch {SetUndulatorAlignmentGap -type GapScan -gap $XBPMTests(GapScan.gapTarget)} result] {
		return -code error "Error moving gaps to alignment: $result"
	    }
	    return
	}
    }
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddsmakedataset -col=DeviceName,type=string -data=[join $IDList ,] \
		   -col=Value,type=double -data=[join $valueList ,] -pipe=out \
		   | sddsprocess -pipe=in $tmpRoot.set \
		   "-edit=col,ControlName,DeviceName,ei/:GapSetC/" \
		   "-print=col,ValueString,%lf,Value" } result] {
	return -code error "MoveGaps2: error creating gapsetpoint file: $result"
    }
    if [catch {exec sddsprocess $tmpRoot.set $tmpRoot.start -reedit=col,ControlName,%/:GapSetC/:StartC/ \
		   -reprint=col,ValueString,1 } result] {
	return -code error "MoveGaps3: $result"
    }
    APSAddToTmpFileList -ID xbpm -fileList "$tmpRoot.set $tmpRoot.start $tmpRoot.print"
    if [catch {exec sddsprintout $tmpRoot.set $tmpRoot.print -col=ControlName,format=%20s \
		   -col=ValueString,format=%8s,label=MoveTo \
	       "-title=Following gaps will be moved to MoveTo values\\,\n press OK to continue or cancel to abort" } result] {
	return -code error "Error printing alignment gap: $result"
    }
    global moveGaps
    set moveGaps 0
    APSFileDisplayWindow .gap -fileName $tmpRoot.print -width 80 -modal 1 \
	-closeButton 0 -okButton 1 -cancelButton 1 -okCommand "set moveGaps 1;destroy .gap" \
	-cancelCommand "set moveGaps 0;destroy .gap"
    
    if !$moveGaps {
	SetMainStatus "Moving gaps to minimum gap was canceled!"
	return
    }
  #  if $XPMTests(dryRun) {
#	SetMainStatus "Moving gaps is cancelled in dryRun mode!"
#	return
 #   }
    SetMainStatus "Moving selected gap to minimum gaps..."
    if [catch {exec sddscasr -restore $tmpRoot.set} result] {
	return -code error "MoveGaps4: error moving gaps to minimum: $result"
    }
    after 1000
    if [catch {exec sddscasr -restore $tmpRoot.start} result] {
	return -code error "MoveGaps5:  $result"
    }
    SetMainStatus "waiting for gaps to stop moving..."
    if [catch {APSIDsGoAndWait -IDList $IDList} result] {
	return -code error "MoveGaps6: $result"
    }
    SetMainStatus "done."
}

proc UpdateGapScanList {args} {
    set type GapScan
    APSParseArguments {type}
    SetMainStatus "updating gap scan list..."
    exec /home/helios/oagData/apsu/XbpmSetup/scripts/makeGapScanInputFiles -type $type
    SetMainStatus "done."
}
proc RunUndulatorGapScan {args} {
    global XBPMTests
    set type $XBPMTests(GapScan.gapScanType)
    if ![string length $XBPMTests(GapScan.timestamp)] {
	set XBPMTests(GapScan.timestamp) S[clock format [clock seconds] -format %Y%m%d-%H%M]
    }
    set timestr $XBPMTests(GapScan.timestamp)
    set root $timestr
    for {set sector 1} {$sector<=35} {incr sector} {
	set usds ""
	set sectorf [format %02d $sector]
	set expDir /home/helios/oagData/apsu/XbpmSetup/data/S${sectorf}ID/daily
	set s0 $sectorf
	set s1 [format %02d [expr $sector+1]]
	set lastGap 0
	set lastID ""
	set IDList ""
	foreach st {us ds} {
	    if $XBPMTests(GapScan.S${sectorf}P1$st) {
		append usds $st
		set ID S${sectorf}ID:[string toupper $st]ID
		lappend IDList $ID
	    }
	}
	if ![string length $usds] {
	    continue
	}
	set rootname ${root}-S${sectorf}ID-${usds}GapScan-$type
	#create parameter file
	set IDtype $XBPMTests(S$sectorf.FE)
	if [catch {exec replaceText /home/helios/oagData/apsu/XbpmSetup/inputFiles/MonFile/S00IDFE-XBPM-BeamScan-${IDtype}.par \
		       $expDir/$rootname.par -orig=<sectorf>,<sector1f> -repl=$sectorf,$s1 } result] {
	    return -code error "Error generating parameter file: $result"
	}
	#create monitor file
	set template   /home/helios/oagData/apsu/XbpmSetup/inputFiles/MonFile/S00IDFE-XBPM-BeamScan-${IDtype}.mon
	set ustemplate /home/helios/oagData/apsu/XbpmSetup/inputFiles/MonFile/S00IDFE-XBPM-BeamScan-USID.mon
	set monFile $expDir/$rootname.mon
	set tmpRoot /tmp/[APSTmpString]
	if $XBPMTests(S[format %02d $sector].usExist) {
	    #if us exist, add us gap monitor
	    if [catch {exec replaceText $template $tmpRoot.ds -orig=<sectorf>,<sector1f> -repl=$sectorf,$s1
		exec replaceText $ustemplate $tmpRoot.us -orig=<sectorf>,<sector1f> -repl=$sectorf,$s1
		exec sddscombine $tmpRoot.ds $tmpRoot.us -merge $monFile -over } result] {
		return -code error "Error generating mon file for S$sectorf: $result"
	    }
	    APSAddToTmpFileList -ID xbpm -fileList "$tmpRoot.ds $tmpRoot.us"
	} else {
	    #the monitor file is multiple pages
	    if [catch {exec replaceText $template  $tmpRoot.mon1 -orig=<sectorf>,<sector1f> -repl=$sectorf,$s1 } result] {
		return -code error "Error generating mon file: $result"
	    }
	    if [catch {exec sddscombine $tmpRoot.mon1 $monFile -merge -over} result] {
		return -code error "Error generating mon file1: $result"
	    }
	    APSAddToTmpFileList -ID xbpm -fileList "$tmpRoot.mon1"
	}
       
	#create exp file
	set tmpRoot /tmp/[APSTmpString]
	set fileList ""
	foreach ID $IDList {
	    if [catch {GetGapFile -ID $ID -scanType $XBPMTests(GapScan.gapScanType) -type GapScan } gapFile] {
		return -code "Error in geting gap file: $gapFile"
	    }
	    switch $XBPMTests(GapScan.minGap) {
		limit {
		    if [catch {exec cavget -list=$ID -list=:DeviceLimitM -pend=10} startGap] {
			return -code error "Error reading device limit of $ID: $startGap"
		    }
		    set startGap [expr $startGap + 0.05]
		}
		softlimit {
		    if [catch {GetRefGapValue -ID $ID -gap softlimit} startGap] {
			return -code error "Error get start gap for $ID: $startGap"
		    }
		}
	    }
	    SetMainStatus "creating new gap file: $gapFile $tmpRoot.$ID.gap"
	    if [catch {exec sddsprocess $gapFile $tmpRoot.$ID.gap -filter=col,GapSet,$startGap,200 } result] {
		return -code error "Error redefine gap file: $result"
	    }
	    APSAddToTmpFileList -ID xbpm -fileList $tmpRoot.$ID.gap
	    if [catch {exec replaceText /home/helios/oagData/apsu/XbpmSetup/inputFiles/ExpFile/IDGapScan.template1.exp \
			   $tmpRoot.$ID.var -orig=<ID>,<valuesFile> -repl=$ID,$tmpRoot.$ID.gap } result] {
		return -code error "Error creating gap scan exp file1: $result"
	    }
	    lappend fileList $tmpRoot.$ID.var
	    APSAddToTmpFileList -ID xbpm -fileList $tmpRoot.$ID.var
	}
	if [catch {exec replaceText /home/helios/oagData/apsu/XbpmSetup/inputFiles/ExpFile/IDGapScan.template2.exp \
		       $tmpRoot.mon -orig=<monFile>,<average> -repl=$monFile,$XBPMTests(GapScan.dwellTime) } result] {
	    return -code error "Error creating gap scan exp file2: $result"
	}
	lappend fileList $tmpRoot.mon
	catch {exec rm $expDir/$rootname.exp}
	if [catch {eval exec cat $fileList > $expDir/$rootname.exp } result] {
	    return -code error "Error creating gap scan exp file: $result"
	}
	SetMainStatus "saving current settings..."
	if [catch {exec sddscasr -save $expDir/$rootname.par $expDir/$rootname.par.sdds } result] {
	    return -code error "Error saving current settings: $result"
	}
	SetMainStatus "Doing scan for S$sectorf $usds ..."
	
	set XBPMTests(GapScan.S${sectorf}scandone) 0
	if $XBPMTests(dryRun) {
	    set command  "sddsexperiment $expDir/$rootname.exp -scalars=$expDir/$rootname.par -dryrun  $expDir/$rootname.sdds -verbose"
	} else {
	    set command  "sddsexperiment $expDir/$rootname.exp -scalars=$expDir/$rootname.par  $expDir/$rootname.sdds -verbose"
	}
	APSExecLog .s$sector -name "S$sector ID gap scan" -lineLimit 1024 \
	    -unixCommand "$command"\
	    -abortCallback "set XBPMTests(GapScan.S${sectorf}scandone) aborted;SetMainStatus \"S$sector ID gap scan aborted.\"" \
	    -callback "set XBPMTests(GapScan.S${sectorf}scandone) done;SetMainStatus \"S$sector ID gap scan done\"" \
	    -cancelCallback "set XBPMTests(GapScan.S${sectorf}scandone) cancelled;SetMainStatus \"S$sector ID gap scan cancelled\"" 
	
    }
    
}


proc RestoreXBPMPosition {args} {
    global XBPMTests
    set dir /home/helios/oagData/apsu/XbpmSetup/data/XYBeamCenter
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	set st ""
	foreach item {us ds} {
	    if $XBPMTests(GapScan.S${sectorf}P1$item) {
		append st $item
	    }
	}
	set dir /home/helios/oagData/apsu/XbpmSetup/data/S${sectorf}ID/daily
	if [string length $st] {
	    set files [glob -nocomplain $dir/S*-$${sectorf}ID-${st}GapScan*.par.sdds]
	    if ![llength $files] {
		SetMainStatus "No bpm data saved for S$sectorf $st."
		continue
	    }
	    set file [lindex [lsort -decreasing $files] 0]
	    SetMainStatus "back to BPM positions saved in $file..."
	    if [catch {exec sddscasr -restore $file} result] {
		return -code error "Error restore BPM settings: $result"
	    }
	    
	}
    }
    SetMainStatus "done."
}

proc DefaultGapScanMonitorMonFile {args} {
    global XBPMTests
    set monDir /home/helios/oagData/apsu/XbpmSetup/inputFiles/MonFile
    set dataDir /home/helios/oagData/apsu/XbpmSetup/data
    if ![string length $XBPMTests(GapScan.timestamp)] {
	set XBPMTests(GapScan.timestamp) [clock format [clock seconds] -format %Y%m%d-%H%M]
    }
    set timestr $XBPMTests(GapScan.timestamp)
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	set s1 [format %02d [expr $sector+1]]
	set FE $XBPMTests(S$sectorf.FE)
	set monFile $monDir/S00IDFE-XBPM-BeamScan-${FE}.mon
	set dir $dataDir/S${sectorf}ID/daily
	if {$XBPMTests(GapScan.S${sectorf}P1ds) || $XBPMTests(GapScan.S${sectorf}P1us)} {
	    set monFile1 $dir/S${timestr}-beam.mon
	    set dataFile $dir/S${timestr}-beam.sdds
	    if [catch {exec replaceText $monFile $monFile1.tmp -orig=<sectorf>,<sector1f> -repl=$sectorf,$s1 } result] {
		return -code error "Error create mon file: $result"
	    }
	    if [catch {exec sddscombine -merge $monFile1.tmp -over -pipe=out \
			   | sddsxref -pipe=in /home/helios/oagData/pvdata/iocRecNamesOAG.sdds $monFile1 \
			   -match=ControlName=rec_name -reuse -nowarn } result] {
		return -code error "Error combine mon file: $result"
	    } 
	    if [catch {exec sddsmonitor $monFile1 $dataFile -time=$XBPMTests(GapScan.monitorTime),minutes \
			   -interval=$XBPMTests(GapScan.monitorInterval),seconds & } result] {
		return -code error "Error starting monitor S$sector xbpm: $result"
	    }
	    set XBPMTests(GapScan.xbpmMonFile) $monFile1
	    break
	}
    }
}

proc DefaultGapScanMonitorDataFile {args} {
    global XBPMTests
    set monDir /home/helios/oagData/apsu/XbpmSetup/inputFiles/MonFile
    set dataDir /home/helios/oagData/apsu/XbpmSetup/data
    if ![string length $XBPMTests(GapScan.timestamp)] {
	set XBPMTests(GapScan.timestamp) [clock format [clock seconds] -format %Y%m%d-%H%M]
    }
    set timestr $XBPMTests(GapScan.timestamp)
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	set FE $XBPMTests(S$sectorf.FE)
	set monFile $monDir/S00IDFE-XBPM-BeamScan-${FE}.mon
	set dir $dataDir/S${sectorf}ID/daily
	if {$XBPMTests(GapScan.S${sectorf}P1ds) || $XBPMTests(GapScan.S${sectorf}P1us)} {
	    set dataFile $dir/S${timestr}-beam.sdds
	    set XBPMTests(GapScan.xbpmMonDataFile) $dataFile
	    break
	}
    }
}


proc PlotXBPMRawData {args} {
    set type GapScan
    APSParseArguments {type}
    
    global XBPMTests
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	set dir  /home/helios/oagData/apsu/XbpmSetup/data/S${sectorf}ID/daily
	set st ""
	foreach item {us ds} {
	    if $XBPMTests(GapScan.S${sectorf}P1$item) {
		append st $item
	    }
	}
	if [string length $st] {
	    set files [glob -nocomplain $dir/*S${sectorf}ID-${st}${type}*.sdds]
	    if ![llength $files] {
		SetMainStatus "No data found for S${sectorf}$item gap scan."
		continue
	    }
	    set XBPMTests(GapScan.S$sectorf.dataFile) ""
	    APSScrolledListWindow .raw$sector -height 10 -name "Select A file" -itemList $files \
		-selectionVar XBPMTests(GapScan.S$sectorf.dataFile)
	    tkwait variable XBPMTests(GapScan.S$sectorf.dataFile)
	    if ![string length $XBPMTests(GapScan.S$sectorf.dataFile)] {
		SetMainStatus "No file chosen for S$sectorf."
		continue
	    }
	    exec /home/helios/oagData/apsu/XbpmSetup/scripts/plotRawXbpmData $sector $st $XBPMTests(GapScan.S$sectorf.dataFile) &
	}
    }

}

proc CreateGapScanWidgets {widget args} {
    set parent ""
    APSParseArguments {parent}
    
    global XBPMTests
    APSFrame $widget -parent $parent -label "" \
	-packOption "-side top"
    set w0 $parent$widget.frame
    APSFrame .f1 -parent $w0 -label "" -packOption "-side top"
    APSFrame .f2 -parent $w0 -label "Move Undulator Gaps" -packOption "-side top"
    APSFrame .f3 -parent $w0 -label "Undulator Gap Scan" -packOption "-side top"
    APSFrame .f4 -parent $w0 -label "Monitor XBPM Data" -packOption "-side top"
    set f1 $w0.f1.frame
    set f2 $w0.f2.frame
    set f3 $w0.f3.frame
    set f4 $w0.f4.frame
    CreateSectorWidget -type GapScan -parent $f1
    set XBPMTests(GapScan.undulatorType) none
    APSFrameGrid .grid -parent $f2 -xList {x1 x2}
    set w1 $f2.grid.x1
    set w2 $f2.grid.x2
    APSRadioButtonFrame .undulator -parent $w1 -label "Undulators In:" -buttonList {All HHLFE CFE None} \
	-orientation horizontal -valueList {all HHLFE CFE none} -variable XBPMTests(GapScan.undulatorType) \
	-commandList [list "SelectUndulators -wtype GapScan -undulatorType all" \
			  "SelectUndulators -wtype GapScan -undulatorType HHLFE" \
			  "SelectUndulators -wtype GapScan -undulatorType CFE" \
			  "SelectUndulators -wtype GapScan -undulatorType none" ]
    set XBPMTests(dryRun) 1
    set XBPMTests(GapScan.gapGridListFile) /home/helios/oagData/apsu/XbpmSetup/inputFiles/GapScan-GapListInfo.sdds
    APSRadioButtonFrame .dry -parent $w2 -label "Dry Run?" -buttonList {Yes No} \
	-valueList {1 0} -variable XBPMTests(dryRun) -orientation horizontal \
	-commandList {"set XBPMTests(GapScan.dwellTime) 3" "set XBPMTests(GapScan.dwellTime) 15"}
    APSLabeledEntry .gap -parent $f2 -label "Gap Grid List:" -width 85 \
	-commandButton 1 -textVariable XBPMTests(GapScan.gapGridListFile)
    set XBPMTests(GapScan.gapTarget) custom
    APSRadioButtonFrame .target -parent $f2 -label "Gap Target:" -orientation horizontal \
	-variable XBPMTests(GapScan.gapTarget) \
	-buttonList {CommonLimit SoftLimit Alignment GapNo1 GapNo2 UserDefined} \
	-valueList {limit softlimit alignment gap1 gap2 custom}
    set XBPMTests(GapScan.customGap) 20.0
    APSLabeledEntry .gap -parent $f2.target -packOption "-side right" -width 20 -label "" \
	-textVariable XBPMTests(GapScan.customGap) 
    APSButton .center -parent $f2 -text "Move To Saved Orbit" -command "RestoreXBPMPosition"
    APSButton .min -parent $f2 -text "Set Undulator Gap To Target" -command "MoveGaps"
    APSButton .update -parent $f2 -text "Update Gap Scan List" -command UpdateGapScanList
    APSButton .show -parent $f2 -text "Show XBPM Signals" -command "ShowXBPMSignals -type GapScan"
 
    APSFrameGrid .grid -parent $f3 -xList {x1 x2}
    set w1 $f3.grid.x1
    set w2 $f3.grid.x2
    set XBPMTests(GapScan.gapScanType) SHORT
    APSRadioButtonFrame .scan -parent $w1 -label "Gap Scan Type:" -buttonList {ExtraLong Long Medium Short ExtraShort} \
	-orientation horizontal -valueList {EXTRALONG LONG MEDIUM SHORT EXTRASHORT} -variable XBPMTests(GapScan.gapScanType) \
	-commandList {UpdateGapScanFiles UpdateGapScanFiles UpdateGapScanFiles UpdateGapScanFiles UpdateGapScanFiles}
    set XBPMTests(GapScan.dwellTime) 15
    APSLabeledEntry .dwell -parent $w2 -label "Dwell Time per Gap(seconds):" -width 15 \
	-textVariable XBPMTests(GapScan.dwellTime)
    APSButton .default -parent $w2.dwell -packOption "-side right" -text default -size small \
	-command "set XBPMTests(GapScan.dwellTime) 15"
    
    set XBPMTests(GapScan.template)  /home/helios/oagData/apsu/XbpmSetup/IDgapScan-SHORT.exp.template
    set XBPMTests(GapScan.gapInputFile) /home/helios/oagData/apsu/XbpmSetup/inputFiles/IDgapScan-SHORT.sdds
    
  #  APSLabeledEntry .file2 -parent $f3 -label "Gap Scan Data File" -width 75 -textVariable XBPMTests(GapScan.gapInputFile) -commandButton 1
 #   APSButton .gen -parent $f3.file2 -packOption "-side right" -text "generate" -size small -command "GenerateGapScanInputFiles"

    APSFrameGrid .grid1 -parent $f3 -xList {x1 x2}
    set w1 $f3.grid1.x1
    set w2 $f3.grid1.x2
    set XBPMTests(GapScan.timestamp) ""
    APSLabeledEntry .stamp -parent $w1 -label "Time Stamp:" -width 40 -textVariable XBPMTests(GapScan.timestamp)
    APSButton .default -parent $w1.stamp -packOption "-side right" -text "default" -size small \
	-command "SetDefaultTimeStamp -type GapScan"
    set XBPMTests(GapScan.minGap) limit
    APSRadioButtonFrame .min -parent $w2 -label "Minimum Gap:" -buttonList {CommonLimit SoftLimit} \
	-valueList {limit softlimit} -orientation horizontal -variable XBPMTests(GapScan.minGap)
    APSButton .start -parent $f3 -text "Run Undulator Gap Scan" -command RunUndulatorGapScan
    APSButton .plot -parent $f3 -text "Plot Raw Data" -command "PlotXBPMRawData -type GapScan"
    #monitor xbpm data frame
    set XBPMTests(GapScan.xbpmMonFile) ""
    set XBPMTests(GapScan.xbpmMonDataFile) ""
    set XBPMTests(GapScan.monitorTime) 30
    set XBPMTests(GapScan.monitorInterval) 1.0
    APSLabeledEntry .mon -parent $f4 -label "Monitor file:" -textVariable XBPMTests(GapScan.xbpmMonFile) -width 80 \
	-commandButton 1
    APSButton .default -parent $f4.mon -text "default" -command "DefaultGapScanMonitorMonFile"
    APSLabeledEntry .data -parent $f4 -label "Data file:" -textVariable XBPMTests(GapScan.xbpmMonDataFile) -width 80 \
	-commandButton 1
    APSButton .default -parent $f4.data -text "default" -command "DefaultGapScanMonitorDataFile"
    APSFrameGrid .grid -parent $f4 -xList {x1 x2}
    APSLabeledEntry .time -parent $f4.grid.x1 -label "Monitor duration (min):" -textVariable XBPMTests(GapScan.monitorTime) \
	-width 20 
    APSLabeledEntry .interval -parent $f4.grid.x2 -label "Monitor interval (seconds):" -textVariable XBPMTests(GapScan.monitorInterval) \
	-width 20
    APSButton .start -parent $f4 -text "Start Monitor" -command "StartMonitorXBPM"
    APSButton .plot -parent $f4 -text "Plot Raw Data" -command "PlotRawMonitorData"
}

proc PlotRawMonitorData {args} {
    global XBPMTests
    if ![file exist $XBPMTests(GapScan.xbpmMonDataFile)] {
	SetStatus "$XBPMTests(GapScan.xbpmMonDataFile) does not exist!"
	return
    }
    set ID [file tail [file dir [file dir $XBPMTests(GapScan.xbpmMonDataFile)]]]
    set sector [scan $ID S%ld]
    catch {exec /home/helios/oagData/apsu/XbpmSetup/scripts/plotRawXbpmData $sector us $XBPMTests(GapScan.xbpmMonDataFile) &}
    catch {exec /home/helios/oagData/apsu/XbpmSetup/scripts/plotRawXbpmData $sector ds $XBPMTests(GapScan.xbpmMonDataFile) &}

}

proc StartMonitorXBPM {args} {
    global XBPMTests
    set monDir /home/helios/oagData/apsu/XbpmSetup/inputFiles/MonFile
    set dataDir /home/helios/oagData/apsu/XbpmSetup/data
    set timestr [clock format [clock seconds] -format %Y%m%d-%H%M]
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	set FE $XBPMTests(S$sectorf.FE)
	set s1 [format %02d [expr $sector+1]]
	set monFile $monDir/S00IDFE-XBPM-BeamScan-${FE}.mon
	set dir $dataDir/S${sectorf}ID/daily
	if {$XBPMTests(GapScan.S${sectorf}P1ds) || $XBPMTests(GapScan.S${sectorf}P1us)} {
	    set monFile1 $dir/S${timestr}-beam.mon
	    set dataFile $dir/S${timestr}-beam.sdds
	    if [catch {exec replaceText $monFile $monFile1.tmp  -orig=<sectorf>,<sector1f> -repl=$sectorf,$s1 } result] {
		return -code error "Error create mon file: $result"
	    }
	    if [catch {exec sddscombine -merge $monFile1.tmp -over -pipe=out \
			   | sddsxref -pipe=in /home/helios/oagData/pvdata/iocRecNamesOAG.sdds $monFile1 \
			   -match=ControlName=rec_name -reuse -nowarn } result] {
		return -code error "Error combine mon file: $result"
	    } 
	    if [catch {exec sddsmonitor $monFile1 $dataFile -time=$XBPMTests(GapScan.monitorTime),minutes \
			   -interval=$XBPMTests(GapScan.monitorInterval),seconds & } result] {
		return -code error "Error starting monitor S$sector xbpm: $result"
	    }
	    set XBPMTests(GapScan.xbpmMonFile) $monFile1
	    set XBPMTests(GapScan.xbpmMonDataFile) $dataFile
	    SetMainStatus "S$sector xbpm monitoring started (data file: $dataFile)."
	}
    }
}

proc CreateIDXBPM2FEWidgets {widget args} {
    #All ID XBPM2 FE has CM4ds, only CFE has CM4us.​
    set parent ""
    set label ""
    APSParseArguments {parent label}
    global XBPMTests
    APSFrame $widget -parent $parent -label $label \
	-packOption "-side top"
    set w0 $parent$widget.frame
    APSFrame .f1 -parent $w0
    set w1 $w0.f1.frame
    
   CreateSectorWidget -type IDXBPM2 -parent $w1
  
    APSFrame .f3 -parent $parent$widget.frame
    set w0 $parent$widget.frame.f3.frame
    set  XBPMTests(IDXBPM2.all) 1
    set commandList [list "SelectAll -wtype IDXBPM2 -all 1" "SelectAll -wtype IDXBPM2 -all 0"]
    APSRadioButtonFrame .all1 -parent $w0 -orientation horizontal \
	-buttonList {All None} -valueList {1 0} -label "" -variable XBPMTests(IDXBPM2.all)  \
	-commandList $commandList -packOption "-side left"
    APSButton .default -parent $w0 -packOption "-side left" -text "Default" \
	-command "SetDefaultButtonsAndPars -type IDXBPM2"
    

    APSFrame .f4 -parent $parent$widget.frame -label "Dark Current (DC Offset)" -packOption "-side top -fill x"
    set w0 $parent$widget.frame.f4.frame
    APSFrame .f1 -parent $w0
    set wf $w0.f1.frame
    $wf configure -bd 0
    set XBPMTests(IDXBPM2.refType) range0
    APSRadioButtonFrame .range -parent $wf -label "Reference file:" -buttonList {range0 range1} \
			-valueList {range0 range1} -orientation horizontal -variable XBPMTests(IDXBPM2.refType)
    APSButton .setup -parent $wf -text "Setup TetrAMM" -command "SetupIDTetrAMM -type IDXBPM2"
    APSButton .meas -parent $wf -text "Measure Dark Current/Noise" -command "MeasureDarkCurrentNoiseWidget -type IDXBPM2"
  
    APSButton .ref -parent $wf -text "Select Reference File" -command "MakeDarkCurrentReference -type IDXBPM2"
    APSButton .proc -parent $wf -text "Process Reference Data" -command "ProcessDarkCurrentReference -type IDXBPM2"
  #  APSButton .procAll -parent $wf -text "Reprocess All" -command "ReprocessDarkCurrentAll -type IDXBPM2"
    APSFrame .bot1 -parent $w0 -packOption "-side top"
    set w1 $w0.bot1.frame
    $w1 configure -bd 0
    APSButton .plot -parent $w1 -text "Plot Measurement Data" -command "DarkCurrentDisplayWidget -type IDXBPM2"
    APSButton .review -parent $w1 -text "Review Reference Data" -command "ReviewDarkCurrent -type IDXBPM2"
    APSButton .load -parent $w1 -text "Load Reference Offset to IOC" -command "LoadOffsetToIOC -type IDXBPM2"
   
    APSButton .check -parent $w1 -text "XBPM DAQ Info" -command "XbpmDAQInfo -xbpm IDXBPM2"
    
    APSFrame .init -parent $parent$widget.frame -label "Initialization"
    set w0 $parent$widget.frame.init.frame
    set XBPMTests(IDXBPM2FEcalibrationFile) ""

    APSLabeledEntry .dir -parent $w0 -label "Calibration file:" -width 90 \
	-textVariable XBPMTests(IDXBPM2FEcalibrationFile) -commandButton 1
    APSButton .default -parent $w0.dir -packOption "-side right" -command "SetDefaultIDXBPM2FEFile" -size small -text "default"
    APSButton .gen -parent $w0.dir -packOption "-side right" -command "SetDefaultIDXBPM2FEFile -regenerate 1" -size small -text "generate"
    APSButton .setup -parent $w0 -text "Setup TetrAMM" -command "SetupIDTetrAMM -type IDXBPM2"
    APSButton .setup2 -parent $w0 -text "Setup XBPM2 Default" -command "SetupIDXBPM2Default"
    APSButton .review -parent $w0 -text "Review XBPM Calibration" -command "LoadIDXBPM2Calibration -review 1"
    APSButton .load2 -parent $w0 -text "Load XBPM Calibration" -command "LoadIDXBPM2Calibration"
}

proc SetDefaultDataFiles {args} {
    global XBPMTests
    set dir /home/helios/oagData/apsu/XbpmSetup/inputFiles
    set XBPMTests(XBPM1DetectorNormFile) $dir/IDFE-XBPM1-Detector-Info.sdds
    
    set XBPMTests(tetrAMMLookupTable) $dir/TetrAMM-Network-Info-Short.sdds
    
    set XBPMTests(XBPM1detectorDatabase) $dir/IDFE-XBPM1-Detector-Info.sdds
   # set XBPMTests(XBPM2detectorDatabase) $dir/XBPM2-DetectorDB.sdds
    set XBPMTests(CFEWeightListFile) /home/helios/oagData/apsu/XbpmSetup/inputFiles/WeightInfo-CFE.sdds
    
    set XBPMTests(CFECalFile) /home/helios/oagData/apsu/XbpmSetup/inputFiles/XYCal/Uxx.xmm-CFE-XBPM1-XYCal-Std.sdds
    
    set XBPMTests(HHLFEWeightListFile) /home/helios/oagData/apsu/XbpmSetup/inputFiles/WeightInfo-HHLFE.sdds
    set XBPMTests(HHLFECalFile)  /home/helios/oagData/apsu/XbpmSetup/inputFiles/XYCal/Uxx.xmm-HHLFE-XBPM1-XYCal-Std.sdds
    
    
    set XBPMTests(CFEP1dsCalFile) /home/helios/oagData/apsu/XbpmSetup/inputFiles/S00ID-CFE-P1ds-Calibration.sdds
    set XBPMTests(CFEP1usCalFile) /home/helios/oagData/apsu/XbpmSetup/inputFiles/S00ID-CFE-P1us-Calibration.sdds
    set XBPMTests(HHLFEP1dsCalFile) /home/helios/oagData/apsu/XbpmSetup/inputFiles/S00ID-HHLFE-P1ds-Calibration.sdds
    set XBPMTests(CFEP2dsCalFile) /home/helios/oagData/apsu/XbpmSetup/inputFiles/S00ID-CFE-P2ds-Calibration.sdds
    set XBPMTests(CFEP2usCalFile) /home/helios/oagData/apsu/XbpmSetup/inputFiles/S00ID-CFE-P2us-Calibration.sdds
    set XBPMTests(HHLFEP2dsCalFile) /home/helios/oagData/apsu/XbpmSetup/inputFiles/S00ID-HHLFE-P2ds-Calibration.sdds

    set XBPMTests(Xbpm1SCRTemplate) /home/helios/oagData/apsu/XbpmSetup/inputFiles/Save-N-Restore/SnR-Template-XBPM1.txt
    set XBPMTests(Xbpm2SCRTemplate) /home/helios/oagData/apsu/XbpmSetup/inputFiles/Save-N-Restore/SnR-Template-XBPM2.txt
    
    set XBPMTests(tetrAMMTemplate) /home/helios/oagData/apsu/XbpmSetup/inputFiles/Save-N-Restore/SnR-Template-TetrAMM.txt

    
}
proc CreateDataFileWidgets {widget args} {
    set parent ""
    APSParseArguments {parent}
    global XBPMTests
    
    #set XBPMTest(rootDir) /home/oxygen/DIAG/apsu/fe
    #set XBPMTests(rootDir) [APSGoToDailyDirectory -subdirectory xbpmSetup]
   # set XBPMTests(rootDir) /home/helios/OAG/daily/2022/05/13/3/xbpmSetup
    set XBPMTests(rootDir) /home/helios/oagData/apsu/XbpmSetup
    set XBPMTests(dataRootDir) /home/helios/oagData/apsu/XbpmSetup/data
    set XBPMTests(IDinfo) /home/helios/oagData/apsu/XbpmSetup/inputFiles/APSU-IDInfo.sdds
   
    set width 90
    APSLabeledEntry .dir -parent $parent -label "Data root dir:" -textVariable XBPMTests(dataRootDir) -width $width
    APSButton .daily -parent $parent.dir -packOption "-side right" -text "daily" -size small  \
	-command "set XBPMTests(dataRootDir) [APSGoToDailyDirectory -subdirectory xbpmSetup]"
    APSButton .test -parent $parent.dir -packOption "-side right" -text "test" -size small \
	-command "set XBPMTests(dataRootDir) /home/oxygen/DIAG/apsu/xbpmdata/fe"
    APSButton .archive -parent $parent.dir -packOption "-side right" -text "archive" -size small \
	-command "set XBPMTests(dataRootDir) /home/helios/oagData/apsu/XbpmSetup/data"

    APSLabeledEntry .det -parent $parent -label "XBPM1 Detector Database" -width $width \
	-textVariable XBPMTests(XBPM1detectorDatabase) -commandButton 1
   # APSLabeledEntry .det2 -parent $parent -label "XBPM2 Detector Database" -width $width \
#	-textVariable XBPMTests(XBPM2detectorDatabase)  -commandButton 1
    
    APSLabeledEntry .cf1 -parent $parent -label "CFE Weight List Info" -width $width \
	-textVariable XBPMTests(CFEWeightListFile)  -commandButton 1
   # APSLabeledEntry .cf1a -parent $parent -label "CFE Calibration File" -width $width \
#	-textVariable XBPMTests(CFECalFile)  -commandButton 1
    APSLabeledEntry .hhl1 -parent $parent -label "HHLFE Weight List Info" -width $width \
	-textVariable XBPMTests(HHLFEWeightListFile)  -commandButton 1
  #  APSLabeledEntry .cf2 -parent $parent -label "HHLFE Calibration File" -width $width \
#	-textVariable XBPMTests(HHLFECalFile)  -commandButton 1
    
    APSLabeledEntry .temp -parent $parent -label "XBPM1 SaveRestore Template" -width $width \
	-textVariable XBPMTests(Xbpm1SCRTemplate)  -commandButton 1
    
   
    APSLabeledEntry .temp2 -parent $parent -label "XBPM2 SaveRestore Template" -width $width \
	-textVariable XBPMTests(Xbpm2SCRTemplate)  -commandButton 1

    APSLabeledEntry .temp3 -parent $parent -label "TetrAMM SaveRestore Template" -width $width \
	-textVariable XBPMTests(tetrAMMTemplate)  -commandButton 1

    APSLabeledEntry .temp4 -parent $parent -label "TetrAMM Lookup Table" -width $width \
	-textVariable XBPMTests(tetrAMMLookupTable)  -commandButton 1

    
    APSLabeledEntry .gapscan -parent $parent -label "Gap List for GapScan" -width $width \
	-textVariable XBPMTests(GapScan.gapGridListFile) -commandButton 1

   # set XBPMTests(XYScan.gapGridListFile) /home/helios/oagData/apsu/XbpmSetup/inputFiles/XYScan-GapListInfo.sdds
    APSLabeledEntry .gapscan2 -parent $parent -label "Gap List for XY-CalScan" -width $width \
		    -textVariable XBPMTests(XYScan.gapGridListFile) -commandButton 1

    APSLabeledEntry .idinfo -parent $parent -label "ID information:" -width $width \
		    -textVariable XBPMTests(IDinfo) -commandButton 1

    APSButton .update1 -parent $parent -text "Update GapLists for XY-CalScan" -command \
	"UpdateGapScanList -type XYScan"
    APSButton .update2 -parent $parent -text "update Save-n-Restore PV Lists" -command \
	"UpdateSCRReqFile"
    APSButton .update3 -parent $parent -text "Update Weight Functions" -command \
	"UpdateWeightFunction"
}

proc UpdateSCRReqFile {args} {
    set oldDir [pwd]
    cd  /home/helios/oagData/apsu/XbpmSetup/inputFiles/Save-N-Restore
    SetMainStatus "convert templates to sdds files..."
    exec convertFile
    cd /home/helios/oagData/SCR/requestFiles/
    SetMainStatus "update SCR file..."
    exec makeSRXrayBPMReqFile -install 1
    cd $oldDir
    SetMainStatus "done."
}

proc UpdateWeightFunction {args} {
    SetMainStatus "updating weight function..."
  #  exec  /home/helios/oagData/apsu/XbpmSetup/scripts/makeAllWeightLists HHLFE
    #  exec  /home/helios/oagData/apsu/XbpmSetup/scripts/makeAllWeightLists CFE
    APSExecLog .hhlfe -name "Update weight function for HHLFE" \
	-unixCommand "/home/helios/oagData/apsu/XbpmSetup/scripts/makeAllWeightLists HHLFE"
    APSExecLog .cfe -name "Update weight function for CFE" \
	-unixCommand "/home/helios/oagData/apsu/XbpmSetup/scripts/makeAllWeightLists CFE"
    
    SetMainStatus "done."
}

proc CreateSaveRestoreWidgets {widget args} {
    set parent ""
    APSParseArguments {parent}
    global XBPMTests
    APSFrame $widget -parent $parent -label "" \
	-packOption "-side top"
    set w0 $parent$widget.frame
    APSButton .scr -parent $w0 -text "Save-Compare-Restore" \
	      -command "exec SaveCompareRestore -system SRXrayBPM"
    return 
    
    APSFrame .f1 -parent $w0
    APSFrame .f2 -parent $w0
    set w1 $w0.f1.frame
    set w2 $w0.f2.frame
    CreateSectorWidget -type SaveRestore -parent $w1

    #buttons
    set  XBPMTests(SaveRestore.desc) ""
    APSFrame .f0 -parent $w2 -label ""
    set wf $w2.f0.frame
    APSLabeledEntry .des -parent $wf -label "Description:" -width 85 -textVariable  XBPMTests(SaveRestore.desc)
    APSButton .save -parent $wf -text "Save IOC Setup Data" -command "SaveSetupData -all 1"
    APSButton .load -parent $wf -text "Load Setup Data to Selected IOC" -command "LoadSetupData -all 0"
    APSButton .compare -parent $wf -text "Compare Current IOC with Saved Data File" -command "CompareIOCSetupWithFile"
    APSFrame .fn -parent $w2
    set wf $w2.fn.frame
    APSButton .start -parent $wf -text "Start All XBPM IOCs" -command "StartAllXBPMIOCs"
    
}

proc MeasureDarkCurrentNoiseWidget {args} {
    set type ""
    APSParseArguments {type}
    global XBPMTests

    set XBPMTests(darkCurrentType) $type
    set XBPMTests(TetrAMM.range) both
    set XBPMTests(TetrAMM.interval) 10
    if [winfo exist .dark] {
	destroy .dark
    }
    APSDialogBox .dark -name "GRID-XBPM Dark Current/Noice Measurement" -cancelButton 0
    APSLabeledEntry .sr -parent .dark.userFrame -label "SR current (mA):" -width 20 -textVariable XBPMTests(SRCurrent)
    APSLabeledEntry .read -parent .dark.userFrame -label "TetrAMM Values per read:" -width 20 \
	-textVariable  XBPMTests(TetrAMM.valuesPerRead)
    APSLabeledEntry .ave -parent .dark.userFrame -label "Averaging Time (seconds):" -width 20 \
	-textVariable  XBPMTests(TetrAMM.averageTime)
    APSLabeledEntry .meas -parent .dark.userFrame -label "Total Measurement Time (minutes):" -width 20 \
	-textVariable  XBPMTests(TetrAMM.measTime)
    APSLabeledEntry .interval -parent .dark.userFrame -label "Measurement interval (seconds):" -width 20 \
	-textVariable XBPMTests(TetrAMM.interval)
    APSRadioButtonFrame .range -parent .dark.userFrame -label "Range:" -buttonList {0 1 both} -valueList {0 1 both} \
	-variable XBPMTests(TetrAMM.range) -orientation horizontal
    APSDialogBoxAddButton .run -parent .dark -text "Start Measurement" -command "StartMeasDarkCurrent"
    APSDialogBoxAddButton .abort -parent .dark -text "Abort Measurement" -command "AbortDarkCurrentMeas"
    
}

proc SaveDefaultButtonsAndPars {args} {
    set type ""
    APSParseArguments {type}
    global XBPMTests
    set typeList {TetrAMM Weight SaveRestore IDXBPM2 InitNorm}
    set defaultFile /home/helios/oagData/apsu/XbpmSetup/inputFiles/default.sdds
    set fd [open $defaultFile "w"]
    puts $fd  "SDDS1"
    puts $fd "&parameter name=Type, type=string, &end"
    puts $fd "&column name=VariableName, type=string, &end"
    puts $fd "&column name=Value, type=short, &end"
    puts $fd "&data mode=ascii, no_row_counts=1, &end"

    puts $typeList
    foreach type $typeList {
	puts $fd $type
	switch $type {
	    TetrAMM {
		set unitList {CM1us CM2us CM3us CM4us CM1ds CM2ds CM3ds CM4ds}
	    }
	    IDXBPM2 {
		set unitList {CM4us CM4ds}
	    }
	    InitNorm {
		set unitList {P1us P1ds}
	    }
	    default {
		set unitList {P1us P2us P1ds P2ds}
	    }
	}
	for {set sector 1} {$sector<=35} {incr sector} {
	    foreach unit $unitList {
		set name S[format %02d $sector]$unit
		puts $fd "$name  $XBPMTests($type.$name)"
	    }
	    flush $fd
	}
	puts $fd "    "
    }
    flush $fd
    close $fd
}

proc SetDefaultIDXBPM2FEFile {args} {
    set regenerate 0
    APSParseArguments {regenerate}
    global XBPMTests
    set choice [GetIDXBPM2Selection]
    if ![llength $choice] {
	SetMainStatus "No unit is chosen"
	return
    }
    
    if [llength $choice]>2 {
	SetMainStatus "Error: can only select one unit for this button!"
	return
    }
    set sector [scan $choice S%ld]
    set usds [string range $choice end-1 end]
    SetIDXBPM2CalibrationFile -sector $sector -usds $usds -regenerate $regenerate

}

proc SetDefaultBMFEFile {args} {
    global XBPMTests
    set XBPMTests(BMFEcalibrationFile) /home/helios/oagData/apsu/XbpmSetup/inputFiles/BMFE-XBPM-Calibration.sdds

}

proc SetDefaultButtonsAndPars {args} {
    set type ""
    set IDtype ""
    APSParseArguments {type IDtype}
    global XBPMTests
    
    if {$type=="BMFE"} {
	foreach sector $XBPMTests(BMFEsectorList) {
	    set XBPMTests(BMFE.S${sector}CM1) 1
	}
	return
    }
    set filename  /home/helios/oagData/apsu/XbpmSetup/inputFiles/default.sdds
    set tmpRoot /tmp/[APSTmpString]
   
    if [catch {exec sddsprocess $filename $tmpRoot -match=par,Type=$type } result] {
	return -code error "Error get default selection1: $result"
    }
    APSAddToTmpFileList -ID xbpm -fileList $tmpRoot
    set varList [exec sdds2stream -col=VariableName $tmpRoot]
    set valList [exec sdds2stream -col=Value $tmpRoot]
    foreach var $varList val $valList {
	set sector [scan $var S%ld]
	if {[regexp {P1} $var] || [regexp {P2} $var]} {
	    if {([regexp "us" $var] && [lsearch -exact $XBPMTests(badusList) $sector]>=0) || \
		    ([regexp "ds" $var] && [lsearch -exact $XBPMTests(baddsList) $sector]>=0)} {
		set XBPMTests($type.$var) 0
		continue
	    }
	} 
	set XBPMTests($type.$var) $val
    }
}

proc CreateSCRReqFile {args} {
    set reqFile ""
    APSParseArguments {reqFile}
    if ![string length $reqFile] {
	set timestamp [clock format [clock seconds] -format %Y-%j-%m%d:%H%M%S]
	set reqFile /home/helios/oagData/apsu/XbpmSetup/inputFiles/requestFiles/APSSRXBPM.req.[clock format [clock seconds] -format %Y%m%d:%H%M]]
    }
    global XBPMTests

    set tmpRoot /tmp/[APSTmpString]
    set fileList ""
    set tetrAMMTemplate /home/helios/oagData/apsu/XbpmSetup/inputFiles/Save-N-Restore/SnR-Template-TetrAMM.sdds
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	APSAddToTmpFileList -ID xbpm -fileList $tmpRoot.0
	foreach bpm {P1 P2} index {1 2} {
	    set template /home/helios/oagData/apsu/XbpmSetup/inputFiles/Save-N-Restore/SnR-Template-XBPM${index}.sdds
	    foreach dev {us ds} {
		set name S${sectorf}${bpm}$dev
		if !$XBPMTests(SaveRestore.$name) {
		    continue
		}
		set xbpm S${sectorf}IDFE-XBPM:${bpm}$dev
		set root  S${sectorf}IDFE-XBPM
		set tetra1 S${sectorf}IDFE-XBPM:CM1$dev
		set tetra2 S${sectorf}IDFE-XBPM:CM2$dev
		set tetra3 S${sectorf}IDFE-XBPM:CM3$dev
		set tetra4 S${sectorf}IDFE-XBPM:CM4$dev
		exec replaceText $template $tmpRoot.0 -orig=<root>,<sector>,<bpm>,<tetraRoot1>,<tetraRoot2>,<tetraRoot3>,<tetraRoot4>,<tetra1>,<tetra2>,<tetra3>,<tetra4> \
		    -repl=$xbpm,S${sectorf}ID,${bpm}${dev},$tetra1,$tetra2,$tetra3,$tetra4,CM1$dev,CM2$dev,CM3$dev,CM4$dev
		if [catch {exec sddsprocess $tmpRoot.0 $tmpRoot.s$sector.$bpm.$dev \
			       "-redefine=col,Sector,$sector,type=long" } result] {
		    return -code error "Error creating req file1: $result"
		}
		lappend fileList $tmpRoot.s$sector.$bpm.$dev
		switch $bpm {
		    P1 {
			set tetraList [list CM1$dev CM2$dev CM3$dev]
		    }
		    P2 {
			set tetraList CM4$dev
		    }
		}
		foreach tetra $tetraList {
		    set root S${sectorf}IDFE-XBPM
		    if [catch {exec replaceText $tetrAMMTemplate $tmpRoot.s$sector.$tetra \
				   -orig=<root>,<tetra>,<sector> -repl=$root,$tetra,S${sectorf}ID } result] {
			return -code error "Error creating req file2: $result"
		    }
		    lappend fileList $tmpRoot.s$sector.$tetra
		}
	    }
	}
    }
    #for BM
    set template /home/helios/oagData/apsu/XbpmSetup/inputFiles/Save-N-Restore/SnR-Template-XBPM-BM.sdds
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	if $XBPMTests(SaveRestore.S${sectorf}BMCM1) {
	    set root S${sectorf}BMFE-XBPM
	    if [catch {exec replaceText $template $tmpRoot.s$sector.BM -orig=<root>,<sector> \
			   -repl=$root,S${sectorf}BM } result] {
		return -code error "Error creating BM req file: $result"
	    }
	    lappend fileList $tmpRoot.s$sector.BM
	
	    #add tetra
	    if [catch {exec replaceText $tetrAMMTemplate $tmpRoot.s$sector.BM.tetra \
			   -orig=<root>,<tetra>,<sector> \
			   -repl=S${sectorf}BMFE-XBPM,CM1,S${sectorf}BM } result] {
		return -code error "Error creating BM tetra req file: $result"
	    }
	    lappend fileList $tmpRoot.s$sector.BM.tetra
	}
    }
    APSAddToTmpFileList -ID xbpm -fileList [join $fileList]
    if ![llength $fileList] {
	SetMainStatus "No items chosen"
	return
    }
    
    if [catch {eval exec sddscombine $fileList -merge $reqFile } result] {
	return -code error "Error creating req file: $result"
    }
}

proc SaveSetupData {args} {
    set all 1
    set filename ""
    APSParseArguments {all filename}
    global XBPMTests
    set dir /home/helios/oagData/apsu/XbpmSetup/SCR
    set reqRoot /home/helios/oagData/apsu/XbpmSetup/inputFiles/requestFiles/APSSRXBPM.req
    set timestamp [clock format [clock seconds] -format %Y-%j-%m%d:%H%M%S]
    set reqFile  $reqRoot.$timestamp
    if ![string length $filename] {
	set filename $dir/Setup-${timestamp}.sdds
    }
    SetMainStatus "creating request file $reqFile..."
    if [catch { CreateSCRReqFile -reqFile $reqFile } result] {
	return -code error "Error creating reqeust file: $result"
    }
    SetMainStatus "saving ioc setup..."
    if [catch {exec sddscasr -save $reqFile $filename } result] {
	return -code error "Error save setup: $result"
    }
    
    if [catch {exec sddsprocess $filename -nowarnings -reprint=par,TimeStamp,$timestamp \
		   "-reprint=par,Filename,$filename" \
		   "-reprint=par,Description,[APSMakeSafeQualifierString $XBPMTests(SaveRestore.desc)]" } result] {
	return -code error "Error define description parameter: $result"
    }
    
    exec rm ${filename}~
    SetMainStatus "Setup data saved in $filename."
    return $filename
}

proc MakeLBoxTextLine {data width} {
    set timestamp [lindex $data 0]
    set wt [lindex $width 0]
    set description [lindex $data 1]
    set wd [lindex $width 1]
    set filename [lindex $data 2]
    set wf [lindex $width 2]
    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 RestoreSetupData {TimeStamp Description SnapshotFilename}  {
    global XBPMTests
    set dir /home/helios/oagData/apsu/XbpmSetup/SCR
    
    
    if $XBPMTests(SaveRestore.restoreAll) {
	set restoreFile $dir/$SnapshotFilename
    }  else {
	set tmpFile /tmp/[APSTmpString]
	APSAddToTmpFileList -ID PDM -fileList $tmpFile
	
	set pvList ""
	
	for {set sector 1} {$sector<=35} {incr sector} {
	    set sectorf [format %02d $sector]
	    foreach bpm {P1 P2} {
		foreach nm {us ds} {
		    if $XBPMTests(SaveRestore.S${sectorf}${bpm}$nm) {
			lappend pvList S${sectorf}IDFE-XBPM:${bpm}$nm
			for {set i 1} {$i<=4} {incr i} {
			    lappend pvList S${sectorf}IDFE-XBPM:CM${i}$nm
			}
		    }
		}
	    }
	}
	set matchOpt -match=col,ControlName=[lindex $pvList 0]*
	set pvs [llength $pvList]
	for {set i 1} {$i<$pvs} {incr i} {
	    append matchOpt ,ControlName=[lindex $pvList $i]*,|
	}
	if [catch {exec sddsprocess $dir/$SnapshotFilename $tmpFile $matchOpt } result] {
	    return -code error "Error processing setup data: $result"
	}
	set restoreFile $tmpFile
    }
    
    if [catch {exec sddscasr -restore $restoreFile} result] {
	return -code error "Error restore setup: $result"
    }
    SetMainStatus "$Description ($restoreFile) is restored into IOC."
}


proc LoadSetupData {args} {
    set all 1
    APSParseArguments {all}
    global XBPMTests

    set dir /home/helios/oagData/apsu/XbpmSetup/SCR
    cd $dir
    set files [lsort -decreasing [glob -nocomplain Setup-*.sdds]]
    if ![llength $files] {
	return -code error "No files found."
    }
    #puts $files
    set tmpFile /tmp/[APSTmpString]
    #puts $tmpFile
    APSAddToTmpFileList -ID PDM -fileList $tmpFile
    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 XBPMTests(SaveRestore.restoreAll) $all
    APSMakeSDDSListbox $tmpFile .restore -title "Setup restore choices" \
	-page 0 -labelmaker MakeLBoxTextLine  -packOption "-side top -expand true -fill y" \
        -callback RestoreSetupData  \
        TimeStamp Description Filename
}

proc FormatCurrent {args} {
    global XBPMTests
    set XBPMTests(SRCurrent) [format %0.3f $XBPMTests(SRCurrent)]
}

set XBPMTests(SRCurrent) 0
set XBPMTests(TetrAMM.valuesPerRead) 10000
#seconds
set XBPMTests(TetrAMM.averageTime) 50
#minutes
set XBPMTests(TetrAMM.measTime) 30
set XBPMTests(SRCurrent) 0.5
#pv linkw  XBPMTests(SRCurrent) S35DCCT:currentCC.VAL
#pv umon XBPMTests(SRCurrent) FormatCurrent

proc MeasDarkCurrent {args} {
    set sector ""
    set type ""
    set tetra ""
    set tetraPV ""
    set range ""
    APSParseArguments {sector type tetra tetraPV range}

    global XBPMTests
    set rootdir $XBPMTests(dataRootDir)
    
    set sectorf [format %02d $sector]
    if {$type=="BMFE"} {
	set subDir S${sectorf}BM
	set template /home/helios/oagData/apsu/XbpmSetup/inputFiles/BMXbpmDarkNoise.mon.template
    } else {
	set subDir S${sectorf}ID
	set template /home/helios/oagData/apsu/XbpmSetup/inputFiles/XbpmDarkNoise.mon.template
    }
    set dir $rootdir/$subDir
    if ![file exist $dir] {
	exec mkdir -p $dir
	exec chmod +rwx $dir
    }
    if ![file exist $dir/DarkCurrent] {
	exec mkdir -p $dir/DarkCurrent
	exec chmod +rwx $dir/DarkCurrent
    }
  
    set outDir $dir/DarkCurrent
    #set tetraPV S${sectorf}IDFE-XBPM:$tetra
    set monFile $outDir/S${sectorf}${tetra}-DarkNoise.mon
    if ![file exist $monFile] {
	if [catch {exec replaceText $template $monFile -orig=<sectorf>,<tetra> -repl=$sectorf,$tetra } result] {
	    return -code error "Error creating monito file: $result"
	}
    }
    #start monitoring 
    set outFile $outDir/${tetraPV}-$XBPMTests(TetrAMM.timeStamp).range$range.sdds
    if [catch {exec sddsmonitor $monFile $outFile -interval=$XBPMTests(TetrAMM.interval) \
		   -time=$XBPMTests(TetrAMM.measTime),min -erase &} pid] {
	return -code error "Error measuring dark current for $tetraPV: $pid"
    }
    after 1000
    return $pid
    if [catch {exec /home/helios/oagData/apsu/XbpmSetup/scripts/measXbpmTetrAMMDarkCurrent \
		   -monFile $monFile -outputFile $outputFile \
		   -range $XBPMTests(TetrAMM.range) \
		   -tetraPV $tetraPV \
		   -valuesPerRead $XBPMTests(TetrAMM.valuesPerRead) \
		   -averageTime $XBPMTests(TetrAMM.averageTime) \
		   -measTime $XBPMTests(TetrAMM.measTime) \
		   -interval $XBPMTests(TetrAMM.interval) } pid] {
	return -code error "Error measuring dark current for $tetraPV: $pdi"
    }
    if [catch {exec sddsmonitor $monFile $outFile -interval=$XBPMTests(TetrAMM.interval) \
		   -time=$XBPMTests(TetrAMM.measTime),min -erase &} pid] {
	return -code error "Error measuring dark current for $tetraPV: $pid"
    }
    after 1000
    return $pid

    exec caput ${tetraPV}:Acquire 0
    after 500
    exec caput ${tetraPV}:Range $XBPMTests(TetrAMM.range)
    exec caput ${tetraPV}:ValuesPerRead $XBPMTests(TetrAMM.valuesPerRead)
    exec caput ${tetraPV}:AveragingTime $XBPMTests(TetrAMM.averageTime)
    after 500
    exec caput ${tetraPV}:BiasState 0
    after 500
    exec caput ${tetraPV}:Acquire 1
    set waitTime [format %0.0f [expr ($XBPMTests(TetrAMM.averageTime) + 2)*1000]
    after $waitTime
    set outFile $outDir/${tetraPV}-$XBPMTests(TetrAMM.timeStamp).range$XBPMTests(TetrAMM.range).sdds
    if [catch {exec sddsmonitor $monFile $outFile -interval=1 \
		   -time=$XBPMTests(TetrAMM.measTime),min -erase &} pid] {
	return -code error "Error measuring dark current for S${sectorf}ID $tetra: $pid"
    }
    after 1000
    return $pid
}

set abortDarkCurrent 0
proc AbortDarkCurrentMeas {args} {
    global XBPMTests abortDarkCurrent
    set abortDarkCurrent 1
    if ![llength $XBPMTests(darkCurrMeasID)] {
	return
    }
    foreach pid $XBPMTests(darkCurrMeasID) {
	catch {exec kill -9 $pid}
    }
    SetMainStatus "Dark current measurement aborted."
    set XBPMTests(darkCurrMeasID) ""
    
}

proc MeasDarkCurrent0 {args} {
    set range 0
    set sectorList ""
    set tetraPVList ""
    set tetraList ""
    APSParseArguments {range sectorList tetraPVList tetraList}

    global XBPMTests abortDarkCurrent 
    #check SR current, SR current should be <0.1mA
    #if [catch {exec cavget -list=S35DCCT:currentCC.VAL -pend=10 -printErrors} current] {
#	return -code error "Error reading SR current: $current"
 #   }
    set current 0
    if {$current>=0.1} {
	SetMainStatus "SR current is greater than 0.1mA, dark current measurement is prohibited."
	return
    }
    SetMainStatus "Setup tetrAMM for dark current measurement..."
    if [catch {exec cavput -list=[join $tetraPVList ,] -list=:Acquire=0 -pend=10} result] {
	return -code error "Error clear tetrAMM: $result"
    }
    after 500
    if [catch {exec cavput -list=[join $tetraPVList ,] -list=:Range=$range -pend=10 } result] {
	return -code error "Error seting tetrAMM range: $result"
    }
    if [catch {exec cavput -list=[join $tetraPVList ,] -list=:ValuesPerRead=$XBPMTests(TetrAMM.valuesPerRead) -pend=10 } result] {
	return -code error "Error seting tetrAMM ValuesPerRead: $result"
    }
    if [catch {exec cavput -list=[join $tetraPVList ,] -list=:AveragingTime=$XBPMTests(TetrAMM.averageTime) -pend=10 } result] {
	return -code error "Error seting tetrAMM AveragingTime: $result"
    }
    if [catch {exec cavput -list=[join $tetraPVList ,] -list=:FastAveragingTime=$XBPMTests(TetrAMM.averageTime) -pend=10 } result] {
	return -code error "Error seting tetrAMM AveragingTime: $result"
    }
    after 500
    if [catch {exec cavput -list=[join $tetraPVList ,] -list=:BiasState=0 -pend=10} result] {
	return -code error "Error set tetrAMM \BiasState: $result"
    }
    after 500
    SetMainStatus "Start acquiring..."
    if [catch {exec cavput -list=[join $tetraPVList ,] -list=:Acquire=1 -pend=10} result] {
	return -code error "Error set tetrAMM BiasState: $result"
    }
    set wait [expr $XBPMTests(TetrAMM.averageTime) +2]
    SetMainStatus "wait for $wait seconds..."
    for {set i 0} {$i<$wait} {incr i}  {
	if $abortDarkCurrent {
	    SetMainStatus "Dark current measurement aborted."
	    set abortDarkCurrent 0
	    return
	}
	after 1000
	update
    }
    
    set XBPMTests(darkCurrMeasID) ""
    set XBPMTests(TetrAMM.timeStamp) [clock format [clock seconds] -format %Y-%m%d:%H%M%S]
    
    foreach sector $sectorList  tetra $tetraList tetraPV $tetraPVList {
	if [catch {MeasDarkCurrent -sector $sector  -type $XBPMTests(darkCurrentType) -range $range \
		       -tetra $tetra -tetraPV $tetraPV} pid] {
	    return -code error "Error measuring $tetraPV dark current: $pid"
	}
	lappend XBPMTests(darkCurrMeasID) $pid
	SetMainStatus "$tetraPV dark current measurement started. (PID: $pid)."
    }
    set measTime [expr $XBPMTests(TetrAMM.measTime)*60]
    for {set i 0} {$i<$measTime} {incr i} {
	if $abortDarkCurrent {
	    SetMainStatus "Dark current measurement aborted."
	    set abortDarkCurrent 0
	    return
	}
	after 1000
	update
    }
    SetMainStatus "Dark Current Measurement done."
    SetMainStatus "restore default values after dark current measurement."
    if [catch {exec cavput -list=[join $tetraPVList ,] -list=:ValuesPerRead=1667 -pend=10 } result] {
	return -code error "Error seting tetrAMM ValuesPerRead: $result"
    }
    if [catch {exec cavput -list=[join $tetraPVList ,] -list=:AveragingTime=0.1 -pend=10 } result] {
	return -code error "Error seting tetrAMM AveragingTime: $result"
    }
    if [catch {exec cavput -list=[join $tetraPVList ,] -list=:FastAveragingTime=1.0 -pend=10 } result] {
	return -code error "Error seting tetrAMM AveragingTime: $result"
    }
}

proc StartMeasDarkCurrent {args} {
    global XBPMTests abortDarkCurrent
    
    set abortDarkCurrent 0
    set XBPMTests(TetrAMM.timeStamp) [clock format [clock seconds] -format %Y-%m%d:%H%M%S]
    
    set XBPMTests(darkCurrMeasID) ""
    set tetraPVList ""
    set sectorList ""
    set tetraList ""
    switch $XBPMTests(darkCurrentType) {
	BMFE {
	    set unitList CM1
	    set xbpm BM
	}
	TetrAMM {
	    set unitList {CM1ds CM2ds CM3ds CM1us CM2us CM3us}
	    set xbpm ID
	}
	IDXBPM2 {
	    set unitList {CM4ds CM4us}
	    set xbpm ID
	}
    }
    set type $XBPMTests(darkCurrentType)
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	foreach unit $unitList {
	    set name S${sectorf}$unit
	    if $XBPMTests($type.$name) {
		lappend tetraPVList S${sectorf}${xbpm}FE-XBPM:$unit
		lappend sectorList $sector
		lappend tetraList $unit
	    }
	}    }
    if ![llength $tetraPVList] {
	return -code error "No tetrAMM selected."
    }
    if {$XBPMTests(TetrAMM.range)=="both"} {
	set rangeList {0 1}
    } else {
	set rangeList $XBPMTests(TetrAMM.range)
    }
    foreach range $rangeList {
	SetMainStatus "Measure dark current for range $range ..."
	if [catch {MeasDarkCurrent0 -range $range -tetraList $tetraList -sectorList $sectorList -tetraPVList $tetraPVList } result] {
	    return -code error "Error measuring dark current: $result"
	}
    }
}

proc ProcessDarkCurrentData {args} {
    set filename ""
    set tetraRoot ""
    set print 1
    set type ""
    APSParseArguments {filename tetraRoot print type}
    
    if [regexp "benchNoise" $filename] {
	if [catch {ProcessNoiseBenchData -file $filename -tetraRoot $tetraRoot} result] {
	    return -code error "Error processing benchNoise $filename: $result"
	}
    } else {
	set cols [exec sddsquery -col $filename]
	if [lsearch -exact $cols "Acquire"]<0 {
	    set extraOpt " -define=col,Acquire,1.0 "
	} else {
	    set extraOpt " "
	}
	#read current scale, current data should be data/oldscale * current scale
	if [catch {exec cavget -list=${tetraRoot}:CurrentScale -list=1,2,3,4 -pend=10} scaleList] {
	    return -code error "error reading current scale: $scaleList"
	}
	foreach in {1 2 3 4} {
	    set scale$in [lindex $scaleList [expr $in -1]]
	    switch [set scale$in] {
		1e+09 {
		    set unit$in nA
		}
		1e+12 {
		    set unit$in pA
		}
		1e+06 {
		    set unit$in uA
		}
		1e+03 {
		    set unit$in mA
		}
		default {
		    set unit$in A
		}
	    }
	}
	
	
	if [catch {eval exec sddsprocess $filename -pipe=out \
		       "-redefine=par,ReadingScale1,$scale1" \
		       "-redefine=par,ReadingScale2,$scale2" \
		       "-redefine=par,ReadingScale3,$scale3" \
		       "-redefine=par,ReadingScale4,$scale4" \
		       $extraOpt \
		       \"-redefine=col,RunTime,Time StartTime -,units=seconds" \
		       \"-redef=col,CurrentOffset1,CurrentOffset1 CurrentScale1 / $scale1 *,units=$unit1\" \
		       \"-redef=col,CurrentOffset2,CurrentOffset2 CurrentScale2 / $scale2 *,units=$unit2\" \
		       \"-redef=col,CurrentOffset3,CurrentOffset3 CurrentScale3 / $scale3 *,units=$unit3\" \
		       \"-redef=col,CurrentOffset4,CurrentOffset4 CurrentScale4 / $scale4 *,units=$unit4\" \
		       \"-redef=col,Current1,Current1:MeanValue_RBV CurrentScale1 / $scale1 *,units=$unit1\" \
		       \"-redef=col,Current2,Current2:MeanValue_RBV CurrentScale2 / $scale2 *,units=$unit2\" \
		       \"-redef=col,Current3,Current3:MeanValue_RBV CurrentScale3 / $scale3 *,units=$unit3\" \
		       \"-redef=col,Current4,Current4:MeanValue_RBV CurrentScale4 / $scale4 *,units=$unit4\" \
		       \"-redef=col,CurrentNoise1,Current1:Sigma_RBV CurrentScale1 / $scale1 *,units=$unit1\" \
		       \"-redef=col,CurrentNoise2,Current2:Sigma_RBV CurrentScale2 / $scale2 *,units=$unit2\" \
		       \"-redef=col,CurrentNoise3,Current3:Sigma_RBV CurrentScale3 / $scale3 *,units=$unit3\" \
		       \"-redef=col,CurrentNoise4,Current4:Sigma_RBV CurrentScale4 / $scale4 *,units=$unit4\" \
		       \"-redef=col,DarkCurrent1,CurrentOffset1 Current1 +,units=$unit1\" \
		       \"-redef=col,DarkCurrent2,CurrentOffset2 Current2 +,units=$unit2\" \
		       \"-redef=col,DarkCurrent3,CurrentOffset3 Current3 +,units=$unit3\" \
		       \"-redef=col,DarkCurrent4,CurrentOffset4 Current4 +,units=$unit4\" \
		       | sddsprocess  -pipe  \
		       -print=par,TetraRoot,${tetraRoot} \
		       -print=par,InputConfig,Diode \
		       -proc=Acquire,average,AcquireStatus \
		       -proc=ValuesPerRead,average,ValuesPerRead \
		       -proc=AveragingTime,average,AveragingTime \
		       -proc=DarkCurrent1,average,DarkCurrent1 \
		       -proc=DarkCurrent2,average,DarkCurrent2 \
		       -proc=DarkCurrent3,average,DarkCurrent3 \
		       -proc=DarkCurrent4,average,DarkCurrent4 \
		       -proc=CurrentNoise1,average,CurrentNoise1 \
		       -proc=CurrentNoise2,average,CurrentNoise2 \
		       -proc=CurrentNoise3,average,CurrentNoise3 \
		       -proc=CurrentNoise4,average,CurrentNoise4 \
		       -proc=DarkCurrent1,standarddeviation,DarkCurrent1_Sigma \
		       -proc=DarkCurrent2,standarddeviation,DarkCurrent2_Sigma \
		       -proc=DarkCurrent3,standarddeviation,DarkCurrent3_Sigma \
		       -proc=DarkCurrent4,standarddeviation,DarkCurrent4_Sigma \
		       | sddsconvert -pipe=in $filename.proc -retain=col,Step,Time,DarkCurrent*,CurrentNoise* } result] {
	    return -code error "Error processing $filename: $result"
	}
    }
    if $print {
	exec sddsprintout -par $filename.proc $filename.print
	APSFileDisplayWindow [APSUniqueName .noise] -fileName $filename.print  -width 100  -height 20 -printCommand "enscript -r"
    }
}

proc ReprocessDarkCurrentAll {args} {
    set type TetrAMM
    APSParseArguments {type}

    global XBPMTests
    
    switch $type {
	BMFE {
	    set unitList CM1
	    set xbpm BM
	}
	IDXBPM2 {
	    set unitlist {CM4us CM4ds}
	    set xbpm ID
	}
	default {
	    set unitList {CM1us CM2us CM3us CM1ds CM2ds CM3ds}
	    set xbpm ID
	}
    }
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	set dir $XBPMTests(dataRootDir)/S${sectorf}$xbpm/DarkCurrent
	foreach unit $unitList {
	    if $XBPMTests($type.S$sectorf$unit) {
		set root S${sectorf}${xbpm}FE-XBPM:$unit
		set files [glob -nocomplain ${dir}/${root}-????-*.sdds]
		if ![llength $files] {
		    continue
		}
		SetMainStatus "Reprocessing data for $root..."
		foreach file $files {
		    if [catch {ProcessDarkCurrentData -filename $file -print 0\
				   -tetraRoot $root -type $type } result] {
			return -code error "Error processing darkcurrent ($file): $result"
		    }
		}
	    }
	}
    }
    SetMainStatus "done."
}

proc SelectDarkCurrentFile {args} {
    set sector ""
    set tetraRoot ""
    APSParseArguments {sector tetraRoot}
    global XBPMTests
    set sectorf [format %02d $sector]
    if {$XBPMTests(dataRootDir)=="." || $XBPMTests(dataRootDir)=="./"} {
	set dir [pwd]
    } else {
	if [regexp {BM} $tetraRoot] {
	    set dir  $XBPMTests(dataRootDir)/S${sectorf}BM/DarkCurrent
	} else {
	    set dir $XBPMTests(dataRootDir)/S${sectorf}ID/DarkCurrent
	}
    }
    
    set files [glob -nocomplain $dir/${tetraRoot}-*.sdds]
    if ![llength $files] {
	return -code error "Error no files found for $sector $tetraRoot"
    }
    set XBPMTests(darkCurrent.rawData) ""
    APSScrolledListWindow .dark$tetraRoot -height 10 -name "Select A File" -itemList $files \
	-selectionVar XBPMTests(darkCurrent.rawData)
    tkwait variable XBPMTests(darkCurrent.rawData)
    if ![string length $XBPMTests(darkCurrent.rawData)] {
	return -code error "No dark current file chosen for $tetraRoot!"
    }
    return $XBPMTests(darkCurrent.rawData)
}



proc PlotDarkCurrentData {args} {
    set type ""
    APSParseArguments {type}
    
    global XBPMTests
    set fileList ""
    switch $type {
	BMFE {
	    set unitList CM1
	    set xbpm BM
	}
	IDXBPM2 {
	    set unitList {CM4us CM4ds}
	    set xbpm ID
	}
	default {
	    set unitList {CM1us CM2us CM3us CM1ds CM2ds CM3ds}
	    set xbpm ID
	}
    }
    
    for {set sector 1} {$sector<=35} {incr sector} {
	foreach unit $unitList {
	    set tetraRoot S[format %02d $sector]${xbpm}FE-XBPM:${unit}
	    if $XBPMTests($type.S[format %02d $sector]$unit) {
		if [catch {SelectDarkCurrentFile -sector $sector -tetraRoot $tetraRoot} filename] {
		    SetMainStatus "Error for plot $tetraRoot: $filename"
		    continue
		}
	    }
	    
	    if [catch {ProcessPlotDarkCurrentData -filename $filename -tetraRoot $tetraRoot } result] {
		return -code error "Error processing $filename: $result"
	    }
	    lappend fileList $filename.proc
	}
    }
    
    if [llength $fileList] {
	
	

    }
}

proc SetTetrAMMUnit {args} {
    set type ""
    APSParseArguments {type}
    global XBPMTests
    if {$type=="BMFE"} {
	set XBPMTests(TetrAMM.XBPM) S$XBPMTests(TetrAMM.plotSector)BMFE-XBPM
    } else {
	set XBPMTests(TetrAMM.XBPM) S$XBPMTests(TetrAMM.plotSector)IDFE-XBPM
    }
    LookupTetrAMMQRcode -type $type
}

proc DarkCurrentDisplayWidget {args} {
    set sector ""
    set type ""
    APSParseArguments {sector type}

    if [winfo exist .processDark] {
	destroy .processDark
    }
    global XBPMTests
    set XBPMTests(TetrAMM.plotSector) 25
    if {$type=="BMFE"} {
	set  XBPMTests(TetrAMM.plotUnit) CM1
	set unitList CM1
	set XBPMTests(TetrAMM.plotSector) 09
	set lookupList [list "LookupTetrAMMQRcode -type BMFE"]
	set sectorList $XBPMTests(BMFEsectorList)
	set XBPMTests(TetrAMM.XBPM) S$XBPMTests(TetrAMM.plotSector)BMFE-XBPM
    } else {
	if {$type=="IDXBPM2"} {
	    set XBPMTests(TetrAMM.plotUnit) CM4us
	    set unitList {CM4us CM4ds}
	    set lookupList [APSReplicateItem -item LookupTetrAMMQRcode -number 2]
	} else {
	    set XBPMTests(TetrAMM.plotUnit) CM1us
	    set unitList {CM1us CM2us CM3us CM1ds CM2ds CM3ds}
	    set lookupList [APSReplicateItem -item LookupTetrAMMQRcode -number 6]
	}
	for {set sector 1} {$sector<=35} {incr sector} {
	    lappend sectorList [format %02d $sector]
	}
	 set XBPMTests(TetrAMM.XBPM) S$XBPMTests(TetrAMM.plotSector)IDFE-XBPM
    
    }
    APSDialogBox .processDark -name "$type GRID-XBPM Dark Current Data Display" -cancelButton 0
    set commList ""
    foreach sector $sectorList  {
	lappend commList "SetTetrAMMUnit -type $type"
    }
    APSRadioButtonFrame .sector -parent .processDark.userFrame -label "Select Sector:" \
	-buttonList $sectorList -valueList $sectorList -variable XBPMTests(TetrAMM.plotSector) \
	-orientation vertical -limitPerRow 4 -commandList $commList
   
    APSRadioButtonFrame .unit -parent .processDark.userFrame -label "TetrAMM Unit:" -orientation horizontal \
	-buttonList $unitList -valueList $unitList -variable XBPMTests(TetrAMM.plotUnit) -limitPerRow 3 \
	-commandList $lookupList
    
    APSFrame .f1 -parent .processDark.userFrame 
    set f1 .processDark.userFrame.f1.frame
    set XBPMTests(TetrAMM.QRCode) 30xxx
    APSLabeledEntry .code -parent $f1 -label "TetrAMM QR Code:" -width 20 -packOption "-side left" \
	-textVariable XBPMTests(TetrAMM.QRCode)
    APSButton .look -parent $f1.code -packOption "-side right" -size small -text "Lookup" -command "LookupTetrAMMQRcode -type $type"
    global plotVerbose
    set plotVerbose 0
    set XBPMTests(TetrAMM.plotRange) 0
    APSButton .add -parent $f1 -packOption "-side left" -text "Add Bench Test Data" -command "AddBenchTestData -type $type"
    set XBPMTests(darkCurrent.rawData) ""
    APSLabeledEntry .raw -parent .processDark.userFrame -label "Raw data:" -width 90 -textVariable XBPMTests(darkCurrent.rawData)
    APSRadioButtonFrame .verb -parent .processDark.userFrame -label "Verbose:" -buttonList {0 1 2} \
	-valueList {0 1 2 3} -variable plotVerbose -orientation horizontal
    APSRadioButtonFrame .range  -parent .processDark.userFrame -label "Range:" -buttonList {0 1} \
	-valueList {0 1} -variable XBPMTests(TetrAMM.plotRange) -orientation range
    
    APSButton .ref -parent .processDark.userFrame.raw -text "Reference" -size small -command "MakeReference -type darkCurrent -xbpm $type"
    
    APSDialogBoxAddButton .hist -parent .processDark -text "Make History Summary" \
	-command "MakeDarkCurrentHistorySummary -type $type"
    APSDialogBoxAddButton .plot -parent .processDark -text "Plot Dark Current History" \
	-command "PlotDarkCurrentHistory -type current -xbpm $type"
    APSDialogBoxAddButton .noise -parent .processDark -text "Plot Noise History" \
	-command "PlotDarkCurrentHistory -type noise -xbpm $type" 
    
    APSDialogBoxAddButton .raw -parent .processDark -text "Plot Raw Data" \
	-command "PlotDarkCurrentRawData -type $type"
    # APSDialogBoxAddButton .raw1 -parent .processDark -text "Plot Raw Noise" \
	#	-command "PlotDarkCurrentRawData -type rawNoise"
    

}

proc ReviewDarkCurrent {args} {
    set type TetrAMM
    APSParseArguments {type}
    global XBPMTests
    if {$type=="BMFE"} {
	set unitList CM1
	set xbpm BM
    } else {
	if {$type=="IDXBPM2"} {
	    set unitList {CM4us CM4ds}
	} else {
	    set unitList {CM1us CM2us CM3us CM1ds CM2ds CM3ds}
	}
	set xbpm ID
    }
    
    set tmpRoot /tmp/[APSTmpString]
    
    for {set sector 1} {$sector<=35} {incr sector} {
	set chosen($sector) 0
	set sectorf [format %02d $sector]
	set fileList1 ""
	set fileList2 ""
	set dir $XBPMTests(dataRootDir)/S${sectorf}$xbpm/DarkCurrent
	
	catch {exec rm $dir/S${sectorf}${xbpm}.darkcurrent}
	catch {exec rm $dir/S${sectorf}${xbpm}.noise }
	foreach unit $unitList {
	    if $XBPMTests($type.S${sectorf}$unit) {
		set chosen($sector) 1
		set root S${sectorf}${xbpm}FE-XBPM:$unit
		if [file exist $dir/${root}.ref] {
		    set procFile $dir/[file tail [file readlink $dir/$root.ref]].proc
		    lappend fileList $procFile
		} else {
		    SetMainStatus "Reference file for $root does not exit, please make the reference first!"
		    continue
		}
		if ![file exist $procFile] {
		    if [catch {ProcessDarkCurrentData -filename [file root $procFile] -print 0 -type $type \
				   -tetraRoot $root } result] {
			return -code error "Error processing darkcurrent1a: $result"
		    }
		}
		if [catch {exec sddscollapse $procFile -pipe=out \
			       | sddsconvert -pipe -retain=col,TetraRoot,DarkCurrent? \
			       | sddsconvert -pipe -edit=col,*,%/DarkCurrent/Chan/ \
			       | sddsprocess -pipe -reprint=par,ID,S${sectorf}$xbpm -reprint=col,TetrAMM,$unit \
			       | sddsrowstats -pipe=in -mean=Average,Chan* -max=Maximum,Chan* -min=Minimum,Chan* \
			       ${tmpRoot}.S${sectorf}${xbpm}$unit.darkcurrent } result] {
		    return -code error "Error process darkcurrent review: $result"
		}
		lappend fileList1 $tmpRoot.S${sectorf}${xbpm}$unit.darkcurrent
		if [catch {exec sddscollapse $procFile -pipe=out \
			       | sddsconvert -pipe -retain=col,TetraRoot,CurrentNoise? \
			       | sddsconvert -pipe -edit=col,*,%/CurrentNoise/Chan/ \
			       | sddsprocess -pipe -reprint=par,ID,S${sectorf}$xbpm -reprint=col,TetrAMM,$unit \
			       | sddsrowstats -pipe=in -mean=Average,Chan* -max=Maximum,Chan* -min=Minimum,Chan* \
			       $tmpRoot.S${sectorf}$xbpm$unit.noise } result] {
		    return -code error "Error process darkcurrent review: $result"
		}
		lappend fileList2 $tmpRoot.S${sectorf}$xbpm$unit.noise
	    }
	}
	
	if ![llength $fileList1] {
	    #SetMainStatus "No refrence files found for S$sectorf"
	    continue
	}
	if [catch {eval exec sddscombine $fileList1 -merge -pipe=out \
		       | sddsprocess -pipe=in $tmpRoot.S${sectorf}.darkcurrent -process=Chan*,ave,%sAve \
		       -proc=Maximum,max,AllMax -proc=Average,ave,AllAve -proc=Minimum,min,AllMin } result] {
	    return -code error "Error processing S$sector dark current: $result"
	}
	if [catch {eval exec sddscombine $fileList2 -merge -pipe=out \
		       | sddsprocess -pipe=in $tmpRoot.S${sectorf}.noise -process=Chan*,ave,%sAve \
		       -proc=Maximum,max,AllMax -proc=Average,ave,AllAve -proc=Minimum,min,AllMin } result] {
	    return -code error "Error processing S$sector dark noise: $result"
	}
    }
    set files [glob -nocomplain $tmpRoot.*]
    if ![llength $files] {
	SetMainStatus "No unit chosen!"
	return
    }
    APSAddToTmpFileList -ID xbpm -fileList $files
    set filename $XBPMTests(dataRootDir)/DarkCurrentReview.$xbpm.print
    set filename $tmpRoot.darkcurrentreview.$xbpm.print
    set fid [open $filename "w"]
    puts $fid "                      GRID-XBPM Dark Current/Noise Data Display"
   
    
    foreach type {darkcurrent noise} {
	switch $type {
	    darkcurrent {
		puts $fid "Dark Current(nA)"
	    }
	    noise {
		puts $fid "Noise Current(nA)"
	    }
	}
	
	puts $fid "  TetrAMM    Chan1    Chan2    Chan3    Chan4   Average  Maximum   Minimum"
	for {set sector 1} {$sector<=35} {incr sector} {
	    if !$chosen($sector) {
		continue
	    }
	    set sectorf [format %02d $sector]
	    set fileList1 ""
	    set fileList2 ""
	    set dir $XBPMTests(dataRootDir)/S${sectorf}ID/DarkCurrent
	    set file $tmpRoot.S${sectorf}.$type
	    if {[file exist $dir] && [file exist $file]} {
		puts $fid "S${sectorf}$xbpm ======================================================================"
		
		set rootList [exec sdds2stream -col=TetrAMM $file]
		set parline [format %9s "All Units"]
		foreach col {Chan1 Chan2 Chan3 Chan4 Average Maximum Minimum} par {Chan1Ave Chan2Ave Chan3Ave Chan4Ave AllAve AllMax AllMin} {
		    set ${col}List [exec sdds2stream -col=$col $file]
		    set value [exec sdds2stream -par=$par $file]
		    append parline "[format %9.3f $value]"
		}
		
		set rows [llength $rootList] 
		for {set i 0} {$i<$rows} {incr i} {
		    set linevalue [format %9s [lindex $rootList $i]]
		    foreach col {Chan1 Chan2 Chan3 Chan4 Average Maximum Minimum} {
			append linevalue "[format %9.3f [lindex [set ${col}List] $i]]"
		    }
		    puts $fid $linevalue
		}
		puts $fid $parline
	    }
	}
	puts $fid "--------------------------------------------------------------------------"
	puts $fid "\n\n"
    }
    close $fid
    APSFileDisplayWindow [APSUniqueName .noise] -fileName $filename -width 100  -height 30 -printCommand "enscript -r"
}

proc PrintHelpInfo {args} {
    set xbpm ""
    APSParseArguments {xbpm}
    if {$xbpm=="BMFE"} {
       set filename /home/helios/oagData/apsu/XbpmSetup/notes/XbpmSetup-BMFE-Help.txt
    } elseif {$xbpm=="IDXBPM2"} {
	set filename /home/helios/oagData/apsu/XbpmSetup/notes/XbpmSetup-XBPM2-Help.txt
    } else {
	set filename /home/helios/oagData/apsu/XbpmSetup/notes/XbpmSetup-XBPM1-Help.txt
    }
    APSFileDisplayWindow [APSUniqueName .help] -fileName $filename -width 100  -height 30 -printCommand "enscript -r"
}
proc ReviewDarkCurrent0 {args} {
    global XBPMTests
    set unitList {CM1us CM2us CM3us CM4us CM1ds CM2ds CM3ds CM4ds}
    set fileList ""
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	foreach unit $unitList {
	    if $XBPMTests(TetrAMM.S${sectorf}$unit) {
		set root S${sectorf}IDFE-XBPM:$unit
		set dir $XBPMTests(dataRootDir)/S${sectorf}ID/DarkCurrent
		if [file exist $dir/${root}.ref] {
		    set procFile $dir/[file tail [file readlink $dir/$root.ref]].proc
		    lappend fileList $procFile
		} else {
		    SetMainStatus "Reference file for $root does not exit, please make the reference first!"
		    continue
		}
		if ![file exist $procFile] {
		    if [catch {ProcessDarkCurrentData -filename [file root $procFile] -print 0\
				   -tetraRoot S[format %02d $sector]IDFE-XBPM:$unit } result] {
			return -code error "Error processing darkcurrent1: $result"
		    }
		}
	    }
	}
    }
    if ![llength $fileList] {
	return -code error "No reference file found!"
    }
    set dir $XBPMTests(dataRootDir)
    for {set chan 1} {$chan<=4} {incr chan} {
	foreach op {ave max min} {
	    lappend opt -proc=DarkCurrent$chan,$op,DarkCurrent${chan}$op
	    lappend opt -proc=CurrentNoise$chan,$op,CurrentNoise${chan}$op
	}
    }
    
    if [catch {eval exec sddscombine $fileList -pipe=out \
		   | sddscollapse -pipe \
		   | sddsprocess -pipe=in $dir/DarkCurrent.review \
		   $opt } result] {
	return -code error "Error process stats of dark current: $result"
    }
    set rootList [exec sdds2stream -col=TetraRoot $dir/DarkCurrent.review]
    for {set chan 1} {$chan<=4} {incr chan} {
	foreach nm {DarkCurrent CurrentNoise} {
	    set $nm$chan [exec sdds2stream -col=$nm$chan $dir/DarkCurrent.review]
	    foreach item {ave max min} {
		set $nm$chan$item [format %0.3f [exec sdds2stream -par=$nm$chan$item $dir/DarkCurrent.review]]
	    }
	}
	foreach root $rootList val [set $nm$chan] {
	    set ID [string range $root 0 4]
	    set unit [lindex [split $root ":"] 1]
	    set ${unit}($ID.$chan) [format %0.3f $val]
	}
    }
    
    puts $dir/DarkCurrent.review
    set filename $dir/DarkCurrent.review.print
    set fd [open $filename w]
    puts $fd "                    GRID-XBPM Dark Current Data Display"
    puts $fd "\n"
    puts $fd "Most Recent Data (nA)"
    puts $fd "Most Recent Dark Current Data:"
    puts $fd "---------------------------------------------------------------"
    
    foreach chan {1 2 3 4} {
	puts $fd "Channel $chan"                     
	puts $fd " ID       CM1us     CM2us     CM3us     CM4us     CM1ds     CM2ds     CM3ds     CM4ds"
	set darkList [set DarkCurrent$chan]
	set i 0
	
	foreach root $rootList {
	    set ID [string range $root 0 4]
	    set valList $ID
	    foreach unit {CM1us CM2us CM3us CM4us CM1ds CM2ds CM3ds CM4ds} {
		if ![info exist ${unit}($ID.$chan)] {
		    append valList "[format %10s  "NA/NS"]"
		} else {
		    append valList "[format %10.3f [set ${unit}($ID.$chan)]]"
		}
	    }
	    puts $fd $valList
	}
	
	    
#	puts $fd "---------------------------------------------------------------"
	puts $fd "\n"
	puts $fd "Averaage Dark Current (nA):   [format %6.3f  [set DarkCurrent${chan}ave]]           Average Noise (nA):  [set CurrentNoise${chan}ave]"
	puts $fd "Maximum Dark Current (nA):    [format %6.3f [set DarkCurrent${chan}max]]           Maximum Noise (nA):  [set CurrentNoise${chan}max]"
	puts $fd "Minimum Dark Current (nA):    [format %6.3f [set DarkCurrent${chan}min]]           Minimum Noise (nA):  [set CurrentNoise${chan}min]"

	puts $fd "\n\n"

	
	puts $fd "---------------------------------------------------------------"
    }
    close $fd
    APSFileDisplayWindow [APSUniqueName .noise] -fileName $dir/DarkCurrent.review.print -width 100  -height 30 -printCommand "enscript -r"
    
}

proc LoadOffsetToIOC {args} {
    set type TetrAMM
    APSParseArguments {type} 
    global XBPMTests
    set rootdir $XBPMTests(rootDir)
    set datadir $XBPMTests(dataRootDir)
    set outdir $rootdir/SCR
    if ![file exist $outdir] {
	exec mkdir $outdir
	exec chmod +755 $outdir
    }
    set fileList ""
    if {$type=="BMFE"} {
	set unitList CM1
	set xbpm BM
    } else {
	if {$type=="IDXBPM2"} {
	    set unitList {CM4us CM4ds}
	} else {
	    set unitList {CM1us CM2us CM3us CM4us CM1ds CM2ds CM3ds CM4ds}
	}
	set xbpm ID
    }
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	foreach unit $unitList {
	    if !$XBPMTests($type.S${sectorf}$unit) {
		continue
	    }
	    set file $datadir/S${sectorf}$xbpm/DarkCurrent/S${sectorf}${xbpm}FE-XBPM:${unit}.ref
	    SetMainStatus "Loading S${sectorf}$unit $xbpm offsets..."
	    SetMainStatus "reference file: $file"
	    set tetraRoot S${sectorf}${xbpm}FE-XBPM:$unit
	    if [file exist $file] {
		set rawfile [file readlink $file]
		set rawFile $datadir/S${sectorf}$xbpm/DarkCurrent/[file tail $rawfile]
		set procFile $rawFile.proc
		#need reprocess dark current file with current scale1 (reading from scale pvs)
		if [catch {ProcessDarkCurrentData -filename $rawFile -print 0\
			       -tetraRoot S${sectorf}${xbpm}FE-XBPM:$unit -type $type} result] {
		    return -code error "Error processing dark current2: $result"
		}
		
	    } else {
		set fileList0 [glob -nocomplain  $datadir/S${sectorf}$xbpm/DarkCurrent/S${sectorf}${xbpm}FE-XBPM:${unit}*.sdds]
		set files ""
		foreach file $fileList0 {
		    if [regexp "history" $file] {
			#skip
			continue
		    }
		    lappend files $file
		}
		if ![llength $files] {
		    SetMainStatus "No data found for S${sectorf}${xbpm}FE-XBPM:${unit}"
		    continue
		}
		set file [lindex [lsort -decreasing $files] 0]
		if [catch {ProcessDarkCurrentData -filename $file \
			       -tetraRoot S${sectorf}${xbpm}FE-XBPM:$unit } result] {
		    return -code error "Error processing dark current2: $result"
		}
		set procFile $file.proc
	    }
	    
	    lappend fileList $procFile
	}
    }
    if ![llength $fileList] {
	SetMainStatus "No proc file found!"
	return
    }
   # puts $fileList
    if [catch {eval exec sddscombine $fileList -pipe=out \
		   | sddscollapse -pipe \
		   | sddsconvert -pipe=in -retain=col,TetraRoot,DarkCurrent* $outdir/DarkCurrent.ref.sdds } result] {
	return -code error "Error comine dark current data: $result"
    }
    set fileList ""
   # puts $outdir
    for {set chan 1} {$chan<=4} {incr chan} {
	if [catch {exec sddsconvert $outdir/DarkCurrent.ref.sdds -pipe=out -retain=col,TetraRoot,DarkCurrent$chan \
		       | sddsprocess -pipe=in  $outdir/DarkCurrent.ref.sdds.chan$chan \
		       -edit=col,ControlName,TetraRoot,ei/:CurrentOffset$chan/ \
		       "-print=col,ValueString,%lf,DarkCurrent$chan" } result] {
	    return -code error "Error processing dark current file1: $result"
	}
	lappend fileList $outdir/DarkCurrent.ref.sdds.chan$chan
    }
    
    #set snapFile $outdir/DarkCurrent-[clock format [clock seconds] -format %Y-%j-%m%d:%H%M%S]
    #SetMainStatus "save offsets before loading..."
    #SetMainStatus "sddscasr -save /home/helios/oagData/apsu/XbpmSetup/inputFiles/DarkCurrent.req $snapFile -pend=10"
    #puts "[exec which sddscasr]"
    #if [catch {exec sddscasr -save /home/helios/oagData/apsu/XbpmSetup/inputFiles/DarkCurrent.req $snapFile -pend=10  } result] {
    #	return -code error "Error saving offsets before loading: $result"
    #   }
    
    if [catch {eval exec sddscombine $fileList -merge -pipe=out \
		   | tee $outdir/DarkCurrent.ref.sdds.load \
		   | sddscasr -pipe=in -restore } result] {
	return -code error "Error load dark current (offset) to IOC: $result"
    }
    SetMainStatus "Darkcurrent (offset) is loaded to IOC."
}


proc ProcessDarkCurrentReference {args} {
    set type ""
    APSParseArguments {type}
    
    global XBPMTests DarkCurrentFiles verbose
    set rootdir $XBPMTests(dataRootDir)
    if {$type=="BMFE"} {
	set unitList {CM1}
	set xbpm BM
    } elseif {$type=="IDXBPM2"} {
	set unitList {CM4us CM4ds}
	set xbpm ID
    } else {
	set unitList {CM1us CM2us CM3us CM1ds CM2ds CM3ds}
	set xbpm ID
    }
    for {set sector 1} {$sector<=35} {incr sector} {
	foreach unit $unitList {
	    if !$XBPMTests($type.S[format %02d $sector]$unit) {
		continue
	    }
	    set tetraRoot S[format %02d $sector]${xbpm}FE-XBPM:$unit
	    set dir $rootdir/S[format %02d $sector]$xbpm/DarkCurrent
	    set refFile $dir/${tetraRoot}.ref
	    if ![file exist $refFile] {
		SetMainStatus "$tetraRoot reference file does not exist yet, use Make Reference button to create ref."
		continue
	    }
	    set file $dir/[file tail [file readlink $refFile]]
	    SetMainStatus "process dark current reference for $tetraRoot..."
	    if [catch {ProcessDarkCurrentData -filename $file -tetraRoot $tetraRoot -print $verbose -type $type } result] {
		return -code error "Error processing dark current reference: $result"
	    }
	}
    }
    SetMainStatus "done."
}

proc MakeDarkCurrentReference {args} {
    set type ""
    APSParseArguments {type}
    
    global XBPMTests DarkCurrentFiles 
    
    set rootdir $XBPMTests(dataRootDir)
    switch $type {
	BMFE {
	    set xbpm BM
	    set unitList CM1
	}
	IDXBPM2 {
	    set unitList {CM4us CM4ds}
	    set xbpm ID
	}
	default {
	    set unitList {CM1us CM2us CM3us CM1ds CM2ds CM3ds}
	    set xbpm ID
	}
    }
    
    set DarkCurrentFiles ""
    set fileList ""
    for {set sector 1} {$sector<=35} {incr sector} {
	foreach unit $unitList {
	    if $XBPMTests($type.S[format %02d $sector]$unit) {
		set tetraRoot S[format %02d $sector]${xbpm}FE-XBPM:$unit
		set dir $rootdir/S[format %02d $sector]$xbpm/DarkCurrent
		if {$XBPMTests($type.refType)=="default"} {
		    #use Rang1 for CMXds in HHLDE, and Range0 for CMXus and CMXds in CFE, where X=1,2,3
		    switch $XBPMTests(S[format %02d $sector].FE) {
			CFE {
			    set rangeType range0
			}
			HHLFE {
			    set rangeType range1
			}
		    }
		} else {
		    set rangeType $XBPMTests($type.refType)
		}
		
		set files [glob -nocomplain $dir/${tetraRoot}-????-*.$rangeType.sdds]
		if ![llength $files] {
		    continue
		}
		set file [lindex [lsort -decreasing $files] 0]
		lappend fileList $file
	    }
	}
    }
    if ![llength $fileList] {
	SetMainStatus "Error: No dark current data found!"
	return
    }
    APSScrolledListWindow .dark  -height 20 -name "Select Files to make reference" -itemList $fileList \
	-selectionVar DarkCurrentFiles
    tkwait variable DarkCurrentFiles
    if ![llength $DarkCurrentFiles] {
	SetMainStatus "no files chosen!"
	return
    }
    set oldDir [pwd]
    foreach file $DarkCurrentFiles {
	if {$type=="BMFE"} {
	    set tetraRoot [string range [file tail $file] 0 15]
	} else {
	    set tetraRoot [string range [file tail $file] 0 17]
	}
	set dir [file dir $file]
	cd $dir
	catch {exec rm $tetraRoot.ref}
	exec ln -s $file $tetraRoot.ref
    }
    cd $oldDir
    SetMainStatus "references made."
}

proc MakeReference {args} {
    set xbpm ""
    set type darkCurrent
    APSParseArguments {type xbpm}

    global XBPMTests
    set rawData  $XBPMTests($type.rawData) 
    if ![string length $rawData] {
	return -code error "No raw data provided!"
    }
    set oldDir [pwd]
    set dir [file dir $rawData]
    cd $dir

    set root  $XBPMTests(TetrAMM.XBPM):$XBPMTests(TetrAMM.plotUnit)
    catch {exec rm $root.ref}
    exec ln -s [file tail $rawData] $root.ref
    cd $oldDir
    SetMainStatus "$root reference data created."

}
proc PlotDarkCurrentHistory {args} {
    set type current 
    set xbpm ID
    APSParseArguments {type xbpm}
    global XBPMTests plotVerbose
    set sectorf $XBPMTests(TetrAMM.plotSector)
    if {$xbpm=="BMFE"} {
	set dir $XBPMTests(dataRootDir)/S${sectorf}BM/DarkCurrent
	set tetraRoot S${sectorf}BMFE-XBPM:$XBPMTests(TetrAMM.plotUnit)
    } else {
	set dir $XBPMTests(dataRootDir)/S${sectorf}ID/DarkCurrent
	 set tetraRoot S${sectorf}IDFE-XBPM:$XBPMTests(TetrAMM.plotUnit)
    }
    #puts $dir
    set filename $dir/${tetraRoot}.range0.history.sdds
    if ![file exist $filename] {
	if [catch {MakeDarkCurrentHistorySummary -type $xbpm} result] {
	    return -code error "Error make dark current history for $tetraRoot: $result"
	}
    }
    switch $type {
	current {
	    set ColumnRoot DarkCurrent
	    set printName Current
	}
	noise {
	    set ColumnRoot CurrentNoise
	    set printName Noise
	}
    }
    exec sddsplot -layout=2,2 -tick=xtime   \
	$filename \
	-col=StartTime,${ColumnRoot}1 -topline=$tetraRoot:${ColumnRoot}1 -newpanel \
	-col=StartTime,${ColumnRoot}1  -graph=symb,scale=2 \
	-col=StartTime,${ColumnRoot}2 -topline=$tetraRoot:${ColumnRoot}2  -newpanel \
	-col=StartTime,${ColumnRoot}2 -graph=symb,scale=2 \
	-col=StartTime,${ColumnRoot}3 -topline=$tetraRoot:${ColumnRoot}3 -newpanel \
	-col=StartTime,${ColumnRoot}3  -graph=symb,scale=2 \
	-col=StartTime,${ColumnRoot}4 -topline=$tetraRoot:${ColumnRoot}4 -newpanel \
	-col=StartTime,${ColumnRoot}4  -graph=symb,scale=2  &

    if $plotVerbose {
	#if ![file exist $filename.$type.print] {
	    exec sddsprintout $filename $filename.$type.print -col=TimeStamp,format=%28s \
		-col=${ColumnRoot}?,format=%5.3f 

	#}
	APSFileDisplayWindow [APSUniqueName .noise] -fileName $filename.$type.print  -width 100  -height 30 -printCommand "enscript -r"
    }
}


proc PlotTetrAMMRawData {args} {
    set type ""
    set tetraRoot ""
    set widget .dark
    set filename ""
    APSParseArguments {type tetraRoot widget filename}
    global XBPMTests plotVerbose
    
    if ![string length $XBPMTests(darkCurrent.rawData)] {
	set parent $widget.userFrame.sl.listbox
	if ![winfo exist $parent] {
	    return
	}
	set chosenList [$parent curselection]
	if ![llength $chosenList] {
	    return -code error "No files are chosen"
	}
	set filename [lindex $XBPMTests(darkCurrent.rawFiles) [lindex $chosenList 0]]
    }
    if ![file exist $filename.proc] {
	if [catch {ProcessDarkCurrentData -filename $filename -tetraRoot $tetraRoot -print 0} result] {
	    return -code error "Error procesing dark current data: $result"
	}
    }
    if $plotVerbose {
	APSFileDisplayWindow [APSUniqueName .noise] -fileName $filename.print  -width 100  -height 30 -printCommand "enscript -r"
    }
    if $plotVerbose==2 {
	switch $type {
	    rawNoise {
		set col Sigma_RBV
	    }
	    rawCurrent {
		set col MeanValue_RBV
	    }
	}
	#if ![file exist $filename.print.col] {
	    exec sddsprintout $filename $filename.$type.print \
	    -col=Time,format=%15.0f -col=*${col},format=%7.3f
	    
	#}
	APSFileDisplayWindow [APSUniqueName .noise] -fileName $filename.$type.print  -width 120  -height 100 -printCommand "enscript -r"
    }
    set cols [exec sddsquery -col $filename]
    if [lsearch -exact $cols RunTime]<0 {
	if [catch {exec sddsprocess $filename -nowarn "-redefine=col,RunTime,Time StartTime -,units=seconds" } result] {
	    return -code error "Error define RunTime column: $result"
	}
	catch {exec rm ${filename}~}
    }
    set cols [exec sddsquery -col $filename.proc]
    if [lsearch -exact $cols RunTime]<0 {
	if [catch {exec sddsprocess $filename.proc -nowarn "-redefine=col,RunTime,Time StartTime -,units=seconds" } result] {
	    return -code error "Error define RunTime column: $result"
	}
	catch {exec rm ${filename}.proc~}
    }
    switch $type {
	current {
	    exec sddsplot $filename.proc -legend -col=Step,DarkCurrent* -grap=line,vary &
	    if $XBPMTests(savePNG) {
		exec sddsplot $filename.proc -legend -col=Step,DarkCurrent* -grap=line,vary -device=png -output=$filename.current.png
	    }
	}
	rawNoise {
	    exec sddsplot $filename -legend=edit=%/$tetraRoot//%/://%/Sigma_RBV// -col=RunTime,*:Sigma_RBV -grap=line,vary \
		-topline=${tetraRoot}:CurrentX:Sigma_RBV   &
	    if $XBPMTests(savePNG) {
		exec sddsplot $filename -legend=edit=%/$tetraRoot//%/://%/Sigma_RBV// -col=RunTime,*:Sigma_RBV -grap=line,vary \
		    -topline=${tetraRoot}:CurrentX:Sigma_RBV  -device=png -output=$filename.noise.png
	    }
	}
	rawCurrent {
	    exec sddsplot $filename -legend=edit=%/$tetraRoot//%/://%/MeanValue_RBV// -grap=line,vary -col=RunTime,*MeanValue_RBV  \
		-topline=${tetraRoot}:CurrentX:MeanValue_RBV   &
	    
	    if $XBPMTests(savePNG) {
		exec sddsplot $filename -legend=edit=%/$tetraRoot//%/://%/MeanValue_RBV// -grap=line,vary -col=RunTime,*MeanValue_RBV  \
		    -topline=${tetraRoot}:CurrentX:MeanValue_RBV  -device=png -output=$filename.raw.png
	    }
	}
	rawDark {
	    exec sddsplot $filename.proc -legend -col=Step,DarkCurrent* -grap=line,vary &
	    if $XBPMTests(savePNG) {
		exec sddsplot $filename.proc -legend -col=Step,DarkCurrent* -grap=line,vary -device=png -output=$filename.darkcurrent.png
	    }
	}
    }

}

proc DeleteDarkCurrentData {args} {
    set widget .dark
    APSParseArguments {action dir widget}
    global XBPMTests
    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 $XBPMTests(darkCurrent.rawFiles)
	set file [lindex $XBPMTests(darkCurrent.rawFiles) [expr $index-$index0]]
	if [APSYesNoPopUp "Are you sure to delete $file and related files?"] {
	    file delete -force $file $file.proc
	    SetMainStatus "$file delete."
	    set index [expr $index - $index0]
	    $parent delete $index $index
	    set XBPMTests(darkCurrent.rawFiles) [lreplace $files $index $index]
	    incr index0
	}
    }
}
proc PlotDarkCurrentRawData {args} {
    set type ""
    APSParseArguments {type}

    global XBPMTests plotVerbose
    set sectorf $XBPMTests(TetrAMM.plotSector)
    if {$type=="BMFE"} {
	set dir $XBPMTests(dataRootDir)/S${sectorf}BM/DarkCurrent
	 set tetraRoot S${sectorf}BMFE-XBPM:$XBPMTests(TetrAMM.plotUnit)
    } else {
	set dir $XBPMTests(dataRootDir)/S${sectorf}ID/DarkCurrent
	set tetraRoot S${sectorf}IDFE-XBPM:$XBPMTests(TetrAMM.plotUnit)
    }
    
    set files [glob -nocomplain $dir/${tetraRoot}-????-*.sdds]
    if ![llength $files] {
	return -code error "Error no files found for S${sectorf}IDFE-XBPM:$XBPMTests(TetrAMM.plotUnit)"
    }
    set files [lsort -decreasing $files]
    set XBPMTests(darkCurrent.rawFiles) $files
    set XBPMTests(darkCurrent.rawData) ""
    APSScrolledListWindow .dark  -height 10 -name "Select A File" -itemList $files \
	-selectionVar XBPMTests(darkCurrent.rawData) -acceptButton 0
    
   # APSDialogBoxAddButton .rawcurrent -parent .dark -text "Plot Raw Current" -command "PlotTetrAMMRawData -type rawCurrent -tetraRoot $tetraRoot"
    APSDialogBoxAddButton .rawnoise -parent .dark -text "Plot Raw Noise" -command "PlotTetrAMMRawData -type rawNoise -tetraRoot $tetraRoot"
    APSDialogBoxAddButton .rawdark -parent .dark -text "Plot Dark Current" -command "PlotTetrAMMRawData -type rawDark -tetraRoot $tetraRoot"
    
    APSDialogBoxAddButton .delete -parent .dark -text "Delete" -command "DeleteDarkCurrentData -widget .dark"
    set XBPMTests(savePNG) 1
    APSCheckButtonFrame .png -parent .dark -packOption "-side right" -label "" -buttonList {"Save PNG File"} -variableList XBPMTests(savePNG) \
	-orientation horizontal
    
    tkwait variable XBPMTests(darkCurrent.rawData)
    PlotTetrAMMRawData -type $type -tetraRoot $tetraRoot -filename $XBPMTests(darkCurrent.rawData)
    tkwait variable XBPMTests(darkCurrent.rawData)
    PlotTetrAMMRawData -type $type -tetraRoot $tetraRoot -filename $XBPMTests(darkCurrent.rawData)
    
    return
    if ![string length $XBPMTests(darkCurrent.rawData)] {
	return -code error "No file chosen!"
    }
    set filename $XBPMTests(darkCurrent.rawData)
    if ![file exist $filename.proc] {
	if [catch {ProcessDarkCurrentData -filename $filename -tetraRoot $tetraRoot -print 0} result] {
	    return -code error "Error procesing dark current data: $result"
	}
    }
    if $plotVerbose {
	APSFileDisplayWindow [APSUniqueName .noise] -fileName $filename.print  -width 100  -height 30 -printCommand "enscript -r"
    }
    if $plotVerbose==2 {
	switch $type {
	    rawNoise {
		set col Sigma_RBV
	    }
	    rawCurrent {
		set col MeanValue_RBV
	    }
	}
	#if ![file exist $filename.print.col] {
	    exec sddsprintout $filename $filename.$type.print \
	    -col=Time,format=%15.0f -col=*${col},format=%7.3f
	    
	#}
	APSFileDisplayWindow [APSUniqueName .noise] -fileName $filename.$type.print  -width 120  -height 30 -printCommand "enscript -r"
    }
    set cols [exec sddsquery -col $filename]
    if [lsearch -exact $cols RunTime]<0 {
	if [catch {exec sddsprocess $filename -nowarn "-redefine=col,RunTime,Time StartTime -,units=seconds" } result] {
	    return -code error "Error define RunTime column: $result"
	}
	catch {exec rm ${filename}~}
    }
    set cols [exec sddsquery -col $filename.proc]
    if [lsearch -exact $cols RunTime]<0 {
	if [catch {exec sddsprocess $filename.proc -nowarn "-redefine=col,RunTime,Time StartTime -,units=seconds" } result] {
	    return -code error "Error define RunTime column: $result"
	}
	catch {exec rm ${filename}.proc~}
    }
    switch $type {
	current {
	    exec sddsplot $filename.proc -legend -col=Step,DarkCurrent* -grap=line,vary &
	}
	rawNoise {
	    exec sddsplot $filename -legend=edit=%/$tetraRoot//%/://%/Sigma_RBV// -col=RunTime,*:Sigma_RBV -grap=line,vary \
		-topline=${tetraRoot}:CurrentX:Sigma_RBV   &
	}
	rawCurrent {
	    exec sddsplot $filename -legend=edit=%/$tetraRoot//%/://%/MeanValue_RBV// -grap=line,vary -col=RunTime,*MeanValue_RBV  \
		-topline=${tetraRoot}:CurrentX:MeanValue_RBV   &
	    
	}
    }
}

proc MakeDarkCurrentHistorySummary {args} {
    set type ""
    APSParseArguments {type}

    global XBPMTests
    
    set sectorf $XBPMTests(TetrAMM.plotSector)
    if {$type=="BMFE"} {
	set dir $XBPMTests(dataRootDir)/S${sectorf}BM/DarkCurrent
	set tetraRoot S${sectorf}BMFE-XBPM:$XBPMTests(TetrAMM.plotUnit)
    } else {
	set dir $XBPMTests(dataRootDir)/S${sectorf}ID/DarkCurrent
	set tetraRoot S${sectorf}IDFE-XBPM:$XBPMTests(TetrAMM.plotUnit)
    }

    set oldDir [pwd]
    cd $dir
    set files [glob -nocomplain $dir/${tetraRoot}-*.range$XBPMTests(TetrAMM.plotRange).sdds]
    if ![llength $files] {
	return -code error "No dark current files found for $tetraRoot."
    }
    set files [lsort -decreasing $files]
    set XBPMTests(darkCurrent.historyFiles) ""
    APSScrolledListWindow .dark  -height 20 -name "Select Files to add" -itemList $files \
	-selectionVar XBPMTests(darkCurrent.historyFiles) 
    tkwait variable XBPMTests(darkCurrent.historyFiles)
    if ![llength $XBPMTests(darkCurrent.historyFiles)] {
	return -code error "No files chosen!"
    }
    set files $XBPMTests(darkCurrent.historyFiles)
    set fileList ""
    foreach file $files {
	if [regexp "History" $file] {
	    continue
	}
	if ![file exist $file.proc] {
	    if [catch {ProcessDarkCurrentData -print 0 -filename $file -tetraRoot $tetraRoot} result] {
		return -code error "Error process $file for making history data: $result"
	    }
	}
	set par [exec sddsquery -par $file.proc]
	if [lsearch -exact $par "AcquireStatus"]<0 {
	    if [catch {exec sddsprocess $file.proc -nowarn "-redefine=par,AcquireStatus,1.0" } result] {
		return -code error "Error define acquire status: $result"
	    }
	}
	lappend fileList $file.proc
    }
    if ![llength $fileList] {
	return -code error "No raw data file chosen"
    }
    if [catch {eval exec sddscombine $fileList -pipe=out \
		   | sddsprocess -pipe -nowarning -filter=par,AcquireStatus,0.99,1.5 \
		   | sddscollapse -pipe=in $dir/${tetraRoot}.range0.history.sdds } result] {
	return -code error "Error combine dark current data files: $result"
    }
    SetMainStatus "$tetraRoot dark current history created ($dir/${tetraRoot}.range0.history.sdds)."
}

proc LookupTetrAMMQRcode {args} {
    set type ""
    APSParseArguments {type}

    global XBPMTests
    set lookupTable /home/helios/DIAG/apsu/xbpmdata/tetra/TetrAMMlocatiionAndID.sdds
    set lookupTable /home/helios/oagData/apsu/XbpmSetup/inputFiles/TetraAMM_lookup_table.sdds
    set sectorf $XBPMTests(TetrAMM.plotSector)
    if {$type=="BMFE"} {
	set tetraRoot S${sectorf}BMFE-XBPM:$XBPMTests(TetrAMM.plotUnit)
    } else {
	set tetraRoot S${sectorf}IDFE-XBPM:$XBPMTests(TetrAMM.plotUnit)
    }
    if [catch {exec sddsprocess $lookupTable -match=col,ElementName=$tetraRoot -pipe=out \
		   | sdds2stream -pipe -col=QRCode } QRCode] {
	return -code error "Error look up the QRcode for $tetraRoot: $QRCode"
    }
    set XBPMTests(TetrAMM.QRCode) $QRCode
}

proc AddBenchTestData {args} {
    set type ""
    APSParseArguments {type}
    global XBPMTests
    LookupTetrAMMQRcode -type $type
    set sectorf $XBPMTests(TetrAMM.plotSector)
    if {$type=="BMFE"} {
	set tetraRoot S${sectorf}BMFE-XBPM:$XBPMTests(TetrAMM.plotUnit)
    } else {
	set tetraRoot S${sectorf}IDFE-XBPM:$XBPMTests(TetrAMM.plotUnit)
    }
    set dir /home/helios/DIAG/apsu/xbpmdata/tetra/QR$XBPMTests(TetrAMM.QRCode)
    set files1 [glob -nocomplain $dir/Noise/*.DCSource]
    set files2 [glob -nocomplain $dir/Noise/*.OPEN]
    set files3 [glob -nocomplain $dir/Noise/*.SHUNT]
    set files [concat $files1 $files2 $files3]
    if ![llength $files] {
	return -code error "No noise file founds for $tetraRoot"
    }
    set XBPMTests(TetrAMM.noiseFiles) ""
    APSScrolledListWindow .dark  -height 20 -name "Select Files to add" -itemList $files \
	-selectionVar XBPMTests(TetrAMM.noiseFiles) 
    tkwait variable XBPMTests(TetrAMM.noiseFiles) 
    if ![llength $XBPMTests(TetrAMM.noiseFiles)] {
	return -code error "No files found!"
    }
    #Noice calculation parameters
    set pageLength 50
    
   
    foreach file $XBPMTests(TetrAMM.noiseFiles) {
	set root [file root [file root [file tail $file]]]
	set source [lindex [split [file tail $file] "."] end]
	set ymd [lindex [split $root "-"] 1]
	set time [lindex [split $root "-"] 2]
	set timestamp [string range $ymd 0 3]-[string range $ymd 4 7]:$time
	set outRoot $XBPMTests(dataRootDir)/S${sectorf}ID/DarkCurrent/${tetraRoot}-${timestamp}.benchNoise.$source
#	puts $outRoot
	#puts $file
	foreach range {0 1} {
	    APSAddToTmpFileList -ID xbpm -fileList $outRoot.$range
	    if [catch {exec sddsprocess $file $outRoot.range$range.sdds -filter=par,Range,[expr $range - 0.5],[expr $range+0.5] } result] {
		#puts $outRoot.$range
		#does not exist, no need to process
		SetMainStatus "$file range$range data does not exist, no need process."
		continue
	    }
	    #puts  $outRoot.range$range.sdds t
	    if [catch {exec sddsbreak  $outRoot.range$range.sdds  -pipe=out -changeof=Time,amount=$pageLength \
			   | sddsprocess -pipe -redefine=par,nrows,n_rows,type=long \
			   | sddsprocess -pipe -filter=par,nrows,30,100000 -nowarnings \
			   | sddsprocess -pipe \
			   "-redef=col,DarkCurrent1,CurrentOffset1 Current1:MeanValue_RBV +,units=nA" \
			   "-redef=col,DarkCurrent2,CurrentOffset2 Current2:MeanValue_RBV +,units=nA" \
			   "-redef=col,DarkCurrent3,CurrentOffset3 Current3:MeanValue_RBV +,units=nA" \
			   "-redef=col,DarkCurrent4,CurrentOffset4 Current4:MeanValue_RBV +,units=nA" \
			   -process=DarkCurrent1,average,DarkCurrent1 \
			   -process=DarkCurrent2,average,DarkCurrent2 \
			   -process=DarkCurrent3,average,DarkCurrent3 \
			   -process=DarkCurrent4,average,DarkCurrent4 \
			   -process=DarkCurrent1,standarddeviation,CurrentNoise1 \
			   -process=DarkCurrent2,standarddeviation,CurrentNoise2 \
			   -process=DarkCurrent3,standarddeviation,CurrentNoise3 \
			   -process=DarkCurrent4,standarddeviation,CurrentNoise4 \
			   -process=Step,first,Step  -process=DayOfMonth,first,DayOfMonth \
			   -process=Time,first,Time  -process=TimeOfDay,first,TimeOfDay \
			   | sddscollapse -pipe \
			   | sddsprocess -pipe \
			   "-reprint=par,TetraRoot,$tetraRoot" \
			   -process=DarkCurrent1,average,DarkCurrent1 \
			   -process=DarkCurrent2,average,DarkCurrent2 \
			   -process=DarkCurrent3,average,DarkCurrent3 \
			   -process=DarkCurrent4,average,DarkCurrent4 \
			   -process=DarkCurrent1,standarddeviation,DarkCurrent1_Sigma \
			   -process=DarkCurrent2,standarddeviation,DarkCurrent2_Sigma \
			   -process=DarkCurrent3,standarddeviation,DarkCurrent3_Sigma \
			   -process=DarkCurrent4,standarddeviation,DarkCurrent4_Sigma \
			   -process=CurrentNoise1,average,CurrentNoise1 \
			   -process=CurrentNoise2,average,CurrentNoise2 \
			   -process=CurrentNoise3,average,CurrentNoise3 \
			   -process=CurrentNoise4,average,CurrentNoise4 \
			   -process=CurrentNoise1,standarddeviation,CurrentNoise1_Sigma \
			   -process=CurrentNoise2,standarddeviation,CurrentNoise2_Sigma \
			   -process=CurrentNoise3,standarddeviation,CurrentNoise3_Sigma \
			   -process=CurrentNoise4,standarddeviation,CurrentNoise4_Sigma \
			   -process=TimeStamp,first,TimeStamp           -process=StartTime,first,StartTime \
			   -process=Range,first,RangeValue              -process=BiasVoltage,first,BiasVoltage \
			   -process=AveragingTime,first,AveragingTime   -process=NumAverage,first,NumAverage \
			   -process=SampleTime,first,SampleTime         -process=ValuesPerRead,first,ValuesPerRead \
			   -process=Temperature,first,Temperature        \
			   -process=InputConfig,first,InputConfig       -process=MacAddress,first,MacAddress \
			   -process=QRcode,first,QRcode \
			   | sddsconvert -pipe=in $outRoot.range$range.sdds.proc \
			   -del=col,TimeStamp,StartTime,Range,BiasVoltage,AveragingTime,NumAverage,SampleTime,ValuesPerRead \
			   -del=col,Temperature,TetraRoot,InputConfig,MacAddress,QRcode } result] {
		return -code error "Error processing noise bench data1 ($file): $result"
	    }
	    SetMainStatus "$file is converted to $outRoot.range$range.sdds.proc"
	}	
    }
    SetMainStatus "Bench noise data added for $tetraRoot."
}

proc ProcessNoiseBenchData {args} {
    set file ""
    set tetraRoot ""
    APSParseArguments {file tetraRoot} 
    set pageLength 50
    if [catch {exec sddsbreak  $file  -pipe=out -changeof=Time,amount=$pageLength \
		   | sddsprocess -pipe -redefine=par,nrows,n_rows,type=long \
		   | sddsprocess -pipe -filter=par,nrows,30,100000 -nowarnings \
		   "-redef=col,DarkCurrent1,CurrentOffset1 Current1:MeanValue_RBV +,units=nA" \
		   "-redef=col,DarkCurrent2,CurrentOffset2 Current2:MeanValue_RBV +,units=nA" \
		   "-redef=col,DarkCurrent3,CurrentOffset3 Current3:MeanValue_RBV +,units=nA" \
		   "-redef=col,DarkCurrent4,CurrentOffset4 Current4:MeanValue_RBV +,units=nA" \
		   | sddsprocess -pipe \
		   "-reprint=par,TetraRoot,$tetraRoot" \
		   -process=DarkCurrent1,average,DarkCurrent1 \
		   -process=DarkCurrent2,average,DarkCurrent2 \
		   -process=DarkCurrent3,average,DarkCurrent3 \
		   -process=DarkCurrent4,average,DarkCurrent4 \
		   -process=DarkCurrent1,standarddeviation,CurrentNoise1 \
		   -process=DarkCurrent2,standarddeviation,CurrentNoise2 \
		   -process=DarkCurrent3,standarddeviation,CurrentNoise3 \
		   -process=DarkCurrent4,standarddeviation,CurrentNoise4 \
		   -process=Step,first,Step  -process=DayOfMonth,first,DayOfMonth \
		   -process=Time,first,Time  -process=TimeOfDay,first,TimeOfDay \
		   | sddscollapse -pipe \
		   | sddsprocess -pipe \
		   "-reprint=par,TetraRoot,$tetraRoot" \
		   -process=DarkCurrent1,average,DarkCurrent1 \
		   -process=DarkCurrent2,average,DarkCurrent2 \
		   -process=DarkCurrent3,average,DarkCurrent3 \
		   -process=DarkCurrent4,average,DarkCurrent4 \
		   -process=DarkCurrent1,standarddeviation,DarkCurrent1_Sigma \
		   -process=DarkCurrent2,standarddeviation,DarkCurrent2_Sigma \
		   -process=DarkCurrent3,standarddeviation,DarkCurrent3_Sigma \
		   -process=DarkCurrent4,standarddeviation,DarkCurrent4_Sigma \
		   -process=CurrentNoise1,average,CurrentNoise1 \
		   -process=CurrentNoise2,average,CurrentNoise2 \
		   -process=CurrentNoise3,average,CurrentNoise3 \
		   -process=CurrentNoise4,average,CurrentNoise4 \
		   -process=CurrentNoise1,standarddeviation,CurrentNoise1_Sigma \
		   -process=CurrentNoise2,standarddeviation,CurrentNoise2_Sigma \
		   -process=CurrentNoise3,standarddeviation,CurrentNoise3_Sigma \
		   -process=CurrentNoise4,standarddeviation,CurrentNoise4_Sigma \
		   -process=TimeStamp,first,TimeStamp           -process=StartTime,first,StartTime \
		   -process=Range,first,RangeValue              -process=BiasVoltage,first,BiasVoltage \
		   -process=AveragingTime,first,AveragingTime   -process=NumAverage,first,NumAverage \
		   -process=SampleTime,first,SampleTime         -process=ValuesPerRead,first,ValuesPerRead \
		   -process=Temperature,first,Temperature       \
		   -process=InputConfig,first,InputConfig       -process=MacAddress,first,MacAddress \
		   | sddsconvert -pipe=in $file.proc \
		   -del=col,TimeStamp,StartTime,Range,BiasVoltage,AveragingTime,NumAverage,SampleTime,ValuesPerRead \
		   -del=col,Temperature,TetraRoot,InputConfig,MacAddress,QRcode } result] {
	return -code error "Error processing noise bench data2 ($file): $result"
    }
}

proc SelectWeightConfig {args} {
    global XBPMTests
    set dir /home/helios/oagData/apsu/XbpmSetup/inputFiles/Weight/Config
    
    set files [glob -nocomplain $dir/WeightConfig*.sdds]
    if ![llength $files] {
	return -code error "No weight config files found!"
    }
    APSScrolledListWindow .weight -height 10 -name "Select A File" -itemList $files \
	-selectionVar XBPMTests(Init.weightConfig)
}

proc MakeDefaultWeightFunctionName {args} {
    global XBPMTests
    UpdateXBPMNormParameters
    set dir /home/helios/oagData/apsu/XbpmSetup/inputFiles/Weight
    set sector [scan $XBPMTests(Init.choice) S%ld]
    set unit [string range $XBPMTests(Init.choice) 3 end]
    set XBPMTests(Init.weightFunc) $dir/WeightFunc-S[format %02d $sector]IDFE-XBPM:${unit}.sdds
    set XBPMTests(Init.weightConfig) $dir/Config/WeightConfig-$XBPMTests(Norm.frontEnd)-Default.sdds
}

set XBPMTests(InitCal.choice) ""
proc SelectInitCalItem {args} {
    set item ""
    APSParseArguments {item}
   
    global XBPMTests
    if [string length $item] {
	set bpm P1
	foreach nm {us ds} {
	    for {set sector 1} {$sector<=35} {incr sector} {
		set sectorf [format %02d $sector]
		set item1 S${sectorf}$bpm$nm
		set XBPMTests(InitCal.$item1) 0
	    }
	}
    
	set XBPMTests(InitCal.$item) 1
	set XBPMTests(InitCal.choice) $item
    } else {
	set item $XBPMTests(InitCal.choice)
	if ![string length $item] {
	    SetMainStatus "No bpm is chosen!"
	    return
	}
    }
    set sector [scan $item S%ld]
    set st [string range $item end-1 end]
    set sectorf [format %02d $sector]
    if [lsearch -exact $XBPMTests(CUsectorList) $sectorf]<0 {
	set FE HHLFE
    } else {
	set FE CFE
    }
   # set XBPMTests(InitCalFile) /home/helios/oagData/apsu/XbpmSetup/data/S${sectorf}ID/calibration/S${sectorf}ID-${FE}-P1${st}.sdds
    set XBPMTests(InitCalFile)  /home/helios/oagData/apsu/XbpmSetup/data/S${sectorf}ID/XYCal/S${sectorf}ID-[string toupper $st]ID-U[format %.1f $XBPMTests(S${sectorf}.$st.period)]mm-$XBPMTests(S${sectorf}.FE)-P1${st}-XYCal.sdds
    
   # MakeDefaultWeightFunctionName
}

proc GetInitNormList {args} {
    global XBPMTests
    set itemList ""
    set bpm P1
    for {set sector 1} {$sector<=35} {incr sector} {
	foreach nm {us ds} {
	    set sectorf [format %02d $sector]
	    set item1 S${sectorf}$bpm$nm
	    if $XBPMTests(InitNorm.$item1) {
		lappend itemList $item1
	    }
	}
    }
    
    return $itemList
}

proc CopyDefaultCalFactorOffset {args} {
    set type ""
    set plot 0
    set copy 1
    APSParseArguments {type plot copy}
    global XBPMTests
    #only one choice
    set item  $XBPMTests(InitCal.choice)
    if ![string length $item] {
	SetMainStatus "No bpm is chosen!"
	return
    }
    if $copy {
	set sector [scan $item S%ld]
	set st [string range $item end-1 end]
	set sectorf [format %02d $sector]
	set inputFile /home/helios/oagData/apsu/XbpmSetup/inputFiles/XYCal/U[format %.1f $XBPMTests(S${sectorf}.$st.period)]mm-$XBPMTests(S$sectorf.FE)-XBPM1-XYCal-Std.sdds
	if ![file exist $inputFile] {
	    SetMainStatus "$inputFile does not exist!"
	    return
	}
	exec cp $inputFile $XBPMTests(InitCalFile)
	SetMainStatus "XY calibration file is copied to $XBPMTests(InitCalFile)"
	exec chmod 777 $XBPMTests(InitCalFile)
    }
    if $plot {
	set tmpFile /tmp/[APSTmpString]
	set format %10.1f
	APSAddToTmpFileList -ID xbpm -fileList "$tmpFile.x $tmpFile.y $tmpFile"
	if [catch {exec sddsprintout $XBPMTests(InitCalFile) $tmpFile.x "-title=Calibration factor for $item x plane" \
		       -col=Gap,format=%5.1f -col=xCalFactor1,format=$format -col=xOffset1,format=$format \
		       -col=xCalFactor2,format=$format -col=xOffset2,format=$format -col=Wx1,format=$format \
		       -col=Wx2,format=$format -col=Wx3,format=$format \
		       -col=BMc,format=$format } result] {
	    return -code error "Error print cal factor x: $result"
	}
	if [catch {exec sddsprintout $XBPMTests(InitCalFile) $tmpFile.y "-title=\nCalibration factor for $item y plane" \
		       -col=Gap,format=%5.1f -col=yCalFactor1,format=$format -col=yOffset1,format=$format \
		       -col=yCalFactor2,format=$format -col=yOffset2,format=$format -col=Wy1,format=$format \
		       -col=Wy2,format=$format -col=Wy3,format=$format \
		       -col=BMc,format=$format } result] {
	    return -code error "Error print cal factor y: $result"
	}
	exec cat $tmpFile.x $tmpFile.y >  $tmpFile
	APSFileDisplayWindow [APSUniqueName .cal] -fileName $tmpFile  -width 120  -height 20 \
	    -printCommand "enscript -r"
    }
    
    SetMainStatus "done."
}

proc LoadIDXBPM1Calibration {args} {
    global XBPMTests
  #  set choiceList [GetInitList]
    set item $XBPMTests(InitCal.choice)
    if ![string length $item] {
	SetMainStatus "NO bpm is chosen!"
	return
    }
    set calFile $XBPMTests(InitCalFile)
    if ![file exist $calFile] {
	SetMainStatus "calibration file $calFile does not exist! calibration is not loaded."
	return
	#CopyDefaultCalFactorOffset -copy 1 -plot 0
    }
    SetMainStatus "Loading XBPM1 calibration factor for $item..."
    if [catch {LoadXYCalToXBPM1 -calFile $calFile -bpm $item} result] {
	return -code error "Error loading XBPM1 calibration for $item: $result"
    }
    SetMainStatus "done."
    return
    set choiceList $XBPMTests(InitCal.choice)
    if ![string length $choiceList] {
	SetMainStatus "No item chosen!"
	return
    }
    set mainDir /home/helios/oagData/apsu/XbpmSetup/data
    foreach choice $choiceList {
	set sector [scan $choice S%ld]
	set usds [string range $choice end-1 end]
	set sectorf [format %02d $sector]
	set filename /home/helios/oagData/apsu/XbpmSetup/data/S${sectorf}ID/calibration/S${sectorf}ID-P1${usds}-calibration.sdds
	if ![file exist $filename] {
	    if [catch {GenerateIDXBPM1CalibrationFile -sector $sector -usds $usds} result] {
		return -code error "Error generating/loading calibration for $choice : $result"
	    }
	}
	SetMainStatus "Loading xbpm1 calibration for $choice..."
	if [catch {exec sddscasr $filename -restore} result] {
	    return -code error "Error loading xbpm1 calibration for $choice: $result"
	}
	SetMainStatus "done."
    }
}

proc GenerateIDXBPM1CalibrationFile {args} {
    set calFile ""
    set sector ""
    set usds ""
    APSParseArguments {calFile sector usds}
    global XBPMTests
    set sectorf [format %02d $sector]
    set dir /home/helios/oagData/apsu/XbpmSetup/data/S${sectorf}ID/calibration
    if ![string length $calFile] {
	if [lsearch -exact $XBPMTests(CUsectorList) $sectorf]>=0 {
	    set calFile $dir/S${sectorf}ID-CFE-P1${usds}.sdds
	    set refFile $XBPMTests(CFEP1${usds}CalFile)
	} else {
	    set calFile  $dir/S${sectorf}ID-HHLFE-P1${usds}.sdds
	    set refFile $XBPMTests(HHLFEP1${usds}CalFile)
	}
    }
    if ![file exist $calFile] {
	exec cp $refFile $calFile
    }
    set filename $dir/S${sectorf}ID-P1${usds}-calibration.sdds
    
    set root S[format %02d $sector]IDFE-XBPM
    set tmpRoot /tmp/[APSTmpString]
    set fileList ""
    
    set colList {Gap xCalFactor1 xOffset1 xCalFactor2 xOffset2 yCalFactor1 yOffset1 yCalFactor2 yOffset2 Wx1 Wx2 Wx3 Wy1 Wy2 Wy3 BMc}
    set rows [exec sdds2stream -rows=bar $calFile]
    set root S${sectorf}IDFE-XBPM:P1${usds}:
    set fileList ""
    foreach col $colList  {
	set pvList ""
	set valList [exec sdds2stream -col=$col $calFile]
	set name [regsub "xCalFactor" $col "XCal"]
	set name [regsub "xOffset" $name "XOff"]
	set name [regsub "yCalFactor" $name "YCal"]
	set name [regsub "yOffset" $name "YOff"]
	set name [regsub "Gap" $name ""]Gap
	for {set index 1} {$index<=$rows} {incr index} {
	    lappend pvList ${root}${name}${index}C
	}
	if [catch {exec sddsmakedataset $tmpRoot.$col -col=ControlName,type=string -data=[join $pvList ,] \
		       -col=ValueString,type=string -data=[join $valList ,] } result] {
	    return -code error "Error creating calibration file for S$sectorf ID P1: $result"
	}
	APSAddToTmpFileList -ID xbpm -fileList $tmpRoot.$col
	lappend fileList $tmpRoot.$col
    }
    #puts $fileList
    if [catch {eval exec sddscombine $fileList -merge -over $filename } result] {
	return -code error "Error generating calibration for S$sectorf P1$usds: $result "
    }
    return $filename
}


proc LoadIDXBPM2Calibration {args} {
     set review 0
     APSParseArguments {review}
     
    global XBPMTests
    set choiceList [GetIDXBPM2Selection]
    if ![llength $choiceList] {
	SetMainStatus "No unit is chosen"
	return
    }
    set tmpRoot /tmp/[APSTmpString]
    foreach choice $choiceList {
	set sector [scan $choice S%ld]
	set usds [string range $choice end-1 end]
	set sectorf [format %02d $sector]
	if [catch {GenerateIDXBPM2CalibrationFile -sector $sector -usds $usds} result] {
	    return -code error "Error generating/loading calibration for $sector CM4$usds: $result"
	}
	
	if $review {
	    set file $result
	    if [catch {exec sddsprintout $file $tmpRoot.$choice  \
			   "-title=Calibration Factors for S${sectorf}ID:P2$usds" \
			   -col=Sector,label=Index,format=%5d -col=Gap,format=%3.1f \
			   -col=P2:XCalC,label=xCal,format=%8.1f \
			   -col=P2:XOffC,label=xOffset,format=%8.1f \
			   -col=P2:YCalC,label=yCal,format=%8.1f \
			   -col=P2:YOffC,label=yOffset,format=%8.1f \
		       } result] {
		return -code error "Error print $choice calibration: $result"
	    }
	    APSFileDisplayWindow [APSUniqueName .xbpm2] -fileName $tmpRoot.$choice  -width 100  \
		-height 20 -printCommand "enscript -r"
	    continue
	}
	set filename /home/helios/oagData/apsu/XbpmSetup/data/S${sectorf}ID/calibration/S${sectorf}ID-P2${usds}-calibration.sdds
	SetMainStatus "Loading xbpm2 calibration for $choice..."
	if [catch {exec sddscasr $filename -restore} result] {
	    return -code error "Error loading xbpm2 calibration for $choice: $result"
	}
	SetMainStatus "done."
    }
}

proc LoadXBPMCalibration {args} {
    set xbpm ""
    APSParseArguments {xbpm}
    global XBPMTests
    SetMainStatus "Load $xbpm XBPM calibration..."
    set file $XBPMTests(${xbpm}FEcalibrationFile)
    if ![file exist $file] {
	SetMainStatus "calibration file $file does not exit!"
	return
    }
    #P1:YCalC:Alias	CM1:PositionScaleX
    #P1:YOffC:Alias	CM1:PositionOffsetX
    #P2:YCalC:Alias	CM1:PositionScaleY
    #P2:YOffC:Alias	CM1:PositionOffsetY
    set tmpRoot /tmp/[APSTmpString]
    set fileList ""
    foreach col {P1:YCalC P1:YOffC P2:YCalC P2:YOffC} \
	name {CM1:PositionScaleX CM1:PositionOffsetX CM1:PositionScaleY CM1:PositionOffsetY} {
	    if [catch {exec sddsprocess $file $tmpRoot.$col \
			   -print=col,ControlName,%s:$name,PVRoot \
			   -print=col,ValueString,%lf,$col } result] {
		return -code error "Error processing calibration: $result"
	    }
	    lappend fileList $tmpRoot.$col
	    APSAddToTmpFileList -ID xbpm -fileList $tmpRoot.$col
	}
    if [catch {eval exec sddscombine $fileList -merge -pipe=out \
		   | tee $tmpRoot.load \
		   | sddscasr -restore -pend=30 -pipe=in } result] {
	return -code error "Error loading calibration: $result"
    }

    SetMainStatus "$xbpm XBPM calibration loaded."
}

proc LoadXBPMIOCDefaults {args} {
    global XBPMTests
    set sector [string range $XBPMTests(Init.choice) 0 2]
    set bpm [string range $XBPMTests(Init.choice) 3 4]
    set stream [string range $XBPMTests(Init.choice) 5 6]
    switch $bpm {
	P1 {
	    set itemList [list CM1$stream CM2$stream CM3$stream]
	}
	P2 {
	    set itemList CM4$stream
	}
    }
    set putList0 ""
    set tmpRoot /tmp/[APSTmpString]
    set valuesPerRead 100
    set avgTime 0.1
    set fastAvgTime 1.0
    set template /home/helios/oagData/apsu/XbpmSetup/inputFiles/Weight/Config/TetrAMMIOCDefaults.sdds.template
    foreach item $itemList {
	set root ${sector}IDFE-XBPM:$item
	exec caput ${root}:Acquire 0
	if [catch {exec replaceText $template $tmpRoot.$root -orig=<rootPV>,<ValuesPerRead>,<AvgTime>,<FastAvgTime> \
		       -repl=$root,$valuesPerRead,$avgTime,$fastAvgTime } result] {
	    return -code error "Error creating default for $root: $result"
	}
	APSAddToTmpFileList -ID xbpm -fileList $tmpRoot.$root
	SetMainStatus "Load default settings for $root..."
	if [catch {exec sddscasr -restore $tmpRoot.$root } result] {
	    return -code error "Error loading defaults for $root: $result"
	}
	exec caput ${root}:Acquire 1
    }
    SetMainStatus "load calculated weights..."
    if [catch {exec /home/helios/oagData/apsu/XbpmSetup/scripts/loadDefaultXbpmWeight \
		   -xbpmRoot S[format %02d $sector]IDFE-XBPM:${bpm}$stream } result] {
	return -code error "Error loading weights: $result"
    }
    SetMainStatus "done."
}

#[Weight Config]: default file name contains -CFE- for canted front ends, -HHLFE- for high heat load front ends​
#CFE (SXXIDFE): XX = 02, 06, 11, 12, 13, 15, 16, 21, 22, 23, 24, 25, 28, 31, 32, and 34. ​
#HHLFE (SXXIDFE): XX = 01, 03, 04, 05, 07, 08, 09, 10, 14, 17, 18, 19, 20, 26, 27, 29, 30, 33, and 35. ​
set XBPMTests(IDCFE.sectors) {02 06 11 12 13 15 16 21 22 23 24 25 28 31 32 34}
set XBPMTests(IDHHLFE.sectors) {01 03 04 05 07 08 09 10 14 17 18 19 20 26 27 29 30 33 35}


proc GenerateWeightFunction {args} {
    global XBPMTests
    set WeightGrid /home/helios/oagData/apsu/XbpmSetup/inputFiles/Weight/WeightGrid-HHLFE-Default0.sdds
    set gapGrid /home/helios/oagData/apsu/XbpmSetup/inputFiles/Weight/GapGrid0.sdds
    if ![string length $XBPMTests(Init.choice)] {
	return -code error "No item chosen!"
    }
    set FE $XBPMTests(Norm.frontEnd)
   # puts $XBPMTests(Init.weightConfig)
    if [catch {exec sddsinterp $XBPMTests(Init.weightConfig) $XBPMTests(Init.weightFunc) \
		   -fileValues=${gapGrid},column=Gap \
		   -columns=Gap,Wx1,Wx2,Wx3,Wy1,Wy2,Wy3 } result] {
	return -code error "Error generating weight function for $XBPMTests(Init.choice): $result"
    }
    SetMainStatus "Weight function generated for $XBPMTests(Init.choice)"
	
}

proc PlotPrintWeightFunction {args} {
    global XBPMTests verbose
    if ![string length $XBPMTests(Init.choice)] {
	return -code error "No item chosen!"
    }
    if ![file exist $XBPMTests(Init.weightFunc)] {
	GenerateWeightFunction
    }
    exec sddsplot -col=Gap,W* -legend -grap=line,vary $XBPMTests(Init.weightFunc) &
    if $verbose {
	set tmpRoot /tmp/[APSTmpString]
	APSAddToTmpFileList -ID xbpm -fileList $tmpRoot
	exec sddsprintout -col=Gap,format=%5.1f -col=Wx1,format=%5.2f -col=Wx2,format=%5.2f -col=Wx3,format=%5.2f \
	    -col=Wy1,format=%5.2f -col=Wy2,format=%5.2f -col=Wy3,format=%5.2f  $XBPMTests(Init.weightFunc) $tmpRoot.print
	APSFileDisplayWindow [APSUniqueName .weight] -fileName $tmpRoot.print  -width 100  -height 20 -printCommand "enscript -r"

    }
}

proc CompareIOCSetupWithFile {args} {
    global XBPMTests
    set tmpFile /tmp/[APSTmpString]
    set reqFile /home/helios/oagData/apsu/XbpmSetup/inputFiles/APSSRXBPM.req
    
    set dir /home/helios/oagData/apsu/XbpmSetup/SCR
    set files [lsort -decreasing [glob -nocomplain $dir/Setup-*.sdds]]
    if ![llength $files] {
	return -code error "No files found."
    }
    set XBPMTests(compareFile) ""
    APSScrolledListWindow .compare -height 10 -name "Select A File" -itemList $files \
	-selectionVar XBPMTests(compareFile)
    tkwait variable XBPMTests(compareFile)
    if ![string length $XBPMTests(compareFile)] {
	return -code error "No file chosen for comapre"
    }
    if [catch {SaveSetupData -filename $tmpFile} result] {
	return -code error "Error saving setup: $result"
    }
    APSAddToTmpFileList -ID xbpm -fileList $tmpFile
    
    if [catch {exec sddsprocess $XBPMTests(compareFile) $tmpFile.file -match=col,IsNumerical=y \
		   -scan=col,SCRValue,ValueString,%lf
	exec sddsprocess $tmpFile $tmpFile.ioc  -match=col,IsNumerical=y \
		   -scan=col,Current,ValueString,%lf } result] {
	return -code error "No numerical values found: $result"
    }
    if [catch {exec sddsprocess $XBPMTests(compareFile) $tmpFile.file.str -match=col,IsNumerical=n -nowarn
	exec sddsprocess $tmpFile $tmpFile.ioc.str -match=col,IsNumerical=n -nowarn } result] {
	return -code error "No string values found: $result"
    }
    if [catch {exec sddsxref $tmpFile.ioc $tmpFile.file -pipe=out -match=ControlName -take=SCRValue  -nowarn \
	       | sddsprocess -pipe "-define=col,Diff,Current SCRValue - abs" -nowarn \
	       | sddsprocess -pipe=in $tmpFile.num.compare -nowarn \
	       "-test=col,Diff 0.1 >" 
	exec sddsxref $tmpFile.ioc.str $tmpFile.file.str -match=ControlName -rename=col,ValueString=SCRValue \
		   -pipe=out -nowarn \
		   | sddsprocess -pipe "-define=col,Diff,ValueString SCRValue streq ? 1 : 0 $ " -nowarn \
		   | sddsprocess -pipe=in $tmpFile.str.compare "-test=col,Diff 1 <" -nowarn } result] {
	return -code error "Error processing setup files: $result"
    }
    set rows1 [exec sdds2stream -rows=bar $tmpFile.num.compare]
    set rows2 [exec sdds2stream -rows=bar $tmpFile.str.compare]
    if {!$rows1 && !$rows2} {
	SetMainStatus "$XBPMTests(compareFile) for selected XBPMs is the same as current IOC setup!"
	return
    } 
    set printFile $tmpFile.print
    if {$rows1} {
	exec sddsprintout $tmpFile.num.compare $tmpFile.print1 "-title=Following numerical PVs are different in SCR setup and current IOC" \
	    -col=ControlName,format=%25s -col=Current,format=%10.3f -col=SCRValue,format=%10.3f
    }
    if $rows2 {
	exec sddsprintout $tmpFile.str.compare $tmpFile.print2 "-title=Following stringl PVs are different in SCR setup and current IOC" \
	    -col=ControlName,format=%25s -col=ValueString,format=%10s.label=Current -col=SCRValue,format=%10s
    }
    if {$rows1 && $rows2} {
	exec cat $tmpFile.print1 $tmpFile.print2 > $printFile
    } elseif $rows1 {
	set printFile $tmpFile.print1
    } elseif $rows2 {
	set printFile $tmpFile.print2
    }
    set files [glob -nocomplain ${tmpFile}*]
    APSAddToTmpFileList -ID xbpm -fileList [join $files]
    APSFileDisplayWindow [APSUniqueName .compare] -fileName $printFile  -width 100  -height 20 -printCommand "enscript -r"
}

proc StartAllXBPMIOCs {args} {
    global XBPMTests
    set reqFile /home/helios/oagData/apsu/XbpmSetup/inputFiles/APSSRXBPM.req
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddsprocess $reqFile -pipe=out -match=col,Category=CM??s \
		   -edit=col,Rootname,ControlName,S/:/6f30D \
		   | sddssort -pipe -unique -col=Rootname \
		   | sdds2stream -pipe -col=Rootname } rootList] {
	return -code error "Error obtaiing active XBPM ioc list: $result"
    }
    exec cavput -list=[join $rootList ,] -list=:Acquire=1 
    SetMainStatus "Active XBPM iocs are started."
    
}

proc CreateCalibrationWidgets {widget args} {
    set parent ""
    APSParseArguments {parent}
    
    global XBPMTests
    
    APSFrame $widget -parent $parent -label "" \
	-packOption "-side top"
    set w $parent$widget.frame
    
   # set XBPMTests(cali.IDFE-XBPM) 1
    set XBPMTests(cali.XBPM1) 1
    set XBPMTests(cali.XBPM2) 1
    set XBPMTests(cali.us) 1
    set XBPMTests(cali.ds) 1

    set sectorList ""
    set varList ""
    for {set sector 1} {$sector<=35} {incr sector} {
	lappend sectorList [format %02d $sector]
	set XBPMTests(cali.S$sector) 0
	lappend varList XBPMTests(cali.S$sector)
    }
    set XBPMTests(cali.S25) 1
    set XBPMTests(cali.S27) 1
    set XBPMTests(cali.S28) 1
    APSCheckButtonFrame .sector -parent $w -label "Sector:" -buttonList $sectorList \
	-orientation horizontal -limitPerRow 10 -variableList $varList 
    APSCheckButtonFrame .device -parent $w -label "Device:" -buttonList {us ds} \
	-orientation horizontal -variableList {XBPMTests(cali.us) XBPMTests(cali.ds)}
    
    APSCheckButtonFrame .norm -parent $w -label "XBPM selection:" -buttonList {XBPM1 IDFE-XBPM2} \
	-variableList {XBPMTests(cali.XBPM1) XBPMTests(cali.XBPM2)} \
	-orientation horizontal
    
    APSButton .load -parent $w -text "Local Normalization Factors" -command "LoadNormalizationFactors"
    
}

proc LoadWeightFunction {args} {
    global XBPMTests
    if ![string length $XBPMTests(Init.choice)] {
	return -code error "No item chosen!"
    }
    if ![file exist $XBPMTests(Init.weightFunc)] {
	if [catch {GenerateWeightFunction} result] {
	    return -code error "Error generating weight function for $XBPMTests(Init.choice)"
	}
    }
    SetMainStatus "loading weight function for $choice..."


    SetMainStatus "done."

}


proc LoadXbpmGainFactor {args} {
    global XBPMTests
    
    set calFile $XBPMTests(XBPM1DetectorNormFile)
    set colList [exec sddsquery -col $calFile]
    foreach col $colList {
	set ${col}List [exec sdds2stream -col=$col $calFile]
    }
    foreach sector $SectorList FE $FrontEndList det $DetectorIDList \
	QR $DetectorQRList gain1 $GainF1List gain2 $GainF2List gain3 $GainF3List \
	gain4 $GainF4List gain5 $GainF5List gain6 \
	$GainF6List gain7 $GainF7List gain8 $GainF8List {
	    set sectorf [format %02d $sector]
	    
	    set XBPMTests(S${sectorf}P1.$FE.det$det.SN) SN$QR
	    for {set i 1} {$i<=8} {incr i} {
		set XBPMTests(S${sectorf}P1.$FE.det$det.gain$i) [set gain$i]
	    }
	}
    
    return
    #load xbpm2 factor
    set caliFile $caliDir/IDFE-XBPM2-Detectors.sdds
    set caliFile $XBPMTests(XBPM2detectorDatabase)
    set diodeList {A B C D E F G H}
    set serialList [exec sdds2stream -col=SerialNumber $caliFile]
    set FEList [exec sdds2stream -col=FrontEnd $caliFile]
    for {set i 0} {$i<[llength $diodeList]} {incr i} {
	set gain[expr $i+1] [exec sdds2stream -col=Gain:Diode[lindex $diodeList $i] $caliFile]
    }
    for {set j 0} {$j<[llength $serialList]} {incr j} {
	set serial [lindex $serialList $j]
	set FE [lindex $FEList $j]
	for {set i 1} {$i<=8} {incr i} {
	    set GainFactor(Xbpm2.$FE.$serial.$i) [lindex [set gain$i] $j]
	}
	#puts "$serial $FE $GainFactor(Xbpm2.$FE.$serial.1) $GainFactor(Xbpm2.$serial.$FE.8)"
    }
}

proc CloseDisplayWidgets {args} {
    global XBPMTests
    puts $XBPMTests(wList) 
    foreach win $XBPMTests(wList) {
	if [winfo exist $win] {
	    destroy $win
	}
    }
    after 1000
    set XBPMTests(wList) ""
}

set XBPMTests(wList) ""
proc LoadCFEXbpm1NormFactor {args} {
    global XBPMTests GainFactor
    set dryRun 0
    set sector ""
    set usds ""
    APSParseArguments {dryRun sector usds}

    #us
    
   # M1us.Ch1 A4 CFE-CM1us.Ch1-A4
    #CM1us.Ch2 B5 CFE-CM1us.Ch2-B5
    #CM1us.Ch3 A5 CFE-CM1us.Ch3-A5
    #CM1us.Ch4 B4 CFE-CM1us.Ch4-B4
    #A B Label
    #CM2us.Ch1 A3 CFE-CM2us.Ch1-A3
    #CM2us.Ch2 B6 CFE-CM2us.Ch2-B6
    #CM2us.Ch3 A6 CFE-CM2us.Ch3-A6
    #CM2us.Ch4 B3 CFE-CM2us.Ch4-B3
    #A B Label
    #CM3us.Ch1 A2 CFE-CM3us.Ch1-A2
    #CM3us.Ch2 B7 CFE-CM3us.Ch2-B7
    #CM3us.Ch3 A7 CFE-CM3us.Ch3-A7
    #CM3us.Ch4 B2 CFE-CM3us.Ch4-B2

    #CM4us.Ch1 A1 CFE-CM4us.Ch1-A1
    #CM4us.Ch2 B8 CFE-CM4us.Ch2-B8
    #CM4us.Ch3 A8 CFE-CM4us.Ch3-A8
    #CM4us.Ch4 B1 CFE-CM4us.Ch4-B1
    
    #ds
   
   # CM1ds.Ch1 C5 CFE-CM1ds.Ch1-C5
    #CM1ds.Ch2 D4 CFE-CM1ds.Ch2-D4
    #CM1ds.Ch3 C4 CFE-CM1ds.Ch3-C4
    #CM1ds.Ch4 D5 CFE-CM1ds.Ch4-D5
    #A B Label
    #CM2ds.Ch1 C6 CFE-CM2ds.Ch1-C6
    #CM2ds.Ch2 D3 CFE-CM2ds.Ch2-D3
    #CM2ds.Ch3 C3 CFE-CM2ds.Ch3-C3
    #CM2ds.Ch4 D6 CFE-CM2ds.Ch4-D6
    #A B Label
    #CM3ds.Ch1 C7 CFE-CM3ds.Ch1-C7
    #CM3ds.Ch2 D2 CFE-CM3ds.Ch2-D2
    #CM3ds.Ch3 C2 CFE-CM3ds.Ch3-C2
    #CM3ds.Ch4 D7 CFE-CM3ds.Ch4-D7

    #CM4ds.Ch1 C8 CFE-CM4ds.Ch1-C8
    #CM4ds.Ch2 D1 CFE-CM4ds.Ch2-D1
    #CM4ds.Ch3 C1 CFE-CM4ds.Ch3-C1
    #CM4ds.Ch4 D8 CFE-CM4ds.Ch4-D8
    
    #us dector A, B
    #ds dector C, D
   
    switch $usds {
	us {
	    set detList {A B}
	} 
	ds {
	    set detList {C D}
	}
    }
    set sectorf [format %02d $sector]
    set tmpFile /tmp/[APSTmpString]
    APSAddToTmpFileList -ID xbpm -fileList $tmpFile
    set fd [open $tmpFile "w"]
    puts $fd "Sector=$sector, device=$usds, xbpm=XBPM1, dryRun=$dryRun"
    set choice S[format %02d $sector]P1$usds
    puts $fd "$choice ID FrontEnd = CFE $detList"
    set bpm S${sectorf}P1
    foreach detector $detList {
	set SN$detector $XBPMTests($bpm.CFE.det$detector.SN)
	puts $fd "Sector=$sector $usds detector=$detector, SN$detector=[set SN$detector]"
    }
   
    puts $fd "XBPM1 detector gain factors"
    puts $fd "Detector   SN\#     Gain1  Gain2  Gain3  Gain4  Gain5  Gain6  Gain7  Gain8"
    foreach det $detList {
	set SN [set SN$det]
	set linetext "$det       $SN  "
	for {set i 1} {$i<=8} {incr i} {
	    append linetext " [format %6.3f $XBPMTests($bpm.CFE.det$det.gain$i)]"
	}
	puts $fd  "$linetext"
    }
    
    set putList ""
    set rootPV S[format %02d $sector]IDFE-XBPM
    set sectorf [format %02d $sector]
    
    puts $fd "\nxbpmRootPV = $rootPV, root1=${rootPV}:CM1$usds, root2=${rootPV}:CM2$usds, root3=${rootPV}:CM3$usds"
    switch $usds {
	us {
	    #detector A, B
	    lappend putList ${rootPV}:CM1us:Current1NormC=[expr 1.0/$XBPMTests($bpm.CFE.detA.gain4)]
	    lappend putList ${rootPV}:CM1us:Current2NormC=[expr 1.0/$XBPMTests($bpm.CFE.detB.gain5)]
	    lappend putList ${rootPV}:CM1us:Current3NormC=[expr 1.0/$XBPMTests($bpm.CFE.detA.gain5)]
	    lappend putList ${rootPV}:CM1us:Current4NormC=[expr 1.0/$XBPMTests($bpm.CFE.detB.gain4)]

	    lappend putList ${rootPV}:CM2us:Current1NormC=[expr 1.0/$XBPMTests($bpm.CFE.detA.gain3)]
	    lappend putList ${rootPV}:CM2us:Current2NormC=[expr 1.0/$XBPMTests($bpm.CFE.detB.gain6)]
	    lappend putList ${rootPV}:CM2us:Current3NormC=[expr 1.0/$XBPMTests($bpm.CFE.detA.gain6)]
	    lappend putList ${rootPV}:CM2us:Current4NormC=[expr 1.0/$XBPMTests($bpm.CFE.detB.gain3)]
	    
	    lappend putList ${rootPV}:CM3us:Current1NormC=[expr 1.0/$XBPMTests($bpm.CFE.detA.gain2)]
	    lappend putList ${rootPV}:CM3us:Current2NormC=[expr 1.0/$XBPMTests($bpm.CFE.detB.gain7)]
	    lappend putList ${rootPV}:CM3us:Current3NormC=[expr 1.0/$XBPMTests($bpm.CFE.detA.gain7)]
	    lappend putList ${rootPV}:CM3us:Current4NormC=[expr 1.0/$XBPMTests($bpm.CFE.detB.gain2)]
	    if {0} {
	    lappend putList ${rootPV}:CM4us:Current1NormC=[expr 1.0/$XBPMTests($bpm.CFE.detA.gain1)]
	    lappend putList ${rootPV}:CM4us:Current2NormC=[expr 1.0/$XBPMTests($bpm.CFE.detB.gain8)]
	    lappend putList ${rootPV}:CM4us:Current3NormC=[expr 1.0/$XBPMTests($bpm.CFE.detA.gain8)]
	    lappend putList ${rootPV}:CM4us:Current4NormC=[expr 1.0/$XBPMTests($bpm.CFE.detB.gain1)]
	    }
	    
	    set i 1
	    set j 1
	    foreach line $putList {
		puts $fd "Tetra \#$i, channel \#$j: $line"
		incr j
		if {$j>4} {
		    set j 1
		    set i [expr $i+1]
		}
	    }
	}
	ds {
	    #detector C, D
	    lappend putList ${rootPV}:CM1ds:Current1NormC=[expr 1.0/$XBPMTests($bpm.CFE.detC.gain5)]
	    lappend putList ${rootPV}:CM1ds:Current2NormC=[expr 1.0/$XBPMTests($bpm.CFE.detD.gain4)]
	    lappend putList ${rootPV}:CM1ds:Current3NormC=[expr 1.0/$XBPMTests($bpm.CFE.detC.gain4)]
	    lappend putList ${rootPV}:CM1ds:Current4NormC=[expr 1.0/$XBPMTests($bpm.CFE.detD.gain5)]
	    
	    lappend putList ${rootPV}:CM2ds:Current1NormC=[expr 1.0/$XBPMTests($bpm.CFE.detC.gain6)]
	    lappend putList ${rootPV}:CM2ds:Current2NormC=[expr 1.0/$XBPMTests($bpm.CFE.detD.gain3)]
	    lappend putList ${rootPV}:CM2ds:Current3NormC=[expr 1.0/$XBPMTests($bpm.CFE.detC.gain3)]
	    lappend putList ${rootPV}:CM2ds:Current4NormC=[expr 1.0/$XBPMTests($bpm.CFE.detD.gain6)]

	    lappend putList ${rootPV}:CM3ds:Current1NormC=[expr 1.0/$XBPMTests($bpm.CFE.detC.gain7)]
	    lappend putList ${rootPV}:CM3ds:Current2NormC=[expr 1.0/$XBPMTests($bpm.CFE.detD.gain2)]
	    lappend putList ${rootPV}:CM3ds:Current3NormC=[expr 1.0/$XBPMTests($bpm.CFE.detC.gain2)]
	    lappend putList ${rootPV}:CM3ds:Current4NormC=[expr 1.0/$XBPMTests($bpm.CFE.detD.gain7)]
	    if {0} {
	    lappend putList ${rootPV}:CM4ds:Current1NormC=[expr 1.0/$XBPMTests($bpm.CFE.detC.gain8)]
	    lappend putList ${rootPV}:CM4ds:Current2NormC=[expr 1.0/$XBPMTests($bpm.CFE.detD.gain1)]
	    lappend putList ${rootPV}:CM4ds:Current3NormC=[expr 1.0/$XBPMTests($bpm.CFE.detC.gain1)]
	    lappend putList ${rootPV}:CM4ds:Current4NormC=[expr 1.0/$XBPMTests($bpm.CFE.detD.gain8)]

	    }
	    set i 1
	    set j 1
	    foreach line $putList {
		puts $fd "Tetra \#$i, channel \#$j: $line"
		incr j
		if {$j>4} {
		    set j 1
		    set i [expr $i+1]
		}
	    }
	}
    }
    close $fd
    if !$dryRun {
	SetMainStatus "loadCFE-XBPM1NormFactor: Calculate and load CFE-XBPM1 Detector Norm Factors..."
	if [catch {exec cavput -list=[join $putList ,] -pend=10 } result] {
	    return -code error "Error loading gain factor for XBPM1 CFE: $result"
	}
	SetMainStatus "done."
    } else {
	set win [APSUniqueName .det]
	APSFileDisplayWindow $win -fileName $tmpFile  -width 120  -height 20 -printCommand "enscript -r"
	lappend XBPMTests(wList) $win
    }
}

proc LoadCFEXbpm2NormFactor {args} {
    global XBPMTests GainFactor
    set sector ""
    set usds ""
    set dryRun 0
    APSParseArguments {sector usds dryRun}

    #XBPM2 CFE config
    #Table 3: CFE XBPM2 patch cables for TetrAMM A (from)B (to)Label
    #CM4us.Ch1  A  CFE-CM4us.Ch2-P2A
    #CM4us.Ch2  B  CFE-CM4us.Ch2-P2B
    #CM4us.Ch3  C  CFE-CM4us.Ch3-P2C
    #CM4us.Ch4  D  CFE-CM4us.Ch4-P2D
    #CM4ds.Ch1  E  CFE-CM4ds.Ch1-P2E
    #CM4ds.Ch2  F  CFE-CM4ds.Ch1-P2F
    #CM4ds.Ch3  G  CFE-CM4ds.Ch3-P2G
    #CM4ds.Ch4  H  CFE-CM4ds.Ch4-P2H

    SetMainStatus "Sector=$sector, device=$usds, xbpm=XBPM2, dryRun=$dryRun"
    set SN $XBPMTests(Norm.XBPM2.SN)
    if {$SN=="NONE"} {
	SetMainStatus "Sector $sector XBPM2 detector serial number does not exist!"
	return
    }
    SetMainStatus "FrontEnd = CFE"
    SetMainStatus "XBPM2 detector gain factors"
    SetMainStatus "SN\#     Gain1  Gain2  Gain3  Gain4  Gain5  Gain6  Gain7  Gain8"
    set linetext "$SN   "
    for {set i 1} {$i<=8} {incr i} {
	append linetext " [format %6.3f $GainFactor(Xbpm2.CFE.$SN.$i)]"
    }
    SetMainStatus "$linetext"
    SetMainStatus "xbpmRootPV = $rootPV, tetraRoot=${rootPV}:CM4$usds"
    set putList ""
    set rootPV S[format %02d $sector]IDFE-XBPM
    
    switch $usds {
	us {
	    lappend putList ${rootPV}:CM4us:Current1NormC=[expr 1.0/$GainFactor(Xbpm2.CFE.$SN.1)]
	    lappend putList ${rootPV}:CM4us:Current2NormC=[expr 1.0/$GainFactor(Xbpm2.CFE.$SN.2)]
	    lappend putList ${rootPV}:CM4us:Current3NormC=[expr 1.0/$GainFactor(Xbpm2.CFE.$SN.3)]
	    lappend putList ${rootPV}:CM4us:Current4NormC=[expr 1.0/$GainFactor(Xbpm2.CFE.$SN.4)]
	    set i 1
	    foreach line $putList {
		SetMainStatus "Channel \#%i: $line"
		incr i
	    }
	}
	ds {
	    lappend putList ${rootPV}:CM4ds:Current1NormC=[expr 1.0/$GainFactor(Xbpm2.CFE.$SN.5)]
	    lappend putList ${rootPV}:CM4ds:Current2NormC=[expr 1.0/$GainFactor(Xbpm2.CFE.$SN.6)]
	    lappend putList ${rootPV}:CM4ds:Current3NormC=[expr 1.0/$GainFactor(Xbpm2.CFE.$SN.7)]
	    lappend putList ${rootPV}:CM4ds:Current4NormC=[expr 1.0/$GainFactor(Xbpm2.CFE.$SN.8)] 
	    set i 1
	    foreach line $putList {
		SetMainStatus "Channel \#%i: $line"
		incr i
	    }
	}
    }
   # SetMainStatus "$putList"
    if !$dryRun {
	SetMainStatus "loadCFE-XBPM2NormFactor: Calculate and load CFE-XBPM2 Detector Norm Factors..."
	if [catch {exec cavput -list=[join $putList ,] -pend=10 } result] {
	    return -code error "Error loading gain factor for XBPM2 CFE: $result"
	}
	SetMainStatus "done."
    }
}

proc LoadHHLFEXbpm1NormFactor {args} {
    global XBPMTests GainFactor
    set sector ""
    set usds ""
    set dryRun 0
    APSParseArguments {sector usds dryRun}

    if {$usds=="us"} {
	SetMainStatus "XBPM1 HHLFE not available for us device"
	return
    }
    # ds
   
    set sectorf [format %02d $sector]
    set bpm S${sectorf}P1
    
    set tmpFile /tmp/[APSTmpString]
    set fd [open $tmpFile "w"]
    APSAddToTmpFileList -ID xbpm -fileList $tmpFile

    puts $fd "Sector=$sector, device=$usds, xbpm=XBPM1, dryRun=$dryRun"
    puts $fd "FrontEnd = HHLFE"
    puts $fd "Sector=$sector $usds SNA=$XBPMTests($bpm.HHLFE.detA.SN) SNB=$XBPMTests($bpm.HHLFE.detB.SN)"
    
    puts $fd "Detector   SN\#     Gain1  Gain2  Gain3  Gain4  Gain5  Gain6  Gain7  Gain8"
    foreach det {A B} {
	set linetext "$det       $XBPMTests($bpm.HHLFE.det$det.SN)  "	 	
	for {set i 1} {$i<=8} {incr i} { 
	    append linetext " [format %6.3f $XBPMTests($bpm.HHLFE.det$det.gain$i)]"
	}
	puts $fd "$linetext"
    }
    
    set putList ""
    set rootPV S[format %02d $sector]IDFE-XBPM
    puts $fd "xbpmRootPV = $rootPV, root1=${rootPV}:CM1$usds, root2=${rootPV}:CM2$usds, root3=${rootPV}:CM3$usds"

    lappend putList ${rootPV}:CM1ds:Current1NormC=[expr 1.0/$XBPMTests($bpm.HHLFE.detA.gain2)]
    lappend putList ${rootPV}:CM1ds:Current2NormC=[expr 1.0/$XBPMTests($bpm.HHLFE.detA.gain1)]
    lappend putList ${rootPV}:CM1ds:Current3NormC=[expr 1.0/$XBPMTests($bpm.HHLFE.detB.gain8)]
    lappend putList ${rootPV}:CM1ds:Current4NormC=[expr 1.0/$XBPMTests($bpm.HHLFE.detB.gain7)]
    
    
    lappend putList ${rootPV}:CM2ds:Current1NormC=[expr 1.0/$XBPMTests($bpm.HHLFE.detA.gain4)]
    lappend putList ${rootPV}:CM2ds:Current2NormC=[expr 1.0/$XBPMTests($bpm.HHLFE.detA.gain3)]
    lappend putList ${rootPV}:CM2ds:Current3NormC=[expr 1.0/$XBPMTests($bpm.HHLFE.detB.gain6)]
    lappend putList ${rootPV}:CM2ds:Current4NormC=[expr 1.0/$XBPMTests($bpm.HHLFE.detB.gain5)]

    lappend putList ${rootPV}:CM3ds:Current1NormC=[expr 1.0/$XBPMTests($bpm.HHLFE.detA.gain6)]
    lappend putList ${rootPV}:CM3ds:Current2NormC=[expr 1.0/$XBPMTests($bpm.HHLFE.detA.gain5)]
    lappend putList ${rootPV}:CM3ds:Current3NormC=[expr 1.0/$XBPMTests($bpm.HHLFE.detB.gain4)]
    lappend putList ${rootPV}:CM3ds:Current4NormC=[expr 1.0/$XBPMTests($bpm.HHLFE.detB.gain3)]
    if {0} {
    lappend putList ${rootPV}:CM4ds:Current1NormC=[expr 1.0/$XBPMTests($bpm.HHLFE.detA.gain8)]
    lappend putList ${rootPV}:CM4ds:Current2NormC=[expr 1.0/$XBPMTests($bpm.HHLFE.detA.gain7)]
    lappend putList ${rootPV}:CM4ds:Current3NormC=[expr 1.0/$XBPMTests($bpm.HHLFE.detB.gain2)]
    lappend putList ${rootPV}:CM4ds:Current4NormC=[expr 1.0/$XBPMTests($bpm.HHLFE.detB.gain1)]
    }
    set i 1
    set j 1
    foreach line $putList {
	puts $fd "Tetra \#$i, channel \#$j: $line"
	incr j
	if {$j>4} {
	    set j 1
	    set i [expr $i+1]
	}
    }
    close $fd
    if !$dryRun {
	SetMainStatus "Load normalization factors for $bpm $usds."
	if [catch {exec cavput -list=[join $putList ,] -pend=20 } result] {
	    return -code error "Error load HHLFE XBPM1 norm factor: $result"
	}
    } else {
	set win  [APSUniqueName .det]
	APSFileDisplayWindow [APSUniqueName .det] -fileName $tmpFile  -width 120  -height 20 -printCommand "enscript -r"
	lappend XBPMTests(wList)  $win
    }
}


proc LoadHHLFEXbpm2NormFactor {args} {
    global XBPMTests GainFactor
    set sector ""
    set usds ""
    set dryRun 0
    APSParseArguments {sector usds dryRun}
    
    #CM4ds:Ch1 A; CM4ds:Ch2 B; CM4ds:Ch3 C; CM4ds:Ch4 D
    set SN $XBPMTests(Norm.XBPM2.SN)
    if {$SN=="NONE"} {
	SetMainStatus "sector $sector XBPM2 detector serial number does not exit!"
	return
    }
    SetMainStatus "FrontEnd = CFE"
    SetMainStatus "XBPM2 detector gain factors"
    SetMainStatus "SN\#     Gain1  Gain2  Gain3  Gain4  Gain5  Gain6  Gain7  Gain8"
    set linetext "$SN   "
    for {set i 1} {$i<=8} {incr i} {
	append linetext " [format %6.3f $GainFactor(XBPM2.HHLFE.$SN.$i)]"
    }
    SetMainStatus "$linetext"

    set rootPV S[format %02d $sector]IDFE-XBPM
    SetMainStatus "xbpmRootPV = $rootPV, tetraRoot=${rootPV}:CM4$usds"

    set putList ""
    lappend putList ${rootPV}:CM4${usds}:Current1NormC=[expr 1.0/$GainFactor(XBPM2.HHLFE.$SN.1)]
    lappend putList ${rootPV}:CM4${usds}:Current2NormC=[expr 1.0/$GainFactor(XBPM2.HHLFE.$SN.2)]
    lappend putList ${rootPV}:CM4${usds}:Current3NormC=[expr 1.0/$GainFactor(XBPM2.HHLFE.$SN.3)]
    lappend putList ${rootPV}:CM4${usds}:Current4NormC=[expr 1.0/$GainFactor(XBPM2.HHLFE.$SN.4)]
    
    set i 1
    foreach line $putList {
	SetMainStatus "Channel \#%i: $line"
	incr i
    }
    if !$dryRun {
	if [catch {exec cavput -list=[join $putList ,] -pend=20 } result] {
	    return -code error "Error load HHLFE XBPM2 norm factor: $result"
	}
    }
}

proc SetNormStatus {text} {
    global NormStatus
    set NormStatus $text
    update
}

proc UpdateXBPMNormParameters {args} {
    global XBPMTests
    set loadParsOnly 0
    APSParseArguments {loadParsOnly}
    
    LoadXbpmGainFactor
    if ![info exist XBPMTests(Init.choice)] {
	SetMainStatus "Init sector not chosen!"
	return
    }
    set choice $XBPMTests(Init.choice)
    if ![string length $choice] {
	SetMainStatus "Init item not chosen!"
	return
    }
    set XBPMTests(Norm.sector) [scan $choice S%ld]
    if [regexp {P1} $choice] {
	set XBPMTests(Norm.bpmType) 1
    } else {
	set XBPMTests(Norm.bpmType) 2
    }
    if [regexp {us} $choice] {
	set XBPMTests(Norm.usds) us
    } else {
	set XBPMTests(Norm.usds) ds
    }
    
    set sector $XBPMTests(Norm.sector)
    set usds $XBPMTests(Norm.usds)
    set bpm $XBPMTests(Norm.bpmType)
    
    set caliDir /home/helios/DIAG/apsu/xbpmdata/detector/inputFiles
    set xbpmFile $caliDir/IDFE-XBPM.sdds
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTmpFileList -ID xbpm -fileList $tmpRoot.S$sector
    if [catch {exec sddsprocess $xbpmFile -pipe=out -filter=col,Sector,$sector,$sector \
		   | tee $tmpRoot.S$sector \
		   | sdds2stream -pipe=in -col=FrontEnd } frontEnd] {
	return -code error "Error obtain front end type: $frontEnd"
    }
    set XBPMTests(Norm.frontEnd) $frontEnd
    foreach det {A B C D} {
	set XBPMTests(Norm.XBPM1.SN$det) [exec sdds2stream -col=XBPM1$det $tmpRoot.S$sector]
    }
    set XBPMTests(Norm.XBPM2.SN) [exec sdds2stream -col=XBPM2 $tmpRoot.S$sector]
    
    #load SN number from IDFE-XBPM1-Detector-Info.sdds for XBPM1
    set filename /home/helios/oagData/apsu/XbpmSetup/inputFiles/IDFE-XBPM1-Detector-Info.sdds
    set sectorList [exec sdds2stream -col=sector $filename ]
    set FEList [exec sdds2stream -col=FrontEnd $filename]
    set detList [exec sdds2stream -col=DetectorID $filename]
    set detPosList [exec sdds2stream -col=DetectorPos $filename]
    set QRList [exec sdds2stream -col=DetectorQR $filename]
    
    foreach sector $sectorList FE $FEList det $detList pos $detPosList QR $QRList {
	set sectorf [format %02d $sector]
	if [regexp "DS" $pos] {
	    set usds ds
	} else {
	    set usds us
	}
	set XBPMTests(S${sectorf}P1${usds}.Norm.FE) $FE
	set XBPMTests(S${sectorf}P1${usds}.Norm.det$det.SN) SN$QR
    }

    if $loadParsOnly {
	return
    }
   
    set detList ""
    if {$bpm=="1"} {
	#XBPM1
	switch $frontEnd {
	    CFE {
		if {$usds=="us"} {
		    set detList {A B}
		} else {
		    set detList {C D}
		}
	    }
	    HHLFE {
		if {$usds=="ds"} {
		    set detList {A B}
		} else {
		    SetMainStatus "Sector=$sector XBPM1 HHLEF not available for us device."
		    return
		}
	    }
	}
	foreach det $detList {
	    set SN$det $XBPMTests(Norm.XBPM1.SN$det)
	    if {[set SN$det]=="NONE"} {
		SetMainStatus "Sector=$sector XBPM1 $usds detector$det Serial Number does not exist!"
		return
	    } else {
		SetMainStatus "S$sector XBPM1 detector $det serial number=[set SN$det]"
	    }
	}
    } else {
	#XBPM2
	set SN $XBPMTests(Norm.XBPM2.SN)
	if {$SN=="NONE"} {
	    SetMainStatus "Sector=$sector XBPM2  detector Serial Number does not exist!"
	    return
	}
    }
}

proc LoadNormalizationFactorsWidget {args} {
    global XBPMTests NormStatus
    set XBPMTests(Norm.sector) 25
    set XBPMTests(Norm.usds) us
    set XBPMTests(Norm.bpmType) 1
    
    set sectorList ""
    set commList ""
    for {set sector 1} {$sector<=35} {incr sector} {
	lappend sectorList [format %02d $sector]
	lappend commList "UpdateXBPMNormParameters -sector $sector"
    }
    
    APSDialogBox .norm -name "GRID-XBPM Dector Normalization Data" -cancelButton 0
    set NormStatus ""
    APSScrolledStatus .status -parent .norm.userFrame -textVariable NormStatus \
	-width 50 -height 6 -packOption "-fill both -expand true"
    APSRadioButtonFrame .sector -parent .norm.userFrame -limitPerRow 7 -label "Sector"  \
	-orientation horizontal -buttonList $sectorList -valueList $sectorList -variable XBPMTests(Norm.sector) \
	-commandList $commList
    UpdateXBPMNormParameters -loadParsOnly 1
    APSLabeledEntryFrame .det1 -parent .norm.userFrame -label "XBPM1 Dectors (A/B/C/D):" -width 15 \
	-variableList {XBPMTests(Norm.XBPM1.SNA) XBPMTests(Norm.XBPM1.SNB) XBPMTests(Norm.XBPM1.SNC) XBPMTests(Norm.XBPM1.SND)} \
	-orientation horizontal
    APSLabeledEntry .bpm2 -parent .norm.userFrame -label "XBPM2 detector:" -width 15 -textVariable XBPMTests(Norm.XBPM2.SN) 

    APSLabel .l1 -parent .norm.userFrame -text "XBPM paremeters for loading normalization factors."
    APSRadioButtonFrame .device -parent .norm.userFrame -label "Device:" -buttonList {us ds} -valueList {us ds} \
	-orientation horizontal -variable XBPMTests(Norm.usds) \
	-commandList {"UpdateXBPMNormParameters -usds us" "UpdateXBPMNormParameters -usds ds"}
    APSRadioButtonFrame .bpm -parent .norm.userFrame -label "XBPM:  " -buttonList {XBPM1 XBPM2} -valueList {1 2} \
	-orientation horizontal -variable XBPMTests(Norm.bpmType) \
	-commandList {"UpdateXBPMNormParameters -bpm 1" "UpdateXBPMNormParameters -bpm 2"}
    
    APSButton .show -parent .norm.userFrame -text "Show Calibration/Normalization Data" -command "LoadNormalizationFactors -dryRun 1"
    APSButton .load -parent .norm.userFrame -text "Load Normalization Data" -command "LoadNormalizationFactors -dryRun 0"
   
    return
    
}

proc LoadXYCalToXBPM1 {args} {
    set calFile ""
    set bpm ""
    APSParseArguments {calFile bpm}
    set tmpRoot /tmp/[APSTmpString]
    set cols [exec sddsquery -col $calFile]
    set sector [scan $bpm S%ld]
    set sectorf [format %02d $sector]
    set st [string range $bpm end-1 end]
    set pvroot S${sectorf}IDFE-XBPM:P1${st}:
    puts "$calFile $bpm"
    set fileList ""
    foreach col $cols {
	set name [regsub "xCalFactor" $col "XCal"]
	set name [regsub "xOffset" $name "XOff"]
	set name [regsub "yCalFactor" $name "YCal"]
	set name [regsub "yOffset" $name "YOff"]
	set name [regsub "Gap" $name ""]Gap
	if [catch {exec sddsconvert $calFile -pipe=out -retain=col,$col \
		       | sddsprocess -pipe=in $tmpRoot.$col "-redefine=col,Index,i_row 1 +,type=long" \
		       "-print=col,ControlName,${pvroot}${name}%dC,Index" -print=col,ValueString,%lf,$col } result] {
	    return -code error "Error creating $col file for $bpm: $result"
	}
	lappend fileList $tmpRoot.$col
	APSAddToTmpFileList -ID xbpm -fileList $tmpRoot.$col
    }
    APSAddToTmpFileList -ID xbpm -fileList $tmpRoot.$bpm
    puts $tmpRoot.$bpm
    if [catch {eval exec sddscombine $fileList -merge -pipe=out \
		   | tee $tmpRoot.$bpm \
		   | sddscasr -pipe=in -restore } result] {
	return -code error "Error loading XYcalibration for $bpm: $result"
    }
}

proc LoadDefaultCalibrationsToXBPM1 {args} {
    global XBPMTests
    
#The button [Load Default Calibration to Selected XBPM1] performs the following tasks for the selected XBPM1s:​

#    In HHLFE, find the undulator period xxmm of the device DSID, read file XbpmSetup/inputFiles/XYCal/Uxxmm-HHLFE-XBPM1-XYCal-Std.sdds and load the values to PV: SzzIDFE-XBPM:P1ds:GapnC, XCal1GapnC, XCal2GapnC, XOff1GapnC, XOff2GapnC, Wx1GapnC, Wx2GapnC, Wx3GapnC, YCal1GapnC, YCal2GapnC, YOff1GapnC, YOff2GapnC, Wy1GapnC, Wy2GapnC, Wy3GapnC, where n = 1, …, 32 are in Index column.​

#    In CFE, find the undulator period xxmm of the source USID, read file XbpmSetup/inputFiles/XYCal/Uxxmm-CFE-XBPM1-XYCal-Std.sdds and caput the values to PV: SzzIDFE-XBPM:P1us:GapnC, XCal1GapnC, XCal2GapnC, XOff1GapnC, XOff2GapnC, Wx1GapnC, Wx2GapnC, Wx3GapnC, YCal1GapnC, YCal2GapnC, YOff1GapnC, YOff2GapnC, Wy1GapnC, Wy2GapnC, Wy3GapnC, where n = 1, …, 32 are in Index column.​

#    Also in CFE, find undulator period xxmm of the source DSID, read file XbpmSetup/inputFiles/XYCal/Uxxmm-CFE-XBPM1-XYCal-Std.sdds and load the values to PV: SzzIDFE-XBPM:P1ds:*, …, Wy3GapnC, where n = 1, …, 32 are in Index column.​

    set initList [GetInitNormList]
    if ![llength $initList] {
	SetMainStatus "No BPM is chosen!"
	return
    }
    set calDir /home/helios/oagData/apsu/XbpmSetup/inputFiles/XYCal
    SetMainStatus "Saving SRXrayBPM SCR before loading default calibrations to XBPM1s.."
    if [catch {APSSaveMachine -machine SRXrayBPM -description "Save before loading default calibrations to XBPM1s..."} result] {
	return -code error "LoadDefaultCalibrationsToXBPM1(1): Error doing SCR save: $result"
    }
    
    foreach bpm $initList {
	set sector [scan $bpm S%ld]
	set sectorf [format %02d $sector]
	set st [string range $bpm end-1 end]
	set period [format %.1f $XBPMTests(S$sectorf.$st.period)]
	set FE $XBPMTests(S$sectorf.FE)
	set calFile $calDir/U${period}mm-${FE}-XBPM1-XYCal-Std.sdds
	if ![file exist $calFile] {
	    SetMainStatus "Error: $calFile does not exist, skip $bpm."
	    continue
	}
	SetMainStatus "Loading $calFile to $bpm..."
	if [catch {LoadXYCalToXBPM1 -calFile $calFile -bpm $bpm} result] {
	    return -code error "Error loadind default calibrations to $bpm: $result"
	}
    }
    SetMainStatus "Saving SRXrayBPM SCR after loading default calibrations to XBPM1s.."
    if [catch {APSSaveMachine -machine SRXrayBPM -description "Save after loading default calibrations to XBPM1s..."} result] {
	return -code error "LoadDefaultCalibrationsToXBPM1(1): Error doing SCR save: $result"
    }
    SetMainStatus "Loading default calibration factors to [join $initList ,] done."
}

proc LoadNormalizationFactors {args} {
    global XBPMTests GainFactor 
    set dryRun 1
    APSParseArguments {dryRun}
    
    global XBPMTests
    LoadXbpmGainFactor 
   
    set initList [GetInitNormList]
    foreach choice $initList {
	set sector [scan $choice S%ld]
	if [regexp "P1" $choice] {
	    set bpm 1
	} else {
	    set bpm 2
	}
	set usds [string range $choice end-1 end]
	set sectorf [format %02d $sector]
	if [lsearch -exact $XBPMTests(CUsectorList) $sectorf]<0 {
	    set FE HHLFE
	} else {
	    set FE CFE
	}
	switch $FE {
	    CFE {
		#SetMainStatus "Calling: LoadCFEXbpm${bpm}NormFactor"
		if [catch {LoadCFEXbpm${bpm}NormFactor -sector $sector -usds $usds \
			       -dryRun $dryRun} result] {
		    return -code error "Error loading CFE norm factor for $choice: $result"
		}
	    }
	    HHLFE {
		#SetMainStatus "Calling LoadHHLFEXbpm${bpm}NormFactor"
		if [catch {LoadHHLFEXbpm${bpm}NormFactor -sector $sector -usds $usds \
			       -dryRun $dryRun} result] {
		    return -code error "Error loading HHLEF norm factor for $choice: $result"
		}
	    }
	}
    }
    SetMainStatus "done."
}

proc CheckNetwork {args} {
    set xbpm ID
    APSParseArguments {xbpm}
    global XBPMTests
    
    set type $xbpm
    switch $xbpm {
	IDXBPM1 {
	    set unitList {CM1us CM2us CM3us CM1ds CM2ds CM3ds}
	    set xbpm ID
	    set type TetrAMM
	}
	IDXBPM2 {
	    set unitList {CM4us CM4ds}
	    set xbpm ID
	}
	BMFE -
	BM {
	    set unitList CM1
	    set xbpm BM
	    set type BMFE
	}
    }
    set count 0
    set failList ""
    for {set sector 1} {$sector<=35} {incr sector} {
	foreach unit $unitList {
	    set IP ""
	    set name S[format %02d $sector]${xbpm}FE-XBPM:$unit
	    if $XBPMTests($type.S[format %02d $sector]$unit) {
		if [info exist XBPMTests(TetrAMM.$name.IP)] {
		    set IP $XBPMTests(TetrAMM.$name.IP)
		} else {
		    SetMainStatus "No IP info for $name."
		}
	    }
	    if ![string length $IP] {
		continue
	    }
	    incr count
	    SetMainStatus "Checking network connection of $name (IP=$IP) ..."
	    if [catch {exec ping -c 5 $IP } result] {
		
	    }
	    after 5000
	    set alist [split $result "\n"]
	    if [regexp "error" $result] {
		SetMainStatus "Error connecting to $name ($IP): [lindex $alist end-1]"
		SetMainStatus "                                 [lindex $alist end]"
		lappend failList $name
	    } else {
		SetMainStatus "[lindex $alist end-1]"
		SetMainStatus "[lindex $alist end]"
		SetMainStatus "connection success."
	    }
	 }
     }
    if [llength $failList] {
	SetMainStatus "[join $failList] network checking failed."
    }
    if !$count {
	SetMainStatus "No unit is selected or no IP info available for selected item."
    } else {
	SetMainStatus "Network checking done."
    }
}

proc ReadConfig {args} {
    global XBPMTests
    set configFile $XBPMTests(tetrAMMLookupTable)
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddsprocess $configFile $tmpRoot "-match=col,FE=*ID,FE=*BM,|" } result] {
	return -code error "ReadConfig1:$result"	 
    }
    APSAddToTmpFileList -ID xbpm -fileList $tmpRoot
    set elementList [exec sdds2stream -col=ElementName $tmpRoot]
    set ipList [exec sdds2stream -col=IPAddress $tmpRoot]
    foreach element $elementList ip $ipList {
	set XBPMTests(TetrAMM.$element.IP) $ip
    }
}
SetDefaultDataFiles
ReadConfig

set mainStatus ""
proc SetMainStatus {text} {
    global mainStatus
    set mainStatus "[exec date]: $text"
    update
}

proc SetupIDTetrAMM {args} {
    set type TetrAMM
    APSParseArguments {type}

    global XBPMTests
    if {$type=="IDXBPM2"} {
	set unitList {CM4us CM4ds}
    } else {
	set unitList {CM1us CM2us CM3us CM1ds CM2ds CM3ds}
    }
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	
	set FE $XBPMTests(S$sectorf.FE)
	if {$type=="IDXBPM2" || $FE=="HHLFE"} {
	    set range 1
	} else {
	    set range 0
	}
	foreach unit $unitList {
	    if $XBPMTests($type.S$sectorf$unit) {
		SetMainStatus "Setup TetrAMM for ID S$sectorf$unit ..."
		if [catch {exec /home/helios/oagData/apsu/XbpmSetup/scripts/setTetrAMM-ID \
			       S${sectorf}IDFE-XBPM:$unit  $range 1667   0.1   0.1  } result] {
		    return -code error "Error setup S$sectorf $unit ID tetrAMM: $resul"
		}
	    }
	}
    }	 
    SetMainStatus "done."

}

proc GetIDXBPM2Selection {args} {
    global XBPMTests
    set choiceList ""
    for {set sector 1} {$sector<=35} {incr sector} {
	foreach item {CM4us CM4ds} {
	    set name S[format %02d $sector]$item
	    if $XBPMTests(IDXBPM2.$name) {
		lappend choiceList $name
	    }
	}
    }
    return $choiceList
}

proc SetIDXBPM2CalibrationFile {args} {
    global XBPMTests
    set sector ""
    set usds ""
    set regenerate 0
    APSParseArguments {sector usds regenerate}

    set sectorf [format %02d $sector]
    if [lsearch -exact $XBPMTests(CUsectorList) $sectorf]>=0 {
	set filename /home/helios/oagData/apsu/XbpmSetup/data/S${sectorf}ID/calibration/S${sectorf}ID-CFE-P2${usds}.sdds
	set origFile /home/helios/oagData/apsu/XbpmSetup/inputFiles/IDCFE-XBPM-P2${usds}-calibration.sdds
    } else {
	set filename  /home/helios/oagData/apsu/XbpmSetup/data/S${sectorf}ID/calibration/S${sectorf}ID-HHLFE-P2${usds}.sdds
	set origFile  /home/helios/oagData/apsu/XbpmSetup/inputFiles/IDHHLFE-XBPM-P2${usds}-calibration.sdds
    }
    set XBPMTests(IDXBPM2FEcalibrationFile) $filename
    exec cp $origFile $filename
    return
    #P2us:XCalC:Alias	CM4us:PositionScaleX
    #P2us:XOffC:Alias	CM4us:PositionOffsetX
    #P2us:YCalC:Alias	CM4us:PositionScaleY
    #P2us:YOffC:Alias	CM4us:PositionOffsetY
    # P2:XCalC:Alias	CM4ds:PositionScaleX
    #P2:XOffC:Alias	CM4ds:PositionOffsetX
    #P2:YCalC:Alias	CM4ds:PositionScaleY
    #P2:YOffC:Alias	CM4ds:PositionOffsetY
    
    if {![file exist $filename] || $regenerate} {
	SetMainStatus "Generating calibration file for $root XBPM2..."
	if [catch {GenerateIDXBPM2CalibrationFile -filename $filename -sector $sector -usds $usds} result] {
	    return -code error "Error generating cali file for $root: $result"
	}
	SetMainStatus "done."
    }
}

proc GenerateIDXBPM2CalibrationFile {args} {
    set filename ""
    set sector ""
    set usds ""
    APSParseArguments {filename sector usds}
    global CUsectorList
    set sectorf [format %02d $sector]
    set dir /home/helios/oagData/apsu/XbpmSetup/data/S${sectorf}ID/calibration
    if [lsearch -exact $CUsectorList $sectorf]>=0 {
	set calFile $dir/S${sectorf}ID-CFE-P2${usds}.sdds
    } else {
	set calFile  $dir/S${sectorf}ID-HHLFE-P2${usds}.sdds
    }
    
    set filename $dir/S${sectorf}ID-P2${usds}-calibration.sdds
    
    set root S[format %02d $sector]IDFE-XBPM
    set tmpRoot /tmp/[APSTmpString]
    set fileList ""
    #set nameList [list CM4${usds}:PositionScaleX CM4${usds}:PositionOffsetX CM4${usds}:PositionScaleY CM4${usds}:PositionOffsetY]
    set sectList [exec sdds2stream -col=Sector $calFile]
    set index 1
    set root S${sectorf}IDFE-XBPM:P2${usds}:
    set fileList ""
    foreach col {Gap P2:XCalC P2:XOffC P2:YCalC P2:YOffC} name {Gap XCalGap XOffGap YCalGap YOffGap}  {
	set pvList ""
	set valList [exec sdds2stream -col=$col $calFile]
	foreach sect $sectList {
	    lappend pvList ${root}${name}${sect}C
	}
	if [catch {exec sddsmakedataset $tmpRoot.$index -col=ControlName,type=string -data=[join $pvList ,] \
		       -col=ValueString,type=string -data=[join $valList ,] } result] {
	    return -code error "Error creating calibration file for S$sectorf ID P2: $result"
	}
	APSAddToTmpFileList -ID xbpm -fileList $tmpRoot.$index
	lappend fileList $tmpRoot.$index
	incr index
    }
    #puts $fileList
    if [catch {eval exec sddscombine $fileList -merge -over $filename } result] {
	return -code error "Error loading calibration for S$sectorf"
    }
    
    return $calFile
    
    foreach col {P2:XCalC P2:XOffC P2:YCalC P2:YOffC} name $nameList {
	
	if [catch {exec sddsprocess $origCalFile -pipe=out -filter=col,Sector,$sector,$sector \
		       | sddsprocess -pipe=in $tmpRoot.$col \
		       -process=Gap,first,GapValue \
		       -print=par,PVRoot,$root \
		       -print=col,Suffix,$name \
		       -print=col,ControlName,$root:$name \
		       -print=col,ValueString,%lf,$col } result] {
	    return -code error "Error creating calibration for $root: $result"
	}
	APSAddToTmpFileList -ID xbpm -fileList $tmpRoot.$col
	lappend fileList $tmpRoot.$col
    }
    if [catch {eval exec sddscombine $fileList -merge -over $filename } result] {
	return -code error "Error creating calibration file for $root: $result"
    }
}

proc SetupXBPM1Default {args} {
    global XBPMTests
    set choice $XBPMTests(InitCal.choice)
    set sector [scan $choice S%ld]
    set st [string range $choice end-1 end]
    set sectorf [format %02d $sector]
    set root S${sectorf}IDFE-XBPM
    if [lsearch -exact $XBPMTests(CUsectorList) $sectorf]>=0 {
	SetMainStatus "Set $choice CFE default..."
	SetMainStatus "/home/helios/oagData/apsu/XbpmSetup/scripts/setupXBPM1${st}-CFE $root 0"
	if [catch {exec /home/helios/oagData/apsu/XbpmSetup/scripts/setupXBPM1${st}-CFE $root 0} result] {
	    SetMainStatus "Error set default $root XBPM1 CFE: $result"
	}
    } else {
	SetMainStatus "Set $choice HHLFE default..."
	SetMainStatus " /home/helios/oagData/apsu/XbpmSetup/scripts/setupXBPM1${st}-HHLFE $root 0"
	if [catch {exec  /home/helios/oagData/apsu/XbpmSetup/scripts/setupXBPM1${st}-HHLFE $root 0} result] {
	    SetMainStatus "Error set default $root XBPM1 HHLFE: $result"
	}
    }
    SetMainStatus "done."
}

proc InitializeXBPM1 {args} {
    global XBPMTests
    set done 0
    for {set sector 1} {$sector<=35} {incr sector} {
	foreach item {us ds} {
	    set name S[format %02d $sector]P1$item
	    if !$XBPMTests(InitNorm.$name) {
		continue
	    }
	    set sectorf [format %02d $sector]
	    set root S${sectorf}IDFE-XBPM
	    if [lsearch -exact $XBPMTests(CUsectorList) $sectorf]>=0 {
		SetMainStatus "initializing $name CFE..."
		SetMainStatus "/home/helios/oagData/apsu/XbpmSetup/scripts/setupXBPM1${item}-CFE $root 1"
		if [catch {exec /home/helios/oagData/apsu/XbpmSetup/scripts/setupXBPM1${item}-CFE $root 1} result] {
		    SetMainStatus "Error initialize $root XBPM1 CFE: $result"
		}
	    } else {
		SetMainStatus "initializing $name HHLEF..."
		SetMainStatus " /home/helios/oagData/apsu/XbpmSetup/scripts/setupXBPM1${item}-HHLFE $root 1"
		if [catch {exec  /home/helios/oagData/apsu/XbpmSetup/scripts/setupXBPM1${item}-HHLFE $root 1} result] {
		    SetMainStatus "Error initialize $root XBPM1 CFE: $result"
		}
	    }
	    incr done
	}
    }
    if !$done {
	SetMainStatus " no item chosen!"
    } else {
	SetMainStatus "done."
    }
}
    
proc SetupIDXBPM2Default {args} {
    global XBPMTests
    set selectionList [GetIDXBPM2Selection]
    if ![llength $selectionList] {
	SetMainStatus "No XBPM2 selected."
	return
    }
    
    foreach item $selectionList {
	set sector [scan $item S%ld]
	set sectorf [format %02d $sector]
	if {[info exist done(S$sectorf)] && $done(S$sectorf)} {
	    continue
	}
	set root S${sectorf}IDFE-XBPM
	SetMainStatus "setup $root XBPM2..."
	if [lsearch -exact $XBPMTests(CUsectorList) $sectorf]>=0 {
	    if [catch { exec /home/helios/oagData/apsu/XbpmSetup/scripts/setupXBPM2-CFE $root } result] {
		SetMainStatus "Error setup $root CFE: $result"
	    }
	} else {
	    if [catch { exec /home/helios/oagData/apsu/XbpmSetup/scripts/setupXBPM2-HHLFE $root} result] {
		SetMainStatus "Error setup $root HHLFE: $result"
	    }
	}
	set done(S$sectorf) 1
	update
    }
    SetMainStatus "done."

}

proc SetupBMTetrAMM {args} {
    global XBPMTests
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	if $XBPMTests(BMFE.S${sectorf}CM1) {
	    SetMainStatus "Setup TetrAMM for S$sectorf BM..."
	    if [catch {exec /home/helios/oagData/apsu/XbpmSetup/scripts/setTetrAMM-BM \
			   S${sectorf}BMFE-XBPM:CM1   1  1667   0.1   0.1  } result] {
		return -code error "Error setup S$sectorf BM tetrAMM: $resul"
	    }
	}
    }	 
    SetMainStatus "done."
}

proc XbpmDAQInfo {args} {
    set xbpm ""
    APSParseArguments {xbpm}

    global XBPMTests
    
    APSDialogBox .daqinfo -name "$xbpm XBPM DAQ Info" -cancelButton 0
    
    APSButton .help -parent .daqinfo.userFrame -text "Help" -command "PrintHelpInfo -xbpm $xbpm"
	
    APSButton .check -parent .daqinfo.userFrame -text "Check Network Connection" -command "CheckNetwork -xbpm $xbpm"
    APSButton .froze -parent .daqinfo.userFrame -text "Detect Frozen IOC" -command "DetectFrozenTetra -xbpm $xbpm"
    
}



proc DetectFrozenTetra {args} {
    set xbpm ""
    APSParseArguments {xbpm}
    global XBPMTests
    if {$xbpm=="BMFE"} {
	set unitList CM1
	set xbpm BM
	set type BMFE
    }  else {
	if {$xbpm=="IDXBPM2"} {
	    set unitList {CM4us CM4ds}
	    set xbpm ID
	    set type IDXBPM2
	} else {
	    set unitList {CM1ds CM2ds CM3ds CM1us CM2us CM3us}
	    set type TetrAMM
	    set xbpm ID
	}
    }
    set count 0
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	foreach unit $unitList {
	    set name S$sectorf$unit
	    if $XBPMTests($type.$name) {
		incr count
		set tetraRoot  S${sectorf}${xbpm}FE-XBPM:$unit
		if [catch {exec /home/helios/oagData/apsu/XbpmSetup/scripts/checkFrozenTetrAMM  \
			       -RootPV $tetraRoot} result] {
		    SetMainStatus "Error checing frozen tetrAMM: $result"
		} else {
		    SetMainStatus "$tetraRoot frozen channels: [join $result]"
		}
	    }
	}	
    }
    if !$count {
	SetMainStatus "No unit selected."
    }
    SetMainStatus "done"
}

proc ReadIDUndulatorInfo {args} {
    global XBPMTests
    set IDinfo /home/helios/oagData/apsu/XbpmSetup/inputFiles/APSU-IDInfo.sdds
    foreach name {Sector usIDType usIDPeriod dsIDType dsIDPeriod usIDPeriod1 dsIDPeriod1}  {
	set ${name}List [exec sdds2stream -col=$name $IDinfo]
    }
    set FEList [exec sdds2stream -col=FrontEnd $IDinfo]
    foreach sector $SectorList FE $FEList {
	set XBPMTests(S[format %02d $sector].FE) $FE
    }
    set XBPMTests(badusList)  ""
    set XBPMTests(baddsList) ""
    foreach st {us ds} {
	set typeList [set ${st}IDTypeList] 
	set periodList [set ${st}IDPeriodList]
	set period1List [set ${st}IDPeriod1List]
	foreach sector $SectorList type $typeList period $periodList period1 $period1List {
	    if {$type=="NONE" || $period==0} {
		lappend XBPMTests(bad${st}List) $sector
		set XBPMTests(S[format %02d $sector].${st}Exist) 0
	    } else {
		set XBPMTests(S[format %02d $sector].${st}Exist) 1
	    }
	    set XBPMTests(S[format %02d $sector].${st}.period) $period
	    set XBPMTests(S[format %02d $sector].${st}.period1) $period1
	}
    }
}

proc SelectUndulators {args} {
    set wtype ""
    set undulatorType ""
    set varRoot ""
    APSParseArguments {wtype varRoot undulatorType}
    global XBPMTests
    if ![string length $varRoot] {
	set varRoot $wtype
    }
    if {$undulatorType=="all" || $undulatorType=="none"} {
	set value 1
	if {$undulatorType=="none"} {
	    set value 0
	}
	SelectAll -wtype $wtype -varRoot $varRoot -all $value
	return
    }
    switch $wtype {
	TetrAMM {
	    set itemList {CM1ds CM2ds CM3ds CM1us CM2us CM3us}
	}
	BMFE {
	    set itemList {CM1}
	}
	IDXBPM2 {
	    set itemList {CM4us CM4ds}
	}
	GapScan {
	    set itemList {P1us P1ds}
	}
	XYScan {
	    set itemList {P1us P1ds}
	}
	SaveRestore {
	    set itemList {P1us P1ds P2us P2ds BMCM1}
	}
	Init -
	InitCal {
	    set itemList {P1us P1ds}
	}
    }
    for {set sector 1} {$sector<=35} {incr sector} {
	set sectorf [format %02d $sector]
	if {[string compare $XBPMTests(S$sectorf.FE) "$undulatorType"]!=0} {
	    foreach item $itemList {
		set XBPMTests($varRoot.S${sectorf}$item) 0
	    }
	    continue
	}
	foreach item $itemList {
	    if {$wtype=="BMFE" && [lsearch -exact $XBPMTests(BMFEsectorList) $sectorf]<0 } {
		continue
	    } elseif {[regexp {P1} $item] || [regexp {P2} $item]} {
		if {([regexp "us" $item] && [lsearch -exact $XBPMTests(badusList) $sector]>=0) || \
			([regexp "ds" $item] && [lsearch -exact $XBPMTests(baddsList) $sector]>=0)} {
		    continue
		}
	    } elseif {[regexp "us" $item] && [lsearch -exact $XBPMTests(CUsectorList) $sectorf]<0} {
		continue
	    }
	    set XBPMTests($varRoot.S${sectorf}$item) 1
	}
    }
}

if {[wm geometry .] == "1x1+0+0"} {
wm geometry . +10+10
}

set tabList {DarkCurrent-Xbpm1 Calibration-XBPM1 XY-Scan GapScan IDXBPM2  BMFE SetupFiles}

APSApplication . -name APSUXbpmSetup -version 1 \
  -overview {This application is for APSU xray bpm tests and calibration.}

APSScrolledStatus .status -parent .userFrame -textVariable mainStatus \
	-width 90 -height 15 -packOption "-fill both -expand true"

set win .userFrame
ReadIDUndulatorInfo

set widgetList [APSTabFrame .tabs -parent $win -width 1000 -height 500 \
                  -labelList [join $tabList] -label ""]
CreateDarkCurrentWidgets .dark -parent [lindex $widgetList 0]
CreateInitWidgets .init -parent [lindex $widgetList 1]
CreateXYScanWidgets .scan -parent [lindex $widgetList 2]
CreateGapScanWidgets .gap -parent [lindex $widgetList 3]
CreateIDXBPM2FEWidgets .xbpm -parent [lindex $widgetList 4]
CreateBMFEWidgets .bmfe -parent [lindex $widgetList 5]
#CreateSaveRestoreWidgets .scr -parent [lindex $widgetList 6]
CreateDataFileWidgets .data -parent [lindex $widgetList 6]

foreach type {TetrAMM Weight SaveRestore IDXBPM2 InitNorm} {
    SetDefaultButtonsAndPars -type $type
}

#P1 distance from ID 3.23m
set XBPMTests(P1L) 3.23
set XBPMTests(P0L) 2.75
