#Not used
proc APSIDGoAndWait {args} {
    set ID ""
    set tolerance 0.05
    set timeout 10
    set retries 30
    APSStrictParseArguments {ID tolerance timeout retries}

    set suffix ""
    if [catch {exec cavget -pend=5 -list=${ID}:GapSetC -printErrors} setGap] {
        APSMpReturn error "APSIDGoAndWait1a: $setGap"
    }
    if {$setGap>50} {
	set closeGap 0
    } else {
	set closeGap 1
    }
    if [catch {APSCheckIDStatus -ID $ID -closeGap $closeGap} result] {
	APSMpReturn error "APSIDGoAndWait1: $result"
    }
    set errorMessage ""
    set upperLimit [expr $setGap+$tolerance]
    set lowerLimit [expr $setGap-$tolerance]
    
    while {$retries>0} {
        if [catch {exec cavput -pend=5 -list=${ID}:StartC=1} result] {
	    APSMpReturn error "APSIDGoAndWait3: Error moving $ID: $result"
	}
	after 1000
	if [catch {APSCheckIDStatus -ID $ID -closeGap $closeGap} result] {
	    APSMpReturn error "APSIDGoAndWait4: $result"
	}
	if [catch {exec cawait -interval=1 -timelimit=$timeout \
			 -waitFor=${ID}:GapM,lower=$lowerLimit,upper=$upperLimit} result] {
            set errorMessage "APSIDGoAndWait5: $result"
        } else {
            set errorMessage ""
            break
        }
        incr retries -1
    }
    if [catch {exec cavget -list=${ID}:GapM -pend=15 -printErrors} gap] {
        APSMpReturn error "APSIDGoAndWait6: $gap"
    }
    set diff [format %.3f [expr abs($setGap-$gap)]]
    if {$diff>$tolerance} {
        append errorMessage "\n$ID: the difference between gap setpoint and readback values is $diff > tolerance=$tolerance"
    }
    if [string length $errorMessage] {
        APSMpReturn error "$errorMessage"
    }
}

#Called by APSMpIDSetGapToMinimum and setIDSteeringAngles
proc APSIDsGoAndWait {args} {
    set IDList ""
    set tolerance 0.05
    set timeout 10
    set retries 30
    set confirm 0
    set statusCallback ""
    APSStrictParseArguments {IDList tolerance timeout retries confirm statusCallback}
    if [llength $IDList]==0 {
        APSMpReturn error "APSIDsGoAndWait(0): IDList is empty"
    }
    set errorMessage ""
    if [catch {exec cavget -list=[join $IDList ,] -list=:GapSetC -pend=5 -printErrors} setGapList0] {
	APSMpReturn error "APSIDsGoAndWait (1): $setGapList"
    }
    if [catch {exec cavget -list=[join $IDList ,] -list=:GapM -pend=5 -printErrors} gapList0] {
	APSMpReturn error "APSIDsGoAndWait (1): $gapList"
    }
    set IDList0 $IDList
    while {$retries>0} {
	set cawaitOptions ""
	set IDList ""
	foreach ID $IDList0 gapSet $setGapList0 gap $gapList0 {
	    if {$gap>=50 && $gapSet<50} {
		#close gap from above 50mm will trip the beam if shutter is closed
		set closeGap 1
	    } else {
		set closeGap 0
	    }
	    if [catch {APSCheckIDStatus -ID $ID -closeGap $closeGap} result] {
		if [string length $statusCallback] {
		    eval $statusCallback {"$result"}
		}
	    } else {
		lappend IDList $ID
	    }
	}
	
	if ![llength $IDList] {
	    break
	}
	if [catch {exec cavget -list=[join $IDList ,] -list=:GapSetC -pend=5 -printErrors} setGapList] {
	    APSMpReturn error "APSIDsGoAndWait (2): $setGapList"
	}
	set first 1
	foreach ID $IDList setGap $setGapList {
	    set upperLimit [expr $setGap+$tolerance]
	    set lowerLimit [expr $setGap-$tolerance]
	    lappend cawaitOptions -waitFor=${ID}:GapM,lower=$lowerLimit,upper=$upperLimit
	    if !$first {
		lappend cawaitOptions -and
	    }
	    set first 0
	}
	
        #sometimes Stop and then Start can fixed the stalled IDs
        if [catch {exec cavput -pend=5 -list=[join $IDList ,] -list=:StopC=1} result] {
            APSMpReturn error "APSIDsGoAndWait (3a): can not stop IDs: $result"
        }
        after 2000
        if [catch {exec cavput -pend=5 -list=[join $IDList0 ,] -list=:StartC=1} result] {
	    APSMpReturn error "APSIDsGoAndWait (3b): can not move IDs: $result"
	}
	after 1000
        if [catch {eval exec cawait -interval=1 -timelimit=$timeout \
		       $cawaitOptions} result] {
            set errorMessage "APSIDsGoAndWait (3): $result"
        } else {
            set errorMessage ""
            break
        }
        incr retries -1
    }
    if [catch {exec cavget -list=[join $IDList0 ,] -list=:GapM -pend=30 -printErrors} gapList0] {
        APSMpReturn error "APSIDsGoAndWait (4): $gapList"
    }
     if [catch {exec cavget -list=[join $IDList0 ,] -list=:GapSetC -pend=30 -printErrors} setGapList0] {
        APSMpReturn error "APSIDsGoAndWait (4): $gapList"
    }
    set first 1
    foreach ID $IDList0 setGap $setGapList0 gap $gapList0 {
        set diff [format %.3f [expr abs($setGap - $gap)]]
        if {$diff > $tolerance} {
            if {$first} {
                append errorMessage "\nThe difference between gap setpoint and readback of following IDs are greater than the tolerance($tolerance): "
            }
            append errorMessage "\n$ID: $diff"
            set first 0
        }
    }
    if [string length $errorMessage] {
        APSMpReturn error $errorMessage
    }
}

set apsIDSectorListMtime -1
set apsIDSectorListData ""
set apsBMSectorListMtime -1
set apsBMSectorListData ""
set apsAMSectorListMtime -1
set apsAMSectorListData ""
#Called by SR PEM, SRAMSteering and SRBMSteering
proc APSGetSourcePointSectors {args} {
    set numberFormat %ld
    set group ID
    APSStrictParseArguments {numberFormat group}

    switch $group {
        ID {
            set dirName /home/helios/oagData/sr/IDs
            set sectorsFile $dirName/sectors.sdds
        }
        BM {
            set dirName /home/helios/oagData/sr/BMs
            set sectorsFile $dirName/sectors.sdds
        }
        AM {
            set dirName /home/helios/oagData/sr/AMs
            set sectorsFile $dirName/sectors.sdds
        }
        default {
            APSMpReturn error "APSGetSourcePointSectors: Invalid group named."
        }
    }
    global apsIDSectorListData apsIDSectorListMtime
    global apsBMSectorListData apsBMSectorListMtime
    global apsAMSectorListData apsAMSectorListMtime
    set theTime [expr int([exec timeconvert -break=now])]

    if [string compare [file type $sectorsFile] link]==0 {
        set sectorsFile [file readlink $sectorsFile]
        if [string length [file dirname $sectorsFile]]<2 {
            set sectorsFile $dirName/$sectorsFile
        }
    }
    if ![file exists $sectorsFile] {
        APSMpReturn error "Unable to return $group sector list---file not found!"
    }
    set mtime [file mtime $sectorsFile]
    if {[subst \$aps${group}SectorListMtime]<0 || $mtime>[subst \$aps${group}SectorListMtime]} {
        if [catch {exec sdds2stream -column=Sector $sectorsFile} result] {
            APSMpReturn error "Unable to return ${group} sector list: $result"
        }
        set aps${group}SectorListData $result
        set aps${group}SectorListMtime $theTime
    }
    set returnList ""
    foreach elem [subst \$aps${group}SectorListData] {
        lappend returnList [format $numberFormat $elem]
    }
    return $returnList
}

#Called by SR PEM and SRBunchTrain
proc APSIDOpenAllGaps {} {
    if [catch {exec cavput -pendIOTime=5 -list=ID:OpenDevice=1} result] {
        APSMpReturn error "APSIDOpenAllGaps(cavput): $result"
    }
}

#Called by SR PEM
proc APSCheckRFPower {args} {
    if [catch {exec cavget -list=SRF: -list=K4,K3,K2,K1 -list=:ED1:Ch1KWatt -pend=20 -printErrors} valList] {
        APSMpReturn error "APSCheckRFSystem(1): $valList"
    }
    set message ""
    foreach pv {K4 K3 K2 K1} val $valList {
        if {$val>=735.0} {
            append message "$pv foward power is $val.\n"
        }
    }
    if [string length $message] {
        append message "\nThe klystron forward power is nearing the RF Group limit of 750kW."
        return $message
    }
    if [catch {exec cavget -list=SRF: -list=S40,S37,S36 -list=:AveragePowerM -pend=10 -printErrors} valList] {
        APSMpReturn error "APSCheckRFSystem(2): $valList"
    }
    foreach pv {S40 S37 S36} val $valList {
        if {$val>=89.0} {
            append message "$pv avecavity forward power is $val.\n"
        }
    }
    if [string length $message] {
        append message "\nThe average forward power is nearing the RF Group limit of 90kW."
    }
    return $message
}

#Called by SR PEM
proc APSIDStaggerGaps {args} {
    set IDList ""
    set interval 5
    set returnGaps 0
    APSStrictParseArguments {IDList interval returnGaps}
    if ![llength $IDList] {
        APSMpReturn ok
    }
    if $returnGaps {
        set ext CloseDeviceC
        set gapExt GapReturnM
    } else {
        set ext StartC
        set gapExt GapSetC
    }
    
    #Due to on-going restriction on the SR rf systems, we need the option to stagger the closing of the gaps by a selectable time interval T.
    #if N IDs are to be closed, the commands to start closing would be issued in a loop with a wait time of T, so that
    #issuing all the close commands would take (N-1)*T
    
    #special case for 2 ID, the ID2us has to be over 60mm before closing the ID2ds
    set procList ""
    set descList ""
    set index 1
    
    set IDList0 $IDList 
    #set scuList {ID01ds ID06ds ID07ds}
    #FIX THIS - No SCU in the APSU initially
    #set scuList {S01ID:DSID S06ID:DSID S07ID:DSID}
    set scuList {}
    set IDList ""
    foreach ID $IDList0 {
        if {[lsearch -exact $scuList $ID]>=0} {
            if [catch {exec cavget -list=$ID:$gapExt -pend=20 -printErrors} value] {
                APSMpReturn error "APSIDStaggerGaps1: Error reading $ID:$gapExt: $value"
            }
            set id$index [APSMpParallel -mode "Automatic" -procedure "APSSRMoveSCUID -ID $ID -moveTo $value"]
            lappend procList id$index
            lappend descList "moving $ID"
            incr index
        } elseif [regexp "S29ID" $ID] {
	    #IEX is different from other IDs (revisit here later)
	    
	} else {
            lappend IDList $ID
        }
    }
    
    if [llength $IDList] {
        set id$index [APSMpParallel -mode "Automatic" -procedure "APSIDMoveRegularGaps -IDList \"$IDList\" -interval $interval -returnGaps $returnGaps"]
        lappend procList id$index
        lappend descList "moving other gaps."
        incr index

    }
    foreach procID $procList desc $descList {
        APSMpStep "Running $desc"
        if [catch {APSMpJoin [set $procID]} results] {
            if {[APSPEMTKDialog .warningDialog -text "Problem occured $desc: $results"]==1} {
                APSMpReturn error "APSIDStaggerGaps3: $results"
            }
        } 
    }
    APSMpReturn ok
}

#Called by SR PEM
proc APSIDMoveRegularGaps {args} {
    set IDList ""
    set interval 5
    set returnGaps 0
    APSStrictParseArguments {IDList interval returnGaps}
    if ![llength $IDList] {
        APSMpReturn ok
    }
    if $returnGaps {
        set ext CloseDeviceC
    } else {
        set ext StartC
    }
    #Due to on-going restriction on the SR rf systems, we need the option to stagger the closing of the gaps by a selectable time interval T.
    #if N IDs are to be closed, the commands to start closing would be issued in a loop with a wait time of T, so that
    #issuing all the close commands would take (N-1)*T
    foreach ID $IDList {
        if [catch {APSCheckRFPower} result] {
            APSMpReturn error "APSIDMoveRegularGaps(1)- Error in checking RF power: $result"
        }
        if [string length $result] {
            set answer [APSMultipleChoice .info -modal 1 -name "SR RF power checking failed" \
                          -question "${result}\nDo you wish to continue or abort this procedure?" \
                          -labelList {Continue-at-your-own-risk Abort} \
                          -returnList {Continue Abort} ]
            if {$answer=="Abort"} {
                APSMpReturn error "APSIDMoveRegularGaps(2): aborted because:\n$result"
            }
        }
        if !$returnGaps {
            if [catch {exec cavget -list=$ID -list=:GapM,:GapSetC -printErrors} valList] {
                APSMpReturn error "APSIDMoveRegularGaps(3): $valList"
            }
            set gap [lindex $valList 0]
            set setgap [lindex $valList 1]
            if {[expr abs($gap-$setgap)]<=0.05} {
                continue
            }
        }
        if [catch {exec cavput -list=${ID}:${ext}=1} result] {
            set answer [APSMultipleChoice .warning -modal 1 -name "start moving gap failed" \
                          -question "move $ID gap failed:$result\nDo you wish to continue or abort?" \
                          -labelList {Continue-at-your-own-risk Abort} \
                          -returnList {Continue Abort}]
            if {$answer=="Abort"} {
                APSMpReturn error "APSIDMoveRegularGaps(4): $result"
            }
        }
        APSWaitWithUpdate -waitSeconds $interval -updateInterval 1
    }
    APSMpReturn ok
}

#Called by SRBunchTrain
proc APSIDReturnAllGaps {} {
    if [catch {exec cavput -pendIOTime=5 -list=ID:CloseDevice=1} result] {
        APSMpReturn error "APSIDReturnAllGaps: $result"
    }
}

#Called by SR PEM
#FIX THIS - the MotorDriveStatus PV name has changed
proc APSIDGetBadDeviceList {args} {
    set closeGap 0
    APSStrictParseArguments {closeGap}
    if $closeGap {
	#check PS1 shutter, if the PS1 shutter is closed, can not move gaps
	if [catch {exec sddsprocess /home/helios/oagData/sr/IDs/devices.sdds -pipe=out \
		       -print=col,ControlName,S%02dID-FEEPS:PS1:OpenedM,Sector \
		       | sddscasr -pipe -save -pend=20 -num \
		       | sddsprocess -pipe -scan=col,Value,ValueString,%lf \
		       | sddsprocess -pipe -filter=col,Value,-0.5,0.5 -nowarn \
		       | sdds2stream -pipe -col=DeviceName} dataList0] {
	    return -code error "APSIDGetDeviceList0: unable to get the PS1 shutter closed devices: $dataList0"
	}
    } else {
	set dataList0 ""
    }
    if [catch {exec sddsprocess /home/helios/oagData/sr/IDs/sectors.sdds -pipe=out \
		   -print=col,DeviceName,S%02dID:USID,Sector \
		   -print=col,ControlName,S%02dID:USID:MotorDriveStatusM,Sector \
		   -filter=col,Sector,29,29,! \
		   | sddscasr -pipe -save -pend=20 \
		   | sddsprocess -pipe -nowarnings -match=col,CAError=n \
		   -scan=col,Value,ValueString,%lf \
		   -filter=col,Value,-0.5,0.5 \
		   | sdds2stream -pipe -col=DeviceName} dataList1] {
	return -code error "APSIDGetDeviceList1a: $dataList1"
    }
    if [catch {exec sddsprocess /home/helios/oagData/sr/IDs/sectors.sdds -pipe=out \
		   -print=col,DeviceName,S%02dID:DSID,Sector \
		   -print=col,ControlName,S%02dID:DSID:MotorDriveStatusM,Sector \
		   -filter=col,Sector,29,29,! \
		   | sddscasr -pipe -save -pend=20 \
		   | sddsprocess -pipe -nowarnings -match=col,CAError=n \
		   -scan=col,Value,ValueString,%lf \
		   -filter=col,Value,-0.5,0.5 \
		   | sdds2stream -pipe -col=DeviceName} dataList2] {
	return -code error "APSIDGetDeviceList1b: $dataList2"
    }
    
    #include "system manager" mode also, because gap can not be moved in this mode.
    if [catch {exec sddsprocess /home/helios/oagData/sr/IDs/devices.sdds -pipe=out \
                 -edit=col,ControlName,DeviceName,ei/:AccessSecurityC/ \
                 | sddscasr -pipe -save -pend=20 -numerical  \
                 | sddsprocess -pipe -nowarnings -match=col,CAError=n \
                 -scan=col,Value,ValueString,%lf \
                 "-filter=col,Value,3,3" \
                 | sdds2stream -pipe -col=DeviceName} dataList3] {
	return -code error "APSIDGetDeviceList2: $dataList3"
    }
    #include "global busy"
    if [catch {exec sddsprocess /home/helios/oagData/sr/IDs/devices.sdds -pipe=out \
                 -edit=col,ControlName,DeviceName,ei/:GlobalBusyM/ \
                 | sddscasr -pipe -save -pend=20 -numerical  \
                 | sddsprocess -pipe -nowarnings -match=col,CAError=n \
                 -scan=col,Value,ValueString,%lf \
                 "-filter=col,Value,1,1" \
                 | sdds2stream -pipe -col=DeviceName} dataList4] {
	return -code error "APSIDGetDeviceList3: $dataList3"
    }
    set dataList [lsort -unique [concat $dataList0 $dataList1 $dataList2 $dataList3 $dataList4]]
    return [join $dataList]
}

#Called by SR PEM, setIDSteeringAngles and SRIDIntensityOptimization
#FIX THIS - the MotorDriveStatus PV name has changed
proc APSIDGetDeviceList {args} {
    set full 1
    set closeGap 0
    APSStrictParseArguments {full closeGap}
    set dataList [exec sdds2stream /home/helios/oagData/sr/IDs/devices.sdds -col=DeviceName]
    if !$full {
	set badList [APSIDGetBadDeviceList -closeGap $closeGap]
	if [llength $badList] {
	    foreach ID $badList {
		set index [lsearch -exact $dataList $ID]
		set dataList [lreplace $dataList $index $index]
	    }
	}
    }
    foreach item $dataList {
        lappend returnList [string trim $item]
    }
    return $returnList
}

#Called by SR PEM
#FIX THIS - the MotorDriveStatus PV name has changed
proc APSIDGetTaperDeviceList {args} {
    set full 1
    APSStrictParseArguments {full} 
    if $full {
        if [catch {exec sddsprocess /home/helios/oagData/sr/IDs/devices.sdds \
                     -pipe=out -filter=col,Taper,0.5,1.5 \
                     | sdds2stream -pipe -col=DeviceName } deviceList] {
            APSMpReturn error "APSIDGetTaperDeviceList: $deviceList"
        }
    } else {
	set IDList [APSIDGetDeviceList -full 0]
	set tmpRoot /tmp/[APSTmpString]
	if [catch {exec sddsmakedataset $tmpRoot.1 -col=DeviceName,type=string \
		       -data=[join $IDList ,] } result] {
	    APSMpReturn error "APSIDGetTaperDeviceList1: $result"
	}
	APSAddToTmpFileList -ID pem -fileList $tmpRoot.1
        if [catch {exec sddsselect /home/helios/oagData/sr/IDs/devices.sdds $tmpRoot.1 \
		       -pipe=out -match=DeviceName \
		       |  sddsprocess -pipe \
		       -filter=col,Taper,0.5,1.5 \
                     | sdds2stream -pipe -column=DeviceName} deviceList] {
            APSMpReturn error "$deviceList"
        }
    }
    foreach item $deviceList {
        lappend returnList [string trim $item]
    }
    return $returnList
}

#Called by SRBunchTrain
proc APSIDMinimumActualGap {} {
    set deviceList [APSIDGetDeviceList]
    if [catch {exec cavget -label -list=[join $deviceList ,] -list=:GapM -printErrors} gapList] {
        APSMpReturn error "APSIDMiniumActualGap: $gapList"
    }
    array set gapArray $gapList
    set minimum 1000
    set checked 0
    set PVName ""
    foreach elem [array names gapArray] {
        if {[string compare $gapArray($elem) ?] && 1==[scan $elem "S%02dID" IDNumber] } {
            incr checked
            # negative values of gap are false readings and should be ignored
            if {[expr $gapArray($elem) > 0] && 
                [expr $gapArray($elem)<$minimum]} {
                set minimum $gapArray($elem)
                set PVName $elem
            }
        }
    }
    if !$checked {
        APSMpReturn error "APSIDMiniumActualGap: No gaps returned."
    }
    scan $PVName "S%02dID" IDNumber
    return [list $minimum $IDNumber]
}

#Called by a bunch of programs
proc APSIDSectorList {args} {
    return [eval APSGetSourcePointSectors $args -group ID]
}

#Called by XrayBPMReview
proc APSBMSectorList {args} {
    return [eval APSGetSourcePointSectors $args -group BM]
}

# Changes gap access mode.  Returns previous mode list.
#Not used
proc APSIDControlGapAccess {args} {
    # newModes is a string of the form <pvName>=<value>[,<pvName>=<value>...]
    set newModes ""
    # newMode is either User or Operator
    set newMode ""
    set readOnly 1
    APSStrictParseArguments {newModes newMode readOnly}

    if {!$readOnly} {
        if {[string length $newModes] && [string length $newMode]} {
            APSMpReturn error \
              "APSIDControlGapAccess: give either -newModes or -newMode, not both."
        }
        if {[string length $newMode] && \
              [lsearch {User Operator} $newMode]==-1} {
            APSMpReturn error "APSIDControlGapAccess: -newMode invalid: $newMode"
        }
    }

    # get present ID security modes plus a list to use
    # for setting modes from the -newMode option, if given
    set deviceList [APSIDGetDeviceList]
    if [catch {exec cavget -pend=5 -label -list=[join $deviceList ,] \
                 -list=:AccessSecurityC -printErrors} accessList] {
        APSMpReturn error "APSIDControlGapAccess: $accessList"
    }
    set previousModeList ""
    set newModeList ""
    set indexLimit [llength $accessList]
    for {set index 0} {$index<$indexLimit} {incr index 2} {
        set value [lindex $accessList [expr $index+1]]
        if [string compare $value ?] {
            lappend previousModeList [lindex $accessList $index]=$value
            lappend newModeList [lindex $accessList $index]=$newMode
        }
    }
    if $readOnly {
        return [join $previousModeList ,]
    }

    if [string length $newModes] {
        if [catch {exec cavput -list=$newModes -pend=5} result] {
            APSMpReturn error "APSIDControlGapAccess: $result"
        }
    } else {
        if [catch {exec cavput -list=[join $newModeList ,] -pend=5} result] {
            APSMpReturn error "APSIDControlGapAccess: $result"
        }
    }
    return [join $previousModeList ,]
}

proc APSMpIDSwitchToMachinePhysicsModeInfo {} {
    return "Switch *all* IDs to machine physics mode, with optional opening of the gaps.  Intended to be run at the end of a user period."
}

proc APSMpIDSwitchToMachinePhysicsModeInitDialog {frame} {
    global APSMpIDSwitchToMachinePhysicsMode
    set APSMpIDSwitchToMachinePhysicsMode(openGaps) 1
    set APSMpIDSwitchToMachinePhysicsMode(restoreXbpmRefGaps) 0
    set APSMpIDSwitchToMachinePhysicsMode(closeInterval) 3
    label $frame.label -relief ridge -text "Warning!" -bg red -fg white
    pack $frame.label -side top -fill x
    message $frame.msg -relief ridge -justify center -bd 2 \
      -width 500 -text "You are about to switch all IDs to machine physics mode.\nBe certain this is what you want to do!\n"
    pack $frame.msg -side top -fill both -expand 1

    APSRadioButtonFrame .open -parent $frame -orientation horizontal \
      -variable APSMpIDSwitchToMachinePhysicsMode(openGaps) \
      -label "Open gaps?" \
      -buttonList "Yes No" -valueList "1 0" \
      -commandList {"set APSMpIDSwitchToMachinePhysicsMode(restoreXbpmRefGaps) 0" ""} \
      -contextHelp "Select whether or not to open the ID gaps.  User return values will be saved in any event."
    APSRadioButtonFrame .xref -parent $frame -orientation horizontal \
      -variable APSMpIDSwitchToMachinePhysicsMode(restoreXbpmRefGaps) \
      -commandList {"set APSMpIDSwitchToMachinePhysicsMode(openGaps) 0" ""} \
      -label "Restore xray bpm reference gaps?" \
      -buttonList "Yes No" -valueList "1 0" \
      -contextHelp "Select whether or not to restore xray bpm reference gaps."
    APSLabeledEntry .interval -parent $frame -textVariable APSMpIDSwitchToMachinePhysicsMode(closeInterval) \
      -label "Interval of closing gaps (seconds):" -width 20 \
      -contextHelp "Due to on-going restrictions on the SR rf systems, we need to tagger the closing of the gaps by a selectable time interval, i.e. issuing the next gap close command after T seconds of the previous one."
}

#Called by SR PEM
proc APSMpIDSwitchToMachinePhysicsMode {args} {
    set openGaps 0
    set restoreXbpmRefGaps 0
    set closeInterval 3
    APSStrictParseArguments {openGaps restoreXbpmRefGaps closeInteral}

    APSMpStep init -promptDialog APSMpIDSwitchToMachinePhysicsModeInitDialog \
      -vars "openGaps restoreXbpmRefGaps closeInterval"

    if {$openGaps && $restoreXbpmRefGaps} {
        APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode: open gaps and restore xray bpm reference gaps should  not be done at the same time."
    }
    tk_dialog2 .dialog "Warning" "Warning: This procedure takes about several minutes, please be patient." warning -1 OK
    foreach par {openGaps restoreXbpmRefGaps} {
        append paramString "$par=\"[set $par]\" "
    }
    catch {APSLogScriptAction \
             -procedure  APSMpIDSwitchToMachinePhysicsMode \
             -action initialize \
             -state ok \
             -parameters $paramString \
         }
    # Get a list of all the installed devices.
    set deviceList [APSIDGetDeviceList]
    set taperList [APSIDGetTaperDeviceList]
    #save snapshots before switching to machine physics mode"
    
    APSMpStep "Routine SCR Save before switching to machine physics mode."
    if [catch {APSSaveMachine -machine SR \
                 -description "Routine save: User gap setpoints before studies."} result] {
        APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(1 - SR user gap setpoints save before studies): $result"
    }
    APSMpStep "XrayBPM Save before switching to machine physics mode"
    if [catch {APSSaveMachine -machine SRXrayBPM \
                 -description "XrayBPM Save before switching to machine physics mode."} result] {
        APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(2 - SRXrayBPM save): $result"
    }
    
    if $openGaps {
        APSMpStep "Open gaps"
        if [catch {APSIDOpenAllGaps} result] {
            APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(4 - OpenAllGaps): $result"
        }
	after 60000
	set IDList [APSIDGetDeviceList -full 0 -closeGap 0]
        if {[catch {APSMpCheckAndWaitForIDs -deviceList $IDList} results]} {
            if {[APSPEMTKDialog .warningDialog -text "APSMpIDSwitchToMachinePhysicsMode(4a - wait for IDs open): Problem occurred while waiting restoring ID gaps\n$results"] == 1} {
                APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(4b): $results"
            }
        }

        APSMpStep "Change access mode"
        #changed to use global command for changing the access mode
        if [catch {exec cavput "-list=ID:AccessSecurity=Machine Physics" -pend=20} result] {
            if [catch {exec caput ID:AccessSecurity 2} result] {
                APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(5 - exec caput ID:AccessSecurity 2): $result"
            }
        }
        after 1000
        
	if [catch {APSSaveMachine -machine SR \
		       -description "Routine save: open gaps after switch to studies."} result] {
	    APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(5a - SR save): $result"
	}
        APSMpReturn ok
    }
    
    # If we make it here then the gaps are not to be opened.

    # Figure out which devices connect and what their access security state is.
    if [catch {exec cavget -pend=5 -printErrors -list=[join $deviceList ,] \
                 -list=:AccessSecurityC -num} accessValueList] {
        APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(6 - cavget): $accessList"
    }
    set problemList ""
    set userModeList ""
    set managerModeList ""
    foreach device $deviceList accessValue $accessValueList {
        if [string compare $accessValue ?]==0 {
            lappend problemList $device
        } elseif {$accessValue==3} {
            lappend managerModeList $device
        } else {
            lappend userModeList $device
            if [lsearch -exact $taperList $device]!=-1 {
                lappend userModeTaperList $device
            }
        }
    }
    
    if [llength $problemList] {
        # Allow user to abort if there are CA problems
        APSMpStep "Problem with CA for some devices"
        set abort [APSMultipleChoice [APSUniqueName .] -modal 1 \
                     -question "Problems with channel access for these devices:\n[join $problemList ,]\nWhat do you want to do?" \
                     -labelList "Abort Continue" \
                     -returnList "1 0"]
        if $abort {
            APSMpStep "Problem with CA---aborted by user" 
            APSMpReturn ok "Aborted by user request"
        }
    }
    if [llength $userModeList]==0 {
        APSMpReturn error "All devices are in manager mode"
    }
    
    set gaptolerance 0.1
    set tapertolerance 0.1
    APSMpStep "Get user gap values"
    if [catch {exec cavget -list=[join $userModeList ,] -list=:GapSetC -printErrors -pend=10} gapSetList] {
        APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(7 - cavget): $gapSetList"
    }
    if [catch {exec cavget -list=[join $userModeList ,] -list=:GapM -printErrors -pend=10} gapList] {
        APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(8 - cavget): $gapSetList"
    }
    set diffList ""
    foreach gap $gapList gapset $gapSetList pv $userModeList {
        set diff [expr abs($gap - $gapset)]
        if {$diff>$gaptolerance} {
            lappend diffList "[format %8s $pv]    $diff"
        }
    }
    if [llength $diffList] {
        APSAlertBox .warning -errorMessage "The difference of gap setpoint and readback values of following IDs are bigger than $gaptolerance:\n[format %8s ID]    difference\n[join $diffList \n]"
    }
    APSMpStep "Get user taper values"
    if [catch {exec cavget -list=[join $userModeTaperList ,] -list=:TaperGapSetC -pend=10 -printErrors} taperSetList] {
        APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(9 - cavget): $taperSetList"
    }
    if [catch {exec cavget -list=[join $userModeTaperList ,] -list=:TaperGapM -pend=10 -printErrors} taperList] {
        APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(10 - cavget): $taperSetList"
    }
    set diffList ""
    foreach taper $taperList taperset $taperSetList pv $userModeTaperList {
        
        set diff [expr abs($taper - $taperset)]
        if {$diff>$tapertolerance} {
            lappend diffList "[format %8s $pv]    $diff"
        }
    }
    if [llength $diffList] {
        APSAlertBox .warning -errorMessage "The difference of taper setpoint and current taper values of following IDs are bigger than $tapertolerance:\n[format %8s ID]    difference\n[join $diffList \n]"
    }
    APSMpStep "Send user gap and taper values to return PVs"
    set list1 ""
    set list2 ""
    foreach device $userModeList gap $gapSetList {
        lappend list1 $device=$gap
    }
    foreach device $userModeTaperList taper $taperSetList {
        lappend list2 $device=$taper
    }
    if [catch {exec cavput -list=[join $list1 ,] -list=:GapReturnM
        exec cavput -list=[join $list2 ,] -list=:TaperGapReturnM} result] {
        APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(11 - cavput): $result"
    }
    #FIX THIS - No SCUs with the APSU initially
    if {0} {
        #for SCU1 and SCU0 do current return
        if [catch {APSSetSCUCurrentReturnValues } result] {
            APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(11a Error in setting SCU current returns): $result"
        }
    }
    after 1000
    APSMpStep "Set saved access mode to User"
    if [catch {exec cavput -list=[join $userModeList ,] -list=:SaveAccess_=User} result] {
        APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(12 - cavput): $result"
    }
    after 1000

    APSMpStep "Set global access security mode to Machine Physics"
    if [catch {exec cavput -list=[join $deviceList ,] \
                 "-list=:AccessSecurityC=Machine Physics"} result] {
        APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(13 - cavput): $result"
    }
    after 1000
    
    APSMpStep "Set flags to inhibit saving user return gaps"
    if [catch {exec cavput -list=[join $deviceList ,] -list=:OpenFlagM=1} result] {
        APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(14 - cavput): $result"
    }
    
    after 10000
    APSMpStep "Routine SCR Save after switching to machine physics mode."
    if [catch {APSSaveMachine -machine SR \
                 -description "Routine save: User gap setpoints after switch to studies."} result] {
        APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(15 - SR save): $result"
    }

    if $restoreXbpmRefGaps {
        APSMpStep "Restore xbpm reference gaps. (it may take several minutes, please be patient)."
      
        if [catch {APSMpIDRestoreGaps -gapfile XbpmRefGaps -wait 1 -confirm 0 -switchToMachinePhysics 0 -closeInterval $closeInterval} result] {
            set abort [APSMultipleChoice [APSUniqueName .] -modal 1 -question "Problem during restore xbpm reference gaps:\n $result\nWhat do you want to do?" \
                         -labelList "Abort Continue" \
                         -returnList "1 0"]            
            if $abort {
                APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(16): problem with restore xbpm gaps): $result"
            }
        }
        APSMpStep "Routine SRXrayBPM Save after switching to machine physics mode and restoring xbpm reference gaps."
        if [catch {APSSaveMachine -machine SRXrayBPM \
                     -description "15mm Gaps."} result] {
            APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(17 - SRXrayBPM save): $result"
        }
        APSMpStep "Routine SR Save after switching to machine physics mode and restoring xbpm reference gaps."
        if [catch {APSSaveMachine -machine SR \
                     -description "15mm Gaps."} result] {
            APSMpReturn error "APSMpIDSwitchToMachinePhysicsMode(18 - SR save): $result"
        }
    }
    
    APSMpReturn ok
}

proc APSMpIDTransferSettingsToReturnValuesInfo {} {
    return "Transfers the present values of ID gap and taper to the user's return values.  This means that when the gap close command is issued, the gap will go to these values.  You will have the opportunity to choose individual IDs on which to perform this action."
}

proc APSMpIDTransferSettingsToReturnValuesInitDialog {frame} {
    global APSMpIDTransferSettingsToReturnValues
    set deviceList0 [lsort [array names APSMpIDTransferSettingsToReturnValues]]
    foreach item $deviceList0 {
        if [string match ID* $item] {
            lappend deviceList $item
            lappend variableList APSMpIDTransferSettingsToReturnValues($item)
        }
    }
    
    APSCheckButtonFrame .cb -parent $frame -label "Choose IDs" \
      -limitPerRow 8 -buttonList "$deviceList" \
      -variableList "$variableList" -orientation horizontal -allNone 1 
}

#Called by SR PEM
proc APSMpIDTransferSettingsToReturnValues {args} {
    # transfer gap and taper setpoints to return values
    set fullDeviceList [APSIDGetDeviceList]
    set deviceList $fullDeviceList
    APSStrictParseArguments {deviceList}

    foreach item $fullDeviceList {
        if [lsearch -exact $deviceList $item]!=-1 {
            set $item 1
        } else {
            set $item 0
        }
    }

    APSMpStep init -promptDialog APSMpIDTransferSettingsToReturnValuesInitDialog \
      -vars "$fullDeviceList"
    
    foreach par $fullDeviceList {
        append paramString "$par=\"[set $par]\" "
    }
    catch {APSLogScriptAction \
             -procedure   APSMpIDTransferSettingsToReturnValues  \
             -action initialize \
             -state ok \
             -parameters $paramString \
         }
    
    set deviceList ""
    foreach item $fullDeviceList {
        if [set $item] {
            lappend deviceList $item
        }
    }
    if ![llength $deviceList] {
        APSMpStep "No devices selected"
        APsMpReturn ok
    }

    APSMpStep "Devices selected: $deviceList"

    APSMpStep "Get present gap values"
    if [catch {exec cavget -list=[join $deviceList ,] -list=:GapSetC -pend=10 -printErrors} gapSetList] {
        APSMpReturn error "APSMpIDTransferSettingsToReturnValues: $gapSetList"
    }

    APSMpStep "Get present taper values"
    set taperFullDeviceList [APSIDGetTaperDeviceList]
    set taperDeviceList ""
    foreach device $taperFullDeviceList {
        if [lsearch -exact $deviceList $device]!=-1 {
            lappend taperDeviceList $device
        }
    }
    if [catch {exec cavget -list=[join $taperDeviceList ,] -list=:TaperGapSetC -pend=10 -printErrors} taperSetList] {
        APSMpReturn error "APSMpIDTransferSettingsToReturnValues: $taperSetList"
    }
    foreach device $deviceList gap $gapSetList {
        lappend returnList $device:GapReturnM=$gap
    }
    foreach device $taperDeviceList taper $taperSetList {
        lappend returnList $device:TaperGapReturnM=$taper
    }
    APSMpStep "Set access to user mode"
    if [catch {exec cavput -list=[join $deviceList ,] -list=:AccessSecurityC=User} result] {
        APSMpReturn error "APSMpIDTransferSettingsToReturnValues: $result"
    }
    after 1000

    APSMpStep "Send values to return values"
    if [catch {exec cavput -list=[join $returnList ,]} result] {
        APSMpReturn error "APSMpIDTransferSettingsToReturnValues: $result"
    }
    after 1000
    
    APSMpReturn ok
}

#Called by APSMpIDSwitchToMachinePhysicsMode and APSMpIDTransferSettingsToReturnValues
#FIX THIS - I don't know what the PV names should be
#Not used for the APSU initally
proc APSSetSCUCurrentReturnValues {args} {
    if [catch {exec cavget -list=ID01ds,ID06ds -list=:MainCurrentSet -pend=20} result] {
        return -code error "APSSetSCUCurrentReturnValues (Error reading SCU1 and SCU0 current set): $result"
    }
    set ID01dsCurr [lindex $result 0]
    set ID06dsCurr [lindex $result 1]
    if [catch {exec cavput -list=ID01ds:CurrentReturn=$ID01dsCurr,ID06ds:CurrentReturn=$ID06dsCurr -pend=30} result] {
        return -code error "APSSetSCUCurrentReturnValues (Error set SCU1 and SCU0 current return): $result"
    }
}

proc APSMpIDSwitchToUserModeInfo {} {
    return "Switch *all* IDs to user mode, with optionally returning of the gaps.  This is normally used just before returning the machine to user mode."
}

proc APSMpIDSwitchToUserModeInitDialog {frame} {
    global APSMpIDSwitchToUserMode
    set APSMpIDSwitchToUserMode(returnGaps) 1
    set APSMpIDSwitchToUserMode(closeInterval) 1
    set APSMpIDSwitchToUserMode(setupCerenkov) 0
    label $frame.label -relief ridge -text "Warning!" -bg red -fg white
    pack $frame.label -side top -fill x
    message $frame.msg -relief ridge -justify center -bd 2 \
      -width 500 -text "You are about to switch all IDs to user mode.\nBe certain this is what you want to do!\n"
    pack $frame.msg -side top -fill both -expand 1

    APSRadioButtonFrame .open -parent $frame -orientation horizontal \
      -variable APSMpIDSwitchToUserMode(returnGaps) \
      -label "Return gaps?" \
      -buttonList "Yes No" -valueList "1 0" \
      -contextHelp "Select whether or not to return the ID gaps."
    APSRadioButtonFrame .ceren -parent $frame -orientation horizontal \
      -variable APSMpIDSwitchToUserMode(setupCerenkov) -label "Setup Cerenkov detector?"  \
      -buttonList "Yes No" -valueList "1 0" \
      -contextHelp "Select whether or not to setup Cerenkov detectors."
    APSLabeledEntry .interval -parent $frame -textVariable APSMpIDSwitchToUserMode(closeInterval) \
      -label "Interval of closing gaps (seconds):" -width 20 \
      -contextHelp "Due to on-going restrictions on the SR rf systems, we need to tagger the closing of the gaps by a selectable time interval, i.e. issuing the next gap close command after T seconds of the previous one."
}

#Called by SR PEM
proc APSMpIDSwitchToUserMode {args} {
    set returnGaps 1
    set closeInterval 3
    set setupCerenkov 1
    APSStrictParseArguments {returnGaps closeInterval setupCerenkov}

    APSMpStep init -promptDialog APSMpIDSwitchToUserModeInitDialog \
      -vars {returnGaps closeInterval setupCerenkov}
    set deviceList [APSIDGetDeviceList]
    
    catch {APSLogScriptAction \
             -procedure  APSMpIDSwitchToUserMode \
             -action initialize \
             -state ok \
             -parameters "returnGaps=$returnGaps" \
         }
    #save snapshots before switching to user mode"
    APSMpStep "Routine SCR Save before switching to user mode."
    if [catch {APSSaveMachine -machine SR \
                 -description "Routine save: gap setpoints before switching to user mode."} result] {
        APSMpReturn error "APSMpIDSwitchToUserMode(1 - SR routine save): $result"
    }
    APSMpStep "XrayBPM Save before switching to user mode"
    if [catch {APSSaveMachine -machine SRXrayBPM \
                 -description "XrayBPM Save before switching to user mode."} result] {
        APSMpReturn error "APSMpIDSwitchToUserMode(2 - SRXrayBPM save): $result"
    }
    APSMpStep "Change access mode"
    #set to machine physics and then set to user mode later so that the global close can take effect.
    if [catch {exec cavput -list=ID:AccessSecurity=2 -pend=20} result] { 
        if [catch {exec caput ID:AccessSecurity 2 } result] {
            APSMpReturn error "APSMpIDSwitchToUserMode(3 - exec caput ID:AccessSecurity 2): $result"
        }
    }
    after 1000
    
    if [catch {exec cavput -list=ID:AccessSecurity=User -pend=20} result] {
        if [catch {exec caput ID:AccessSecurity 0 } result] {
            APSMpReturn error "APSMpIDSwitchToUserMode(4 - exec caput ID:AccessSecurity 0): $result"
        }
    }
    
    #ID29 IEX
    if [catch {exec cavput -list=S29ID:AccessSecurityC=User -pend=20} result] {
	if [catch {exec cavput -list=S29ID:AccessSecurityC=0 -pend=20 } result] {
	    APSMpReturn error "APSMpIDSwitchToUserMode(4b - exec caput S29ID:AccessSecurityC 0): $result"
	}
    }
    
    after 1000

    if $returnGaps {
        APSMpStep "Return gaps"
        set deviceList [APSIDGetDeviceList -full 0 -closeGap 1]
        #Due to on-going restriction on the SR rf systems, we need the option to stagger the closing of the gaps by a selectable time interval T.
        APSMpStep "$deviceList"
        if [catch {APSIDStaggerGaps -IDList $deviceList -interval $closeInterval -returnGaps 1} result] {
            APSMpReturn error "APSMpIDSwitchToUserMode(14a): Error in close gaps with staggering: $result"
        }
        APSMpStep "waiting for 60 seconds..."
        after 60000
	APSMpStep "checking ID gaps..."
	if {[catch {APSMpCheckAndWaitForIDs -deviceList $deviceList} results]} {
            if {[APSPEMTKDialog .warningDialog -text "APSMpIDSwitchToUserMode(14a - wait for IDs return user gaps): Problem occurred while waiting restoring ID gaps\n$results"] == 1} {
                APSMpReturn error "APSMpIDSwitchToUserMode(14a): $results"
            }
        }
    } else {
        set taperList [APSIDGetTaperDeviceList]
        set deviceList [APSIDGetDeviceList]
        set tmpfile /tmp/[APSTmpString]
        set gaptolerance 0.05
        set tapertolerance 0.015
        APSMpStep "Checking gap/taper setpoint and value difference..."
        APSAddToTmpFileList -ID 1 -fileList "$tmpfile.taper $tmpfile.gap $tmpfile.gapdiff $tmpfile.gapdiff"
        if [catch {exec cavget -list=[join $taperList ,] \
                     -list=:TaperGapM -pend=30 -printErrors} taperVal ] {
            APSMpReturn error "APSMpIDSwitchToUserMode(6 - cavget): Error in getting TaperGap Value: $taperVal"
        }
        if [catch {exec cavget -list=[join $taperList ,] \
                     -list=:TaperGapSetC -pend=30 -printErrors} taperSet ] {
            APSMpReturn error "APSMpIDSwitchToUserMode(7 - cavget): Error in getting TaperGapSet Value: $taperSet"
        }
        if [catch {exec cavget -list=[join $deviceList ,] \
                     -list=:GapM -pend=30 -printErrors} gapVal ] {
            APSMpReturn error "APSMpIDSwitchToUserMode(8 - cavget): Error in getting Gap Value: $gapVal"
        }
        if [catch {exec cavget -list=[join $deviceList ,] \
                     -list=:GapSetC -pend=30 -printErrors} gapSet ] {
            APSMpReturn error "APSMpIDSwitchToUserMode(9 - cavget): Error in getting GapSet Value: $gapSet"
        }
        if [catch {exec sddsmakedataset -pipe=out \
                     -col=DeviceName,type=string -data=[join $deviceList ,] \
                     -col=Gap,type=double -data=[join $gapVal ,] \
                     -col=GapSet,type=double -data=[join $gapSet ,] \
                     -col=ValueString,type=string -data=[join $gapSet ,] \
                     | tee $tmpfile.gap \
                     | sddsprocess -pipe \
                     "-define=col,GapDiff,Gap GapSet - abs" \
                     | sddsprocess -pipe=in $tmpfile.gapdiff \
                     "-filter=col,GapDiff,0,$gaptolerance,!" -nowarnings } result] {
            APSMpReturn error "APSMpIDSwitchToUserMode(10 - sddsmakedataset): $result"
        }
        if [catch {exec sddsmakedataset -pipe=out \
                     -col=DeviceName,type=string -data=[join $taperList ,] \
                     -col=Taper,type=double -data=[join $taperVal ,] \
                     -col=TaperSet,type=double -data=[join $taperSet ,] \
                     -col=ValueString,type=string -data=[join $taperSet ,] \
                     | tee $tmpfile.taper \
                     | sddsprocess -pipe \
                     "-define=col,TaperDiff,Taper TaperSet - abs" \
                     | sddsprocess -pipe=in $tmpfile.taperdiff \
                     "-filter=col,TaperDiff,0,$tapertolerance,!" -nowarnings } result] {
            APSMpReturn error "APSMpIDSwitchToUserMode(11 - sddsmakedataset): $result"
        }
        set gapdiffs [exec sdds2stream $tmpfile.gapdiff -rows=bare]
        set taperdiffs [exec sdds2stream $tmpfile.taperdiff -rows=bare]
        if $gapdiffs {
            set gapList [exec sdds2stream $tmpfile.gapdiff -col=DeviceName]
            set answer [APSMultipleChoice [APSUniqueName .] -modal 1 -name Warning \
                          -question "The difference of gap setpoint and current gap values of [join $gapList ,] are bigger than $gaptolerance, Continue or abort?" \
                          -returnList {Continue Abort} -labelList {Continue Abort} ]
            
            if {$answer=="Abort"} {
                APSMpReturn error "APSMpIDSwitchToUserMode(12): Setting gap/taper values was aborted due to mis-match of gap setpoint and value!"
            }
        }
        if $taperdiffs {
            set taperList [exec sdds2stream $tmpfile.taperdiff -col=DeviceName]
            set answer [APSMultipleChoice [APSUniqueName .] -modal 1 -name Warning \
                          -question "The difference of taper setpoint and current taper values of [join $taperList ,] are bigger than $tapertolerance, Continue or abort?"\
                          -returnList {Continue Abort} -labelList {Continue Abort}]
            
            if {$answer=="Abort"} {
                APSMpReturn error "APSMpIDSwitchToUserMode(13): Setting gap/taper return values was aborted due to mis-match of taper setpoint and value!"
            }
        }
        APSMpStep "Setting gap/taper return values to gap/taper values"
        if [catch {exec sddsprocess $tmpfile.gap \
                     -edit=col,ControlName,DeviceName,ei/:GapReturnM/ \
                     -pipe=out \
                     | sddscasr -restore -pipe=in 
            exec sddsprocess $tmpfile.taper \
                     -edit=col,ControlName,DeviceName,ei/:TaperGapReturnM/ \
                     -pipe=out \
                     | sddscasr -restore -pipe=in } result] {
            APSMpReturn error "APSMpIDSwitchToUserMode(14 - sddscasr): Error in setting GapReturn and TaperGapReturn: $result"
        }
    }
    APSMpStep "Routine SCR Save after switching to user mode."
    if [catch {APSSaveMachine -machine SR \
                 -description "Routine save: gap setpoints after switching to user mode."} result] {
        APSMpReturn error "APSMpIDSwitchToUserMode(16 - SR save): $result"
    }
    APSMpStep "XrayBPM Save after switching to user mode"
    if [catch {APSSaveMachine -machine SRXrayBPM \
                 -description "XrayBPM Save after switching to user mode."} result] {
        APSMpReturn error "APSMpIDSwitchToUserMode(17 - SRXrayBPM save): $result"
    }
    if $setupCerenkov {
        APSMpStep "Setup Cerenkov detectors."
        if [catch {APSSetupSRCerenkovDector} result] {
            APSMpReturn error "APSMpIDSwitchToUserMode(17a - setup Cerenkov detectors): $result"
        }
    }
    after 1000
    APSMpReturn ok
}

proc APSMpIDRestoreUserGapsInfo {} {
    return "Generally, you would use this only if you have a problem with one or more gap values.  It restores selected user gap values from an SCR file and sets the devices to user mode. Restores the gap setpoints and the user return values.  Optionally moves the gaps to the setpoints or return values."
}

proc APSMpIDRestoreUserGapsInitDialog {frame} {
    global APSMpIDRestoreUserGaps
    set APSMpIDRestoreUserGaps(closeInterval) 3
    set deviceList0 [lsort [array names APSMpIDRestoreUserGaps]]
    foreach item $deviceList0 {
        if [string match ID* $item] {
            lappend deviceList $item
            lappend variableList APSMpIDRestoreUserGaps($item)
        }
    }
    APSCheckButtonFrame .cb -parent $frame -label "Choose IDs" \
      -limitPerRow 8 -buttonList "$deviceList" \
      -variableList "$variableList" -orientation horizontal -allNone 1 
    APSRadioButtonFrame .sp -parent $frame -orientation horizontal \
      -variable APSMpIDRestoreUserGaps(gapsToSetpoints) \
      -label "Move gaps to setpoint?" \
      -buttonList "Yes No" -valueList "1 0" \
      -commandList {"set APSMpIDRestoreUserGaps(gapsToReturnValues) 0" ""} \
      -contextHelp "Select whether or not to move the ID gaps to the setpoints."
    APSRadioButtonFrame .rv -parent $frame -orientation horizontal \
      -variable APSMpIDRestoreUserGaps(gapsToReturnValues) \
      -label "Move gaps to user return value?" \
      -buttonList "Yes No" -valueList "1 0" \
      -commandList {"set APSMpIDRestoreUserGaps(gapsToSetpoints) 0" ""} \
      -contextHelp "Select whether or not to move the ID gaps to the user return value. This is supposedly where the user wanted the gap."
    APSLabeledEntry .interval -parent $frame -textVariable APSMpIDRestoreUserGaps(closeInterval) \
      -label "Interval of closing gaps (seconds):" -width 50 \
      -contextHelp "Due to on-going restrictions on the SR rf systems, we need to tagger the closing of the gaps by a selectable time interval, i.e. issuing the next gap close command after T seconds of the previous one."
    APSAddSCRDialog .scr -parent $frame -system SR -arrayName APSMpIDRestoreUserGaps \
      -defaultFile $APSMpIDRestoreUserGaps(ShortFilename)
}

#Called by SR PEM
proc APSMpIDRestoreUserGaps {args} {
    set fullDeviceList [APSIDGetDeviceList]
    set deviceList $fullDeviceList
    set closeInterval 3
    APSStrictParseArguments {deviceList closeInterval}

    foreach item $fullDeviceList {
        if [lsearch -exact $deviceList $item]!=-1 {
            set $item 1
        } else {
            set $item 0
        }
    }
    set gapsToSetpoints 1
    set gapsToReturnValues 0
    set ShortFilename ""

    APSMpStep init -promptDialog APSMpIDRestoreUserGapsInitDialog \
      -desc "Choose devices and SCR file" \
      -vars "$fullDeviceList ShortFilename gapsToSetpoints gapsToReturnValues closeInterval"

    if ![string length $ShortFilename] {
        APSMpReturn error "APSMpIDRestoreUserGaps: No file chosen."
    }
    set varList "$fullDeviceList ShortFilename gapsToSetpoints gapsToReturnValues"
    foreach par $varList {
        append paramString "$par=\"[set $par]\" "
    }
    catch {APSLogScriptAction \
             -procedure  APSMpIDRestoreUserGaps \
             -action initialize \
             -state ok \
             -parameters $paramString \
         }
    set fullFilename /home/helios/oagData/SCR/snapshots/SR/$ShortFilename
    if {[string length $ShortFilename] && ![file exists $fullFilename]} {
        APSMpReturn error "APSMpIDRestoreUserGaps: SCR file $ShortFilename not found"
    }
    set first 1
    set deviceList ""
    set matchOpt ""
    foreach device $fullDeviceList {
        if {[set $device]} {
            lappend deviceList $device
            if $first {
                set first 0
                set matchOpt -match=column,ControlName=$device:*
            } else {
                set matchOpt $matchOpt,ControlName=$device:*,|
            }
        }
    }
    if ![llength $deviceList] {
        APSMpStep "No devices selected"
        APsMpReturn ok
    }
    #get the mode before changing it
    if [catch {exec cavget -list=[join $deviceList ,] -list=:AccessSecurityC -numerical \
                 -pend=30 -printErrors} origList] {
        APSMpReturn error "APSMpIDRestoreUserGaps: $origList"
    }
    if [catch {exec cavget -list=[join $deviceList ,] -list=:BusyM -numerical \
                 -pend=30 -printErrors} busyList] {
        APSMpReturn error "APSMpIDRestoreUserGaps: $busyList"
    }
    set cavputList ""
    foreach device $deviceList val $origList busy $busyList {
        lappend cavputList ${device}:AccessSecurityC=$val
    }
    APSMpStep "Set devices to user mode"
    if [catch {exec cavput -list=[join $deviceList ,] -list=:AccessSecurityC=User} result] {
        APSMpReturn error "APSMpIDRestoreUserGaps: $result"
    }
    after 1000
    
    APSMpStep "Prepare device values"
    set tmpFile /tmp/[APSTmpString]
    APSAddToTempFileList $tmpFile
    if [catch {exec sddsprocess $fullFilename $tmpFile $matchOpt} result] {
        APSMpReturn error "APSMpIDRestoreUserGaps: $result"
    }
    APSMpStep "Restore device values"
    if [catch {exec sddscasr -restore $tmpFile } result] {
        APSMpReturn error "APSMpIDRestoreUserGaps: $result"
    }
    after 1000

    if $gapsToSetpoints {
        APSMpStep "Moving gaps to setpoints"
        if [catch {APSIDStaggerGaps -IDList $deviceList -interval $closeInterval -returnGaps 0} result] {
            APSMpReturn error "APSMpIDRestoreUserGaps: $result"
        }
        after 1000
    }
    if $gapsToReturnValues {
        APSMpStep "Moving gaps to return values"
        if [catch {APSIDStaggerGaps -IDList $deviceList -interval $closeInterval -returnGaps 1} result] {
            APSMpReturn error "APSMpIDRestoreUserGaps: $result"
        }
        after 1000
    }
    #check if gaps are moving
    if {$gapsToSetpoints || $gapsToReturnValues} {
        APSMpStep "Waiting for ID gaps stop moving. (it may take several minutes, please be patient.)"
        if {[catch {APSMpCheckAndWaitForIDs -deviceList $deviceList} results]} {
            if {[APSPEMTKDialog .warningDialog -text "APSMpIDRestoreUserGaps: Problem occurred while waiting restoring ID gaps\n$results"] == 1} {
                APSMpReturn error "APSMpIDRestoreUserGaps: $results"
            }
        }
    }
    APSMpStep "Restore the gap mode."
    if [catch {exec cavput -list=[join $cavputList ,] -pend=30} result] {
        APSMpReturn error "APSMpIDRestoreUserGaps: $result"
    }
    APSMpReturn ok
}

#Not used
proc APSMpIDTimeRestoreUserGapsInfo {} {
    return "Restore selected user gap values at a specified time from the PV history file.  Sets the devices to user mode. Restores the gap setpoints and the user return values.  Optionally moves the gaps to the setpoints or return values."
}

#Not used
proc APSMpIDTimeRestoreUserGapsInitDialog {frame} {
    global APSMpIDTimeRestoreUserGaps
    set deviceList0 [lsort [array names APSMpIDTimeRestoreUserGaps]]
    foreach item $deviceList0 {
        if [string match ID* $item] {
            lappend deviceList $item
            lappend variableList APSMpIDTimeRestoreUserGaps($item)
        }
    }
    set APSMpIDTimeRestoreUserGaps(closeInterval) 3
    
    APSCheckButtonFrame .cb -parent $frame -label "Choose IDs" \
      -limitPerRow 8 -buttonList "$deviceList" \
      -variableList "$variableList" -orientation horizontal -allNone 1 
    APSRadioButtonFrame .sp -parent $frame -orientation horizontal \
      -variable APSMpIDTimeRestoreUserGaps(gapsToSetpoints) \
      -label "Move gaps to setpoint?" \
      -buttonList "Yes No" -valueList "1 0" \
      -commandList {"set APSMpIDTimeRestoreUserGaps(gapsToReturnValues) 0" ""} \
      -contextHelp "Select whether or not to move the ID gaps to the setpoints."
    APSRadioButtonFrame .rv -parent $frame -orientation horizontal \
      -variable APSMpIDTimeRestoreUserGaps(gapsToReturnValues) \
      -label "Move gaps to user return value?" \
      -buttonList "Yes No" -valueList "1 0" \
      -commandList {"set APSMpIDTimeRestoreUserGaps(gapsToSetpoints) 0" ""} \
      -contextHelp "Select whether or not to move the ID gaps to the user return value. This is supposedly where the user wanted the gap."

    APSDateTimeAdjEntry .date -parent $frame \
      -yearVariable APSMpIDTimeRestoreUserGaps(year) \
      -monthVariable APSMpIDTimeRestoreUserGaps(month) \
      -dayVariable APSMpIDTimeRestoreUserGaps(day) \
      -hourVariable APSMpIDTimeRestoreUserGaps(hour) \
      -label "Date/time (year, month, day, hour): " -defaultHour 0 
    
    APSLabeledEntry .interval -parent $frame -textVariable APSMpIDTimeRestoreUserGaps(closeInterval) \
      -label "Interval of closing gaps (seconds):" -width 20 \
      -contextHelp "Due to on-going restrictions on the SR rf systems, we need to tagger the closing of the gaps by a selectable time interval, i.e. issuing the next gap close command after T seconds of the previous one."
}

#Not used
proc APSMpIDTimeRestoreUserGaps {args} {
    set fullDeviceList [APSIDGetDeviceList]
    set deviceList $fullDeviceList
    set closeInterval 3
    APSStrictParseArguments {deviceList closeInterval}

    foreach item $fullDeviceList {
        if [lsearch -exact $deviceList $item]!=-1 {
            set $item 1
        } else {
            set $item 0
        }
    }
    set gapsToSetpoints 1
    set gapsToReturnValues 0
    set ShortFilename ""
    APSSetVarsFromList \
      -valueList [clock format  [clock seconds]  -format "%Y %m %d %H:%M:%S"] \
      -variableList [list year month day hour]

    APSMpStep init -promptDialog APSMpIDTimeRestoreUserGapsInitDialog \
      -desc "Choose devices and SCR file" \
      -vars "$fullDeviceList gapsToSetpoints gapsToReturnValues year month day hour closeInterval"
    if [catch {clock scan "$month/$day/$year $hour"} timeValue] {
        APsMpReturn error "APSMpIDTimeRestoreUserGaps: Problem with date/time specification: be sure to use HH:MM:SS for time"
    }
    set varList "$fullDeviceList gapsToSetpoints gapsToReturnValues year month day hour"
    foreach par $varList {
        append paramString "$par=\"[set $par]\" "
    }
    catch {APSLogScriptAction \
             -procedure  APSMpIDTimeRestoreUserGaps \
             -action initialize \
             -state ok \
             -parameters $paramString \
         }
    APSMpStep "Check device selection"
    set first 1
    set deviceList ""
    set matchOpt ""
    foreach device $fullDeviceList {
        if [set $device] {
            lappend deviceList $device
            if $first {
                set first 0
                set matchOpt -match=column,ControlName=$device:*
            } else {
                set matchOpt $matchOpt,ControlName=$device:*,|
            }
        }
    }
    if ![llength $deviceList] {
        APSMpStep "No devices selected"
        APsMpReturn ok
    }

    APSMpStep "Check for data"
    set fileFilter \
      /home/helios/oagData/logonchange/SR/[format SR-%4d-*-%02d%02d.???? $year $month $day]
    set fileList [lsort [glob -nocomplain $fileFilter]]
    if [llength $fileList]==0 {
        APsMpReturn error "APSMpIDTimeRestoreUserGaps: No file for that date"
    }

    APSMpStep "Prepare data for restore (takes a while)"
    set tmpFile /tmp/[APSTmpString]
    APSAddToTempFileList $tmpFile
    if [catch {eval exec sddscombine $fileList -pipe=out \
                 | sddsderef -pipe \
                 -column=ControlName,array=ControlName,ControlNameIndex \
                 | sddsconvert -pipe -delete=array,* -retain=col,ControlName,Time,Value \
                 | sddscombine -merge -pipe \
                 | sddsprocess -pipe -match=col,ControlName=ID* \
                 -filter=column,Time,0,$timeValue -nowarning \
                 | sddssort -pipe -col=ControlName -col=Time,incr \
                 | sddsbreak -change=ControlName -pipe \
                 | sddsprocess -pipe -clip=0,1,invert -nowarning \
                 -print=column,ValueString,%.15f,Value \
                 -print=column,ControlType,pv \
                 -print=column,Lineage,- \
                 -define=column,Count,1,type=long \
                 -print=parameter,SnapType,Absolute \
                 | sddscombine -pipe -merge \
                 | sddsprocess -pipe=in $tmpFile $matchOpt -nowarning} result] {
        APSMpReturn error "APSMpIDTimeRestoreUserGaps: $result"
    }

    APSMpStep "Set devices to user mode"
    if [catch {exec cavput -list=[join $deviceList ,] -list=:AccessSecurity=User} result] {
        APSMpReturn error "APSMpIDTimeRestoreUserGaps: $result"
    }
    after 1000

    APSMpStep "Restore device values"
    if [catch {exec sddscasr -restore $tmpFile } result] {
        APSMpReturn error "APSMpIDTimeRestoreUserGaps: $result"
    }
    after 1000

    if $gapsToSetpoints {
        APSMpStep "Moving gaps to setpoints"
        # if [catch {exec cavput -list=[join $deviceList ,] -list=:Start=1} result] {
        #     APSMpReturn error "APSMpIDTimeRestoreUserGaps: $result"
        # }
        #Due to on-going restriction on the SR rf systems, we need the option to stagger the closing of the gaps by a selectable time interval T.
        if [catch {APSIDStaggerGaps -IDList $deviceList -interval $closeInterval -returnGaps 0} result] {
            APSMpReturn error "APSMpIDTimeRestoreUserGaps: Error in close gaps with staggering: $result"
        }
        after 1000
    }
    if $gapsToReturnValues {
        APSMpStep "Moving gaps to return values"
        #if [catch {exec cavput -list=[join $deviceList ,] -list=:CloseDevice=1} result] {
        #    APSMpReturn error "APSMpIDTimeRestoreUserGaps: $result"
        #}
        if [catch {APSIDStaggerGaps -IDList $deviceList -interval $closeInterval -returnGaps 1} result] {
            APSMpReturn error "APSMpIDTimeRestoreUserGaps: Error in close gaps with staggering: $result"
        }
        after 1000
    }
    APSMpReturn ok
}

#Not Used
proc APSMpCPUInitializeInfo {} {
    return "Sets up the CPU with the correct DC files and AC waveform files. Also sets up the proper limits for operation.\n\nThe CPU should be at zero current when executing this command."
}

#Not Used
proc APSMpCPUInitialize {} {
    APSMpStep init -promptDialog "APSMpPromptInitDialog"
    # Should only initialize when the ID is at zero readback. (Setpoint of zero is 
    # not reliable since the CPU may be still be ramping to zero.)
    if [catch {exec cavget -list=ID04b: -list=H,V -list=_coil.VAL -pend=10 -printErrors} readbacks] {
        APSMpReturn error "APSMpCPUInitialize: $result"
    }
    if { [expr abs([lindex $readbacks 0]) > 5] || [expr abs([lindex $readbacks 1]) > 5] } {
        # not at zero yet.
        APSAlertBox .warning -errorMessage "CPU readbacks not at zero. No action taken.\n\nTry again when CPU is at zero current."
        APSMpReturn error "APSMpCPUInitialize: Aborted because CPU readbacks are not at zero."
    }
    # Set the default files
    if [catch {exec cavput -list=ID04b:corrFile=/sr/IDs/CPU/DCmodes/default} result] {
        APSMpReturn error "APSMpCPUInitialize: $result"
    }
    set ACfile(1) /sr/IDs/CPU/ACmodes/vcorr2.default
    set ACfile(2) /sr/IDs/CPU/ACmodes/hcorr2.default
    set ACfile(3) /sr/IDs/CPU/ACmodes/hcorr1.default
    set ACfile(4) /sr/IDs/CPU/ACmodes/vcorr1.default
    set ACfile(5) /sr/IDs/CPU/ACmodes/normalQuad.sdds
    set ACfile(6) /sr/IDs/CPU/ACmodes/skewOct.sdds
    set ACfile(7) /sr/IDs/CPU/ACmodes/skewQuad.sdds
    if [catch {exec cavput -list=ID04b:corrFile_ \
                 -list=1=$ACfile(1),2=$ACfile(2),3=$ACfile(3),4=$ACfile(4),5=$ACfile(5),6=$ACfile(6),7=$ACfile(7) \
             } result] {
        APSMpReturn error "APSMpCPUInitialize: $result"
    }
    # load the files
    if [catch {exec cavput -list=ID04b:loadCorr=1 \
             } result] {
        APSMpReturn error "APSMpCPUInitialize: $result"
    }
    if [catch {exec cavput -list=ID04b:loadCorr_=1 -list=1,2,3,4,5,6,7 \
             } result] {
        APSMpReturn error "APSMpCPUInitialize: $result"
    }
    
    # set some numercial PVs
    set halfPeriod 1
    if [catch {exec cavput -list=ID04b:timer.VAL=$halfPeriod \
             } result] {
        APSMpReturn error "APSMpCPUInitialize: $result"
    }
    APSMpReturn ok
}

proc APSMpResetCPUAfgInfo {args} {
    return "This procedure resets CPU afg when channels are stuck while beam is stored. It is important that the real-time feedback be running while beam is stored, otherwise the beam will be dumped by the orbit change."
}

#Not used
proc APSMpResetCPUAfg {args} {
    
    APSMpStep "ResetCPUAfg - Step 0: Turn off CPU main current"
    #to make it turn off the CPU main current, 
    #switch the Trigger select to 'Internal', switch the polarization mode to 'CW/CCW'
    #Once the CPU is turned back on after AFG get reset, it returns to the default 
    #mode that matches the default state of the AFG ???
    if [catch {exec cavget -list=ID04b:set_V_coil -pend=30 -printErrors} ID4Current] {
        APSMpReturn error "APSMpResetCPUAfg: $ID4Current"
    }
    if {$ID4Current=="?"} {
        APSMpReturn error "APSMpResetCPUAfg: can not read value of ID04b:set_V_coil"
    }
    if [catch {exec cavput -list=ID04b:TriggerSelect.VAL=Internal,ID04b:DesiredMode.VAL=CW/CCW -pend=30} result] {
        APSMpReturn error "APSMpResetCPUAfg: $result"
    }
    if [catch {exec cavput -list=ID04b:set_V_coil=0,ID04b:on_off=Off -pend=30} result] {
        APSMpReturn error "APSMpResetCPUAfg: $result"
    }
    
    APSMpStep "ResetCPUAfg - Step 1: Check if RTFB is running."
    #make sure RTFB (e.g. SRFB:GBL:HLoopStatusBI) is running in both
    #planes with sector 5 loops closed. (it is possible to have RTFB running
    #with some particular sectors open. It happened to me
    #during the procedure tests due to not reseting from a previous trip.
    #So all sector loops, e.g. S1FB:GB2:Hor:CloseLoopBO have to be checked.)
    #If some loops are open, reset/open all loops, and re-close them.
    if [catch {exec cavget -list=SRFB:GBL: -list=H,V -list=LoopStatusBI -pend=30 -printErrors} valList] {
        APSMpReturn error "APSMpResetCPUAfg: $valList"
    }
    foreach val $valList nm {horizontal vertical} {
        if {$val!="On"} {
            APSMpReturn error "APSMpResetCPUAfg: the $nm plane RTFB is not running!"
        }
    }
    #check if any loops are open
    for {set i 2} {$i<=39} {incr i} {
        set ioc [expr ($i - 1) / 2 * 2 + 1]
        lappend crateList S${ioc}FB:GB${i}
    }
    if [catch {exec cavget -list=[join $crateList ,] -list=:Hor,:Vert -list=:CloseLoopBO -pend=30 -printErrors -label} loopList] {
        APSMpReturn error "APSMpResetCPUAfg: $loopList"
    }
    if [lsearch -exact $loopList "Open"]>=0 {
        APSMpStep "ResetCPUAfg - Step 1a: Reset/Open RTFB Loops"
        global apshpFilterCutoffVert apshpFilterCutoffHoriz apshpFilterInitialVert apshpFilterInitialHoriz apshpFilterRampPoints apshpFilterRampInterval
        APSMpSetRTFBGlobalParameters -readonly 1 
        if [catch {APSMpRTFBResetOpenLoops -hpFilterInitialVert $apshpFilterInitialVert \
                     -hpFilterInitialHoriz $apshpFilterInitialHoriz } result] {
            APSMpReturn error "APSMpResetCPUAfg (open RTFB loops): $result"
        }
        APSMpStep "ResetCPUAfg - Step 1c: Close RTFB loops - this will take some time for ramping."
        if [catch {APSMpRTFBCloseLoops -hpFilterCutoffVert $apshpFilterCutoffVert \
                     -hpFilterCutoffHoriz $apshpFilterCutoffHoriz \
                     -hpFilterInitialVert $apshpFilterInitialVert \
                     -hpFilterInitialHoriz $apshpFilterInitialHoriz \
                     -hpFilterRampPoints $apshpFilterRampPoints \
                     -hpFilterRampInterval $apshpFilterRampInterval } result] {
            APSMpReturn error "APSMpResetCPUAfg (cloose RTFB loops): $result"
        }   
    }
    APSMpStep "ResetCPUAfg - Step 2: Change RTFB trip limit."
    if [catch {exec cavput -list=SRFB:GBL:HCorDeltaMaxP=50,SRFB:GBL:VCorDeltaMaxP=50 \
                 -pend=30} result] {
        APSMpReturn error "APSMpResetCPUAfg: $result"
    }
    if [catch {exec cavput -list=SRFB:GBL:loadBO=1 -pend=30} result] {
        APSMpReturn error "APSMpResetCPUAfg: $result"
    }
    
    APSMpStep "ResetCPUAfg - Step 3: Change datapool despiking limit for H plane."
    if [catch {exec cavput -list=DP:S:OrbitControlLawXSDDS.SPKE=1 -pend=30} result] {
        APSMpReturn error "APSMpResetCPUAfg: $result"
    }

    APSMpStep "ResetCPUAfg - Step 4: Increase datapool corrector range limit to 20 A for both planes and generate controllaw files."
    APSInfoWindow .info -name "Regenerate controllaw files." -modal 1\
      -width 50 -infoMessage "ResetCPUAfg - Step 4: Increase datapool corrector range limit to 20 A \n\n Go to SR orbit correction application,\n\n increase the corrector range limit to 20 A for both planes, \n\n and then press \"GENERATE\" and \"START PVTEST\" for both planes."
    APSMpStep "ResetCPUAfg - Step 5: reset AFG."
    APSInfoWindow .info -name "Reset AFG" -width 50 -modal 1\
      -infoMessage "ResetCPUAfg - Step 5: reset AFG\n\ngo to CPU cabinet, look for VME crate (accessible through a hole in the door)\n\n and press the red rest button on the AFG card. The reset operation takes a few seconds. \n You can check that the corrector channels are zero, by opening the door of the left cabinet,\n and read the KEPCO supply LED displays."
    APSMpStep "ResetCPUAfg - Step 6: start CPU operation."
    #ask louis how ???
    if [catch {exec cavput -list=ID04b:set_V_coil=$ID4Current,ID04b:on_off=On -pend=30} result] {
        APSMpReturn error "APSMpResetCPUAfg: $result"
    }
    
    APSMpStep "ResetCPUAfg - Step 7: Return datapool corrector range limit to 10A."
    APSInfoWindow .info -name "Regenerate controllaw files." -modal 1 \
      -width 50 -infoMessage "ResetCPUAfg - Step 6: Return datapool corrector range limit to 10A\n\nGo to SR orbit correction application, \n\n return the corrector range limit to 10 A for both planes, \n\n and press \"GENERATE\" and \"START PVTEST\" for both planes."
    
    APSMpStep "ResetCPUAfg - Step 8: Reramp datapool despiking limit."
    APSInfoWindow .info -name "Reramp datapool despiking limit." -modal 1 \
      -width 50 -infoMessage "ResetCPUAfg - Step 8: Reramp datapool despiking limit.\n\n Go to orbit correction application, \n\n press \"Re-ramp Despike Threshold\" button in the \"Depike Threshold Ramp\" tab to reramp datapool despiking limit."

    APSMpStep "ResetCPUAfg - Step 9: Restore the RTFB trip limits."
    if [catch {exec cavput -list=SRFB:GBL:HCorDeltaMaxP=10,SRFB:GBL:VCorDeltaMaxP=10 -pend=30} result] {
        APSMpReturn error "APSMpResetCPUAfg: $result"
    }
    if [catch {exec cavput -list=SRFB:GBL:loadBO=1 -pend=30} result] {
        APSMpReturn error "APSMpResetCPUAfg: $result"
    }
    APSMpReturn ok
}

#Not used
proc APSMpIDRestoreMinimumGapsInfo {args} {
    return "Restore the minumum gaps from /home/helios/oagData/sr/IDs/MinimumGaps file"
}

#Not used
proc APSMpIDRestoreMinimumGapsInitDialog {frame} {
    global APSMpIDRestoreMinimumGaps
    set APSMpIDRestoreMinimumGaps(closeInterval) 3
    APSLabeledEntry .interval -parent $frame -textVariable  APSMpIDRestoreMinimumGaps(closeInterval) \
      -label "Interval of closing gaps (seconds):" -width 20 \
      -contextHelp "Due to on-going restrictions on the SR rf systems, we need to tagger the closing of the gaps by a selectable time interval, i.e. issuing the next gap close command after T seconds of the previous one."
    
}

proc APSMpIDRestoreXbpmRefGapsInitDialog {frame} {
    global APSMpIDRestoreXbpmRefGaps
    
    set APSMpIDRestoreXbpmRefGaps(closeInterval) 3
    APSLabeledEntry .interval -parent $frame -textVariable  APSMpIDRestoreXbpmRefGaps(closeInterval) \
      -label "Interval of closing gaps (seconds):" -width 20 \
      -contextHelp "Due to on-going restrictions on the SR rf systems, we need to tagger the closing of the gaps by a selectable time interval, i.e. issuing the next gap close command after T seconds of the previous one."
    set APSMpIDRestoreXbpmRefGaps(group) ""
    APSRadioButtonFrame .group -parent $frame -variable APSMpIDRestoreXbpmRefGaps(group) \
      -label "Select group of gaps to restore:" -buttonList {"A" "B" "Both"} \
      -valueList {A B Both} \
      -contextHelp "due to higher amount of forward power needed if close all gaps, now split the xbpm reference gaps into group a and b, user may \
choose which group (A or B) to restore, or restore all gaps (both) if allowed."
}

#Called by SR PEM
proc APSMpIDRestoreXbpmRefGaps {args} {
    set closeInterval 3
    set group ""
    set pem 1
    set wait 1
    APSStrictParseArguments {closeInterval group pem wait}

    APSMpStep init -promptDialog "APSMpIDRestoreXbpmRefGapsInitDialog" -vars {closeInterval group}
    
    if ![string length $group] {
        APSMpReturn error "ID gap group is not provided."
    }
    
    if {$group=="Both"} {
        set file XbpmRefGaps
    } else {
        set file XbpmRefGaps$group
    }
    if [catch {APSMpIDRestoreGaps -gapfile $file -closeInterval $closeInterval -pem $pem -wait $wait} result] {
        APSAlertBox .error -errorMessage "APSMpIDRestoreXbpmRefGaps: $result"
        APSMpReturn error "APSMpIDRestoreXbpmRefGaps: $result"
    }
    APSMpStep "Restore Xbpm Reference gaps done."
    APSMpReturn ok
}

#Not used
proc APSMpIDRestoreMinimumGaps {args} {
    set closeInterval 3
    APSStrictParseArguments {closeInterval}

    APSMpStep init -promptDialog "APSMpIDRestoreMinimumInitDialog" -vars closeInterval
    
    if [catch {APSMpIDRestoreGaps -gapfile MinimumGaps -closeInterval $closeInterval} result] {
        APSAlertBox .error -errorMessage "APSMpIDRestoreMinimuGaps: $result"
        APSMpReturn error "APSMpIDRestoreMinimumGaps: $result"
    }
    APSMpStep "Restore minimum gaps done."
    APSMpReturn ok
}

proc APSMpIDRestoreXbpmRefGapsInfo {args} {
    return "Restore the xray bpm gaps from /home/helios/oagData/sr/IDs/XbpmRefGaps file if group \"Both\" selected, or XbpmRefGapA for group \"A\" or XbpmRefGapsB for group \"B\"."
}
proc APSMpIDSetGapTo60mmInfo {args} {
    return "Restore the xray bpm gaps from /home/helios/oagData/sr/IDs/SetGapTo60mm file"
}
proc APSMpIDSetGapTo140mmInfo {args} {
    return "Restore the xray bpm gaps from /home/helios/oagData/sr/IDs/SetGapTo140mm file"
}
proc APSMpIDSetGapToMinimumInfo {args} {
    return "Restore the xray bpm gaps from /home/helios/oagData/sr/IDs/MinimumGaps file"
}
proc APSMpIDSetGapToBPLDTripLimitsInfo {args} {
    return "Restore the xray bpm gaps from /home/helios/oagData/sr/IDs/SetGapToBPLDTripLimits file"
}
proc APSMpIDSetGapToMinimumInitDialog {frame} {
    global APSMpIDSetGapToMinimum
    set APSMpIDSetGapToMinimum(closeInterval) 3
    APSLabeledEntry .interval -parent $frame -textVariable  APSMpIDSetGapToMinimum(closeInterval) \
      -label "Interval of closing gaps (seconds):" -width 20 \
      -contextHelp "Due to on-going restrictions on the SR rf systems, we need to tagger the closing of the gaps by a selectable time interval, i.e. issuing the next gap close command after T seconds of the previous one."
    
}

#Called by SR PEM
proc APSMpIDSetGapToMinimum {args} {
    set closeInterval 3
    APSStrictParseArguments {closeInterval}
    APSMpStep init -promptDialog "APSMpIDSetGapToMinimumInitDialog" -vars closeInterval
    APSMpStep "Set Xray bpm gaps to minim gap values..."
    if [catch {APSCloseID35Shutter} result] {
        APSMpReturn error "APSMpIDSetGapToMinimum: error in closing ID35 shutter: $result"
    }
    if [catch {APSMpIDRestoreGaps -gapfile MinimumGaps -closeInterval $closeInterval } result] {
        APSAlertBox .error -errorMessage "APSMpIDSetGapToMinimum: $result"
        APSMpReturn error "APSMpIDSetGapToMinimum: $result"
    }
    APSMpStep "Set Xray bpm gaps to minimum gaps done."
    set IDList [exec sdds2stream -col=GapName /home/helios/oagData/sr/IDs/MinimumGaps]
    if [catch {APSIDsGoAndWait -IDList "$IDList"} result] {
        APSMpReturn error "APSMpIDSetGapToMinimum: $result"
    }
    APSMpStep "Routine SCR Save after gaps moved minimum gap."
    if [catch {APSSaveMachine -machine SR \
                 -description "Routine save: save after gaps moved to minimum gap."} result] {
        APSMpReturn error "APSMpIDSetGapToMinimum: $result"
    }
    APSMpStep "XrayBPM Save after gaps moved to minimum gap"
    if [catch {APSSaveMachine -machine SRXrayBPM \
                 -description "XrayBPM Save gaps moved to minimum gap."} result] {
        APSMpReturn error "APSMpIDSetGapToMinimum: $result"
    }
    
    APSMpReturn ok
}

proc APSMpIDSetGapToBPLDTripLimitsInitDialog {frame} {
    global APSMpIDSetGapToBPLDTripLimits
    set APSMpIDSetGapToBPLDTripLimits(closeInterval) 3
    APSLabeledEntry .interval -parent $frame -textVariable  APSMpIDSetGapToBPLDTripLimits(closeInterval) \
      -label "Interval of closing gaps (seconds):" -width 20 \
      -contextHelp "Due to on-going restrictions on the SR rf systems, we need to tagger the closing of the gaps by a selectable time interval, i.e. issuing the next gap close command after T seconds of the previous one."
    
}

#Called by SR PEM
proc APSMpIDSetGapToBPLDTripLimits {args} {
    set closeInterval 3
    set orbitSwitch 0
    APSStrictParseArguments {closeInterval orbitSwitch}

    
    APSMpStep init -promptDialog "APSMpIDSetGapToBPLDTripLimitsInitDialog" -vars "closeInterval"
    
    APSMpStep "Set Xray bpm gaps to BPLD Trip Limits..."
    if [catch {APSMpIDRestoreGaps -gapfile  SetGapToBPLDTripLimits -closeInterval $closeInterval -orbitSwitch $orbitSwitch} result] {
        APSAlertBox .error -errorMessage "APSMpIDSetGapToBPLDTripLimits: $result"
        APSMpReturn error "APSMpIDSetGapToBPLDTripLimits: $result"
    }
    APSMpStep "Set Xray bpm gaps to BPLDTripLimits done."
    APSMpReturn ok
}

proc APSMpIDSetGapTo60mmInitDialog {frame} {
    global APSMpIDSetGapTo60mm
    set APSMpIDSetGapTo60mm(closeInterval) 3
    APSLabeledEntry .interval -parent $frame -textVariable  APSMpIDSetGapTo60mm(closeInterval) \
      -label "Interval of closing gaps (seconds):" -width 20 \
      -contextHelp "Due to on-going restrictions on the SR rf systems, we need to tagger the closing of the gaps by a selectable time interval, i.e. issuing the next gap close command after T seconds of the previous one."
    
}

#Called by SR PEM
proc APSMpIDSetGapTo60mm {args} {
    set closeInterval 3
    set orbitSwitch 0
    APSStrictParseArguments {closeInterval orbitSwitch}

    
    APSMpStep init -promptDialog "APSMpIDSetGapTo60mmInitDialog" -vars "closeInterval"
    
    APSMpStep "Set Xray bpm gaps to 60mm..."
    if [catch {APSMpIDRestoreGaps -gapfile SetGapTo60mm -closeInterval $closeInterval -orbitSwitch $orbitSwitch} result] {
        APSAlertBox .error -errorMessage "APSMpIDSetGapTo60mm: $result"
        APSMpReturn error "APSMpIDSetGapTo60mm: $result"
    }
    APSMpStep "Set Xray bpm gaps to 60mm done."
    APSMpReturn ok
}

#Called by SR PEM
proc APSMpIDSetGapTo140mm {args} {
    set orbitSwitch 1
    APSStrictParseArguments {orbitSwitch}
    APSMpStep init -promptDialog "APSMpPromptInitDialog"
    #change to use global open for this one
    if [catch {APSIDOpenAllGaps} result] {
	APSMpReturn error "APSMpIDSetGapTo140mm(Error in opening gaps): $result"
    }
    APSMpStep "Be pation while opening gaps to 140mmm...."
    after 60000
    APSMpReturn ok
    APSMpStep "Set Xray bpm gaps to 140mm..."
    if [catch {APSMpIDRestoreGaps -gapfile SetGapTo140mm -closeInterval 0.1 -orbitSwitch $orbitSwitch} result] {
        APSAlertBox .error -errorMessage "APSMpIDSetGapTo140mm: $result"
        APSMpReturn error "APSMpIDSetGapTo140mm: $result"
    }
    APSMpStep "Set Xray bpm gaps to 140mm done."
    APSMpReturn ok
}

#Not used
proc APSMpIDRestoreOpenGapsInfo {args} {
    return "Open gaps"
}

#Not used
proc APSMpIDRestoreOpenGaps {args} {
    set orbitSwitch 1
    APSStrictParseArguments {orbitSwitch}
    APSMpStep "Open Xray bpm gaps..."
    if [catch {APSMpIDRestoreGaps -gapfile OpenGaps -orbitSwitch $orbitSwitch} result] {
        APSAlertBox .error -errorMessage "APSMpIDRestoreOpenGaps: $result"
        APSMpReturn error "APSMpIDRestoreOpenGaps: $result"
    }
    APSMpStep "Open xray bpm gaps done."
    APSMpReturn ok
}

#Called by APSMpSRSingleGapScan
proc APSSRPrepareMovingID01Gaps {args} {
    set dsGap ""
    set usGap ""
    set orbitSwitch 0
    APSStrictParseArguments {dsGap usGap orbitSwitch}
    
    if {![string length $dsGap] && ![string length $usGap]} {
        #gaps not provided, do nothing.
        return
    }
    if [catch {exec cavget -list=S01ID -list=:DSID,:USID -list=:GapM -pend=30} gaps] {
        return -code error "APSSRPrepareMovingID01Gaps1: error reading S01ID gaps: $gaps"
    }
    set DSgap [lindex $gaps 0]
    set USgap [lindex $gaps 1]
    #FIX THIS - I don't know what the PV names should be
    #FIX THIS - There is not SCU initially so this will have to change somehow
    if [catch {exec cavget -list=ID01ds:MainOn -num -pend=30} scu1OnOff] {
        return -code error "APSSRPrepareMovingID01Gaps2: error reading S01ID:DS on/off:$ scu1OnOff"
    }
    if {[string length $dsGap] && [string length $usGap] && $dsGap<170 && $usGap<170} {
        return -code error "APSSRPrepareMovingID01Gaps3: error: S01ID ds and us can not close at the same time!"
    }
    if {$orbitSwitch && [string length $dsGap] && $dsGap>170 && $scu1OnOff} {
        #turn off scu1 for orbitSwitch when opening SCU1.
        APSMpStep "Turn off SCU1 after opening SCU1 in orbit switch..."
        #FIX THIS - I don't know what the PV names should be
        if [catch {exec cavput -list=ID01ds:Main_OnOff=0  -pend=30
            exec cawait -interval=1 -timelimit=600 -waitFor=S01ID:DSID:GapM,lower=139,upper=141 } result] {
            return -code error "APSSRPrepareMovingID01Gaps4: Error opening S01ID:DS gap: $result"
        }
        #scu1 is off now
        set scu1OnOff 0
    }
    #it is ok if both are greater than 170
    
    if {[string length $usGap] && $usGap<170 && $scu1OnOff} {
        #need open SCU1 and then turn it off
        if [string length $dsGap] {
            set gap $dsGap
            set low [expr $gap -1]
            set upper [expr $gap +1]
        } else {
            set gap 140
            set low 139
            set upper 141
        }
        #SCU1 is on
        if {$DSgap<$gap} {
            #turn scu1 off and wait for it open
            APSMpStep "turn off SCU1 and wait for its current turning to zero (be patient, it may take several minutes)..."
            #FIX THIS - I don't know what the PV names should be
            if [catch {exec cavput -list=ID01ds:Main_OnOff=0  -pend=30
                exec cawait -interval=1 -timelimit=600 -waitFor=S01ID:DSID:GapM,lower=$low,upper=$upper } result] {
                return -code error "APSSRPrepareMovingID01Gaps4: Error opening S01ID:DS gap: $result"
            }
            while {1} {
                #FIX THIS - I don't know what the PV names should be
                if [catch {exec cavget -list=ID01ds:MainOn -num -pend=30} onOff] {
                    return -code errr "APSSRPrepareMovingID01Gaps4a: error reading ID01ds:MainOn: $onOff"
                }
                if {!$onOff} {
                    break
                }
                set answer [APSMultipleChoice [APSUniqueName .] -modal 1 \
                              -question "SCU1 is not off yet, would you like turn in off again or abort" \
                              -returnList {1 0} \
                              -labelList {Turn_Off_Again Abort}]
                if !$answer {
                    return -code error "APSSRPrepareMovingID01Gaps4b: can not turn off SCU1!"
                }
                #FIX THIS - I don't know what the PV names should be
                if [catch {exec cavput -list=ID01ds:Main_OnOff=0  -pend=30 } result] {
                    return -code error "APSSRPrepareMovingID01Gaps4c: Error turning off SCU1: $result"
                }
                APSWaitWithUpdate -waitSeconds 5 -update 1
            }
        }
    }
    #if SCU1 is off, the gap must be 140, nothing need to do.
    if {[string length $dsGap] && $dsGap<170 && !$scu1OnOff} {
        #open ID01us
        if [string length $usGap] {
            set gap $usGap
            set low [expr $gap -1]
            set upper [expr $gap +1]
        } else {
            set gap 140
            set low 139
            set upper 141
        }
        if {$USgap<$gap} {
            APSMpStep "Opening S01ID:USID gap..."
            if [catch {exec cavput -list=S01ID:USID:GapSetC=$gap -pend=30
                exec cavput -list=S01ID:USID:StartC=1  -pend=30
                exec cawait -interval=1 -timelimit=500 -waitFor=S01ID:USID:GapM,lower=$low,upper=$upper } result] {
                return -code error "APSSRPrepareMovingID01Gaps6: Error opening S01ID:US gap: $result"
            }
        }
        #turn on SCU1
        APSMpStep "Waiting for SCU1 to turn on..."
        while {1} {
            #FIX THIS - I don't know what the PV names should be
            if [catch {exec cavput -list=ID01ds:Main_OnOff=1 -pend=30 } result] {
                return -code error "APSSRPrepareMovingID01Gaps7: Error turning on S01ID:DS: $result"
            }
            APSWaitWithUpdate -waitSeconds 20 -update 1
            #FIX THIS - I don't know what the PV names should be
            if [catch {exec cavget -list=ID01ds:MainOn -num -pend=30} onOff] {
                return -code errr "APSSRPrepareMovingID01Gaps8: error reading ID01ds:MainOn: $onOff"
            }
            if $onOff {
                break
            }
            set answer [APSMultipleChoice [APSUniqueName .] -modal 1 \
                          -question "SCU1 is not on yet, would you like turn in on again or abort" \
                          -returnList {1 0} \
                          -labelList {Turn_On_Again Abort}]
            if !$answer {
                return -code error "APSSRPrepareMovingID01Gaps9: can not turn SCU1 on!"
            }
        }
    }
}

#ID 06 us (regular gap) and ID06ds (SCU0)
#Called by APSMpSRSingleGapScan
proc APSSRPrepareMovingSCU0Gaps {args} {
    #FIX THIS - No SCU in the APSU initially
    return
    set gapList ""
    set IDList ""
    set orbitSwitch 0
    APSStrictParseArguments {gapList IDList orbitSwitch}
    
    if {![llength $gapList]} {
        return -code error "APSSRPrepareMovingSCU0Gaps0: gapList not provided."
    }
    if {![llength $IDList]} {
        return -code error "APSSRPrepareMovingSCU0Gaps0: IDList not provided."
    }
    
    if [catch {exec cavget -list=[join $IDList ,]-list=:GapM -pend=30} gaps] {
        return -code error "APSSRPrepareMovingSCU0Gaps1: error reading $IDList gaps: $gaps"
    }
    
    foreach ID $IDList gapRead $gaps gap $gapList {
        #FIX THIS - I don't know what the PV names should be
        if [catch {exec cavget -list=$ID:MainOn -num -pend=30} onOff1] {
            return -code error "APSSRPrepareMovingSCU0Gaps2: error reading $ID on/off: $onOff1"
        }
        if {$gap>170 && $onOff1} {
            APSMpStep "Turn off $ID after opening it, be patient (it may take several minutes) ..."
            if [catch {exec cavput -list=$ID:Main_OnOff=0  -pend=30
                exec cawait -interval=1 -timelimit=600 -waitFor=$ID:GapM,lower=139,upper=141 } result] {
                return -code error "APSSRPrepareMovingSCU0Gaps4: Error opening $ID gap: $result"
            }
            while {1} {
                if [catch {exec cavget -list=$ID:MainOn -num -pend=30} onOff] {
                    return -code errr "APSSRPrepareMovingSCU0Gaps4a: error reading $ID:MainOn: $onOff"
                }
                if {!$onOff} {
                    break
                }
                set answer [APSMultipleChoice [APSUniqueName .] -modal 1 \
                              -question "$ID is not off yet, would you like turn in off again or abort" \
                              -returnList {1 0} \
                              -labelList {Turn_Off_Again Abort}]
                if !$answer {
                    return -code error "APSSRPrepareMovingSCU0Gaps4b: can not turn off SCU0!"
                }
                if [catch {exec cavput -list=$ID:Main_OnOff=0  -pend=30 } result] {
                    return -code error "APSSRPrepareMovingSCU0Gaps4c: Error turning off $ID: $result"
                }
                APSWaitWithUpdate -waitSeconds 5 -update 1
            }
            
        } elseif {$gap<170 && !$onOff1} {
            #if gap < 170 and gap is off, turn it on
            APSMpStep "Turn on $ID, wait for 60 seconds..."
            if [catch {exec cavput -list=$ID:Main_OnOff=1  -pend=30 } result] {
                return -code error "APSSRPrepareMovingSCU0Gaps5: Error turning on $ID gap: $result"
            }
            APSWaitWithUpdate -waitSeconds 60 -update 1
            while {1} {
                if [catch {exec cavget -list=$ID:MainOn -num -pend=30} onOff] {
                    return -code errr "APSSRPrepareMovingSCU0Gaps5a: error reading $ID:MainOn: $onOff"
                }
                
                if {$onOff} {
                    break
                }
                
                set answer [APSMultipleChoice [APSUniqueName .] -modal 1 \
                              -question "$ID is not on would you like turn in on again or abort" \
                              -returnList {1 0} \
                              -labelList {Turn_On_Again Abort}]
                if !$answer {
                    return -code error "APSSRPrepareMovingSCU0Gaps5b: can not turn on SCU0!"
                }
                if [catch {exec cavput -list=$ID:Main_OnOff=1  -pend=30 } result] {
                    return -code error "APSSRPrepareMovingSCU0Gaps5c: Error turning on $ID: $result"
                }
                APSWaitWithUpdate -waitSeconds 5 -update 1
            }
        }
    }
}

#Called by SR PEMs
proc APSMpIDRestoreGaps {args} {
    set gapfile ""
    set wait 0
    set confirm 1
    set switchToMachinePhysics 1
    set closeInterval 3
    set pem 1
    APSStrictParseArguments {gapfile wait confirm switchToMachinePhysics closeInterval pem}
    
    # Get a list of all the installed devices.
    set deviceList [APSIDGetDeviceList]
    set taperList [APSIDGetTaperDeviceList]
    if $switchToMachinePhysics {
        #first change to machine physics mode
        APSMpStep "Set global access security mode to Machine Physics"
        if [catch {exec cavput -list=[join $deviceList ,] \
                     "-list=:AccessSecurityC=Machine Physics"} result] {
            APSMpReturn error "APSMpIDRestoreGaps(1 - cavput access mode): $result"
        }
    }
    if [catch {exec cavget -list=[join $taperList ,] -list=:TaperGapM -pend=30 -printErrors} taperValList] {
        APSMpReturn error "APSMpIDRestoreGaps(2 - cavget tapergap): $taperValList"
    }
    after 1000
    APSMpStep "Restore Xray bpm gaps..."
    set gapfile /home/helios/oagData/sr/IDs/$gapfile
    set tmpfile /tmp/[APSTmpString]
    APSAddToTmpFileList -ID 1 -fileList $tmpfile.taperset
    if [catch {exec sddsmakedataset -pipe=out -col=DeviceName,type=string \
                 -data=[join $taperList ,] \
                 -col=Value,type=double -data=[join $taperValList ,] \
                 | sddsxref -pipe $gapfile -match=DeviceName -nowarnings -leave=* \
                 | sddsprocess -pipe=in $tmpfile.taperset \
                 -edit=col,ControlName,DeviceName,ei/:TaperGapSetC// \
                 -filter=col,Value,0,0,! \
                 -reprint=col,ValueString,0 \
             } result] {
        APSMpReturn error "APSMpIDRestoreGaps(3 - sddsmakedataset): $result"
    }
    set movableList [APSIDGetDeviceList -full 0]
    set badList [APSIDGetBadDeviceList]
    if [llength $badList] {
        APSAlertBox .warning -errorMessage "The [join $badList ,] gaps will not be moved, because their :MotorDriveStatusM are not ready. Please contact control group if you need move them."
    }
    if [catch {exec sddsmakedataset $tmpfile.full -col=DeviceName,type=string -data=[join $movableList ,]} result] {
        APSMpReturn error "APSMpIDRestoreGaps(4 - sddsmakedataset): $result"
    }
    APSAddToTmpFileList -ID 1 -fileList "$tmpfile.set $tmpfile.printout $tmpfile.start $tmpfile.full"
    
    if [catch {exec sddsselect $gapfile $tmpfile.full -pipe=out -match=DeviceName -nowarnings  \
                 | sddsconvert -pipe -retain=col,GapName,DeviceName,ReadbackName,ValueString \
                 | sddsprocess -pipe -scan=col,MoveGapTo,ValueString,%f,type=float \
                 | sddsconvert -pipe -rename=col,ReadbackName=ControlName \
                 | sddscasr -pipe -save \
                 | sddsprocess -pipe=in $tmpfile.set \
                 -reedit=col,ControlName,%/:GapM/:GapSetC/ \
                 -scan=col,PresentValue,ValueString,%f,type=float \
                 -reprint=col,ValueString,%f,MoveGapTo} result] {
        APSMpReturn error "APSMpIDRestoreGaps(5 - sddsselect): $result"
    }

    
    if [regexp "SetGapTo60mm" $gapfile] {
        #leave the gaps alone if their values are greater than "60mm"
        if [catch {exec sddsprocess $tmpfile.set $tmpfile.set1 "-test=col,MoveGapTo PresentValue >" -nowarnings} result] {
            APSMpReturn error "APSMpIDRestoreGaps(5b - sddsprocess): $result"
        }
        set rows [exec sdds2stream -rows=bar $tmpfile.set1]
        if !$rows {
            #all gaps are equal to or bigger than "60mm"
            APSMpReturn ok
        }
        exec mv $tmpfile.set1 ${tmpfile}.set
    }
    if [catch {exec sddsprocess $tmpfile.set $tmpfile.start \
                 -reedit=col,ControlName,%/:GapSetC/:StartC/ \
                 -reprint=col,ValueString,1 } result] {
        APSMpReturn error "APSMpIDRestoreGaps(6 - sddsprocess): $result"
    }
    if $confirm {
        if [catch {exec sddsprintout $tmpfile.set $tmpfile.printout \
                     "-title=The current gap values and the values that gaps are going to be moved to." \
                     -col=ControlName,format=%30s \
                     -col=PresentValue,format=%.3f -col=MoveGapTo,format=%.3f } result] {
            APSMpReturn error "APSMpIDRestoreGaps(7 - sddsprintout): $result"
        }
        global moveGaps
        set moveGaps ""
        APSFileDisplayWindow .gap -fileName $tmpfile.printout -width 80 -modal 1 \
          -closeButton 0 -okButton 1 -cancelButton 1 -okCommand "set moveGaps 1;destroy .gap" \
          -cancelCommand "set moveGaps 0;destroy .gap"
	
        if !$moveGaps {
            APSMpStep "Moving gaps was canceled!"
            APSMpReturn ok
        }
    }
    APSMpStep "Setting gap tapper to zero..."
    if [catch {exec sddscasr -restore $tmpfile.taperset} result] {
        APSMpReturn error "APSMpIDRestoreGaps(8 - sddscasr -restore $tmpfile.taperset): $result"
    }
    
    APSMpStep "Moving Xray bpm gaps (it may be take minutes)"
    if [catch {exec sddscasr -restore $tmpfile.set } result] {
        APSMpReturn error "APSMpIDRestoreGaps(9 - sddscasr -restore $tmpfile.set): $result"
    }
    
    set waitList [exec sdds2stream -col=DeviceName $tmpfile.set]
    if $pem {
        if [catch {APSIDStaggerGaps -IDList $waitList -returnGaps 0 -interval $closeInterval} result] {
            APSMpReturn error "APSMpIDRestoreGaps(10): error in stagger gaps: $result"
        }
    } else {
        #can not run in parallel without pem
        set scuList ""
        set otherGaps ""
        set moveID01us 0
        #FIX THIS - not sure if this is correct for the APSU
        foreach ID $waitList {
            if {$ID=="S01ID:DSID" || $ID=="S06ID:DSID" || $ID=="S07ID:DSID"} {
                #FIX THIS - No SCU in the APSU initially
                #lappend scuList $ID
                lappend otherGaps $ID
            } elseif {$ID=="S01ID:USID"} {
                set moveID01us 1
            } else {
                lappend otherGaps $ID
            }
        }
        if [llength $otherGaps] {
            if [catch {APSIDMoveRegularGaps -IDList $otherGaps -interval $closeInterval} result] {
                return -code error "APSSRMoveIDGaps13: $result"
            }
        }
        if [llength $scuList] {
            foreach ID $scuList {
                if [catch {exec cavget -list=$ID:GapSetC -pend=20 -printErrors} value] {
                    return -code error "APSSRMoveIDGaps14: Error reading $ID:GapSetC: $value"
                }
                if [catch {APSSRMoveSCUID -ID $ID -moveTo $value} result] {
                    return -code error "APSSRMoveIDGaps15: error moving SCU $ID: $result"
                }
            }
        }
        if $moveID01us {
            if [catch {exec cavget -list=S01ID:USID:GapSetC -pend=20 -printErrors} value] {
                return -code error "APSSRMoveIDGaps16: Error reading ID01us:GapSetC: $value"
            }
	    #there is no SCU now (need fix it in the future), Shang, Feb. 2024
           # if [catch {APSSRMoveID01US -moveTo $value} result] {
            #    return -code error "APSSRMoveIDGaps17: error moving S01ID:USID gap: $result"
            #}
        }
    }
    after 1000
    if {$wait && [llength $waitList]} {
        if {[catch {APSMpCheckAndWaitForIDs -deviceList $waitList} results]} {
            if {[APSPEMTKDialog .warningDialog -text "APSMpIDRestoreGaps: Problem occurred while waiting restoring ID gaps\n$results"] == 1} {
                APSMpReturn error "APSMpIDRestoreGaps(20): $results"
            }
        }
    }
    APSMpReturn ok
}

#Not used
proc APSMpWaitForIDs {args} {
    #wait for ID gaps stop moving
    set deviceList ""
    set timeout 0
    APSStrictParseArguments {deviceList timeout}
    
    if ![llength $deviceList] {
        APSMpReturn ok
    }
    set options ""
    set first 1
    foreach device $deviceList {
        if $first {
            set options "-waitFor=${device}:BusyM,equalTo=0"
            set first 0
        } else {
            append options " -waitFor=${device}:BusyM,equalTo=0"
            append options " -and"
        }
    }
    if $timeout {
        append options " -timeLimit=$timeout"
    }
    update
    if [catch {eval exec cawait $options} result] {
        APSMpReturn error "APSMpWaitForIDs: $result"
    }
    update
    APSMpReturn ok
}

proc APSMpIDRestoreGapsFromSCRInfo {} {
    return "It restores selected user gap values from an SCR file. Restores the gap setpoints and gap taper setpoints.  Optionally moves the gaps to the setpoints or return values."
}

proc APSMpIDRestoreGapsFromSCRInitDialog {frame args} {
    global APSMpIDRestoreGapsFromSCR
    set deviceList0 [lsort [array names  APSMpIDRestoreGapsFromSCR]]
    set APSMpIDRestoreGapsFromSCR(closeInterval) 3
    foreach item $deviceList0 {
        if [string match ID* $item] {
            lappend deviceList $item
            lappend variableList APSMpIDRestoreGapsFromSCR($item)
        }
    }
    set pem 1
    set label ""
    APSStrictParseArguments {pem label}
    if !$pem {
        set  APSMpIDRestoreGapsFromSCR(cancel) 0
        APSDialogBox .idscr -name $label -cancelCommand "set APSMpIDRestoreGapsFromSCR(cancel) 1"
        set frame .idscr.userFrame
    }
    APSCheckButtonFrame .cb -parent $frame -label "Choose IDs" \
      -limitPerRow 8 -buttonList "$deviceList" \
      -variableList "$variableList" -orientation horizontal -allNone 1 
    APSLabeledEntry .interval -parent $frame -textVariable  APSMpIDRestoreGapsFromSCR(closeInterval) \
      -label "Interval of closing gaps (seconds):" -width 70 \
      -contextHelp "Due to on-going restrictions on the SR rf systems, we need to tagger the closing of the gaps by a selectable time interval, i.e. issuing the next gap close command after T seconds of the previous one."
    APSAddSCRDialog .scr -parent $frame -system SR \
      -arrayName APSMpIDRestoreGapsFromSCR \
      -defaultFile $APSMpIDRestoreGapsFromSCR(ShortFilename)
    if !$pem {
        tkwait window .idscr
        if $APSMpIDRestoreGapsFromSCR(cancel) {
            APSMpReturn error "Restore ID gaps from SCR was cancelled."
        }
    }
}

#Called by SR PEMs, SRBPLDArmingTest and SRIDBPMLDValidation
proc APSMpIDRestoreGapsFromSCR {args} {
    global APSMpIDRestoreGapsFromSCR
    set pem 1
    set label ""
    set fullDeviceList [APSIDGetDeviceList -full 0]
    set deviceList $fullDeviceList
    set closeInterval 3
    set ShortFilename ""
    set orbitSwitch 0
    APSStrictParseArguments {deviceList closeInterval pem label ShortFilename orbitSwitch}

    foreach item $fullDeviceList {
        set APSMpIDRestoreGapsFromSCR($item) 1
        if [lsearch -exact $deviceList $item]!=-1 {
            set $item 1
        } else {
            set $item 0
        }
    }
    if ![string length $ShortFilename] {
        if $pem {
            set ShortFilename ""
            APSMpStep init -promptDialog  APSMpIDRestoreGapsFromSCRInitDialog \
              -desc "Choose devices and SCR file"   \
              -vars "$fullDeviceList ShortFilename closeInterval"
        } else {
            set APSMpIDRestoreGapsFromSCR(ShortFilename) ""
            if [catch {APSMpIDRestoreGapsFromSCRInitDialog frame -pem 0 -label $label } result] {
                APSMpReturn error $result
            }
            set ShortFilename $APSMpIDRestoreGapsFromSCR(ShortFilename)
            set closeInterval $APSMpIDRestoreGapsFromSCR(closeInterval)
            set deviceList ""
            foreach item $fullDeviceList {
                if $APSMpIDRestoreGapsFromSCR($item) {
                    set $item 1
                    lappend deviceList $item
                } else {
                    set $item 0
                }
            }
        }
    }
    if ![string length $ShortFilename] {
        APSMpReturn error "APSMpIDRestoreGapsFromSCR: No file chosen."
    }
    set fullFilename /home/helios/oagData/SCR/snapshots/SR/$ShortFilename
    if {[string length $ShortFilename] && ![file exists $fullFilename]} {
        APSMpReturn error "APSMpIDRestoreGapsFromSCR: SCR file $ShortFilename not found"
    }
    set varList "$fullDeviceList ShortFilename"
    foreach par $varList {
        append paramString "$par=\"[set $par]\" "
    }
    catch {APSLogScriptAction  \
             -procedure  APSMpIDRestoreGapsFromSCR  \
             -action initialize \
             -state ok \
             -parameters $paramString \
         }
    set first 1
    set deviceList ""
    set matchOpt ""
    foreach device $fullDeviceList {
        if {[set $device]} {
            lappend deviceList $device
            if $first {
                set first 0
                set matchOpt -match=column,ControlName=$device:GapSetC,ControlName=$device:TaperGapSetC,|
            } else {
                set matchOpt $matchOpt,ControlName=$device:GapSetC,|,ControlName=$device:TaperGapSetC,|
            }
        }
    }
    if ![llength $deviceList] {
        APSMpStep "No devices selected"
        APsMpReturn ok
    }
    
    #if [catch {exec cavget -list=[join $deviceList ,] -list=:Busy -numerical \
      #             -pend=30 -printErrors} busyList] {
    #   APSMpReturn error "APSMpIDRestoreGapsFromSCR: $busyList"
    #}
    
    APSMpStep "Prepare device values"
    set tmpFile /tmp/[APSTmpString]
    APSAddToTempFileList $tmpFile
    if [catch {exec sddsprocess $fullFilename $tmpFile $matchOpt} result] {
        APSMpReturn error "APSMpIDRestoreGapsFromSCR: $result"
    }
    
    APSMpStep "Restore device values"
    if [catch {exec sddscasr -restore $tmpFile } result] {
        APSMpReturn error "APSMpIDRestoreGapsFromSCR: $result"
    }
    after 1000 
    APSMpStep "Moving gaps to setpoints"
    if $pem {
        if [catch {APSIDStaggerGaps -IDList $deviceList -returnGaps 0 -interval $closeInterval} result] {
            APSMpReturn error "APSMpIDRestoreGaps(10): error in stagger gaps: $result"
        }
    } else {
        #can not run in parallel without pem
        set scuList ""
        set otherGaps ""
        set moveID01us 0
        #FIX THIS - not sure if this is correct for the APSU
	if {0} {
	    foreach ID $deviceList {
		if {$ID=="S01ID:DSID" || $ID=="S06ID:DSID" || $ID=="S07ID:DSID"} {
		    #FIX THIS - No SCU in the APSU initially
		    #lappend scuList $ID
		    lappend otherGaps $ID
		} elseif {$ID=="S01ID:USID"} {
		    set moveID01us 1
		} else {
		    lappend otherGaps $ID
		}
	    }
	}
	#no SCU during commissioning
	set otherGaps $deviceList
        if [llength $otherGaps] {
            if [catch {APSIDMoveRegularGaps -IDList $otherGaps -interval $closeInterval} result] {
                return -code error "APSSRMoveIDGaps13: $result"
            }
        }
        if [llength $scuList] {
            foreach ID $scuList {
                if [catch {exec cavget -list=$ID:GapSetC -pend=20 -printErrors} value] {
                    return -code error "APSSRMoveIDGaps14: Error reading $ID:GapSetC: $value"
                }
                if [catch {APSSRMoveSCUID -ID $ID -moveTo $value} result] {
                    return -code error "APSSRMoveIDGaps15: error moving SCU $ID: $result"
                }
            }
        }
        if $moveID01us {
            if [catch {exec cavget -list=S01ID:USID:GapSetC -pend=20 -printErrors} value] {
                return -code error "APSSRMoveIDGaps16: Error reading S01ID:USID:GapSetC: $value"
            }
            if [catch {APSSRMoveID01US -moveTo $value} result] {
                return -code error "APSSRMoveIDGaps17: error moving S01ID:USID gap: $result"
            }
        }
    }
    after 1000 
    #check if gaps are moving
    APSMpStep "Waiting for ID gaps stop moving. (it may take several minutes, please be patient.)"
    if {[catch {APSMpCheckAndWaitForIDs -deviceList $deviceList} results]} {
        if {[APSPEMTKDialog .warningDialog -text "APSMpIDRestoreGapsFromSCR: Problem occurred while waiting restoring ID gaps\n$results"] == 1} {
            APSMpReturn error "APSMpIDRestoreGapsFromSCR: $results"
        }
    }
    APSMpReturn ok
}

#Called by SR PEMs, SRBPMLDArmingTest and SRIDBPMLDValidation
proc APSMpCheckAndWaitForIDs {args} {
    #wait for ID gaps stop moving
    set deviceList ""
    set timeout 500
    set tolerance 0.1
    APSStrictParseArguments {deviceList tolerance timeout}
    
    if ![llength $deviceList] {
        APSMpReturn ok
    }
    set time0 [expr [clock seconds] + $timeout]
    APSMpStep "APSMpCheckAndWaitForIDs: checking if gaps done moving.."
    
    set errorMsg ""
    set deviceList1 $deviceList
    while {[clock seconds]<$time0} {
        if [catch {exec cavget -list=[join $deviceList ,] -list=:MotorDriveStatusM -numerical -pend=30 -printErrors} valList] {
            APSMpReturn error "Error(APSMpCheckAndWaitForIDs1a): $valList"
        }
        set msg "" 
        set IDList $deviceList
	APSMpStep "waiting for [join $deviceList]"
	APSMpStep "Motor Drive Status for above devices: [join $valList]"
        foreach ID $deviceList val $valList {
            if [catch {exec cavget -list=$ID -list=:GapM,:GapSetC -pend=30  -printErrors} results] {
                APSMpReturn error "Error(APSMpCheckAndWaitForIDs1b): $results"
            }
            set gap [lindex $results 0]
            set gapset [lindex $results 1]
            set diff [expr abs($gap-$gapset)]
            if {$diff<=$tolerance} {
                #remove it from checking.
                set index [lsearch $IDList $ID]
                set IDList [lreplace $IDList $index $index]
            } else {
		if [catch {APSCheckIDStatus -ID $ID} result] {
		    append msg $result
		}
	    }
        }
        if ![llength $IDList] {
            APSMpReturn ok
        }
        set deviceList $IDList
        if [string length $msg] {
            APSMpReturn error "Error(APSMpCheckAndWaitForIDs1c): aborted because\n$msg." 
        }
        if [catch {exec cavget -list=[join $deviceList ,] \
                     -list=:Message1M -pend=30 -printErrors} msgList] {
            APSMpReturn error "Error(APSMpCheckAndWaitForIDs1): $msgList"
        }
        set doneMoving 1
        set errorMsg ""
        set restart 0
        foreach gap $deviceList msg $msgList {
            if {[string compare $msg "Device At Destination"]==0} {
                continue
            }
            if {[string compare $msg "Device Started"]==0} {
                set doneMoving 0
                continue
            }
            
            if {[string compare $msg "Device Stopped!!"]==0} {
                set answer [APSMultipleChoice [APSUniqueName .] -modal 1 \
                              -question "$gap was stopped before reaching the destination, would you like to abort the pem or restart moving the gap?" \
                              -returnList {1 0} \
                              -labelList {Abort Restart}]
                if $answer { 
                    APSMpReturn error "$gap was stopped before reaching the destination!"
                } else {
                    set restart 1
                    APSMpStep "$gap $msg, press Start button again."
                    if [catch {exec cavput -list=$gap:StartC=1 -pend=10} result] {
                        APSMpReturn error "Error(APSMpCheckAndWaitForIDs2): $result" 
                    }
                    set doneMoving 0
                }
            } elseif {[string compare $msg "Device Recovered!"]==0} {
                if [catch {exec cavget -list=$gap -list=:GapM,:GapSetC \
                             -pendIO=30 -printErrors} val0List] {
                    APSMpReturn error "Error(APSMpCheckAndWaitForIDs3): $val0List"
                }
                set gapVal [lindex $val0List 0]
                set gapsetVal [lindex $val0List 1]
                set diff [expr abs($gapVal - $gapsetVal)]
                if $diff>$tolerance {
                    set restart 1
                    APSMpStep "$gap $msg, press Start button again."
                    if [catch {exec cavput -list=$gap:StartC=1 -pend=10} result] {
                        APSMpReturn error "Error(APSMpCheckAndWaitForIDs4): $result" 
                    }
                    set doneMoving 0
                }
            } else { 
                append errorMsg "$gap $msg\n" 
            }
        }
        if $restart {
            APSMpStep "Waiting for gaps to stop moving."
            set time0 [expr $time0 + $timeout]
        }
        if $doneMoving {
            break
        }
        APSWaitWithUpdate -waitSeconds 5
    }
    
    if [catch {exec cavget -list=[join $deviceList1 ,] -list=:GapSetC -pend=30 -printErrors } setList] {
        APSMpReturn error "Error(APSMpCheckAndWaitForIDs5): $setList"
    }
    
    if [catch {exec cavget -list=[join $deviceList1 ,] -list=:GapM -pend=30 -printErrors } valList] {
        APSMpReturn error "Error(APSMpCheckAndWaitForIDs6): $valList"
    }
    
    foreach gap $deviceList1 val $valList set $setList {
        set diff [format %.3f [expr abs($set-$val)]]
        if {$diff>$tolerance} {
            append errorMsg "\n$gap setpoint=$set mm, readback=$val mm,  difference=$diff"
        }
    }
    
    if [string length $errorMsg] {
        APSMpReturn  error "${errorMsg}\n\nThe above devices had problem, please call related person for help."
    }
    APSMpReturn ok
}

#Not used
proc TestCheckIDPem {} {
    set deviceList [APSIDGetDeviceList]
    if {[catch {APSMpCheckAndWaitForIDs -deviceList $deviceList -tolerance 0.5 } results]} {
        if {[APSPEMTKDialog .warningDialog -text "APSMpIDRestoreGapsFromSCR: Problem occurred while waiting restoring ID gaps\n$results"] == 1} {
            APSMpReturn error "APSMpIDRestoreGapsFromSCR: $results"
        }
    }
    APSMpReturn ok
}


#Not used
proc APSMpRebootCPUIOCInfo {} {
    return "After studies of CPU, reboot the CPU ioc and verifying critical operational modes before handed over to users."
}

#Not used
proc APSMpRebootCPUIOC {} {
    global execMode
    APSMpStep init -promptDialog "APSMpPromptInitDialog"
    
    set monFile /home/helios/oagData/sr/IDs/CPU/CPU-reboot.mon
    set tmpRoot /tmp/[APSTmpString].cpu
    
    APSMpStep "Step 1: Set the main coil currents to zero amps."
    if [catch {exec cavput -list=ID04b:set_H_coil.VAL=0,ID04b:set_V_coil.VAL=0 } result] {
        APSMpReturn error "APSMpRebootCPUIOC(Error) -- unable to set the H, V coil current to 0: $result"
    }
    APSMpStep "Step 2: Skip the AFG reset procedures."
    
    APSMpStep "Step 3: Have one of the operators reboot the IOC using iocConsol iocid04b command."
    APSInfoWindow .info -name "reboot ioc." -modal 1\
      -width 50 -infoMessage "Have one of the operators reboot the IOC using iocConsol iocid04b command."

    APSMpStep "Step 4: Perform a hard reset using ctrl-yyy"
    APSInfoWindow .info -name "Preform reset." -modal 1\
      -width 50 -infoMessage "Have a operator perform a hard reset using ctril-yyy."
    
    APSMpStep "Step 5: set the access security mode to User."
    
    if [catch {exec cavput -list=ID04b:AccessSecurity.VAL=User -pend=10 } result] {
        APSMpReturn error "APSMpRebootCPUIOC(Error) -- unable to set the access security mode to user: $result"
    }
    
    APSMpStep "Step 6: verify that, in CPU Main Control Screen, the CM/CCW half-period is set to 2.00 sec."
    
    if [catch {exec cavget -list=ID04b:timer.VAL -printErrors -pend=10} hperiod] {
        APSMpReturn error "APSMpRebootCPUIOC(Error) -- unable to read the CM/CCW half-period: $hperiod"
    }
    set halfPeriod 2.0
    if {$hperiod!=$halfPeriod} {
        if [catch {exec cavput -list=ID04b:timer.VAL=$halfPeriod -pend=10} hperiod] {
            APSMpReturn error "APSMpRebootCPUIOC(Error) -- unable to set the CM/CCW half-period: $hperiod"
        }
    }
    
    APSMpStep "Step 7: verify that in the CPU Correct Files screen, the up, down and user (ramp) limit is set to 0.500s/step."
    
    if [catch {exec cavput -list=ID04b:rate_up.VAL=0.5,ID04b:rate_down.VAL=0.5,ID04b:rate_user.VAL=0.5  \
                 -pend=10 } result] {
        APSMpReturn error "APSMpRebootCPUIOC(Error) -- unable to set the up, down and user limit: $result"
    }
    
    APSMpStep "Step 8: set the operation mode to AC CW/CCW"
    
    if [catch {exec cavput -list=ID04b:DesiredMode.VAL=4 -pend=10 } result] {
        APSMpReturn error "APSMpRebootCPUIOC(Error) -- unable to set the operatonal mode: $result"
    }
    after 2000
    
    APSMpStep "Step 9: Set the trigger select to Extenal"
    
    if [catch {exec cavput -list=ID04b:TriggerSelect.VAL=1 -pend=10 } result] {
        APSMpReturn error "APSMpRebootCPUIOC(Error) -- unable to set the trigger selection: $result"
    }
    
    APSMpStep "Step 10: Setup a screen chart to monitor the PVs."
    exec StripTool /home/helios/SHANG/cpu_corrector.stp &
    exec StripTool /home/helios/SHANG/cpu_current.stp &
    
    
    APSMpStep "Step 11: Turn on the main power supply."
    if [catch {exec cavput -list=ID04b:on_off.VAL=1 -pend=10 } result] {
        APSMpReturn error "APSMpRebootCPUIOC(Error) -- unable to turn on the main power supply: $result"
    }
    APSWaitWithUpdate -waitSeconds 20 -update 1
    while {1} {
        if [catch {APScavget -list=ID04b:Ready -pend=10 -printErrors} ready] {
            APSMpReturn error "APSMpRebootCPUIOC(Error) -- unable to read CPU ready state: $ready"
        }
        if {$ready!=1} {
            after 1000
        } else {
            break
        }
    }
    APSMpStep "Step 12: Ramp the energy t0 0.385KeV\n"
    
    if [catch {exec cavput -list=ID04b:set_energy.VAL=0.385 -pend=10} energy] {
        APSMpReturn error "APSMpRebootCPUIOC(Error) -- unable to set the energy: $energy"
    }
    set monID [exec sddsmonitor $monFile $tmpRoot.cpu \
                 -interval=0.2,seconds -time=20,minutes &]
    after 10000
    
    while {1} {
        if [catch {APScavget -list=ID04b:feedback.VAL -pend=10 -printErrors} ready] {
            APSMpReturn error "APSMpRebootCPUIOC(Error) -- unable to read feedback state: $ready"
        }
        if {$ready!="Ready"} {
            after 1000
        } else {
            break
        }
    }

    APSMpStep "Step 12c: set the trigger select switch to external."
    if [catch {exec cavput -list=ID04b:TriggerSelect.VAL=External -pend=10 } result] {
        APSMpReturn error "APSMpRebootCPUIOC -- unable to set the trigger to external: $result"
    }
    
    APSMpStep "Step 13: set the operational mode to \"CW,RCP\""
    
    if [catch {exec cavput -list=ID04b:DesiredMode.VAL=0 -pend=10 } result] {
        APSMpReturn error "APSMpRebootCPUIOC -- unable to set the operational mode to CW,RCP: $result"
    }
    after 10000
    while {1} {
        if [catch {APScavget -list=ID04b:feedback.VAL -pend=10 -printErrors} ready] {
            APSMpReturn error "APSMpRebootCPUIOC(Error) -- unable to read feedback state: $ready"
        }
        if {$ready!="Ready"} {
            after 1000
        } else {
            break
        }
    }
    
    APSMpStep "Step 14: Set the operation mode to \"CCW,LCP\"\n"
    
    if [catch {exec cavput -list=ID04b:DesiredMode.VAL=1 -pend=10 } result] {
        APSMpReturn error "APSMpRebootCPUIOC -- unable to set the operational mode to CCW,RCP: $result"
    }
    after 10000
    while {1} {
        if [catch {APScavget -list=ID04b:feedback.VAL -pend=10 -printErrors} ready] {
            APSMpReturn error "APSMpRebootCPUIOC(Error) -- unable to read feedback state: $ready"
        }
        if {$ready!="Ready"} {
            after 1000
        } else {
            break
        }
    }
    
    APSMpStep "Step 15: Set the operation mode to \"V\""
    
    if [catch {exec cavput -list=ID04b:DesiredMode.VAL=2 -pend=10} result] {
        APSMpReturn error "APSMpRebootCPUIOC -- unable to set the operational mode to V: $result"
    }
    after 2000
    APSMpStep "Step 16a: Ramp the energy to 0.71 keV"
    if [catch {exec cavput -list=ID04b:set_energy.VAL=0.71 -pend=10 } result] {
        APSMpReturn error "APSMpCPUIOCReboot: unable to set energy to 0.71: $result"
    }
    after 2000
    while {1} {
	if [catch {APScavget -list=ID04b:ActualMode -pend=10} mode] {
	    APSMpReturn error "APSMpCPUIOCReboot: unable to read CPU actual mode: $mode"
	}
	if {$mode!="V"} {
	    after 1000
	} else {
	    break
	}
    }
    APSMpStep "Step 16: Set H coil to 1600A"
    if [catch {exec cavput -list=ID04b:set_H_coil.VAL=1600 -pend=10} result] {
        APSMpReturn error "APSMpCPUIOCReboot: unable to set h coil to 1600: $result"
    }
    after 5000
    while {1} {
        if [catch {APScavget -list=ID04b:feedback.VAL -pend=10 -printErrors} ready] {
            APSMpReturn error "APSMpRebootCPUIOC(Error) -- unable to read feedback state: $ready"
        }
        if {$ready!="Ready" } {
            after 1000
        } else {
            break
        }
    }
    
    
    APSMpStep "Step 17: .Set the operation mode to \"H\""
    
    if [catch {exec cavput -list=ID04b:DesiredMode.VAL=3 -pend=10 } result] {
        APSMpReturn error "APSMpRebootCPUIOC -- unable to set the operational mode to H: $result"
    }
    after 2000
    APSMpStep "Step 18: Ramp the energy to 0.71 keV"
    if [catch {exec cavput -list=ID04b:set_energy.VAL=0.71 -pend=10 } result] {
        APSMpReturn error "APSMpCPUIOCReboot: unable to set energy to 0.71: $result"
    }
    
    after 10000
    while {1} {
        if [catch {APScavget -list=ID04b:feedback.VAL -pend=10 -printErrors} ready] {
            APSMpReturn error "APSMpRebootCPUIOC(Error) -- unable to read feedback state: $ready"
        }
        if {$ready!="Ready" } {
            after 1000
        } else {
            break
        }
    }
    
    APSMpStep "Step 19: Set the operation mode to \"CW/CCW\""
    if [catch {exec cavput -list=ID04b:DesiredMode.VAL=4 -pend=10 } result] {
        APSMpReturn error "APSMpRebootCPUIOC -- unable to set the operational mode to H: $result"
    }
    after 10000
    while {1} {
        if [catch {APScavget -list=ID04b:feedback.VAL -pend=10 -printErrors} ready] {
            APSMpReturn error "APSMpRebootCPUIOC(Error) -- unable to read feedback state: $ready"
        }
        if {$ready!="Ready"} {
            after 1000
        } else {
            break
        }
    }
    
    APSMpStep "Step 20: set the V coil current to 0."
    if [catch {exec cavput -list=ID04b:set_V_coil.VAL=0 -pend=10 } result] {
        APSMpReturn error "APSMpRebootCPUIOC(Error) -- unable to set the V coil current to 0: $result"
    }
    while {1} {
        if [catch {APScavget -list=ID04b:feedback.VAL -pend=10 -printErrors} ready] {
            APSMpReturn error "APSMpRebootCPUIOC(Error) -- unable to read feedback state: $ready"
        }
        if {$ready!="Ready"} {
            after 1000
        } else {
            break
        }
    }
    exec kill -9 $monID
    
    APSMpStep "Step 21: Turn off the main power supply by clicking the \"Off\" button."
    
    if [catch {exec cavput -list=ID04b:on_off.VAL=0 -pend=10 } result] {
        APSMpReturn error "APSMpRebootCPUIOC(Error) -- unable to turn off the power supply: $result"
    }
    set filename $tmpRoot.cpu
    
    APSMpStep "Step 22: Check the correction current chart that all the readouts are smooth and no noise peaks reach 0.1 A.\n"
    if [catch {APSProcessCPUCorrector -filename $filename -halfPeriod $halfPeriod} printFile] {
        APSMpReturn error "APSMpRebootCPUIOC(Error) -- error in process CPU correctors: $printFile"
    }
    if [string length $printFile] {
        APSFileDisplayWindow [APSUniqueName .] -fileName $printFile -modal 1 \
          -width 80 -printCommand "enscript -r"
        APSMpReturn error "Some correctors have more than 0.3A difference from the reference. Please check the different and plot, and make sure it is ok; otherwise, you will need re-run the pem."
    } else {
        APSInfoWindow .info -name "Done" -modal 1\
          -width 50 -infoMessage "CPU IOC reboot done successfully."
    }
    APSMpReturn ok
}

#Not used
proc APSProcessCPUCorrector {args} {
    set filename ""
    set tolerance 0.3
    set lowLimit 25
    APSStrictParseArguments {filename lowLimit tolerance}

    global CPUPlotOpt ""
    set tmpRoot /tmp/[APSTmpString]CPU
    catch { exec sddsplot -col=Time,I* -grap=line,vary -tick=xtime $filename & }
    
    set CPUPlotOpt ""
    
    if [catch {exec sddsbreak $filename -pipe=out -change=ID4:CPU:ActualMode  \
                 | tee /tmp/tta \
                 | sddsprocess -pipe -process,ID4:CPU:ActualMode,first,Mode \
                 -process=Iv,max,IvMax \
                 | tee /tmp/ttb \
                 | sddssplit -pipe=in -root=$tmpRoot -digits=3 } result] {
        return -code error "APSProcessCPUCorrector(1): $result"
    }
    
    set fileList [lsort [glob -nocomplain ${tmpRoot}*.sdds]]
    
    set printFiles ""
    set modeList {CW CCW V H AC}
    set index 0
    foreach file $fileList {
	set mode [format %.0f [exec sdds2stream -par=Mode $file]]
        set IvMax [exec sdds2stream -par=IvMax $file]
        if {($index==0 && $mode!=4) || ($mode==4 && $IvMax<100)} {
            #found the first AC mode, where mode=4, and IvMax>100
            continue
        }
        switch $mode {
            4 {
                if {$index==0} {
                    set vol 0.385
                } else {
                    set vol 0.71
                }
                APSMpStep "Process AC mode at $vol KeV."
                if [catch {APSProcessCPUACMode -filename $file -voltage $vol -tolerance $tolerance} result] {
                    return -code error "APSProcessCPUCorrector(2) -- process AC mode: $result"
                }
                if [string length $result] {
                    lappend printFiles $result
                } else {
                    APSMpStep "No difference found for AC mode at $vol KeV."
                }
            }
            default {
		set mode [lindex $modeList $mode]
                APSMpStep "Process $mode..."
                if [catch {ProcessCPUDCData -filename $file -mode $mode -tolerance $tolerance} result] {
                    return -code error "APSProcessCPUCorrector(3) -- process DC mode: $result"
                }
                if [string length $result] {
                    lappend printFiles $result
                } else {
                    APSMpStep "No difference found for DC $mode mode."
                }
            }
        }
        incr index
    }
    set printFile ""
    if [llength $printFiles]>1 {
        set printFile $tmpRoot.print
        eval exec cat $printFiles > $printFile
    } elseif {[llength $printFiles]==1} {
        set printFile $printFiles
    }
    
    if [llength $printFiles] {
        catch {eval exec sddsplot -axes=x -sep=2  $CPUPlotOpt &}
        return $printFile
    }
}

#Not used
proc APSProcessCPUACMode {args} {
    set filename ""
    set voltage ""
    set tolerance 0.1
    set halfPeriod 3
    APSStrictParseArguments {filename voltage tolerance halfPeriod}
    set tmpRoot /tmp/[APSTmpString]AC
    global CPUPlotOpt
    set gap [expr $halfPeriod - 0.5]
    if [catch {exec sddsprocess $filename "-test=col,Iv 10 >" -pipe=out \
                 | sddsbreak -pipe -gapin=Step,amount=1.5 \
                 | sddsprocess -pipe -clip=2,0 -nowarnings \
                 | sddsprocess -pipe -clip=1,0,invert -nowarnings \
                 | sddscombine -pipe=in $tmpRoot.pos -merge 
        exec sddsprocess $filename -pipe=out "-test=col,Iv -10 <" \
                 | sddsbreak -pipe -gapin=Step,amount=1.5 \
                 | sddsprocess -pipe -clip=5,0 -clip=0,1 -nowarnings \
                 | sddsprocess -pipe -clip=1,0,invert -nowarnings \
                 | sddscombine -pipe -merge \
                 | sddsprocess -pipe=in $tmpRoot.neg "-define=col,IvAbs,Iv abs"  \
             } result] {
        return -code error "APSProcessCPUACMode(1): error in processing file: $result"
    }
    set mainDir /home/helios/oagData/
    set corrList {Vcorr2 Hcorr2 Hcorr1 Vcorr1 NormalQuad RotatedOct RotatedQuad}
    for {set i 1} {$i<=7} {incr i} {
        set col [lindex $corrList [expr $i-1]]
        if [catch {exec cavget -list=ID04b:corrFile_${i}.VAL -pend=20 -printErrors} file] {
            return -code error "APSProcessCPUACMode(2): unable to read ID04b:corrFile_${i}.VAL:$file"
        }
        #special case for skewOct, skewQua, should remove it in the future
        
        if [catch {exec sddsconvert $mainDir/$file -pipe=out -del=par,DCPos,DCNeg \
                     | sddsprocess -pipe \
                     -proc=CurrentPos,last,DCPos -proc=CurrentNeg,last,DCNeg \
                     | sddscollapse -pipe \
                     | tee $tmpRoot.$i.cur \
                     | sddsinterp -pipe=in $tmpRoot.$i.pos \
                     -fileValues=$tmpRoot.pos,column=Iv \
                     -col=MainCurrent,DCPos } result] {
            return -code error "APSProcessCPUACMode(3): $result"
        }
        if [catch {exec sddsinterp $tmpRoot.$i.cur $tmpRoot.$i.neg \
                     -fileValues=$tmpRoot.neg,column=IvAbs \
                     -col=MainCurrent,DCNeg } result] {
            return -code error "APSProcessCPUACMode(4): $result"
        }
        if [catch {exec sddsxref $tmpRoot.pos $tmpRoot.$i.pos -rename=col,DCPos=$col $tmpRoot.pos1 -nowarnings
            exec sddsxref $tmpRoot.neg $tmpRoot.$i.neg -rename=col,DCNeg=$col $tmpRoot.neg1 -nowarnings} result] {
            return -code error "APSProcessCPUACMode(5): $result"
        }
        exec mv $tmpRoot.pos1 $tmpRoot.pos
        exec mv $tmpRoot.neg1 $tmpRoot.neg
    }
    if {0} {
        exec sddsplot $tmpRoot.pos -layout=2,4 -topline=AC "-title=Positive current" \
          -sep=2 -axes=x  \
          -col=Iv,*Hcorr1 -grap=sym,vary=sub -leg  \
          -col=Iv,*Hcorr2 -grap=sym,vary=sub -leg  \
          -col=Iv,*Vcorr1 -grap=sym,vary=sub -leg  \
          -col=Iv,*Vcorr2 -grap=sym,vary=sub -leg  \
          -col=Iv,*NormalQuad -grap=sym,vary=sub -leg  \
          -col=Iv,*RotatedOct -grap=sym,vary=sub -leg  \
          -col=Iv,*RotatedQuad -grap=sym,vary=sub -leg &
        
        exec sddsplot $tmpRoot.neg -layout=2,4 -topline=AC "-title=Negative current" \
          -axes=x -sep=2  \
          -col=Iv,*Hcorr1 -grap=sym,vary=sub -leg  \
          -col=Iv,*Hcorr2 -grap=sym,vary=sub -leg  \
          -col=Iv,*Vcorr1 -grap=sym,vary=sub -leg  \
          -col=Iv,*Vcorr2 -grap=sym,vary=sub -leg  \
          -col=Iv,*NormalQuad -grap=sym,vary=sub -leg  \
          -col=Iv,*RotatedOct -grap=sym,vary=sub -leg  \
          -col=Iv,*RotatedQuad -grap=sym,vary=sub -leg &
        
    }
    
    set printFiles ""
    
    foreach corr $corrList {
        foreach type {pos neg} comm {Positive Negative} {
            if [catch {exec sddsprocess $tmpRoot.$type -pipe=out \
                         "-define=col,Diff,ID4:CPU:$corr $corr - abs" \
                         | sddsprocess -pipe=in $tmpRoot.$corr.$type "-test=col,Diff $tolerance >" -nowarnings} result] {
                return -code error "APSProcessCPUACMode(6): $result"
            }
            set rows [exec sdds2stream -rows=bar $tmpRoot.$corr.$type]
            if {$rows} {
                if [catch {exec sddsprintout $tmpRoot.$corr.$type $tmpRoot.$corr.$type.print \
                             "-title=$corr AC mode at $voltage KeV has bigger than 0.1A difference from the reference." \
                             -col=Iv,format=%15.3f -col=ID4:CPU:$corr,format=%15.3f -col=$corr,format=%15.3f \
                             -col=Diff,format=%15.3f } result] {
                    return -code error "APSProcessCPUACMode(7): $result"
                }
                lappend printFiles $tmpRoot.$corr.$type.print
                lappend CPUPlotOpt  -col=Iv,*${corr} -grap=sym,vary=sub -leg "-title=$comm current" "-topline=AC ($voltage KeV)" $tmpRoot.$type
            }
        }
    }
    APSMpStep "$printFiles"
    if [llength $printFiles]==1 {
        set printFile $printFiles
    } elseif {[llength $printFiles]>1} {
        set printFile $tmpRoot.print
        eval exec cat $printFiles > $printFile
    } else {
        return
    }
    return $printFile
}

#Not used
proc ProcessCPUDCData {args} {
    set filename ""
    set mode "" 
    set tolerance 0.3
    APSStrictParseArguments {filename mode tolerance}
    set mainDir /home/helios/oagData/
    set tmpRoot /tmp/[APSTmpString]DC

    global CPUPlotOpt
    if {$mode=="H"} {
        set current Iv
    } else {
        set current Ih
    }
    if [catch {exec sddsprocess $filename $tmpRoot \
                 -sparse=5 \
                 "-redefine=col,I,$current abs" } result] {
        return -code error "ProcessCPUDCData(1): $result"
    }
    set corrList {Vcorr2 Hcorr2 Hcorr1 Vcorr1 NormalQuad RotatedOct RotatedQuad}
    if [catch {exec cavget -list=ID04b:corrFile.VAL -pend=10 -printErrors} refFile] {
        return -code error "ProcessCPUDCData(2): $refFile"
    }
    
    if [catch {exec sddsprocess $mainDir/$refFile -pipe=out -match=par,Mode=$mode \
                 "-redefine=col,I,I abs" \
                 | sddsinterp -pipe=in $tmpRoot.1 -fileValues=$tmpRoot,column=I \
                 -col=I,*} result] {
        return -code error "ProcessCPUDCData(3): $result"
    }
    
    if [catch {exec sddsxref $tmpRoot $tmpRoot.1 $tmpRoot.$mode -take=[join $corrList ,] -transfer=par,Mode } result] {
        return -code error "ProcessCPUDCData(4): $result"
    }
    if {0} {
        exec sddsplot $tmpRoot.$mode -topline=@Mode \
          -layout=4,2 -sep=2 -axes=x \
          -col=$current,*Hcorr1 -grap=sym,vary=sub -leg \
          -col=$current,*Hcorr2 -grap=sym,vary=sub -leg  \
          -col=$current,*Vcorr1 -grap=sym,vary=sub -leg  \
          -col=$current,*Vcorr2 -grap=sym,vary=sub -leg  \
          -col=$current,*NormalQuad -grap=sym,vary=sub -leg  \
          -col=$current,*RotatedOct -grap=sym,vary=sub -leg  \
          -col=$current,*RotatedQuad -grap=sym,vary=sub -leg &
    }
    
    set printFiles ""
    foreach corr $corrList {
        if [catch {exec sddsprocess $tmpRoot.$mode -pipe=out \
                     "-define=col,Diff,ID4:CPU:$corr $corr - abs" \
                     | sddsprocess -pipe=in $tmpRoot.$corr "-test=col,Diff $tolerance >" -nowarnings} result] {
            return -code error "APSProcessCPUDCMode(5): $result"
        }
        set rows [exec sdds2stream -rows=bar $tmpRoot.$corr]
        if {$rows} {
            if [catch {exec sddsprintout $tmpRoot.$corr $tmpRoot.$corr.print \
                         "-title=$corr $mode DC mode has bigger than 0.1A difference from the reference." \
                         -col=$current,format=%15.3f -col=ID4:CPU:$corr,format=%10.3f -col=$corr,format=%15.3f \
                         -col=Diff,format=%15.3f } result] {
                return -code error "APSProcessCPUDCMode(6): $result"
            }
            lappend printFiles $tmpRoot.$corr.print
            lappend CPUPlotOpt -col=$current,*${corr} -grap=sym,vary=sub -leg -topline=$mode $tmpRoot.$mode
        }
    }
    if [llength $printFiles]==1 {
        set printFile $printFiles
    } elseif {[llength $printFiles]>1} {
        set printFile $tmpRoot.print
        eval exec cat $printFiles > $printFile
    } else {
        return
    }
    
    return $printFile
}

#Called by APSMpIDSwitchToUserMode
proc APSSetupSRCerenkovDector {args} {
    set detectorList [exec sdds2stream -col=Sector /home/helios/oagData/sr/cerenkov/inputFiles/cherenkovSetup.sdds]
    set filename ""
    set statusCallback ""
    APSStrictParseArguments {detectorList filename statusCallback}

    if ![string length $filename] {
        #find the last setup file
        #FIX THIS - We should probably use the same cherenkovSetup.sdds file
        set filename /home/helios/PHOTODIA/DeviceData/SR/Cherenkov/cherenkovSetup.sdds
    }
    if ![file exist $filename] {
        return -code error "APSSetupSRCerenkovDector(1): setup file $filename does not exist!"
    }
    set tmpRoot /tmp/[APSTmpString]
    foreach detector $detectorList {
        set site "${detector}"
        set board [APSGetCherenkovBoard -detector $detector]
        if [catch {exec sddsprocess $filename $tmpRoot -match=col,Site=$site } result] {
            APSMpReturn error "APSSetupSRCerenkovDector(2): error in finding $site in $filename: $result"
        }
        set targetPMTVolt [format %0.1f [exec sdds2stream $tmpRoot -col=targetPMTVolt]]
        set Adc0AIOffset  [format %0.0f [exec sdds2stream $tmpRoot -colum=Adc0AIOffset]]
        set Adc1AIOffset  [format %0.0f [exec sdds2stream $tmpRoot -column=Adc1AIOffset]]
        set Discriminator [format %0.3f [exec sdds2stream $tmpRoot  -column=Discriminator]]
        if [catch { exec /home/helios/oagData/sr/cerenkov/scripts/setupCherenkovOneSector -sector $board \
                      -integratorOffset0 $Adc0AIOffset -integratorOffset1 $Adc1AIOffset -pmtHV $targetPMTVolt \
                      -discriminator $Discriminator \
                  } result] {
            APSMpReturn error "APSSetupSRCerenkovDector(3): error in setup $board: $result"
        }
        APSMpStep "APSStupCherenkovDetector: Complete initializing Cherenkov detector boards at $board."
        if [string length $statusCallback] {
            eval $statusCallback {"APSStupCherenkovDetector: Complete initializing Cherenkov detector boards at $board."}
        }
    }
    APSMpReturn ok
}

#Called by APSSetupSRCerenkovDector
proc APSGetCherenkovBoard {args} {
    set detector ""
    APSStrictParseArguments {detector}

    set detectorList3 { S4A S4B S4C S4D S4E S36a S36b S36c S36d S36e }
    set boardList3    { S3  S5  S6  S7  S8  S36a S36a S36a S36a S36a }
    set detectorIndex [lsearch $detectorList3 $detector]
    if { $detectorIndex > -1 } {
        set board [lindex $boardList3 $detectorIndex]
    } else {
        set board $detector
    }
    return $board
}

proc APSMpIEXInitializeInfo {} {
    return "Prepare IEX for next user operation period by:\n1. Run degaussing and conditioning of the magnet. If you select degauss, then condition will be selected automatically.\n2. Reset IEX parameters to default values."
}

#Called by APSMpIEXInitializeInitDialog
proc UpdateIEXSelection {args} {
    global APSMpIEXInitialize
    if $APSMpIEXInitialize(reset) {
        set APSMpIEXInitialize(degauss) 0
        set APSMpIEXInitialize(condition) 0
    }
    if {$APSMpIEXInitialize(degauss) || $APSMpIEXInitialize(condition)} {
        set APSMpIEXInitialize(reset) 0	
    }
    if $APSMpIEXInitialize(degauss) {
        set APSMpIEXInitialize(condition) 1
    }
}

proc APSMpIEXInitializeInitDialog {frame} {
    global APSMpIEXInitialize
    APSCheckButtonFrame .cb -parent $frame -label "check deguass or condition" \
      -limitPerRow 8 -buttonList {reset degauss condition} \
      -variableList "APSMpIEXInitialize(reset) APSMpIEXInitialize(degauss) APSMpIEXInitialize(condition)" \
      -commandList {UpdateIEXSelection UpdateIEXSelection UpdateIEXSelection}
}

#Called by SR PEM
proc APSMpIEXInitialize {args} {
    global APSMpIEXInitialize
    set APSMpIEXInitialize(reset) 1
    set APSMpIEXInitialize(degauss) 0
    set APSMpIEXInitialize(condition) 0
    
    APSMpStep init -promptDialog "APSMpIEXInitializeInitDialog" \
      -desc "check degauss or condition"

    catch {exec cavput -list=S29ID:Main_on_offC.VAL=1}
    if {[set a [exec cavget -list=S29ID:SaveDioWrite_.VAL -pend=10]] != 8185} {
	APSMpReturn error "IEX status is not correct. Turn off IEX or Ask expert for help.\n Last DIO Write = $a"
    }

    APSMpStep "Step 0: Reset IEX parameters"
    if [catch {
	exec caput S29ID:BxStepLimitC 2
        exec caput S29ID:ByStepLimitC 2
        #        exec caput ID29:QuasiRatio.RVAL 100
        exec caput S29ID:dVSetpt_ 10
        exec caput S29ID:dTSetpt_ 20
        exec caput S29ID:dHSetpt_ 10
        exec caput S29ID:RampWaitTime_ 1.5
	exec caput S29ID:PolarityWaitTime_ 1.5
        exec caput S29ID:PolarityResetSeq_.PROC 1
        after 2000
        exec caput S29ID:SetPSLocRem_ 1
        after 1000
        exec caput S29ID:SetPSLocRem_ 0
        exec caput S29ID:ReadSDDSfile_.PROC 1
        exec caput S29ID:ZeroMult_.PROC 1
        after 1000
        exec caput S29ID:MP2I_.PROC 1
        after 1000
        exec caput S29ID:SetOutputSeq_.PROC 1
        after 1000
        exec caput S29ID:CorrRstSeq_.PROC 1 
	after 1000
	exec caput S29ID:RstIntlckSeq_.PROC 1
    } result] {
        APSMpReturn -error "APSMpIEXInitialize1: error in reset IEX parameters: $result"
    }    
    after 5000

    APSMpStep "Step 1: Check IEX PS status"
    set PScheck 0
    set PScheckErr ""
    set mainPS [exec cavget -list=S29ID:BxRdbkM.VAL,S29ID:ByRdbkM.VAL,S29ID:BxqRdbk_,S29ID:ByqRdbk_]
    set mainPSName "Bx By Bxq Byq"
    set corrPS [exec cavget -list=S29ID:CorrRdbk -list=UST,USB,USQ1,USQ2,USQ3,USQ4,DST,DSB,DSQ1,DSQ2,DSQ3,DSQ4 -list=_]
    set corrPSName "UST USB USQ1 USQ2 USQ3 USQ4 DST DSB DSQ1 DSQ2 DSQ3 DSQ4"
    set earthPS [exec cavget -list=S29ID:CorrRdbkEarth_.VAL]
    if {[expr abs($earthPS + 1.25)]>0.25} {
	set PScheck 1
	lappend PScheckErr "earth"
    }
    foreach ps $mainPS name $mainPSName {
	if {[expr abs($ps)]>0.5} {
	    set PScheck 1
	    lappend PScheckErr $name
	}
    }
    foreach ps $corrPS name $corrPSName {
	if {[expr abs($ps)]>0.02} {
	    set PScheck 1
	    lappend PScheckErr $name
	}
    }
    if $PScheck {
	APSMpReturn error "IEX PS has wrong read backs.\nList=$PScheckErr"
    }

    APSMpStep "Step 2: Check IEX interlock status"
    set intertLockCheck 0
    set intertLockCheckErr ""
    set interLockPV "S29ID:CorrectorReset_ S29ID:MainOnOff_"
    set interLockPV [concat $interLockPV "S29ID:BxPolarity_ S29ID:ByPolarity_ S29ID:BxqPolarity_ S29ID:ByqPolarity_ S29ID:PolarityReset_"]
    set interLockPV [concat $interLockPV "S29ID:MainPS1OutEn_ S29ID:MainPS2OutEn_ S29ID:MainPS3OutEn_ S29ID:MainPS4OutEn_"]
    foreach inter $interLockPV {
	if {![lindex [exec caget -n $inter] 1]} {
	    set intertLockCheck 1
	    lappend intertLockCheckErr $inter
	}
    }
    if {[lindex [exec caget -n S29ID:CorrectorInh_] 1] || [lindex [exec caget -n S29ID:LocalRemote_] 1]} {
	set intertLockCheck 1
	lappend intertLockCheckErr $inter
    }
    if ![string match [set a [exec cavget -list=S29ID:feedbackM.VAL]] Ready] {
	set intertLockCheck 1
	lappend intertLockCheckErr $a	
    }
    if $intertLockCheck {
	APSMpReturn error "IEX interlock status is wrong, goto IEXinterlocks.adl for detail infomation.\n PV=$intertLockCheckErr"
    }

    APSMpStep "Step 3: Start IEX degauss and condition if it has been checked."
    if {$APSMpIEXInitialize(degauss) || $APSMpIEXInitialize(condition)} {
	if {[lindex [exec caget S-DCCT:CurrentM] 1]>1} {
	    APSAlertBox .warning -errorMessage "Current > 1 mA, Dump beam first then continue."
	}
	exec caput S29ID:DegaussMaskBx_ 1
	exec caput S29ID:DegaussMaskBy_ 1
	exec caput S29ID:DegaussMaskBxq_ 1
	exec caput S29ID:DegaussMaskByq_ 1
	exec caput S29ID:LinearCircular_ 0
	if {$APSMpIEXInitialize(degauss)} {
            APSMpStep "degaussing..."
	    exec caput S29ID:CorrDegauss_ 1
	    exec caput S29ID:Main_on_offC.VAL  0
	    exec caput S29ID:dGticks_ 40
	    exec caput S29ID:dGnum_ 10
	    exec caput S29ID:ConditioingSelect_ 0
	    exec caput S29ID:DegaussSeq_.PROC  1
            APSWaitWithUpdate -waitSeconds 180 -updateInterval 1
	}
	if {$APSMpIEXInitialize(condition)} {
            APSMpStep "conditioning ..."
	    exec caput S29ID:CorrDegauss_ 0
	    exec caput S29ID:Main_on_offC.VAL  0
	    exec caput S29ID:dGticks_ 100
	    exec caput S29ID:dGnum_ 5
	    exec caput S29ID:ConditioingSelect_ 1
	    exec caput S29ID:DegaussSeq_.PROC  1
	    APSWaitWithUpdate -waitSeconds 220 -updateInterval 1
	}
        APSMpStep "Turn off..."
	exec caput S29ID:DegaussMaskBx_ 0
	exec caput S29ID:DegaussMaskBy_ 0
	exec caput S29ID:DegaussMaskBxq_ 0
	exec caput S29ID:DegaussMaskByq_ 0
	exec caput S29ID:CorrDegauss_ 0
	exec caput S29ID:Main_on_offC.VAL  1
    }
    APSMpReturn ok
}

#Called by SR PEMs
proc APSSRMoveSCUID {args} {
    set ID ""
    set moveTo ""
    APSStrictParseArguments {ID moveTo}
    
    #FIX THIS - I don't know the new PV names
    if [catch {exec cavget -list=$ID:MainOn -num -pend=30} OnOff] {
        APSMpReturn error "APSSRMoveSCUID1: error reading $ID:MainOn: $OnOff"
    }
    if {$moveTo>50} {
        if $OnOff {
            if [catch {exec cawait  -interval=1 -timelimit=600 -waitFor=$ID:GapM,lower=[expr $moveTo - 1],upper=[expr $moveTo + 1] } result] {
                APSMpReturn error "APSSRMoveSCUID7: error reducing current of $ID: $result"
            }
            #FIX THIS - I don't know the new PV names
            if [catch {exec cavput -list=$ID:Main_OnOff=0  -pend=30 } result] {
                APSMpReturn error "APSSRMoveSCUID7: error turning of SCU $ID: $result"
            }
        }
    } else {
        if !$OnOff {
            #ID01ds is special, has to open ID01us before turn it on
            if {$ID=="S01ID:DSUS"} {
                if [catch {exec cavput -list=S01ID:USID:GapSetC=140 -pend=20
                    exec cavput -list=S01ID:USID:StartC=1 -pend=10
                    exec cawait -waitFor=S01ID:USID:GapM,lowerLimit=139,upperLimit=141 -timeLimit=600 } result] {
                    APSMpReturn error "APSSRMoveSCUID2: Error opening S01ID:USID gap: $result"
                }
            }
            while {1} {
                #turn on SCU
                #FIX THIS - I don't know the new PV names
                if [catch {exec cavput -list=$ID:Main_OnOff=1 -pend=20 } result] {
                    APSMpReturn error "APSSRMoveSCUID3: Error turnning on SCU1: $result"
                }
                
                APSWaitWithUpdate -waitSeconds 20 -updateInterval 1
                if [catch {APScavget -list=$ID:MainOn -num -pend=30} onOff] {
                    APSMpReturn error "APSSRMoveSCUID4: error reading $ID:MainOn: $onOff"
                }
                if $onOff {
                    break
                } else {
                    #wait another 20 seconds
                    for {set i 0} {$i<20} {incr i} {
                        if [catch {APScavget -list=$ID:MainOn -num -pend=30} onOff] {
                            APSMpReturn error "APSSRMoveSCUID4a: error reading $ID:MainOn: $onOff"
                        }
                        APSWaitWithUpdate -waitSeconds 1 -updateInterval 1
                        if $onOff {
                            break
                        }
                    }
                }
                if ${onOff} {
                    break
                }
                set answer [APSMultipleChoice [APSUniqueName .] -modal 1 \
                              -question "SCU $ID is not on yet, would you like turn in on again or abort" \
                              -returnList {1 0} \
                              -labelList {Turn_On_Again Abort}]
                if !$answer {
                    APSMpReturn error "APSSRMoveSCUID5: can not turn SCU1 on!"
                }
            }
        }
        #set to the desired value
        if [catch {exec cavput -list=$ID:GapSetC=$moveTo -pend=30} result] {
            APSMpReturn error "APSSRMoveSCUID6: error change $ID gap to $moveTo: $result"
        }
    }
    APSMpReturn ok
}

#Called by SR PEMs
proc APSSRMoveID01US {args} {
    set moveTo ""
    APSStrictParseArguments {moveTo} 

    if {$moveTo<150} {
        #close ID01us -- has to turn off ID01ds (SCU1)
        #FIX THIS - I don't know the new PV names
        if [catch {exec cavget -list=S01ID:DSID:MainOn -num -pend=30} scu1OnOff] {
            APSMpReturn error "APSSRMoveID01US1: Error reading ID01ds:Main_OnOff: $scu1OnOff"
        }
        if {$scu1OnOff} {
            if [catch {exec cavput  -list=S01ID:DSID:Main_OnOff=0  -pend=20
                exec cawait -waitFor=S01ID:DSID:GapM,lowerLimit=139,upperLimit=141 -timeLimit=600 } result] {
                APSMpReturn error "APSSRMoveID01US2: Error opening ID01ds gap: $result"
            }
        }
    }
    if [catch {exec cavput -list=S01ID:DSID:GapSetC=$moveTo -pend=20 
        exec cavput -list=S01ID:DSID:StartC=1 -pend=20} result] {
        APSMpReturn error "APSSRMoveID01US3: Error moving ID01us to $moveTo: $result"
    }
    APSMpReturn ok
}

#Called by SR PEMs, SRCollectGapFFData and SRFitGapScan
proc APSSRMoveIDGaps {args} {
    set IDList ""
    set moveTo 20
    set minGapList ""
    set lockedIDList ""
    set fixedIDList ""
    set fixedGapList ""
    set closeInterval 3
    #move provided IDList gap to 20mm, and open others if open is 1
    set open 0
    set pem 1
    APSStrictParseArguments {IDList open moveTo minGapList deltaToMinGap lockedIDList fixedIDList fixedGapList closeInterval pem} 
    
    if ![llength $IDList] {
        return
    }
    
    if ![llength $lockedIDList] {
        set lockedIDList [APSSRGetLockedIDDevices]
    }
    set tmpRoot /tmp/[APSTmpString]
    
    foreach ID $fixedIDList {
        set index [lsearch $IDList $ID]
        if $index>=0 {
            set IDList [lreplace $IDList $index $index]
            set minGapList [lreplace $minGapList $index $index]
        }
    }

    if [string compare $moveTo "MinimumGap"]==0 {
        set IDList [concat $IDList $fixedIDList]
        set minGapList [concat $minGapList $fixedGapList]
        
        if [catch {exec sddsmakedataset -pipe=out \
                     -col=DeviceName,type=string -data=[join $IDList ,] \
                     -col=MoveGapTo,type=double -data=[join $minGapList ,] \
                     | sddsprocess -pipe -edit=col,ControlName,DeviceName,ei/:DeviceLimitM/ \
                     | sddssort -pipe -col=DeviceName \
                     | sddscasr -pipe -save \
                     | sddsprocess -pipe=in $tmpRoot.set -match=col,CAError=n \
                     -reedit=col,ControlName,%/DeviceLimitM/GapSetC/ \
                     -scan=col,MinimumGap,ValueString,%f,type=float \
                     "-reprint=col,ValueString,%f,MoveGapTo" } result] {
            return -code error "APSSRMoveIDGaps1: $result"
        }
        if [catch {exec sddsprintout $tmpRoot.set $tmpRoot.printout \
                     -col=ControlName,format=%30s -col=MinimumGap,format=%.3f \
                     -col=MoveGapTo,format=%.3f } result] {
            return -code error  "APSSRMoveIDGaps2: $result"
        }
        global MoveGap
        set MoveGap 0
        APSFileDisplayWindow .gap -fileName $tmpRoot.printout -width 80 -modal 1 \
          -closeButton 0 -okButton 1 -cancelButton 1 -okCommand "set MoveGap 1;destroy .gap" \
          -cancelCommand "set MoveGap 0;destroy .gap" 
        if !$MoveGap {
            return -code error "APSSRMoveIDGaps3: Moving gaps to minimum was canceled!"
        }
        APSSetVarAndUpdate status "Moving gaps to their minimum gap values..."
        if [catch {exec sddsprocess $tmpRoot.set -reedit=col,ControlName,%/GapSetC/TaperGapSetC/ \
                     -nowarnings \
                     -reprint=col,ValueString,0  $tmpRoot.taper} result] {
            return -code error  "APSSRMoveIDGaps4: $result"
        }
    } else {
        set gapList [APSReplicateItem -item $moveTo -number [llength $IDList]]
        if [llength $fixedIDList] {
            set IDList [concat $IDList $fixedIDList]
            set gapList [concat $gapList $fixedGapList]
        }
        
        if [catch {exec sddsmakedataset -pipe=out -col=DeviceName,type=string -data=[join $IDList ,] \
                     -col=MoveGapTo,type=double -data=[join $gapList ,] \
                     | sddssort -pipe -col=DeviceName \
                     | sddsprocess -pipe=in $tmpRoot.set \
                     -edit=col,ControlName,DeviceName,ei/:GapSetC/ \
                     -print=col,ValueString,%lf,MoveGapTo } result] {
            return -code error "APSSRMoveIDGaps5: $result"
        }
        APSSetVarAndUpdate status "Moving gaps to $moveTo mm..."
    }
    
    if [catch {exec sddsprocess $tmpRoot.set $tmpRoot.startmove \
                 -reedit=col,ControlName,%/GapSetC/StartC/ \
                 -reprint=col,ValueString,1 } result] {
        return -code error "APSSRMoveIDGaps6: $result"
    }
    if [string compare $moveTo "MinimumGap"]==0 {
        set rows [exec sdds2stream -rows=bar $tmpRoot.taper]
        if $rows {
            if [catch {exec sddscasr -restore $tmpRoot.taper } result] {
                return -code error  "APSSRMoveIDGaps7: $result"
            }
        }
    }
    if $open {
        #open other gaps 
        APSSetVarAndUpdate status "Open all other gaps..."
        APSMpStep "Open all other gaps..."
        set filterOpt ""
        set lockedIDList [concat $lockedIDList $fixedIDList]
        foreach ID $lockedIDList {
            if [string length $filterOpt] {
                append filterOpt ",GapName=$ID,!,&"
            } else {
                append filterOpt "-match=col,GapName=$ID,!"
            }
        }
        APSAddToTmpFileList -ID fullscan -fileList "$tmpRoot.open $tmpRoot.open.start"
        if [catch {eval exec sddsselect /home/helios/oagData/sr/IDs/SetGapTo140mm $tmpRoot.set \
                     -match=DeviceName -invert -pipe=out \
                     | sddsprocess -pipe=in $filterOpt $tmpRoot.open -reprint=col,IDName,%s,DeviceName
            exec sddscombine $tmpRoot.set $tmpRoot.open -merge $tmpRoot.set1} result] {
            return -code error  "APSSRMoveIDGaps8: $result"
        }
        exec mv $tmpRoot.set1 $tmpRoot.set
    }
    if [catch {exec sddscasr -restore $tmpRoot.set } result] {
        return -code error  "APSSRMoveIDGaps11: $result"
    }
    set moveList [join [exec sdds2stream -col=DeviceName $tmpRoot.set]]
    if $pem {
        if [catch {APSIDStaggerGaps -IDList $moveList} result] {
            return -code error "APSSRMoveIDGaps12: $result"
        }
    } else {
        set otherGaps $moveList
        if [llength $otherGaps] {
            if [catch {APSIDMoveRegularGaps -IDList $otherGaps -interval $closeInterval} result] {
                return -code error "APSSRMoveIDGaps13: $result"
            }
        }
    }
    set fileList [glob -nocomplain ${tmpRoot}.*]
    APSAddToTmpFileList -ID fullscan -fileList $fileList
    return $moveList
}

proc APSGetGoodIDLists {args} {
    set confirm 0
    set IDList ""
    set statusCallback ""
    set closeGap 0
    APSParseArguments {confirm IDList statusCallback closeGap}
    if ![string length $IDList] {
	set IDList [exec sdds2stream -col=DeviceName /home/helios/oagData/sr/IDs/devices.sdds]
    }
    set IDList0 $IDList
    set IDList ""
    set badIDList [APSIDGetBadDeviceList -closeGap $closeGap]
    foreach ID $IDList0 {
	set index [lsearch -exact $badIDList $ID]
	if {$index>=0} {
	    if $confirm {
		if {[APSPEMTKDialog .warningDialog -text "APSGetGoodIDLists: $ID can not be moved."] == 1} {
		    APSMpReturn error "APSGetGoodIDList(1): $ID can not be moved."
		}
	    }
	    if [string length $statusCallback] {
		eval $statusCallback {"Error: $ID can not be moved!"}
	    }
	} else {
	    lappend IDList $ID
	}
    }
    return $IDList
}

proc APSCheckIDStatus {args} {
    set ID ""
    set closeGap 0
    APSParseArguments {ID closeGap}
    set sector [scan $ID S%ld]
    set sectorf [format %02d $sector]
    if [catch {exec cavget -pend=5 -num -list=S${sectorf}ID-FEEPS:PS1:OpenedM,${ID}:MotorDriveStatusM,${ID}:AccessSecurityC,${ID}:GlobalBusyM,S${sectorf}ID-FEEPS:Beamline:CantedM,S${sectorf}ID-FEEPS:Cant_DPSI_StatusM -printError } valList] {
	return -code error "Error reading $ID motor drive status and access security: $valList"
    }
    set shutter [lindex $valList 0]
    set status [lindex $valList 1]
    set security [lindex $valList 2]
    set busy [lindex $valList 3]
    set canted [lindex $valList 4]
    set CUonoff [lindex $valList 5]
    set errorMsg ""
    if !$closeGap {
	#ignore shutter when open gap
	set shutter 1
    } else {
	#for canted ID, need check if the CU corrector is on for close gaps
	if {$canted} {
      	    if !$CUonoff {
		append errorMsg "S$sector CU corrector is off!"
	    }
	}
    }
    if {$shutter==0} {
	append errorMsg "$ID PS1 shutter is closed! "
    }
    if {$status==0} {
	append errorMsg "$ID motor drive is not ready! "
    }
    if {$security==3} {
	append errorMsg "$ID is in system manager mode! "
    }
    if {$busy==1} {
	append errorMsg "$ID is in global busy mode! "
    }
    if [string length $errorMsg] {
	append errorMsg "can not be moved!"
	return -code error $errorMsg
    }
}

proc APSCheckIDsStatus {args} {
    set IDList ""
    set closeGap 0
    APSParseArguments {IDList closeGap}
    set sectorfList ""
    set shutterList ""
    if [catch {exec cavget -list=[join $IDList ,] -list=:GapSetC -pend=5 -printErrors} setGapList] {
	return -code error "Error reading gap set values; $setGapList"
    }
    if [catch {exec cavget -list=[join $IDList ,] -list=:GapSetC -pend=5 -printErrors} gapList] {
	return -code error "Error reading gap values; $gapList"
    }
    foreach ID $IDList setGap $setGapList gap $gapList {
	set sector [scan $ID S%ld]
	set sectorf [format %02d $sector]
	lappend sectorfList $sectorf
	if {$gap>=50 && $setGap<50} {
	    lappend shuterList 1
	    #shutter needs to be open when close gap from above 50mm
	} else {
	    lappend shuterList 0
	}
    }
    if $closeGap {
	if [catch {exec cavget -pend=5 -num -list=S -list=[join $sectorfList ,] -list=ID-FEEPS:PS1:OpenedM -printError} shutterList] {
	    return -code error "APSCheckIDsStatus0: Error reading PS1 shutter: $shutterList"
	}
    }
    if [catch {exec cavget -pend=5 -num -list=[join $IDList ,] -list=:MotorDriveStatusM  -printError } statusList] {
	return -code error "APSCheckIDsStatus1: Error reading $IDList motor drive status: $statusList"
    }
    if [catch {exec cavget -pend=5 -num -list=[join $IDList ,] -list=:AccessSecurityC  -printError } securityList] {
	return -code error "APSCheckIDsStatus2: Error reading $IDList access security: $motorList"
    }
    if [catch {exec cavget -pend=5 -num -list=[join $IDList ,] -list=:GlobalBusyM  -printError } busyList] {
	return -code error "APSCheckIDsStatus2: Error reading $IDList access security: $motorList"
    }
    set errorMsg ""
    foreach ID $IDList shutter $shutterList status $statusList security $securityList busy $busyList {
	if {$shutter==0 || $status==0 || $security==3 || $busy} {
	    append errorMsg "$ID"
	    if {$shutter==0} {
		append errorMsg " PS1 shutter is closed,"
	    }
	    if {$status==0} {
		append errorMsg " motor drive not ready,"
	    }
	    if {$security==3} {
		append errorMsg " in system manager mode,"
	    }
	    if {$busy} {
		append errorMsg " in global busy mode,"
	    }
	    append errorMsg " can not be moved.\n"
	}
    }
    if [string length $errorMsg] {
	return -code error $errorMsg
    }
}
