


proc LMOCS_Recover_ChangeAttenuator {args} {
    set device ""
    set klyDriveRef ""
    APSStrictParseArguments {device klyDriveRef}
    set RF L$device

    #global AttenCtrl AttenCtrlVar abort errorCode RF KlystronVar AttenIncrVar AttenDecVar klyDriveRef klyDrive klyDriveLimit abort
    set timeout 120
    set timeout 20
    if {[catch {APScavget -list=${RF}:KY:DC1RF.VAL -pend=5 -printErrors} klyDrive]} {
        return -code error "Error reading attenuator (${RF}:KY:DC1RF.VAL): $klyDrive"
    }
    if {$klyDrive < $klyDriveRef} {
        #use decrease attenuator button to increase the klystron drive
        set attenVar ${RF}:MA:decKlyBO
        set increase 1
    } elseif {$klyDrive > $klyDriveRef} {
        #use increase attenuator button to descrease the klystron drive
        set attenVar ${RF}:MA:incKlyBO
        set increase 0
    } else {
        #nothing to do
        return
    }
    #toggle increase/decrease button to change attentuator
    set zeroCounts 0
    while {1} {
        if {[catch {APScavget -list=${RF}:KY:DC1RF.VAL -pend=5 -printErrors} klyDrive]} {
            return -code error "Error reading attenuator (${RF}:KY:DC1RF.VAL): $klyDrive"
        }
        if {[expr abs($klyDrive - $klyDriveRef)]<=1} {
            #reach the target already
            APSMpStep "Klystron drive now is $klyDrive, reached the target~$klyDriveRef)."
            return
        }
        if {$klyDrive < $klyDriveRef} {
            #use decrease attenuator button to increase the klystron drive
            set attenVar ${RF}:MA:decKlyBO
        } elseif {$klyDrive > $klyDriveRef} {
            #use increase attenuator button to descrease the klystron drive
            set attenVar ${RF}:MA:incKlyBO
        }
        
        set ratio [expr $klyDrive/$klyDriveRef]
        if {$ratio<0.1} {
            set holdTime 5
            set holdTime 5000
        } elseif {$ratio<0.5} {
            set holdTime 1
            set holdTime 1000
        } elseif {$ratio<0.75} {
            set holdTime .3
            set holdTime 300
        } else {
            set holdTime .05
            set holdTime .1
            set holdTime 100
        }
        APSMpStep "Klystron drive now is $klyDrive ( should be ~$klyDriveRef) (press time=$holdTime milliseconds)..."

        set drive0 $klyDrive
        if {[catch {APScavput -list=${attenVar}=1 -pend=5} results]} {
            return -code error "Error change attenuator: $results"
        }
        #APSWaitWithUpdate -waitSeconds $holdTime
        after $holdTime
        if {[catch {APScavput -list=${attenVar}=0 -pend=5} results]} {
            return -code error "Error stop change attenuator: $results"
        }
        APSWaitWithUpdate -waitSeconds 3
        #when the RF rate is 2 or 4, the klydrive updates very slow, wait for the klydrive to be update before continue 
        #changing attenuator
        APSMpStep "waiting for $RF klystron drive to be updated... $klyDrive $zeroCounts"
        
        if {$klyDrive>5 || $zeroCounts>5} {
            set timeout [expr [clock seconds]+$timeout]
            while {[clock seconds] < $timeout} {
                if {[catch {APScavget -list=${RF}:KY:DC1RF.VAL -pend=5 -printErrors} klyDrive]} {
                    return -code error "Error reading klystron drive: $klyDrive"
                }
                if {[expr abs($klyDrive - $drive0)] > 0.01} {
                    break
                }
                APSWaitWithUpdate -waitSeconds 1
            }
#This problem came up
            if {($klyDrive < 5) && ($zeroCounts > 5)} {
                set answer [APSPEMTKDialog .warningDialog -text "The klystron drive is less than 5W after 5 tries, do you want to manually adjust it and continue or abort?" -strings {Continue "Abort Procedure"}]
                if {$answer == 1} {
                    return -code error "The klystron drive is less than 5W after 5 tries, recovery aborted."
                }
                set zeroCounts 0
            }
            if {[expr abs($klyDrive-$drive0)] < 0.01} {
                return -code error "The klystron drive is not updating within 2 minutes, something wrong, abort recovery."
            }
        } else {
            incr zeroCounts
        }
        APSMpStep "continuing..."
    }
}

proc LMOCS_Recover_CheckVacuumAndWait {args} {
    global apsVacInit
    set vaccumTimeout 300
    set vacPVs ""
    set interval 5
    set L2 0    
    set L5 0
    set L6 0
    set readings 3
    APSStrictParseArguments {vacPVs interval L2 L5 L6 VacuumLimit readings}
    set MultPacketStart(L5) 14e6
    set MultPacketEnd(L5) 18e6
    set MultPacketStart(L6) 14e6
    set MultPacketEnd(L6) 18e6
    set L5_TW_VP_06_Limit 1.0e-7
    #set L2_TW_2IP2_Limit 5.0e-8
    #set L2_TW_2IP2_Limit 5.0e-8

    if {$L5 || $L2 || $L6} {
        set conLimit 5.0e-8
    } else {
        set conLimit 1.0e-8
    }
    set timeout [expr [clock seconds] + $vaccumTimeout]
    set pass 0
    set multPacket 0
    while {[clock seconds]<$timeout} {
        foreach var $vacPVs {
            set Ave($var) 0
        }
        for {set i 0} {$i<$readings} {incr i} {
            if {[catch {APScavget -list=[join $vacPVs ,] -pend=5 -printErrors} vacValues]} {
                return -code error "Error reading vacuum PVs"
            }
            foreach var $vacPVs val $vacValues {
                set Ave($var) [expr $val + $Ave($var)]
            }
            if {$readings > 1} {
                APSWaitWithUpdate -waitSeconds $interval
            }
        }
        set meetRequire 1
        set multpacket 0
        if {$L5} {
            if {[catch {APScavget -list=L5:KY:DC2ARF.VAL -pend=5 -printErrors} KlystronForwardPower]} {
                return -code error "Error reading L5:KY:DC2ARF.VAL"
            }
            if {($KlystronForwardPower >= $MultPacketStart(L5)) && ($KlystronForwardPower <= $MultPacketEnd(L5))} {
                set multpacket 1
            }
        }
        if {$L6} {
            if {[catch {APScavget -list=L6:KY:DC2ARF.VAL -pend=5 -printErrors} KlystronForwardPower]} {
                return -code error "Error reading L6:KY:DC2ARF.VAL"
            }
            if {($KlystronForwardPower >= $MultPacketStart(L6)) && ($KlystronForwardPower <= $MultPacketEnd(L6))} {
                set multpacket 1
            }
        }
        foreach var $vacPVs {
            set Ave($var) [expr $Ave($var) / (1.0 * $readings)]
            if {[info exist ${var}_Limit]} {
                set limit [set ${var}_Limit] 
                if {$Ave($var) > $limit} {
                    APSMpStep "$var vacuum (now $Ave($var)) exceeds $limit"
                    set meetRequire 0
                    break 
                }
                continue
            }
            if {$Ave($var) < $conLimit} {
                continue
            }
            set val [format %\#.2g $apsVacInit($var)]
            set power [string range $val 4 end]
            set power [scan $power %ld]
            set delta [scan 5.0e$power %g]
            if {$multpacket} {
                if {$Ave($var) > $VacuumLimit} {
                    APSMpStep "$var vacuum (now $Ave($var)) exceeds vacuum limit $VacuumLimit"
                    set meetRequire 0
                    break
                }
            } else {
                if {$Ave($var) >= [expr $delta + $apsVacInit($var)]} {
                    APSMpStep "$var vacuum (now $Ave($var)) change exceeds half decade (init=$apsVacInit($var))"
                    set meetRequire 0
                    break
                }
            }
        }
        if {$meetRequire} {
            set pass 1
            break
        } else {
            APSWaitWithUpdate -waitSeconds 5
        }
    }
    if {!$pass} {
        #check if the vaccum exceeds the vaccum limit, if not exceeds, continue
        if {[catch {APScavget -list=[join $vacPVs ,] -pend=5 -printErrors} vacValues]} {
            return -code error "Error reading vacuum PVs"
        }
        if {$multpacket || $L5 || $L6} {
            set limit $VacuumLimit
        } else {
            set limit 1.0e-7
        }
        set passLimit 0
        foreach var $vacPVs val $vacValues {
            if {$val > $limit} {
                set passLimit 1
                return -code error "$var vaccum ($val) exceeds the limit ($limit), RF recovery could not continue."
            }
        }
        if {!$passLimit} {
            APSMpStep "vaccum did not meet the half decade increase requirement after 5 minutes, but did not exceed the limit, continue recovering."
            return 1
        }
    }
    return 1
}

proc LMOCS_Recover_CheckKLYForwardPower {args} {
    set RF ""
    set KLYForwardPowerRef ""
    APSStrictParseArguments {RF KLYForwardPowerRef}

    set refValue [expr $KLYForwardPowerRef - 0.5e6]

    if {$RF == "L2"} {
        if {[catch {APScavget -list=L-K2:LLRF:KlyFwd_PwrRemoteM -pend=5 -printErrors} KlystronForwardPower]} {
            return -code error "Error reading Klystron forward power: $KlystronForwardPower"
        }
    } elseif {$RF == "L5"} {
        if {[catch {APScavget -list=L-K5:LLRF:KlyFwd_PwrRemoteM -pend=5 -printErrors} KlystronForwardPower]} {
            return -code error "Error reading Klystron forward power: $KlystronForwardPower"
        }
    } else {
        if {[catch {APScavget -list=${RF}:KY:DC2ARF -pend=5 -printErrors} KlystronForwardPower]} {
            return -code error "Error reading Klystron forward power: $KlystronForwardPower"
        }
    }
    APSMpStep "Check if Klystron forward power reach $KLYForwardPowerRef ..."
    if {[expr abs($KlystronForwardPower - $KLYForwardPowerRef)] > 0.5e6} {
        return -code error "Klystron forward power ($KlystronForwardPower) is different from the SCR reference $refValue"
    }
    return
}

proc LMOCS_Recover_In_ParallelInfo {args} {
    return "Recovers modulator RF by raising the PFN while constantly checking the vacuum."
}

proc LMOCS_Recover_In_ParallelDialog {frame} {
    pack [frame $frame.top]
    APSCheckButtonFrame .selectSectors \
	-parent $frame.top -label "Select Modulator To Recover" \
	-variableList {LMOCS_Recover_In_Parallel(L1) LMOCS_Recover_In_Parallel(L2) LMOCS_Recover_In_Parallel(L3) LMOCS_Recover_In_Parallel(L4) LMOCS_Recover_In_Parallel(L5) LMOCS_Recover_In_Parallel(L6)} \
	-buttonList {K1 K2 K3 K4 K5 K6} \
	-allNone 1 \
	-packOption {-side top} \
	-orientation horizontal
    APSLabeledEntry .time -parent $frame.top -textVariable LMOCS_Recover_In_Parallel(maxStepSize) \
      -label "Maximum Step size (kV)" -width 40

}
proc LMOCS_Recover_In_Parallel {args} {
    global execMode APSMpLControlPS
    set SCRFile ""
    set L1 0
    set L2 0
    set L3 0
    set L4 0
    set L5 0
    set L6 0
    set maxStepSize 0.5
    APSStrictParseArguments {L1 L2 L3 L4 L5 L6 SCRFile maxStepSize}

    set arrayName APSMpLControlPS
    APSLGenericPSArraySetup -arrayName $arrayName -SCRFile $SCRFile
    if {(![file exists $SCRFile]) && ($execMode == "Automatic")} {
        set execMode "Semi-Automatic"
    }
    if {[file exists $SCRFile]} {

    } else {
        APSMpStep init -promptDialog "APSLGenericPSDialog -packProc LMOCS_Recover_In_ParallelDialog -chooseSCR 1 -arrayName $arrayName -frame " -vars {L1 L2 L3 L4 L5 L6 maxStepSize}

        set SCRFile $APSMpLControlPS(Filename)
    }
    if {![file exists $SCRFile]} {
        APSMpReturn error "LMOCS_Recover_In_Parallel: No SCR file selected"
    }
    if {[catch {exec sdds2stream $SCRFile -parameter=SnapshotDescription -page=1 -noquotes} results]} {
        APSMpReturn error "LMOCS_Recover_In_Parallel: Invalid SCR file"
    }    
    if {[string first "Limited save:" $results] != -1} {
        if {[catch {exec sddssort $SCRFile -pipe=out -column=Beamline -unique | sdds2stream -pipe=in -col=Beamline} results]} {
            APSMpReturn error "LMOCS_Recover_In_Parallel: Problem reading beamlines categories from the SCR file"
        } else {
            if {([lsearch -exact $results L1] == -1) || \
                  ([lsearch -exact $results L2] == -1) || \
                  ([lsearch -exact $results L3] == -1) || \
                  ([lsearch -exact $results L4] == -1) || \
                  ([lsearch -exact $results L5] == -1) || \
                  ([lsearch -exact $results rfGun] == -1) || \
                  ([lsearch -exact $results rfGun1] == -1) || \
                  ([lsearch -exact $results rfGun2] == -1)} {
                APSMpReturn error "LMOCS_Recover_In_Parallel: LIMITED SAVE SCR file does not include all the Linac and rfGun beamline categories"
            }
        }
    }
    if {!($L1) && !($L2) && !($L3) && !($L4) && !($L5) && !($L6)} {
        APSMpReturn error "LMOCS_Recover_In_Parallel: No RF system selected"
    }
    if {$L1} {
        exec runProcGUI LMOCS_Recover -L1 1 -SCRFile $SCRFile &
    }
    if {$L2} {
        #exec runProcGUI TurnOnK400 -klystron K2 -SCRFile $SCRFile &
        exec runProcGUI LMOCS_Recover -L2 1 -SCRFile $SCRFile &
    }
    if {$L3} {
        exec runProcGUI LMOCS_Recover -L3 1 -SCRFile $SCRFile &
    }
    if {$L4} {
        exec runProcGUI LMOCS_Recover -L4 1 -SCRFile $SCRFile &
    }
    if {$L5} {
        exec runProcGUI LMOCS_Recover -L5 1 -SCRFile $SCRFile &
    }
    if {$L6} {
        exec runProcGUI LMOCS_Recover -L6 1 -SCRFile $SCRFile &
    }
    APSMpReturn ok

}


proc LMOCS_RecoverInfo {args} {
    return "Recovers modulator RF by raising the PFN while constantly checking the vacuum."
}

proc LMOCS_RecoverDialog {frame} {
    pack [frame $frame.top]
    APSCheckButtonFrame .selectSectors \
	-parent $frame.top -label "Select Modulator To Recover" \
	-variableList {LMOCS_Recover(L1) LMOCS_Recover(L2) LMOCS_Recover(L3) LMOCS_Recover(L4) LMOCS_Recover(L5) LMOCS_Recover(L6)} \
	-buttonList {K1 K2 K3 K4 K5 K6} \
	-allNone 1 \
	-packOption {-side top} \
	-orientation horizontal
    APSLabeledEntry .time -parent $frame.top -textVariable LMOCS_Recover(maxStepSize) \
      -label "Maximum Step size (kV)" -width 40

}

proc LMOCS_Recover {args} {
    global apsVacInit execMode APSMpLControlPS
    set SCRFile ""
    set L1 0
    set L2 0
    set L3 0
    set L4 0
    set L5 0
    set L6 0
    set ITSMode 0
    set maxStepSize 0.5
    set VacuumLimit 1.0e-7
    APSStrictParseArguments {L1 L2 L3 L4 L5 L6 SCRFile maxStepSize ITSMode}

    if {$execMode == "Manual"} {
        set prefix "Press Continue to "
    } else {
        set prefix ""
    }
    if {[catch {APSLinkToLINACPVs} result]} {
        APSMpReturn error "LMOCS_Recover: $result"
    }
    set arrayName APSMpLControlPS
    APSLGenericPSArraySetup -arrayName $arrayName -SCRFile $SCRFile
    if {(![file exists $SCRFile]) && ($execMode == "Automatic")} {
        set execMode "Semi-Automatic"
    }
    if {[file exists $SCRFile]} {

    } else {
        APSMpStep init -promptDialog "APSLGenericPSDialog -packProc LMOCS_RecoverDialog -chooseSCR 1 -arrayName $arrayName -frame " -vars {L1 L2 L3 L4 L5 L6 maxStepSize}

        set SCRFile $APSMpLControlPS(Filename)
    }
    if {![file exists $SCRFile]} {
        APSMpReturn error "LMOCS_Recover: No SCR file selected"
    }
    if {[catch {exec sdds2stream $SCRFile -parameter=SnapshotDescription -page=1 -noquotes} results]} {
        APSMpReturn error "LMOCS_Recover: Invalid SCR file"
    }    
    if {[string first "Limited save:" $results] != -1} {
        APSMpReturn error "LMOCS_Recover: LIMITED SAVE SCR files cannot be used for this procedure."
    }
    if {!($L1) && !($L2) && !($L3) && !($L4) && !($L5) && !($L6)} {
        APSMpReturn error "LMOCS_Recover: No RF system selected"
    }
    set deviceList ""
    if {$L1} {
        lappend deviceList 1
    }
    if {$L2} {
        lappend deviceList 2
    }
    if {$L3} {
        lappend deviceList 3
    }
    if {$L4} {
        lappend deviceList 4
    }
    if {$L5} {
        lappend deviceList 5
    }
    if {$L6} {
        lappend deviceList 6
    }

    if {[llength $deviceList] > 1} {
        APSMpReturn error "LMOCS_Recover: Please select only one klystron at a time"
    }

    if {$L2} {
        set useDLLRF 1
#        if {[catch {APScavget -list=L-K2:LLRF:digitalSystemInUse -pend=5 -num -printErrors} useDLLRF]} {
#            APSMpReturn error "Error checking for analog or digital LLRF: $useDLLRF"
#        }
        if {[catch {exec sddsselect $SCRFile \
                      /home/helios/oagData/pem/linac/SCRFilterFile \
                      -match=ControlName -pipe=out | sdds2stream -column=ControlName,ValueString -pipe=in} results]} {
            APSMpReturn error "LMOCS_Recover: Invalid SCR file"
        }
        foreach {controlName valueString} $results {
            if {[string range $controlName end-3 end] == ".VAL"} {
                set controlName [string range $controlName 0 end-4]
            }
            if {"L2:MA:klyPosAI" == $controlName} {
                set SCRattnCtrlVoltage $valueString
            } elseif {"L2:KY:DC2ARF" == $controlName} {
                set SCRklystronForwardPower $valueString
            } elseif {"L-K2:LLRF:KlyFwd_PwrRemoteM" == $controlName} {
                set SCRklystronForwardPower $valueString
            } elseif {"L2:SD:DC1ARF" == $controlName} {
                set SCRsledForwardPower $valueString
            } elseif {"L-K2:LLRF:SD:Fwd_PkPwrRemoteM" == $controlName} {
                set SCRsledForwardPower $valueString
            } elseif {"L-K2:LLRF:DSP:FF_AmpC" == $controlName} {
                set SCRllrfAmpDrive $valueString
            }
        }
        if {$useDLLRF} {
            APSMpStep "Increase the LLRF amp drive"
            if {[catch {K400IncreaseLLRFampDrive -klystron K2 \
                          -SCRllrfAmpDrive $SCRllrfAmpDrive \
                          -SCRklystronForwardPower $SCRklystronForwardPower \
                          -SCRsledForwardPower $SCRsledForwardPower} result]} {
                APSMpReturn error $result
            }

        } else {
            APSMpStep "Decrease the attenuator voltage"
            if {[catch {K400DecreaseAttnInTrigState -klystron K2 \
                          -SCRattnCtrlVoltage $SCRattnCtrlVoltage \
                          -SCRklystronForwardPower $SCRklystronForwardPower \
                          -SCRsledForwardPower $SCRsledForwardPower} result]} {
                APSMpReturn error $result
            }
        }
        APSMpReturn ok
    }
    if {$L5} {
        set useDLLRF 1
#        if {[catch {APScavget -list=L-K5:LLRF:digitalSystemInUse -pend=5 -num -printErrors} useDLLRF]} {
#            APSMpReturn error "Error checking for analog or digital LLRF: $useDLLRF"
#        }
        if {[catch {exec sddsselect $SCRFile \
                      /home/helios/oagData/pem/linac/SCRFilterFile \
                      -match=ControlName -pipe=out | sdds2stream -column=ControlName,ValueString -pipe=in} results]} {
            APSMpReturn error "LMOCS_Recover: Invalid SCR file"
        }
        foreach {controlName valueString} $results {
            if {[string range $controlName end-3 end] == ".VAL"} {
                set controlName [string range $controlName 0 end-4]
            }
            if {"L5:MA:klyPosAI" == $controlName} {
                set SCRattnCtrlVoltage $valueString
            } elseif {"L5:KY:DC2ARF" == $controlName} {
                set SCRklystronForwardPower $valueString
            } elseif {"L-K5:LLRF:KlyFwd_PwrRemoteM" == $controlName} {
                set SCRklystronForwardPower $valueString
            } elseif {"L5:SD:DC1ARF" == $controlName} {
                set SCRsledForwardPower $valueString
            } elseif {"L-K5:LLRF:SD:Fwd_PkPwrRemoteM" == $controlName} {
                set SCRsledForwardPower $valueString
            } elseif {"L-K5:LLRF:DSP:FF_AmpC" == $controlName} {
                set SCRllrfAmpDrive $valueString
            }
        }
        if {$useDLLRF} {
            APSMpStep "Increase the LLRF amp drive"
            if {[catch {K400IncreaseLLRFampDrive -klystron K5 \
                          -SCRllrfAmpDrive $SCRllrfAmpDrive \
                          -SCRklystronForwardPower $SCRklystronForwardPower \
                          -SCRsledForwardPower $SCRsledForwardPower} result]} {
                APSMpReturn error $result
            }

        } else {
            APSMpStep "Decrease the attenuator voltage"
            if {[catch {K400DecreaseAttnInTrigState -klystron K5 \
                          -SCRattnCtrlVoltage $SCRattnCtrlVoltage \
                          -SCRklystronForwardPower $SCRklystronForwardPower \
                          -SCRsledForwardPower $SCRsledForwardPower} result]} {
                APSMpReturn error $result
            }
        }
        APSMpReturn ok
    }

    if {[catch {APSRFGUN_DetectSelectedGun} gun]} {
        APSMpReturn error "LMOCS_Recover: $gun"
    }
    if {$ITSMode == 0} {
        if {$gun == "RG2"} {
            set gunDeviceList 2
        } elseif {$gun == "RG1"} {
            set gunDeviceList 1
        } else {
            APSMpReturn error "LMOCS_Recover: Unable to detect which Gun is selected. Check the LINAC RF Switching System State to ensure it is set to RUNNING and not LOCAL SWITCH or REMOTE SWITCH."
        }
    }

    set InitValueList ""
    foreach device $deviceList {
        set RF L$device
        if {($RF != "L2") && ($RF != "L5")} {
            if {[catch {APScavget -list=${RF}:MO:LowPFNvSP -pend=5 -printErrors} InitValue($device)]} {
                APSMpReturn error "LMOCS_Recover: Error reading ${RF}:MO:LowPFNvSP : $InitValue($device)"
            }
            lappend InitValueList $InitValue($device)
            if {[catch {exec sddsprocess $SCRFile \
                          -pipe=out -match=col,ControlName=${RF}:MO:PFNvAO \
                          | sdds2stream -pipe=in -col=ValueString} FinalValue($device)]} {
                APSMpReturn error "LMOCS_Recover: Error in getting value of ${RF}:MO:PFNvAO from SCR: $FinalValue($device)"
            }
            set FinalValue($device) [format %.2f $FinalValue($device)]
            if {[catch {APScavget -list=${RF}:MO:PFNvOpsLimitAO -pend=5 -printErrors} PFNlimit]} {
                APSMpReturn error "LMOCS_Recover: Error reading ${RF}:MO:PFNvOpsLimitAO : $PFNlimit"
            }
            if {$FinalValue($device) > $PFNlimit} {
                APSMpReturn error "LMOCS_Recover: the target PFN value $FinalValue($device) is greater than its limit, please select different SCR!"
            }
        }
        if {[catch {exec sddsprocess $SCRFile \
                      -pipe=out -match=col,ControlName=${RF}:MA:klyPosAI \
                      | sdds2stream -pipe=in -col=ValueString} AttenValue($device)]} {
            APSMpReturn error "LMOCS_Recover: Error in getting value of ${RF}:MA:klyPosAI from SCR : $AttenValue($device)"   
        }
        set AttenValue($device) [format %.2f $AttenValue($device)]
        if {$RF == "L2"} {
            if {[catch {exec sddsprocess $SCRFile \
                          -pipe=out -match=col,ControlName=L-K2:LLRF:KlyFwd_PwrRemoteM \
                          | sdds2stream -pipe=in -col=ValueString} KLYForwardPowerRef($device)]} {
                if {[catch {exec sddsprocess $SCRFile \
                              -pipe=out -match=col,ControlName=${RF}:KY:DC2ARF.VAL \
                              | sdds2stream -pipe=in -col=ValueString} KLYForwardPowerRef($device)]} {
                    APSMpReturn error "LMOCS_Recover: Error in getting value of L-K2:LLRF:KlyFwd_PwrRemoteM from SCR : $KLYForwardPowerRef($device)"
                }   
            }
        } elseif {$RF == "L5"} {
            if {[catch {exec sddsprocess $SCRFile \
                          -pipe=out -match=col,ControlName=L-K5:LLRF:KlyFwd_PwrRemoteM \
                          | sdds2stream -pipe=in -col=ValueString} KLYForwardPowerRef($device)]} {
                if {[catch {exec sddsprocess $SCRFile \
                              -pipe=out -match=col,ControlName=${RF}:KY:DC2ARF.VAL \
                              | sdds2stream -pipe=in -col=ValueString} KLYForwardPowerRef($device)]} {
                    APSMpReturn error "LMOCS_Recover: Error in getting value of L-K5:LLRF:KlyFwd_PwrRemoteM from SCR : $KLYForwardPowerRef($device)"
                }   
            }
        } else {
            if {[catch {exec sddsprocess $SCRFile \
                          -pipe=out -match=col,ControlName=${RF}:KY:DC2ARF.VAL \
                          | sdds2stream -pipe=in -col=ValueString} KLYForwardPowerRef($device)]} {
                APSMpReturn error "LMOCS_Recover: Error in getting value of ${RF}:KY:DC2ARF.VAL from SCR : $KLYForwardPowerRef($device)"
            }
        }
        #for L5 -- make sure all vaccuum level is less than 1.0e-8 torr before recovery
        if {$RF=="L5" || $RF=="L6"} {
            if {[catch {APScavget -list=L5:TW:VP:01 -pend=5 -printErrors} L5KlystronVaccum]} {
                APSMpReturn error "LMOCS_Recover: Error reading L5 Klystron vaccum : $L5KlystronVaccum"
            }
            if {$L5KlystronVaccum > 1.0e-8} {
                APSMpReturn error "LMOCS_Recover: L5 Klystron vaccum $L5KlystronVaccum > 1.0e-8 Torr, can not recover!"
            }
        }
        if {$RF=="L6"} {
            if {[catch {APScavget -list=L6:TW:VP:01 -pend=5 -printErrors} L6KlystronVaccum]} {
                APSMpReturn error "LMOCS_Recover: Error reading L6 Klystron vaccum : $L6KlystronVaccum"
            }
            if {$L6KlystronVaccum > 1.0e-8} {
                APSMpReturn error "LMOCS_Recover: L6 Klystron vaccum $L6KlystronVaccum > 1.0e-8 Torr, can not recover!"
            }
        }
        if {[catch {APScavget -list=${RF}:KY:DC1RF.HIHI -pend=5 -printErrors} klyDriveLimit]} {
            APSMpReturn error "LMOCS_Recover: Error reading ${RF}:KY:DC1RF.HIHI : $klyDriveLimit"
        }
        if {[catch {exec sddsprocess $SCRFile \
                      -pipe=out -match=col,ControlName=${RF}:KY:DC1RF.VAL \
                      | sdds2stream -pipe=in -col=ValueString} klyDriveRef($device)]} {
            APSMpReturn error "LMOCS_Recover: Error in getting value of ${RF}:KY:DC1RF.VAL from SCR : $klyDriveRef($device)"
        }
        if {$klyDriveRef($device) > $klyDriveLimit} {
            APSMpReturn error "LMOCS_Recover: SCR $RF KLY drive exceeds the $RF KLY drive limit"
        }
        if {[catch {APScavget -list=${RF}:LL:readyCC -pend=5 -printErrors} ready]} {
            APSMpReturn error "LMOCS_Recover: Error reading ${RF}:LL:readyCC : $ready"
        }
        if {!$ready} {
            set answer [APSPEMTKDialog .warningDialog -text "$RF LLRF is not on, please turn on it manually or abort recovery?" -strings {"Continue" "Abort Procedure"}]
            if {$answer == 1} {
                APSMpReturn error "LMOCS_Recover: the $RF LLRF is not turned on, can not start recovery!"
            }
            if {[catch {APScavget -list=${RF}:LL:readyCC -pend=5 -printErrors} ready]} {
                APSMpReturn error "LMOCS_Recover: Error reading ${RF}:LL:readyCC : $ready"
            }
            if {!$ready} {
                APSMpReturn error "LMOCS_Recover: the $RF LLRF is not turned on, can not start recovery!"
            }
        }
    }

    set vacPVs ""
    foreach device $deviceList {
        set RF L$device
        set sector $RF
        if {[catch {exec sdds2stream /home/helios/oagData/linac/Linac_RF_Recovery/${RF}vacuum.mon -col=ControlName} pvs]} {
            APSMpReturn error "LMOCS_Recover: $pvs"
        }
        append vacPVs "$pvs "
    }
    
#    APSMpStep "${prefix}Disable modulator permissive" -desc "Disable modulator permissive"
#    foreach device $deviceList {
#        set RF L$device
#        if {[catch {APScavput -list=${RF}:ModSoftIntlk1.SCAN=0 -pend=5} result]} {
#            APSMpReturn error "LMOCS_Recover: Error disabling $RF modulator: $result"
#        }
#    }

    #check the PFN value, if it is higher than the limit, bring down to the limit before
    #adjust the attentuator
    foreach device $deviceList {
        set RF L$device
        if {($RF == "L2") || ($RF == "L5")} {
            continue
        }
        if {[catch {APScavget -list=${RF}:MO:PFNvAO.VAL -pend=5 -printErrors} PFNreading]} {
#            foreach device $deviceList {
#                set RFx L$device
#                catch {APScavput -list=${RFx}:ModSoftIntlk1.SCAN=6 -pend=5}
#            }
            APSMpReturn error "LMOCS_Recover: Error reading $RF voltage: $PFNreading"
        }
        if {$PFNreading > $InitValue($device)} {
            APSMpStep "${prefix}The $RF PFN is higher than the limit, bring it down to the limit before adjusting the attenuator." -desc "The $RF PFN is higher than the limit, bring it down to the limit before adjusting the attenuator."
            if {[catch {APScavput -list=${RF}:MO:PFNvAO.VAL=$InitValue($device) -pend=5 } result]} {
#                foreach device $deviceList {
#                    set RFx L$device
#                    catch {APScavput -list=${RFx}:ModSoftIntlk1.SCAN=6 -pend=5}
#                }
                APSMpReturn error "LMOCS_Recover: Error setting $RF voltage: $PFNreading"
            }
        }
    }


    APSMpStep "${prefix}Check kylstron drive" -desc "Check kylstron drive"
    foreach device $deviceList {
        set RF L$device
        if {[catch {APScavget -list=${RF}:KY:DC1RF.VAL -pend=5 -printErrors} klyDrive]} {
#            foreach device $deviceList {
#                set RFx L$device
#                catch {APScavput -list=${RFx}:ModSoftIntlk1.SCAN=6 -pend=5}
#            }
            APSMpReturn error "LMOCS_Recover: Error reading $RF attenuator value: $klDrive"
        }

        
        if {[expr abs($klyDrive - $klyDriveRef($device))] > 2} {
            APSMpStep "${prefix}$RF klyDrive value is too far away from SCR reference, adjust the attenuator..." -desc "$RF klyDrive value is too far away from SCR reference, adjust the attenuator..."
            if {[catch {LMOCS_Recover_ChangeAttenuator -device $device -klyDriveRef $klyDriveRef($device)} result]} {
#                foreach device $deviceList {
#                    set RFx L$device
#                    catch {APScavput -list=${RFx}:ModSoftIntlk1.SCAN=6 -pend=5}
#                }
                APSMpReturn error "LMOCS_Recover: Error changing attenuator value: $result"
            }
        }
    }

    APSMpStep "${prefix}Check if $RF PFN is on" -desc "Check if PFN is on"
    foreach device $deviceList {
        set RF L$device
        if {($RF == "L2") || ($RF == "L5")} {
            continue
        }
        while {1} {
            if {[catch {APScavget -list=${RF}:MO:PFNPSHighVoltageOnBI -pend=5 -printErrors} pfnOn]} {
#                foreach device $deviceList {
#                    set RFx L$device
#                    catch {APScavput -list=${RFx}:ModSoftIntlk1.SCAN=6 -pend=5}
#                }
                APSMpReturn error "LMOCS_Recover: Error reading ${RF}:MO:PFNPSHighVoltageOnBI: $pfnOn"
            }
            if {!$pfnOn} {
                set answer [APSPEMTKDialog .warningDialog -text "$RF PFN is not on, please turn on it first or abort recovery?" -strings {"Continue" "Abort Procedure"}]
                if {$answer == 1} {
#                    foreach device $deviceList {
#                        set RFx L$device
#                        catch {APScavput -list=${RFx}:ModSoftIntlk1.SCAN=6 -pend=5}
#                    }
                    APSMpReturn error "$RF PFN is not on, recovery aborted."
                }
                APSWaitWithUpdate -waitSeconds 1
            } else {
                break
            }
        }
    }
    foreach device $deviceList {
        set RF L$device
        if {($RF == "L2") || ($RF == "L5")} {
            continue
        }
        APSMpStep "${prefix}Set $RF PFN to $InitValue($device) kV" -desc "Set PFN to initial value"
        if {[catch {APScavput -list=${RF}:MO:PFNvAO.VAL=$InitValue($device) -pend=5} result]} {
#            foreach device $deviceList {
#                set RFx L$device
#                catch {APScavput -list=${RFx}:ModSoftIntlk1.SCAN=6 -pend=5}
#            }
            APSMpReturn error "LMOCS_Recover: Error setting $RF PFN voltage: $result"
        }
    }

    APSMpStep "${prefix}Reset Kicker Interlock" -desc "Reset Kicker Interlock"
    foreach device $deviceList {
        set RF L$device
        while {1} {
            if {[catch {APScavget -list=${RF}:LL:readyCC -pend=10 -printErrors} ready]} {
#                foreach device $deviceList {
#                    set RFx L$device
#                    catch {APScavput -list=${RFx}:ModSoftIntlk1.SCAN=6 -pend=5}
#                }
                APSMpReturn error "LMOCS_Recover: Error reading ${RF}:LL:readyCC: $ready"
            }
            if {$ready} {
                break
            }
            APSAlertBox .warning -name "Reset RF interlocks" \
              -errorMessage "Please reset RF interlocks and turn on the LLRF, press Ok to continue."   -type warning
        }
    }
    APSMpStep "${prefix}Check if $RF PFN is on" -desc "Check if PFN is on"
    foreach device $deviceList {
        set RF L$device
        if {($RF == "L2") || ($RF == "L5")} {
            continue
        }
        while {1} {
            if {[catch {APScavget -list=${RF}:MO:PFNPSHighVoltageOnBI -pend=5 -printErrors} pfnOn]} {
#                foreach device $deviceList {
#                    set RFx L$device
#                    catch {APScavput -list=${RFx}:ModSoftIntlk1.SCAN=6 -pend=5}
#                }
                APSMpReturn error "LMOCS_Recover: Error reading ${RF}:MO:PFNPSHighVoltageOnBI: $pfnOn"
            }
            if {!$pfnOn} {
                set answer [APSPEMTKDialog .warningDialog -text "$RF PFN is not on, please turn on it first or abort recovery?" -strings {"Continue" "Abort Procedure"}]
                if {$answer == 1} {
#                    foreach device $deviceList {
#                        set RFx L$device
#                        catch {APScavput -list=${RFx}:ModSoftIntlk1.SCAN=6 -pend=5}
#                    }
                    APSMpReturn  error "$RF PFN is not on, recovery aborted."
                }
                APSWaitWithUpdate -waitSeconds 1
            } else {
                break
            }
        }
    }

    foreach device $deviceList {
        set RF L$device
        if {$device == 6} {
            set sledRF 5
        }
        set sector $RF
        if {($RF != "L3") && ($RF != "L1")} {
            if {$RF=="L6" || $RF=="L4"} {
                APSMpStep "Check $RF klystron forward power to SLED forward power ratio (1:5 or smaller)"
                set targetRatio .2
            } else {
                APSMpStep "Check $RF klystron forward power to SLED forward power ratio (1:4 or smaller)"
                set targetRatio .25
            }

            set count 0
            while {1} {

                if {$RF == "L2"} {
                    if {[catch {APScavget -list=L-K2:LLRF:KlyFwd_PwrRemoteM -pend=5 -printErrors} KlystronForwardPower]} {
                        APSMpReturn error "LMOCS_Recover: Error reading L-K2:LLRF:KlyFwd_PwrRemoteM : $KlystronForwardPower"
                    }
                } elseif {$RF == "L5"} {
                    if {[catch {APScavget -list=L-K5:LLRF:KlyFwd_PwrRemoteM -pend=5 -printErrors} KlystronForwardPower]} {
                        APSMpReturn error "LMOCS_Recover: Error reading L-K5:LLRF:KlyFwd_PwrRemoteM : $KlystronForwardPower"
                    }
                } else {
                    if {[catch {APScavget -list=${RF}:KY:DC2ARF -pend=5 -printErrors} KlystronForwardPower]} {
                        APSMpReturn error "LMOCS_Recover: Error reading ${RF}:KY:DC2ARF : $KlystronForwardPower"
                    }
                }
                if {$KlystronForwardPower <= 0} {
                    APSMpReturn error "LMOCS_Recover: klystron forward power ${RF}:KY:DC2ARF too low: $KlystronForwardPower"
                }
                if {$RF == "L2"} {
                    if {[catch {APScavget -list=L-K2:LLRF:SD:Fwd_PkPwrRemoteM -pend=5 -printErrors} SLEDForwardPower]} {
                        APSMpReturn error "LMOCS_Recover: Error reading L-K2:LLRF:SD:Fwd_PkPwrRemoteM : $SLEDForwardPower"
                    }
                } elseif {$RF == "L5"} {
                    if {[catch {APScavget -list=L-K5:LLRF:SD:Fwd_PkPwrRemoteM -pend=5 -printErrors} SLEDForwardPower]} {
                        APSMpReturn error "LMOCS_Recover: Error reading L-K5:LLRF:SD:Fwd_PkPwrRemoteM : $SLEDForwardPower"
                    }
                } else {
                    if {[catch {APScavget -list=${sledRF}:SD:DC1ARF -pend=5 -printErrors} SLEDForwardPower]} {
                        APSMpReturn error "LMOCS_Recover: Error reading ${sledRF}:SD:DC1ARF : $SLEDForwardPower"
                    }
                }
                if {$SLEDForwardPower <= 0} {
                    APSMpReturn error "LMOCS_Recover: SLED forward power ${sledRF}:SD:DC1ARF too low: $SLEDForwardPower"
                }
                set ratio [expr $KlystronForwardPower / $SLEDForwardPower]
                if {$ratio <= $targetRatio} {
                    break
                } else {
                    incr count
                    if {$RF=="L6" || $RF=="L4"} {
                        APSMpStep "Klystron/SLED forward power ratio is too high (>1:5), waiting"
                    } else {
                        APSMpStep "Klystron/SLED forward power ratio is too high (>1:4), waiting"
                    }
                    APSWaitWithUpdate -waitSeconds 1
                    if {$count >= 20} {
                        if {$RF=="L6" || $RF=="L4"} {
                            set answer [APSPEMTKDialog .warningDialog -text "${RF} Klystron/SLED forward power ratio is too high (>1:5). If the values are appropriate, please feel free to click click Continue." -strings {Continue Recheck "Abort Procedure"}]
                        } else {
                            set answer [APSPEMTKDialog .warningDialog -text "${RF} Klystron/SLED forward power ratio is too high (>1:4). If the values are appropriate, please feel free to click click Continue." -strings {Continue Recheck "Abort Procedure"}]
                        }
                        if {$answer == 0} {
                            break
                        } elseif {$answer == 1} {
                            set count 0
                        } else {
                            APSMpReturn error "LMOCS_Recover: ${RF} recovery was aborted"
                        }
                    }
                }
            }
        }
    }

    APSMpStep "Check vacuum is less than $VacuumLimit" -desc "Check vacuum is less than 1.0e-7"
    while {1} {
        if {[catch {APScavget -list=[join $vacPVs ,] -pend=5 -printErrors} vacValues]} {
#            foreach device $deviceList {
#                set RFx L$device
#                catch {APScavput -list=${RFx}:ModSoftIntlk1.SCAN=6 -pend=5}
#            }
            APSMpReturn error "LMOCS_Recover: $vacValues"
        }
        set tooHigh 0
        set highPVs ""
        foreach pv $vacPVs val $vacValues {
            if {$val > $VacuumLimit} {
                incr tooHigh
                lappend highPVs $pv
            }
        }
        if {$tooHigh} {
            set answer [APSPEMTKDialog .warningDialog -text "[join $highPVs ,] vacuum is too high" -strings {Continue Recheck "Abort Procedure"}]
            if {$answer == 0} {
                break
            } elseif {$answer == 1} {
                continue
            } else {
#                foreach device $deviceList {
#                    set RFx L$device
#                    catch {APScavput -list=${RFx}:ModSoftIntlk1.SCAN=6 -pend=5}
#                }
                APSMpReturn error "LMOCS_Recover: recovery was aborted"
            }
        } else {
            break
        }
    }

    if {($RF != "L2") && ($RF != "L5")} {
        set rampSteps 1
        foreach device $deviceList {
            set steps [expr int(ceil(($FinalValue($device) - $InitValue($device)) / $maxStepSize))]
            if {$steps > $rampSteps} {
                set rampSteps $steps
            }
        }
        foreach device $deviceList {
            set stepSize($device) [expr ($FinalValue($device) - $InitValue($device)) / ($rampSteps * 1.0)]
        }

        for {set i 1} {$i<=$rampSteps} {incr i} {
            foreach device $deviceList {
                set RF L$device
                if {[catch {APScavget -list=${RF}:LL:readyCC -pend=5 -printErrors} ready]} {
#                    foreach device $deviceList {
#                        set RFx L$device
#                        catch {APScavput -list=${RFx}:ModSoftIntlk1.SCAN=6 -pend=5}
#                    }
                    APSMpReturn error "LMOCS_Recover: Error reading ${RF}:LL:readyCC : $ready"
                }
                if {!$ready} {
                    set answer [APSPEMTKDialog .warningDialog -text "$RF LLRF is not on, please turn on it manually or abort recovery?" -strings {"Continue" "Abort Procedure"}]
                    if {$answer == 1} {
#                        foreach device $deviceList {
#                            set RFx L$device
#                            catch {APScavput -list=${RFx}:ModSoftIntlk1.SCAN=6 -pend=5}
#                        }
                        APSMpReturn error "LMOCS_Recover: the $RF LLRF is not turned on, quiting recovery!"
                    }
                }
            }
            APSMpStep "Reading vacuum PVs before changing RF voltage"
            if {[catch {APScavget -list=[join $vacPVs ,] -pend=5 -printErrors} vacValues]} {
#                foreach device $deviceList {
#                    set RFx L$device
#                    catch {APScavput -list=${RFx}:ModSoftIntlk1.SCAN=6 -pend=5}
#                }
                APSMpReturn error "LMOCS_Recover: $vacValues"
            }
            foreach pv $vacPVs val $vacValues {
                set apsVacInit($pv) $val
            }
            foreach device $deviceList {
                set RF L$device
                set setValue [format %.2f [expr $InitValue($device) + $i * $stepSize($device)]]
                set PFNsetpoint $setValue
                set tries 0
                set failSetting 1
                APSMpStep "Setting $RF PFN to $PFNsetpoint (step $i of $rampSteps)"
                for {set tries 0} {$tries<5} {incr tries} {
                    if {[catch {APScavput -list=${RF}:MO:PFNvAO.VAL=$PFNsetpoint -pend=5} result]} {
                        APSWaitWithUpdate -waitSeconds 1
                        continue
                    } else {
                        set failSetting 0
                        break
                    }
                }
                if {$failSetting} {
                    set answer [APSPEMTKDialog .warningDialog -text "Failed set $RF PFN to $setValue" -strings {Continue "Abort Procedure"}]
                    if {$answer == 1} {
#                        foreach device $deviceList {
#                            set RFx L$device
#                            catch {APScavput -list=${RFx}:ModSoftIntlk1.SCAN=6 -pend=5}
#                        }
                        APSMpReturn error "LMOCS_Recover: Failed set $RF PFN to $setValue : aborted by user"
                    }
                }
            }
            APSMpStep "Pausing 5 seconds"
            APSWaitWithUpdate -waitSeconds 5

            APSMpStep "Checking vacuum..."
            if {[catch {LMOCS_Recover_CheckVacuumAndWait -vacPVs $vacPVs -interval 5 -L5 $L5 -L6 $L6 -VacuumLimit $VacuumLimit} result]} {
#                foreach device $deviceList {
#                    set RFx L$device
#                    catch {APScavput -list=${RFx}:ModSoftIntlk1.SCAN=6 -pend=5}
#                }
                APSMpReturn error "LMOCS_Recover: $result"
            }
        }
    }

#    APSMpStep "${prefix}Enable modulator permissive" -desc "Enable modulator permissive"
#    foreach device $deviceList {
#        set RF L$device
#        if {[catch {APScavput -list=${RF}:ModSoftIntlk1.SCAN=6 -pend=5} result]} {
#            APSMpReturn error "LMOCS_Recover: Error enabling $RF modulator: $result"
#        }
#    }
    
    APSMpStep "Checking Klystron forward power reaches the SCR value"
    foreach device $deviceList {
        set RF L$device
        if {[catch {LMOCS_Recover_CheckKLYForwardPower -RF $RF -KLYForwardPowerRef $KLYForwardPowerRef($device)} result]} {
            APSMpStep "$RF recovery completed, however, $result"
            set answer [APSPEMTKDialog .warningDialog -text "$RF recovery completed, however the klystron forward power did not reach the target" -strings {Continue}]
        } else {
            APSMpStep "$RF recovery completed and klystron forward power reached the target."
        }
    }

    if {$ITSMode} {
        APSMpStep "Ramping LTS:G to 8.0V over 30 seconds"
        if {[catch {exec cavput -list=LTS:G:VoltageAO=8.0 -ramp=step=30,pause=1 -pend=5} result]} {
            APSMpReturn error "LMOCS_Recover: Error ramping LTS:G:VoltageAO : $result"
        }
        APSMpStep "${prefix}Resume ITS fixedCurrent" -desc "Resume fixedCurrent"
        if {[catch {APSMpLSuspendResumeRunControl \
                      -value "Resume" \
                      -name "FixedCurrent" \
                      -group "LinacRFGun" \
                      -deviceList 0 \
                      -port 4592 \
                      -executable "fixedCurrent -gunChoice ITS -start 1"} result]} {
            if {[APSPEMTKDialog .warningDialog -text "Error while resuming the hold current script \n$result"] == 1} {
                APSMpReturn error "LMOCS_Recover: $result"
            }
        }	        
        
    }

    APSMpReturn ok
}

