#!/bin/sh
# \
  exec oagwish "$0" "$@"
set auto_path [linsert $auto_path 0 /usr/local/oag/apps/lib/$env(HOST_ARCH)]
set auto_path [linsert $auto_path 0 /usr/local/oag/lib_patch/$env(HOST_ARCH)]

APSStandardSetup
set RF L2
set SCRFile ""
set args $argv
APSParseArguments {RF SCRFile}

if {$RF == "L2"} {
    exec runProcGUI TurnOnK400 -klystron K2 &
    after 2000
    exit
}
if {$RF == "L5"} {
    exec runProcGUI TurnOnK400 -klystron K5 &
    after 2000
    exit
}


set monDataDir /home/helios/oagData/linac/Linac_RF_Recovery
proc SetupVacuumPVLink {args} {
    global vacuumVarList errorCode monDataDir RF
    
    set pvList [join [exec sdds2stream $monDataDir/${RF}vacuum.mon -col=ControlName]]
    set vacuumVarList [join [exec sdds2stream $monDataDir/${RF}vacuum.mon -col=VariableName]]
    # puts $vacuumVarList
    if [pv linkw $vacuumVarList $pvList] {
        return -code error "Error connecting to vacuum pvs: $errorCode"
    }
    
}

proc Abort {args} {
    global abort RF
    SetRFRecoveryStatus "$RF recovery Aborted."
    set abort 0
}

#waiting vaccum timeout 5 minutes
set vaccumTimeout 300
proc CheckVacuumAndWait {args} {
    global abort vacuumVarList errorCode interval waittime VacuumLimit multPackStart multPackEnd KlystronForwardPower RF vaccumTimeout
    eval global $vacuumVarList 
    
    #read 3 times
    foreach var $vacuumVarList {
        global Init$var
    }
    if {($RF=="L5") || ($RF=="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} {
        if $abort {
            set abort 0
            return -code error "Aborted."
        }
        foreach var $vacuumVarList {
            set Ave$var 0
        }
        for {set i 0} {$i<3} {incr i} {
            if [pv getw $vacuumVarList] {
                return -code error "Error reading vacuum1: $errorCode"
            }
            foreach var $vacuumVarList {
                set Ave$var [expr [set $var] + [set Ave$var]]
            }
            #wait 5 seconds
            APSWaitWithUpdate -waitSeconds $interval -abortVariable abort
        }
        set meetRequire 1
        if [pv getw KlystronForwardPower] {
            return -code error "Error reading klystron forward power: $errorCode"
        }
        set multpacket 0
        if {[string length $multPackStart] && [string length multPackEnd]} {
            if {$KlystronForwardPower>=$multPackStart && $KlystronForwardPower<=$multPackEnd} {
                set multpacket 1
            }
        }
        foreach var $vacuumVarList {
            set Ave$var [expr [set Ave$var]/3.0]
            global ${var}_Limit
            if [info exist ${var}_Limit] {
                set limit [set ${var}_Limit] 
                if {[set Ave$var]>$limit} {
                    SetRFRecoveryStatus "$var vacuum (now [set Ave$var])  exceeds $limit"
                    set meetRequire 0
                    break 
                }
                continue
            }
            if {[set Ave$var]<$conLimit} {
                continue
            }
            set val [format %\#.2g [set Init$var]]
            set power [string range $val 4 end]
            set power [scan $power %ld]
            set delta [scan 5.0e$power %g]
            if $multpacket {
                if {[set Ave$var]>$VacuumLimit} {
                    SetRFRecoveryStatus "$var vacuum (now [set Ave$var]) exceeds vacuum limit $VacuumLimit"
                    set meetRequire 0
                    break
                }
            } else {
                if {[set Ave$var] >= [expr $delta + [set Init$var]]} {
                    # puts "$var current=[set Ave$var], init+half decade=[expr $delta + [set Init$var]] init=[set Init$var]"
                    SetRFRecoveryStatus "$var vacuum (now [set Ave$var])  change exceeds half decade (init=[set Init$var])"
                    set meetRequire 0
                    break
                }
            }
        }
        if $meetRequire {
            set pass 1
            break
        } else {
            if [catch {APSWaitWithUpdate -waitSeconds $waittime -abortVariable abort} result] {
                return -code error $result
            }
        }
    }
    if !$pass {
        #check if the vaccum exceeds the vaccum limit, if not exceeds, continue
        if [pv getw $vacuumVarList] {
            return -code error "Error reading vacuum: $errorCode"
        }
        if {$multpacket || $RF!="L5" || $RF!="L6"} {
            set limit $VacuumLimit
        } else {
            set limit 1.0e-7
        }
        set passLimit 0
        foreach var $vacuumVarList {
            if {[set $var]>$limit} {
                set passLimit 1
                return -code error "$var vaccum ([set $var]) exceeds the limit ($limit), $RF recovery could not continue."
            }
        }
        if !$passLimit {
            SetRFRecoveryStatus "$RF vaccum did not meet the half decade increase requirement after 5 minutes, but did not exceed the limit, continue recovering."
            return 1
        }
    }
    SetRFRecoveryStatus "vaccum checking passed."
    return 1
    #APSEnableButton .userFrame.start.button
}

proc CheckVacuum {args} {
    set limit ""
    set nowait 0
    set waitTime 5
    APSParseArguments {limit nowait waitTime}
    global vacuumVarList errorCode abort
    eval global $vacuumVarList
    
    if [pv getw $vacuumVarList] {
        return -code error "Error reading vacuum pvs1: $errorCode"
    }
    
    set timeout [expr [clock seconds] + $waitTime * 60]
    while {[clock seconds]<$timeout} {
        if $abort {
            Abort
            return 
        }
        set tooHigh 0
        set varList ""
        foreach var $vacuumVarList {
            if {[set $var]>$limit} {
                incr tooHigh
                lappend varList $var
            }
        }
        if $tooHigh {
            if $nowait {
                "[join $varList ,] vacuum is too high"
                return 1
            }
            set answer [APSMultipleChoice .info -name "Vacuum is too high" \
                          -question "[join $varList ,] vacuum is too high,  do you want to wait and check again or abort?" -labelList {Check-Again Abort} \
                          -returnList {Check Abort} ]
            if {$answer=="Abort"} {
                return -code error "[join $varList ,] vacuum too high."
            }
            after 1000
        } else {
            break
        }
    }
    return $tooHigh
}

proc ChangeAtt {args} {
    if [catch {ChangeAttenuator} result] {
        return -code error $result
    }
}



#when the RF rate is not 6, the klystron drive updates very slow, so that it is always overshoot when the RF rate is 2 or 4.
#wait for klystron drive to be updated before continue pressing attenuator

proc ChangeAttenuator {args} {
    global AttenCtrl AttenCtrlVar abort errorCode RF KlystronVar AttenIncrVar AttenDecVar klyDriveRef klyDrive klyDriveLimit abort
    set timeout 120
    if [pv getw klyDrive] {
        return -code error "Error reading attenuator (L2:MA:klyPosAI): $errorCode"
    }
    if {$klyDrive < $klyDriveRef} {
        #use decrease attenuator button to increase the klystron drive
        set attenVar AttenDecVar
        set increase 1
    } elseif {$klyDrive > $klyDriveRef} {
        #use increase attenuator button to descrease the klystron drive
        set attenVar AttenIncrVar
        set increase 0
    } else {
        #nothing to do
        return
    }
    #toggle increase/decrease button to change attentuator
    set zeroCounts 0
    while {1} {
        if $abort {
            Abort
            return -code error "Aborted"
        }
        if [pv getw klyDrive] {
            return -code error "Error reading klydrive: $errorCode"
        }

        if {[expr abs($klyDrive - $klyDriveRef)]<=1} {
            #reach the target already
            SetRFRecoveryStatus "Klystron drive now is $klyDrive, reached the target~$klyDriveRef)."
            break
        }
        if {$klyDrive < $klyDriveRef} {
            #use decrease attenuator button to increase the klystron drive
            set attenVar AttenDecVar
        } elseif {$klyDrive > $klyDriveRef} {
            #use increase attenuator button to descrease the klystron drive
            set attenVar AttenIncrVar
        }
        
        set ratio [expr $klyDrive/$klyDriveRef]
        if {$ratio<0.1} {
            set holdTime 5000
        } elseif {$ratio<0.5} {
            set holdTime 1000
        } elseif {$ratio<0.75} {
            set holdTime 300
        } else {
            set holdTime 50
        }

        SetRFRecoveryStatus "Klystron drive now is $klyDrive ( should be ~$klyDriveRef) (press time=$holdTime milliseconds)..."
        set drive0 $klyDrive
        set $attenVar 1
        if [pv putw $attenVar ] {
            return -code error "Error change attenuator: $errorCode"
        }
        after $holdTime
        set $attenVar 0
        if [catch {pv putw $attenVar  } result] {
            return -code error "Error stop change attenuator: $errorCode"
        }
        APSWaitWithUpdate -waitSeconds 3 -abortVariable abort
        #when the RF rate is 2 or 4, the klydrive updates very slow, wait for the klydrive to be update before continue 
        #changing attenuator
        SetRFRecoveryStatus "waiting for klystron drive to be updated..."
        
        if {$klyDrive>5 || $zeroCounts>5} {
            set timeout [expr [clock seconds]+$timeout]
            while {[clock seconds]<$timeout} {
                if [pv getw klyDrive] {
                    return -code error "Error reading klystron drive: $errorCode"
                }
                if [expr abs($klyDrive-$drive0)]>0.01 {
                    break
                }
                after 1000
                if $abort {
                    set abort 0
                    return -code error "adjust attenuator is aborted."
                }
            }
            if [pv getw klyDrive] {
                return -code error "Error reading klystron drive: $errorCode"
            }
            if {$klyDrive<5 && $zeroCounts>5} {
                set answer [APSMultipleChoice .info1 -name "The klystron drive is less than 5W after 5 tries" \
                              -question "The klystron drive is less than 5W after 5 tries, do you want to manually adjust it and continue or abort?" -labelList {Adjust-Continue  Abort} \
                              -returnList {Continue Abort} ]
                if {$answer=="Abort"} {
                    SetRFRecoveryStatus "The klystron drive is less than 5W after 5 tries, recovery aborted."
                    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
        }
        SetRFRecoveryStatus "continuing..."
    }
}

proc SetRFRecoveryStatus {text} {
    global RFRecoveryStatus logID
    set RFRecoveryStatus "[exec date] $text"
    puts $logID "[exec date] $text"
    flush $logID
    update
}

set monDir /home/helios/oagData/linac/Linac_RF_Recovery

proc StartRecovery {args} {
    global InitValue FinalValue RampSteps AttenCtrl VacuumLimit VacuumToGo RampInterval abort errorCode Linac_RF_Recovery RF monDir PFNsetpoint
    global extravarList maxStepSize vacuumVarList waittime multPackStart multParkEnd errorCode env klyDriveRef klyDriveLimit klyDrive timingSourceRef
    eval global $extravarList
    eval global $vacuumVarList
    
    if [catch {exec cavget -list=$RF:MO:PFNvOpsLimitAO -pend=20 -printErrors} PFNlimit] {
        SetRFRecoveryStatus "Error reading PFN limit: $PFNlimit"
        return
    }
    if {$FinalValue > $PFNlimit} {
        SetRFRecoveryStatus "Error: the target PFN value ($FinalValue) is greater than its limit, please select different SCR!"
        return
    }
    #for L5 -- make sure all vaccuum level is less than 1.0e-8 torr before recovery
    if {$RF=="L5" || $RF=="L6"} {
        if [catch {exec cavget -list=L5:TW:VP:01 -pend=30 -printErrors } L5KylstronVaccum] {
            SetRFRecoveryStatus "Error reading L5 Kylstron vaccum: $L5KylstronVaccum"
            return
        }
        if {$L5KylstronVaccum>1.0e-8} {
            SetRFRecoveryStatus "L5 Klystron vaccum $L5KylstronVaccum > 1.0e-8 Torr, can not recover!"
            return
        }
    }
    if {$RF=="L6"} {
        if [catch {exec cavget -list=L6:TW:VP:01 -pend=30 -printErrors } L6KylstronVaccum] {
            SetRFRecoveryStatus "Error reading L6 Kylstron vaccum: $L6KylstronVaccum"
            return
        }
        if {$L6KylstronVaccum>1.0e-8} {
            SetRFRecoveryStatus "L6 Klystron vaccum $L6KylstronVaccum > 1.0e-8 Torr, can not recover!"
            return
        }
    }
    
    
    if [catch {ReadSCR} result] {
        SetRFRecoveryStatus "Error: $result"
        return
    }
    if [string length $timingSourceRef] {
        #check Linac timing source
        if [catch {exec cavget -list=LI:TM:${RF}TimingSourceC -pend=10 -printErrors } timingSource] {
            SetRFRecoveryStatus "Error reading linac timing source: $timingSource"
            return
        }
        if [string compare $timingSource $timingSourceRef] {
            set answer [APSMultipleChoice .info0 -name "Timing source does not agree" \
                          -question "$RF current timing source is different from SCR, please fix it before continue!" \
                          -labelList {Fix-and-Continue Abort} \
                          -returnList {Continue Abort}]
            if $answer=="Abort" {
                SetRFRecoveryStatus "Current timing source is different from SCR, abort"
                return
            } else {
                break
            }
        }
    }
    if {$klyDriveRef>$klyDriveLimit} {
        SetRFRecoveryStatus "Error: the SCR KLY drive exceeds the KLY drive limit"
        return
    }
    
    if [catch {exec cavget -list=$RF:LL:readyCC -pend=30 -printErrors } ready] {
        return -code error "Error reading $RF:LL:readyCC : $ready"
    }
    if !$ready {
        bell
        bell
        SetRFRecoveryStatus "Error: the $RF LLRF is not turned on, can not start recovery!"
        return
    }

    if {$RF!="L6"} {
        SetRFRecoveryStatus "Step0: disable modulator permissive."
        if [catch {exec cavput -list=$RF:ModSoftIntlk1.SCAN=0 -pend=30} result] {
            SetRFRecoveryStatus "Error disabling $RF modulator: $errorCode"
            return
        }
    }

    if [pv getw RFVoltage] {
        SetRFRecoveryStatus "Error reading $RF voltage: $errorCode"
        if {$RF!="L6"} {
            if [catch {exec cavput -list=$RF:ModSoftIntlk1.SCAN=6 -pend=30} result] {
                SetRFRecoveryStatus "Error disabling $RF modulator: $errorCode"
                return
            }
        }
        return
    }
    #check the PFN value, if it is higher than the limit, bring down to the limit before
    #adjust the attentuator
    if [catch {exec cavget -list=$RF:MO:PFNvAO.VAL -pend=10 } PFNreading] {
        SetRFRecoveryStatus "Error reading $RF voltage: $errorCode"
        if {$RF!="L6"} {
            if [catch {exec cavput -list=$RF:ModSoftIntlk1.SCAN=6 -pend=30} result] {
                SetRFRecoveryStatus "Error disabling $RF modulator: $errorCode"
                return
            }
        }
        return
    }
    if {$PFNreading>$InitValue} {
        SetRFRecoveryStatus "Step 0: the PFN is higher than the limit, bring it down to the limit before adjust the attenuator."
        if [catch {exec cavput -list=$RF:MO:PFNvAO.VAL=$InitValue -pend=10 } result] {
            SetRFRecoveryStatus "Error setting $RF voltage: $errorCode"
            if {$RF!="L6"} {
                if [catch {exec cavput -list=$RF:ModSoftIntlk1.SCAN=6 -pend=30} result] {
                    SetRFRecoveryStatus "Error disabling $RF modulator: $errorCode"
                    return
                }
            }
            return
        }
    }
    
    SetRFRecoveryStatus "Step 1: check kylstron drive (make sure it is close to $klyDriveRef (SCR value)"
    if [pv getw klyDrive] {
        SetRFRecoveryStatus "Error reading attenuator value: $errorCode"
        if {$RF!="L6"} {
            if [catch {exec cavput -list=$RF:ModSoftIntlk1.SCAN=6 -pend=30} result] {
                SetRFRecoveryStatus "Error disabling $RF modulator: $errorCode"
                return
            }
        }
        return
    }
    
    if {[expr abs($klyDrive - $klyDriveRef)]>2} {
        SetRFRecoveryStatus "klyDrive value is too far away from SCR reference, adjust the attenuator..."
        if [catch {ChangeAttenuator} result] {
            SetRFRecoveryStatus "Error changing attenuator value: $result"
            if {$RF!="L6"} {
                if [catch {exec cavput -list=$RF:ModSoftIntlk1.SCAN=6 -pend=30} result] {
                    SetRFRecoveryStatus "Error disabling $RF modulator: $errorCode"
                    return
                }
            }
            return
        }
    }
    if [pv getw AttenCtrlVar] {
        SetRFRecoveryStatus "Error reading attenuator value: $errorCode"
        if {$RF!="L6"} {
            if [catch {exec cavput -list=$RF:ModSoftIntlk1.SCAN=6 -pend=30} result] {
                SetRFRecoveryStatus "Error disabling $RF modulator: $errorCode"
                return
            }
        }
        return
    }
    
    #check if PFN is on
    while {1} {
        if [catch {exec cavget -list=$RF:MO:PFNPSHighVoltageOnBI -num -printErrors -pend=30} pfnOn] {
            SetRFRecoveryStatus "Error reading $RF:MO:PFNPSHighVoltageOnBI: $pfnOn"
            return
        }
        if {!$pfnOn} {
            set answer [APSMultipleChoice .info -name "$RF PFN is not on" \
                          -question "$RF PFN is not on, please turn on it first or abort recovery?" -labelList {Turn-on-and-Check-Again  Abort} \
                          -returnList {Check Abort} ]
            if {$answer=="Abort"} {
                SetRFRecoveryStatus "$RF PFN is not on, recovery aborted."
                return
            }
            after 1000
        } else {
            break
        }
    }

    SetRFRecoveryStatus "Attenuator now = $AttenCtrlVar"
    SetRFRecoveryStatus "set PFN to $InitValue kV..."
    if [catch {exec cavput -list=$RF:MO:PFNvAO.VAL=$InitValue -pend=10 } result] {
        SetRFRecoveryStatus "Error setting $RF voltage: $errorCode"
        if {$RF!="L6"} {
            if [catch {exec cavput -list=$RF:ModSoftIntlk1.SCAN=6 -pend=30} result] {
                SetRFRecoveryStatus "Error disabling $RF modulator: $errorCode"
                return
            }
        }
        return
    }
    
    SetRFRecoveryStatus "Step2: Reset RF interlocks..."
    while {1} {
        if [catch {exec cavget -list=$RF:LL:readyCC -pend=10 -printErrors } ready] {
            if {$RF!="L6"} {
                if [catch {exec cavput -list=$RF:ModSoftIntlk1.SCAN=6 -pend=30} result] {
                    SetRFRecoveryStatus "Error disabling $RF modulator: $errorCode"
                    return
                }
            }
            SetRFRecoveryStatus "Error setting $RF LLRF state: $ready"
            return
        }
        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
    }
    #check if PFN is on
    while {1} {
        if [catch {exec cavget -list=$RF:MO:PFNPSHighVoltageOnBI -num -printErrors -pend=30} pfnOn] {
            SetRFRecoveryStatus "Error reading $RF:MO:PFNPSHighVoltageOnBI: $pfnOn"
            return
        }
        if {!$pfnOn} {
            set answer [APSMultipleChoice .info -name "$RF PFN is not on" \
                          -question "$RF PFN is not on, please turn on it first or abort recovery?" -labelList {Turn-on-and-Check-Again  Abort} \
                          -returnList {Check Abort} ]
            if {$answer=="Abort"} {
                SetRFRecoveryStatus "$RF PFN is not on, recovery aborted."
                return
            }
            after 1000
        } else {
            break
        }
    }

    if {$RF!="L3" && $RF!="L1"} {
        if {$RF=="L6" || $RF=="L4"} {
            SetRFRecoveryStatus "Step3: check klystron forward power to SLED forward power ratio (1:5 or smaller)..."
            set targetRatio .2
        } else {
            SetRFRecoveryStatus "Step3: check klystron forward power to SLED forward power ratio (1:4 or smaller)..."
            set targetRatio .25
        }
        set tries 1
        while {1} {
            if {$abort} {
                set abort 0
                SetRFRecoveryStatus "$RF recovery was aborted."
                if {$RF!="L6"} {
                    if [catch {exec cavput -list=$RF:ModSoftIntlk1.SCAN=6 -pend=30} result] {
                        SetRFRecoveryStatus "Error disabling $RF modulator: $errorCode"
                        return
                    }
                }
                return
            }
            if {[pv getw KlystronForwardPower] || [pv getw SLEDForwardPower]} {
                SetRFRecoveryStatus "Error reading Klystron/SLED feeforward power: $errorCode"
                if {$RF!="L6"} {
                    if [catch {exec cavput -list=$RF:ModSoftIntlk1.SCAN=6 -pend=30} result] {
                        SetRFRecoveryStatus "Error disabling $RF modulator: $errorCode"
                        return
                    }
                }
                return
            }
            
            set ratio [expr $KlystronForwardPower/$SLEDForwardPower]
            if {$ratio <= $targetRatio} {
                break
            }
            if {$tries == 1} {
                if {$RF=="L6" || $RF=="L4"} {
                    SetRFRecoveryStatus "Klystron/SLED forward power ratio is too high (>1:5), wait..."
                } else {
                    SetRFRecoveryStatus "Klystron/SLED forward power ratio is too high (>1:4), wait..."
                }
            }
            if {$tries == 20} {
                if {$RF=="L6" || $RF=="L4"} {
                    set message "$RF Klystron/SLED forward power ratio is too high (>1:5), please fix it then click Recheck. If the values are appropriate, please feel free to click Ignore to continue."
                } else {
                    set message "$RF Klystron/SLED forward power ratio is too high (>1:4), please fix it then click Recheck. If the values are appropriate, please feel free to click Ignore to continue."
                }
                set answer [APSMultipleChoice .info -name "$RF Klysron problem" \
                              -question $message \
                              -labelList {Recheck Ignore Abort} \
                              -returnList {Recheck Ignore Abort}]
                if {$answer=="Abort"} {
                    SetRFRecoveryStatus "$RF Klystron/SLED forward power ratio is too high, aborted"
                    return
                } elseif {$answer=="Ignore"} {
                    break
                }
                set tries 1
            } else {
                incr tries
            }
            after 1000
        }
    }
    
    SetRFRecoveryStatus "Step 4: Check vacuum to less than $VacuumLimit..."
    if [catch {CheckVacuum -limit $VacuumLimit } result] {
        SetRFRecoveryStatus "$result"
        if {$RF!="L6"} {
            if [catch {exec cavput -list=$RF:ModSoftIntlk1.SCAN=6 -pend=30} result] {
                SetRFRecoveryStatus "Error disabling $RF modulator: $result"
                return
            }
        }
        return
    }
    #logmessage
    
    if [catch {LogMessage -action Start -RF $RF} result] {
        SetRFRecoveryStatus "$result"
    }
    #maximum step size 0.5kV
    
    set rampSteps [expr int(ceil(($FinalValue - $InitValue)/$maxStepSize))]
    set stepSize [expr ($FinalValue - $InitValue)/($rampSteps*1.0)]
    
    foreach var $vacuumVarList {
        global Init$var
    }
    set waittime [format %.0d $waittime]
    
    for {set i 1} {$i<=$rampSteps} {incr i} {
        if [catch {exec cavget -list=$RF:LL:readyCC -pend=30 -printErrors } ready] {
            return -code error "Error reading $RF:LL:readyCC : $ready"
        }
        if !$ready {
            bell
            bell
            SetRFRecoveryStatus "Step $i: Error: the LLRF is not ON! quite $RF recovery"
            return
        }
        if $abort {
            Abort
            if [catch {LogMessage -action Abort -RF $RF} result] {
                SetRFRecoveryStatus "$result"
            }
            if {$RF!="L6"} {
                if [catch {exec cavput -list=$RF:ModSoftIntlk1.SCAN=6 -pend=30} result] {
                    SetRFRecoveryStatus "Error disabling $RF modulator: $errorCode"
                    return
                }
            }
            return
        }
        SetRFRecoveryStatus "read vacuum before changing rf voltage..."
        if [pv getw $vacuumVarList] {
            if {$RF!="L6"} {
                if [catch {exec cavput -list=$RF:ModSoftIntlk1.SCAN=6 -pend=30} result] {
                    if [catch {LogMessage -action Abort -RF $RF} result] {
                        SetRFRecoveryStatus "$result"
                    }
                    SetRFRecoveryStatus "Error disabling $RF modulator: $errorCode"
                    return
                }
            }
            return -code error "Error reading vacumm2: $errorCode"
        }
        foreach var $vacuumVarList {
            set Init$var [set $var]
        }
        set setValue [format %.2f [expr $InitValue + $i * $stepSize]]
        set PFNsetpoint $setValue
        set tries 0
        set failSetting 1
        for {set tries 0} {$tries<5} {incr tries} {
            if [pv putw PFNsetpoint] {
                SetRFRecoveryStatus "Error changing $RF voltage to $setValue: $errorCode; retry"
                after 1000
                continue
            } else {
                set failSetting 0
                break
            }
        }
        if $failSetting {
            set answer [APSMultipleChoice .info -name "$RF PFN set failed" \
                          -question "Failed set $RF PFN to $setValue, please check if $RF PFN is $setValue and press Continue to contiue or abort"  \
                          -labelList {Continue  Abort} \
                          -returnList {Check Abort} ]
            if {$answer=="Abort"} {
                SetRFRecoveryStatus "Failed setting $RF PFN to $setValue, recovery aborted."
                if {$RF!="L6"} {
                    if [catch {exec cavput -list=$RF:ModSoftIntlk1.SCAN=6 -pend=30} result] {
                        if [catch {LogMessage -action Abort -RF $RF} result] {
                            SetRFRecoveryStatus "$result"
                        }
                        SetRFRecoveryStatus "Error disabling $RF modulator: $errorCode"
                        return
                    }
                }
                return
            }
        }
        SetRFRecoveryStatus "Step $i of $rampSteps steps, set PFN to $setValue kV, waiting $waittime seconds ..."
        for {set j 0} {$j<$waittime} {incr j} {
            if $abort {
                Abort
                if [catch {LogMessage -action Abort -RF $RF} result] {
                    SetRFRecoveryStatus "$result"
                }
                return
            }
            after 1000
            update
        }
        SetRFRecoveryStatus "Checking vacuum..."
        if [catch {CheckVacuumAndWait } result] {
            SetRFRecoveryStatus "$result"
            if {$RF!="L6"} {
                if [catch {exec cavput -list=$RF:ModSoftIntlk1.SCAN=6 -pend=30} result] {
                    SetRFRecoveryStatus "Error disabling $RF modulator: $errorCode"
                    if [catch {LogMessage -action Abort -RF $RF} result] {
                        SetRFRecoveryStatus "$result"
                    }
                    return
                }
            }
            return
        }
        if [pv getw RFVoltage] {
            SetRFRecoveryStatus "Error reading RF voltage: $errorCode"
            if {$RF!="L6"} {
                if [catch {exec cavput -list=$RF:ModSoftIntlk1.SCAN=6 -pend=30} result] {
                    SetRFRecoveryStatus "Error disabling $RF modulator: $errorCode"
                    if [catch {LogMessage -action Abort -RF $RF} result] {
                        SetRFRecoveryStatus "$result"
                    }
                    return
                }
            }
            return
        }
    }
    
    if [pv getw RFVoltage] {
        SetRFRecoveryStatus "Error reading $RF voltage: $errorCode"
        if {$RF!="L6"} {
            if [catch {exec cavput -list=$RF:ModSoftIntlk1.SCAN=6 -pend=30} result] {
                SetRFRecoveryStatus "Error disabling $RF modulator: $errorCode"
                if [catch {LogMessage -action Abort -RF $RF} result] {
                    SetRFRecoveryStatus "$result"
                }
                return
            }
        }
        return
    }
    if {$RF!="L6"} {
        SetRFRecoveryStatus "Enabled the  modulator permissive."
        if [catch {exec cavput -list=$RF:ModSoftIntlk1.SCAN=6 -pend=30} result] {
            SetRFRecoveryStatus "Error disabling $RF modulator: $errorCode"
        }
    }
    #logmessage
    if [catch {LogMessage -action Finish -RF $RF} result] {
        SetRFRecoveryStatus "$result"
    }
    #check if klystron forward power meet the SCR 
    SetRFRecoveryStatus "check if Klystron forward power reaches the SCR ..."
    if [catch {CheckKLYForwardPower } result] {
        # SetRFRecoveryStatus "Error: $result"
        SetRFRecoveryStatus "$RF recovery completed, however, $result"
        APSAlertBox .alertinfo -name "$RF recovery completed, however the klystron forward power did not reach the target" -type warning -name warning \
          -errorMessage "$RF recovery completed, however the klystron forward power did not reach the target." -modeless 1 -beep once
    } else {
        SetRFRecoveryStatus "$RF recovery completed and klystron forward power reached the target."
        APSAlertBox .alertinfo -name "$RF recovery Done" -type done -name Done \
          -errorMessage "$RF recovery done." -modeless 1 -beep once
    }
}

proc LogMessage {args} {
    set action start 
    set RF ""
    APSParseArguments {action RF}
    global InitValue FinalValue Linac_RF_Recovery env PFNsetpoint
    
    set sledRF $RF
    if {$RF == 6} {
        set sledRF 5
    }

    if [catch {exec cavget -list=$RF -list=:MA:klyPosAI,:KY:DC2ARF.VAL,:MO:PFNvAI,:MO:PFNvAO.VAL -pend=30 -printErrors} valList] {
        return -code error "Error reading attenuator, klystron forward power, sed forward power: $result"
    }
    set atten [lindex $valList 0]
    set kly [lindex $valList 1]
    set pfn [lindex $valList 2]
    set pfnSetpoint [lindex $valList 3]
    set sled 0
    if {$RF!="L3" && $RF!="L1"} {
        if [catch {exec cavget -list=${sledRF}:SD:DC1ARF.VAL -pend=30 -printErrors} sled] {
            return -code error "Error reading sled forward power: $sled"
        }
    }
    
    if [catch {exec logMessage -sourceId=linacRFRecovery \
                 -tag=User $env(USER) \
                 -tag=Host $env(HOST) \
                 -tag=RF $RF \
                 -tag=SCRFile $Linac_RF_Recovery(ShortFilename) \
                 -tag=PFNInitialValue $InitValue \
                 -tag=PFNFinalValue $FinalValue \
                 -tag=PFNReadback $pfn \
                 -tag=Attenuator $atten \
                 -tag=KlystronForwardPower $kly \
                 -tag=SledForwardPower $sled \
                 -tag=Action $action \
                 -tag=PFNsetpoint $pfnSetpoint } result] {
        return -code error "Error logMessage $action: $result"
    }
}


proc ReadSCR {args} {
    global  Linac_RF_Recovery FinalValue RF KLYForwardPowerRef AttenCtrl klyDriveRef timingSourceRef
    if ![string length $Linac_RF_Recovery(ShortFilename)] {
        return -code error "SCR file not chosen"
    }
    if [catch {exec sddsprocess /home/helios/oagData/SCR/snapshots/LPL/$Linac_RF_Recovery(ShortFilename) \
                 -pipe=out -match=col,ControlName=${RF}:MO:PFNvAO \
                 | sdds2stream -pipe=in -col=ValueString} FinalValue] {
        return -code error "Error in getting value of ${RF}:MO:PFNvAO from SCR: $FinalValue"
        
    }
    set FinalValue [format %.2f $FinalValue]
    if [catch {exec sddsprocess /home/helios/oagData/SCR/snapshots/LPL/$Linac_RF_Recovery(ShortFilename) \
                 -pipe=out -match=col,ControlName=${RF}:MA:klyPosAI \
                 | sdds2stream -pipe=in -col=ValueString} attenValue] {
        return -code error "Error in getting value of ${RF}:MA:klyPosAI : $attenValue"
        
    }
    set AttenCtrl [format %.2f $attenValue]
    if [catch {exec sddsprocess /home/helios/oagData/SCR/snapshots/LPL/$Linac_RF_Recovery(ShortFilename) \
                 -pipe=out -match=col,ControlName=${RF}:KY:DC2ARF.VAL \
                 | sdds2stream -pipe=in -col=ValueString} KLYForwardPowerRef ] {
        return -code error "Error in getting value of ${RF}:KY:DC2ARF.VAL : $KLYForwardPowerRef"
    }
    if [catch {exec sddsprocess /home/helios/oagData/SCR/snapshots/LPL/$Linac_RF_Recovery(ShortFilename) \
                 -pipe=out -match=col,ControlName=${RF}:KY:DC1RF.VAL \
                 | sdds2stream -pipe=in -col=ValueString} klyDriveRef ] {
        return -code error "Error in getting value of ${RF}:KY:DC1RF.VAL : $klyDriveRef"
    }
    if [catch {exec sddsprocess /home/helios/oagData/SCR/snapshots/LPL/$Linac_RF_Recovery(ShortFilename) \
                 -pipe=out -match=col,ControlName=LI:TM:${RF}TimingSourceC \
                 | sdds2stream -pipe=in -noquotes -col=ValueString} timingSourceRef ] {
        #SetRFRecoveryStatus  "Error in getting value of ${RF}:KY:DC1RF.VAL : $timingSourceRef"
        set timingSourceRef ""
    }
}

proc CheckKLYForwardPower {args} {
    global RF KLYForwardPowerRef  KlystronForwardPower AttenCtrlVar abort errorCode RF AttenDecVar klyDrive klyDriveLimit
    
    set refValue [expr $KLYForwardPowerRef - 0.5e6]
    if [pv getw KlystronForwardPower]  {
        return -code error "Error reading Klystron forward power: $errorCode"
    }
    SetRFRecoveryStatus "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


    set pv $RF:MA:decKlyBO
    
    while {$KlystronForwardPower < $refValue} {
        if $abort {
            set abort 0
            return -code error "CheckKLYForwardPower aborted."
        }
        if [pv getw klyDrive] {
            return -code error "Error reading klystron drive value: $errorCode"
        }
        
        if {$klyDrive>=$klyDriveLimit} {
            return -code error  "Klystron drive exceeds its limit."
        }
        if [pv getw KlystronForwardPower]  {
            return -code error "Error reading Klystron forward power: $errorCode"
        }
        SetRFRecoveryStatus "The Klystron forward power now is $KlystronForwardPower, decrease attenuator..."
        set AttenDecVar 1
        if [pv putw AttenDecVar ] {
            return -code error "Error decrease attenuator: $errorCode"
        }
        after 300
        set AttenDecVar 0
        if [catch {pv putw AttenDecVar} result] {
            return -code error "Error stop decrease attenuator: $errorCode"
        }
        APSWaitWithUpdate -waitSeconds 20 -abortVariable abort
        if [pv getw KlystronForwardPower]  {
            return -code error "Error reading Klystron forward power: $errorCode"
        }
        SetRFRecoveryStatus "The Klystron forward power now is $KlystronForwardPower"
    }
}

set L5_TW_VP_06_Limit 1.0e-7
set MultPacketStart(L5) 14e6
set MultPacketEnd(L5) 18e6
set MultPacketStart(L6) 14e6
set MultPacketEnd(L6) 18e6
set RFRecoveryStatus ""
#set InitValue 22.0
#read initila value from pv
if [catch {exec cavget -list=${RF}:MO:LowPFNvSP -pend=30 -printErrors} InitValue] {
    puts stderr "Error reading initial value from ${RF}:MO:LowPFNvSP : $InitValue"
    exit 1
}
set FinalValue 31.0
set RampSteps 30
set AttenCtrl 1.88
set VacuumLimit 1.0e-7
set VacuumToGo 5.0e-9
set RampInterval 10
set maxStepSize 0.5
set abort 0
set waittime 30
set klyDriveRef ""
#testing decreasing wait time (will put back to 30 seconds after test
set waittime 5
set interval 5
set outputDir [APSGoToDailyDirectory -subdirectory LinacRFRecovery]
set logFile $outputDir/${RF}Recovery.Log
set logID [open $logFile "a+"]
puts $logID "\nNew recovery started. [exec date]"
flush $logID
set CVSRevisionAuthor "\$Revision: 1.0 $ \$Author: shang $"
APSApplication . -name RFRecovery-$RF -version $CVSRevisionAuthor \
  -overview "Provides tool for recover RF."
APSScrolledStatus .status -parent .userFrame -textVariable  RFRecoveryStatus \
  -width 80 -height 6 -packOption "-fill x" -lineLimit 10000
update

#APSLabeledEntry .dir -parent .userFrame -textVariable outputDir -label "Data dir" -width 75
APSLabeledOutput .init -parent .userFrame -textVariable InitValue \
  -label "Initial value to ramp $RF RF from: (KV)" -width 40 \
  -contextHelp "The RF ramp initial value, i.e. ramp starting value."
APSLabeledOutput .final -parent .userFrame -textVariable FinalValue \
  -label "Final value to ramp $RF RF to: (KV)" -width 40 \
  -contextHelp "final value to ramp $RF RF to."
APSLabeledEntry .time -parent .userFrame -textVariable  maxStepSize \
  -label "Maximum Step size (kV)" -width 40
#APSLabeledEntry .wait -parent .userFrame -textVariable RampInterval \
  #  -label "Ramp interval (seconds)" -width 40
APSLabeledOutput .atten -parent .userFrame -textVariable klyDriveRef \
  -label "Klystron Value (watts):" -width 40 \
  -contextHelp "Attenuator control value for ramping RF, must be set to this value before ramping RF."
APSLabeledOutput .klypower -parent .userFrame -textVariable KLYForwardPowerRef \
  -label "Klystron forward power (watts):" -width 40 \
  -contextHelp "The klystron forward power in selected SCR."
#APSLabeledOutput .atten -parent .userFrame -textVariable AttenCtrl \
  \#  -label "Attenuator Value:" -width 40 \
  \# -contextHelp "Attenuator control value for ramping RF, must be set to this value before ramping RF."
#APSLabeledEntry .vaclimit -parent .userFrame -textVariable VacuumLimit \
  #  -label "Vacuum limit (Torr):" -width 40 \
  # -contextHelp "stop ramping $RF  RF if vacuume exceeds this limit."

#APSLabeledEntry .waittime -parent .userFrame -textVariable waittime -label "Wait time after increasing RF voltage (seconds)" -width 40
#APSLabeledEntry .interval -parent .userFrame -textVariable interval -label "Interval (seconds) between two vaccum readings" -width 40
set machine LPL
if [string length $SCRFile] {
    set Linac_RF_Recovery(ShortFilename) $SCRFile
    ReadSCR
} else {
    set Linac_RF_Recovery(ShortFilename) ""
}

APSAddSCRDialog .src -parent .userFrame -system LPL \
  -arrayName Linac_RF_Recovery \
  -defaultFile $Linac_RF_Recovery(ShortFilename) \
  -label "Choose SCR file:"

APSButton .start -parent .userFrame -text "Start Recovery" -command "APSDisableButton .userFrame.start.button;StartRecovery;APSEnableButton .userFrame.start.button"
APSButton .abort -parent .userFrame -text "Abort" -command "set abort 1"
APSButton .att -parent .userFrame -text "Change Attenuator" -command "ChangeAtt"
#APSButton .log -parent .userFrame -text "LogMessage" -command "LogMessage -action Finish -RF $RF"

set sledRF $RF
if {$RF == 6} {
    set sledRF 5
}

SetupVacuumPVLink
if {$RF!="L3" && $RF!="L1"} {
    set extrapvList [list ${RF}:MO:PFNvAI ${RF}:MA:klyPosAI ${RF}:KY:DC2ARF.VAL ${sledRF}:SD:DC1ARF.VAL ${RF}:KY:DC1RF.VAL ${RF}:MA:incKlyBO ${RF}:MA:decKlyBO $RF:KY:DC1RF.HIHI $RF:KY:DC1RF.VAL $RF:MO:PFNvAO.VAL]
    set extravarList {RFVoltage AttenCtrlVar KlystronForwardPower SLEDForwardPower KylstronVar AttenIncrVar AttenDecVar klyDriveLimit klyDrive PFNsetpoint}
} else {
    set extrapvList [list ${RF}:MO:PFNvAI ${RF}:MA:klyPosAI ${RF}:KY:DC1RF.VAL ${RF}:KY:DC2ARF.VAL ${RF}:MA:incKlyBO ${RF}:MA:decKlyBO $RF:KY:DC1RF.HIHI $RF:KY:DC1RF.VAL $RF:MO:PFNvAO.VAL]
    set extravarList {RFVoltage AttenCtrlVar KlystronVar KlystronForwardPower AttenIncrVar AttenDecVar klyDriveLimit klyDrive PFNsetpoint}
}

if [pv linkw  $extravarList  $extrapvList] {
    puts stderr "Error link pv: $errorCode"
    exit 1
}

#L5 has multi packeting region (14-18MW klystron forward power) where the vaccum could not drop down, skip vaccum checking at this region
if [info exist MultPacketStart($RF)] {
    set multPackStart $MultPacketStart($RF)
    set multPackEnd $MultPacketEnd($RF)
} else {
    set multPackStart ""
    set multPackEnd ""
}
#to replace the library procedure APSAddSCRDialogCallback, it has to be placed in the end
proc APSAddSCRDialogCallback {arrayName machine} {
    global $arrayName apsSCRSnapDir RFRecoveryStatus 
    if [set ${arrayName}(FileNotFound)] {
        set RFRecoveryStatus "File not found!"
        update
        return
    }
    set name [set ${arrayName}(Filename)]
    set descrip [set ${arrayName}(Description)]
    set snapDir $apsSCRSnapDir/$machine
    if ![file exists $snapDir/$name] {
        if [file exists $snapDir/${name}.gz] {
            set name ${name}.gz
        } else {
            set RFRecoveryStatus "File not found!"
            update
            return
        }
    }
    set ${arrayName}(ShortFilename) $name
    set ${arrayName}(Filename) $snapDir/$name
    ReadSCR
}
