#!/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 CVSRevisionAuthor "\$Revision: 1.54 $ \$Author: soliday $"



# comments from original csh version by J. Lewellen
#
# This script is a general watchdog procedure for the thermionic-cathode rf
# gun.  It will force a shutdown of any active script under the following
# conditions:
#    o gun pressure too high
#    o alpha magnet pressure too high
#    o loss of rfgun trigger
#    o rf power too high
#    o cathode heater power too high
#
# This script limits its actions to setting the scope semaphore to "abort all";
# it does not take any active measures to ensure cathode protection, etc.
#
# Lewellen 21 October 1998
#

set start ""
set args $argv
set gunChoice RG2
APSParseArguments {start}

set useRC 1

# Parallel lists of PVs and tcl variables
proc addToLists {args} {
    global pvList tclVarList
    APSAddToParallelLists -listNames  {pvList tclVarList} \
      -listItems $args 
}

#addToLists L1:RFG:HTR:PS:powerCC RFheaterPower
#addToLists L1:HSG:HTR:PS:powerCC HSheaterPower
#addToLists L1:RFG:VP:CO1:controllerDG.VAL RFgunPressure
#addToLists L1:HSG:VP:CO1:controllerDG.VAL HSgunPressure
#addToLists L1:RFG:VP:CO2:controllerDG.VAL RFalphaPressure
#addToLists L1:HSG:VP:CO2:controllerDG.VAL HSalphaPressure
#addToLists L1:RFG:HTR:PS:setCurrAO RFheaterSetpoint
#addToLists L1:HSG:HTR:PS:setCurrAO HSheaterSetpoint
addToLists L1:RG2:HTR:PowerCC RG2heaterPower
addToLists L1:RG1:HTR:PowerCC RG1heaterPower
addToLists L1:RG2:VP:CO1 RG2gunPressure
addToLists L1:RG1:VP:CO1 RG1gunPressure
addToLists L1:RG2:HTR:VoltageAO RG2heaterSetpoint
addToLists L1:RG1:HTR:VoltageAO RG1heaterSetpoint
addToLists L1:RG:LFA:VP:CO1 alphaPressure

addToLists L1:SCOPE1:scopeInUseMO scopeInUse
addToLists L1:SCOPE1:scopeInUseMO.DESC semaphoreText

proc ResetEntries {} {
    global gunChoice
    .userFrame.frame.heater.entry configure -textvariable ${gunChoice}maxHeaterPower
    .userFrame.frame.press.entry configure -textvariable ${gunChoice}maxPressure
    #.userFrame.frame.sectPwrLower.entry configure -textvariable ${gunChoice}minSectPwr
    .userFrame.frame.sectPwrUpper.entry configure -textvariable ${gunChoice}maxSectPwr
    #.userFrame.frame.klyPwrLower.entry configure -textvariable ${gunChoice}minKlyPwr
    .userFrame.frame.klyPwrUpper.entry configure -textvariable ${gunChoice}maxKlyPwr
}

proc switchApplicationState {run} {
    if $run {
        APSEnableButton .userFrame.frame.stop.button
        APSDisableButton .userFrame.frame.run.button
        .userFrame.frame.heater.entry config -state disabled
        .userFrame.frame.press.entry config -state disabled
        #.userFrame.frame.sectPwrLower.entry config -state disabled
        .userFrame.frame.sectPwrUpper.entry config -state disabled
        #.userFrame.frame.klyPwrLower.entry config -state disabled
        .userFrame.frame.klyPwrUpper.entry config -state disabled
	.userFrame.frame.gunChoice.frame.button1 config -state disabled
	.userFrame.frame.gunChoice.frame.button2 config -state disabled
    } else {
        APSEnableButton .userFrame.frame.run.button
        APSDisableButton .userFrame.frame.stop.button
        .userFrame.frame.heater.entry config -state normal
        .userFrame.frame.press.entry config -state normal
        #.userFrame.frame.sectPwrLower.entry config -state normal
        .userFrame.frame.sectPwrUpper.entry config -state normal
        #.userFrame.frame.klyPwrLower.entry config -state normal
        .userFrame.frame.klyPwrUpper.entry config -state normal
	.userFrame.frame.gunChoice.frame.button1 config -state normal
	.userFrame.frame.gunChoice.frame.button2 config -state normal
    }
}

proc ShutdownSystem {args} {
    set description "Unknown"
    set useRC 0
    APSStrictParseArguments {description useRC}

    if $useRC {
        catch {APSRunControlExit}
    }
    global tclVarList gunChoice
    eval global $tclVarList
    set scopeInUse "Abort All"
    set semaphoreText $description
    set ${gunChoice}heaterSetpoint 1
    if [pv putw [list scopeInUse semaphoreText ${gunChoice}heaterSetpoint]] {
        global errorCode
        APSSetVarAndUpdate mainStatus "CA problem shutting down!  $errorCode"
    }
    APSSound -type emergency -volume 100
#    if [catch {exec cavput -list=L:L1StabilizerRC.SUSP=1,L:RFGunBeamIcontrollerRC.SUSP=1,L1:${gunChoice}:KIK:OnBO=0 -numerical -blunderAhead} results] {
#      APSSetVarAndUpdate mainStatus "$results"
#    }
    if [catch {exec cavput -list=L:L1Stabilizer:SDDS.SUSP=1,L:RFGunBeamIcontrollerRC.SUSP=1,L1:${gunChoice}:KIK:OnBO=0 -numerical -blunderAhead} results] {
      APSSetVarAndUpdate mainStatus "$results"
    }
    if [catch {IncreaseL1AttnCtrl} results] {
      APSSetVarAndUpdate mainStatus "$results"
    }
    switchApplicationState 0
}

proc IncreaseL1AttnCtrl {args} {
    set variable "apsIncreaseL1AttnCtrl[APSTmpString]"
    global errorCode $variable ${variable}2 ${variable}3
    set gunLinks "$variable ${variable}2 ${variable}3"
    set gunPVs "L1:MA:klyPosAI L1:KY:DC2A:pwmCtlC L1:LL:lockRfOffBO"
    if {[pv linkw $gunLinks $gunPVs]!=0} {
	return -code error "IncreaseL1AttnCtrl: Linking PVs $errorCode"
    }
    set ${variable}3 "Off"
    if {[pv putw ${variable}3]!=0} {
	return -code error "IncreaseL1AttnCtrl: Setting L1:LL:lockRfOffBO $errorCode"
    }    
    while {[set $variable] < 3.4} {
	set ${variable}2 -1.0
	if {[pv putw ${variable}2]!=0} {
	    return -code error "IncreaseL1AttnCtrl: Setting L1:KY:DC2A:pwmCtlC to 1.0 $errorCode"
	}
	APSWaitWithUpdate -waitSeconds 1
	if {[pv getw $variable]!=0} {
	    return -code error "IncreaseL1AttnCtrl: Reading PVs $errorCode"
	}
    }
    update
}

proc RunRFGunInterlock {} {
    global tclVarList stopInterlocking \
	RG1maxHeaterPower RG2maxHeaterPower \
	RG1maxPressure RG2maxPressure \
	RG1minSectPwr RG2minSectPwr \
	RG1maxSectPwr RG2maxSectPwr \
	RG1maxSafeSectPwr RG2maxSafeSectPwr \
	RG1minKlyPwr RG2minKlyPwr \
	RG1maxKlyPwr RG2maxKlyPwr \
	RG1maxSafeKlyPwr RG2maxSafeKlyPwr \
	maxSafeKlyPowerStatus maxSafeSectPowerStatus \
	minSafeKlyPowerStatus minSafeSectPowerStatus \
	useRC gunChoice bgexecAbort cavgetresults
    eval global $tclVarList 

    set stopInterlocking 0
    set shutdownVar 0
    APSSetVarAndUpdate mainStatus "Running."

    if $useRC {
        if [catch {exec cavget -list=L:RFGunInterlockRC.RUN} result] {
            APSSetVarAndUpdate mainStatus "Unable to check runControl state."
            return
        }
        if $result==1 {
            APSSetVarAndUpdate mainStatus "RF Gun interlock already running."
            return
        }
        catch {APSRunControlExit}
        if {[catch {APSRunControlInit -pv L:RFGunInterlockRC \
                      -description "RF Gun Interlock" \
                      -timeout 60000} result]} {
            APSSetVarAndUpdate mainStatus "Unable to get runControl access: $result"
#            ShutdownSystem -description "Abrt req'd"
            return
        }
    }

    set scopeInUse Available
    if [pv putw scopeInUse] {
	global errorCode
        set message "CA problem initializing rfGunInterlock:  $errorCode\nSystem shutdown."
        ShutdownSystem  -description timeout
        APSSetVarAndUpdate mainStatus $message
        APSAlertBox [APSUniqueName .] -errorMessage $message
    }

    set ${gunChoice}minSafeSectPwr [expr [set ${gunChoice}minSectPwr] * 1.02]
    set ${gunChoice}minSafeKlyPwr [expr [set ${gunChoice}minKlyPwr] * 1.02]
    set ${gunChoice}maxSafeSectPwr2 [expr [set ${gunChoice}maxSectPwr] * .98]
    set ${gunChoice}maxSafeKlyPwr2 [expr [set ${gunChoice}maxKlyPwr] * .98]

    while {$stopInterlocking==0}  {
        if {$useRC && [catch {APSRunControlPing} result]} {
            ShutdownSystem -description "Run Ctrl"
            return
        }
        # Get updates of all the PVs
        if [pv getw $tclVarList] {
	    global errorCode
            set message "CA problem for rfGunInterlock:  $errorCode\nSystem shutdown."
            ShutdownSystem  -description timeout
            APSSetVarAndUpdate mainStatus $message
            APSAlertBox [APSUniqueName .] -errorMessage $message
        }

        # check for the semaphore status    
        if {$scopeInUse == "Abort All"} {
            APSSetVarAndUpdate mainStatus "Abort requested."
            ShutdownSystem -description "Abrt req'd"
            break
        }

        # check for the gun heater power
        if {[set ${gunChoice}heaterPower] > [set ${gunChoice}maxHeaterPower]} {
            APSSetVarAndUpdate mainStatus "Excessive heater power detected: [set ${gunChoice}heaterPower]."
            ShutdownSystem  -description "Htr Pwr"
            break
        }

        # check for gun pressure
        if {[set ${gunChoice}gunPressure] > [set ${gunChoice}maxPressure]} {
            APSSetVarAndUpdate mainStatus "Excessive gun vacuum pressure detected: [set ${gunChoice}gunPressure]"
            ShutdownSystem  -description "Gun Pres"
            break
        }

        # check alpha magnet chamber pressure
        if {$alphaPressure > [set ${gunChoice}maxPressure]} {
            APSSetVarAndUpdate mainStatus "Excessive alpha magnet pressure detected: $alphaPressure"
            ShutdownSystem  -description "Alpha Pres"
            break
        }

        if {$useRC && [catch {APSRunControlPing} result]} {
            ShutdownSystem -description "Run Ctrl"
            return
        }

	if [catch {blt::bgexec bgexecAbort -output cavgetresults cavget -list=L1:SE:DC1ARF.VAL,L1:KY:DC2ARF.VAL -numerical -repeat=number=5,pause=1,average -errorValue=-1} results] {
	    APSSetVarAndUpdate mainStatus "CA problem reading rf power: $results"
	    ShutdownSystem  -description "No rf"
	    break
	}
	if {$bgexecAbort == 1} {continue}
	set SectPower [lindex $cavgetresults 0]
	set KlyPower [lindex $cavgetresults 1]
	if {([regexp {^[-+]?[0-9]*\.?[0-9]*([0-9]\.?e[-+]?[0-9]*)?$} $SectPower] == 0) ||
	    ([regexp {^[-+]?[0-9]*\.?[0-9]*([0-9]\.?e[-+]?[0-9]*)?$} $KlyPower] == 0)} {continue}
	set problems 0
        if {$SectPower < [set ${gunChoice}minSectPwr]} {
	    APSSetVarAndUpdate mainStatus "L1 sector forward power below lower limit. ($SectPower < [set ${gunChoice}minSectPwr])"
	    incr problems
        }
        if {$SectPower > [set ${gunChoice}maxSectPwr]} {
	    APSSetVarAndUpdate mainStatus "L1 sector forward power above upper limit. ($SectPower > [set ${gunChoice}maxSectPwr])"
	    incr problems
        }
        if {$KlyPower < [set ${gunChoice}minKlyPwr]} {
            APSSetVarAndUpdate mainStatus "L1 Kly forward power below lower limit. ($KlyPower < [set ${gunChoice}minKlyPwr])"
            incr problems
        }
        if {$KlyPower > [set ${gunChoice}maxKlyPwr]} {
            APSSetVarAndUpdate mainStatus "L1 Kly forward power above upper limit. ($KlyPower > [set ${gunChoice}maxKlyPwr])"
            incr problems
        }
	if {$problems == 0} {
	    set shutdownVar 0
	} else { 
	    incr shutdownVar
	}
	if {$shutdownVar > 1} {
	    ShutdownSystem  -description "Fwd Pwr"
	}
        if {($SectPower > [set ${gunChoice}maxSafeSectPwr]) || ($SectPower > [set ${gunChoice}maxSafeSectPwr2])} {
	  APSSetVarAndUpdate mainStatus "L1 sector forward power approaching upper limit."
	  incr maxSafeSectPowerStatus 
	  if {$maxSafeSectPowerStatus == "3"} {
	    destroy .dialog1
	    APSDialogBox .dialog1 -name "Warning"
	    pack [message .dialog1.userFrame.text -aspect 300 -text "L1 sector forward power nearing the upper limit.  Please adjust settings."]
	    APSSound -type alert -volume 100 -iterations 3 -period continuous
	  } elseif {$maxSafeSectPowerStatus == "5"} {
	    set maxSafeSectPowerStatus 0
	  }
        } else {
	  set maxSafeSectPowerStatus 0
	}

        if {$SectPower < [set ${gunChoice}minSafeSectPwr]} {
	  APSSetVarAndUpdate mainStatus "L1 sector forward power approaching lower limit."
	  incr minSafeSectPowerStatus 
	  if {$minSafeSectPowerStatus == "3"} {
	    destroy .dialog2
	    APSDialogBox .dialog2 -name "Warning"
	    pack [message .dialog2.userFrame.text -aspect 300 -text "L1 sector forward power nearing the lower limit.  Please adjust settings."]
	    APSSound -type alert -volume 100 -iterations 3 -period continuous
	  } elseif {$minSafeSectPowerStatus == "5"} {
	    set minSafeSectPowerStatus 0
	  }
        } else {
	  set minSafeSectPowerStatus 0
	}

        if {($KlyPower > [set ${gunChoice}maxSafeKlyPwr]) || ($KlyPower > [set ${gunChoice}maxSafeKlyPwr2])} {
	  APSSetVarAndUpdate mainStatus "L1 Kly forward power approaching upper limit."
	  incr maxSafeKlyPowerStatus 
	  if {$maxSafeKlyPowerStatus == "3"} {
	    destroy .dialog3
	    APSDialogBox .dialog3 -name "Warning"
	    pack [message .dialog3.userFrame.text -aspect 300 -text "L1 Kly forward power nearing the upper limit.  Please adjust settings."]
	    APSSound -type alert -volume 100 -iterations 3 -period continuous
	  } elseif {$maxSafeKlyPowerStatus == "5"} {
	    set maxSafeKlyPowerStatus 0
	  }
        } else {
	  set maxSafeKlyPowerStatus 0
	}

        if {$KlyPower < [set ${gunChoice}minSafeKlyPwr]} {
	  APSSetVarAndUpdate mainStatus "L1 Kly forward power approaching lower limit."
	  incr minSafeKlyPowerStatus 
	  if {$minSafeKlyPowerStatus == "3"} {
	    destroy .dialog4
	    APSDialogBox .dialog4 -name "Warning"
	    pack [message .dialog4.userFrame.text -aspect 300 -text "L1 Kly forward power nearing the lower limit.  Please adjust settings."]
	    APSSound -type alert -volume 100 -iterations 3 -period continuous
	  } elseif {$minSafeKlyPowerStatus == "5"} {
	    set minSafeKlyPowerStatus 0
	  }
        } else {
	  set minSafeKlyPowerStatus 0
	}

        APSSetVarAndUpdate mainStatus "Checks ok: [clock format [clock seconds]]"
        APSSetVarAndUpdate mainStatus "  Semaphore text: $semaphoreText  Heater: [format %.1f [set ${gunChoice}heaterPower]]W  Gun Pres: [format %.2g [set ${gunChoice}gunPressure]]T"
        APSSetVarAndUpdate mainStatus "  Alpha Pres: [format %.2g $alphaPressure]T  Sect Fwd Pwr: [format %.3g $SectPower]W  Kly Fwd Pwr: [format %.3g $KlyPower]W"
    }
    if $useRC {
        catch {APSRunControlExit}
    }
    if $stopInterlocking {
        APSSetVarAndUpdate mainStatus "Responded to request to stop interlock: [clock format [clock seconds]]"
    }
}

proc ExitNicely {} {
    global useRC
    .userFrame.frame.stop.button flash
    .userFrame.frame.stop.button invoke
    if $useRC {
	catch {APSRunControlExit}
    }
}

proc Restart {cid addr port} {
    #Only the localhost will be allowed to restart this program
    if {$addr != "127.0.0.1"} {
	close $cid
	return
    }
    close $cid
    .userFrame.frame.stop.button flash
    .userFrame.frame.stop.button invoke
    
    global gunChoice switchPosition errorCode
    if [pv getw switchPosition] {
	APSAlertBox [APSUniqueName .] -errorMessage "CA problem: $errorCode"
	exit 1
    }	
    if {$switchPosition == "RG2"} {
	set gunChoice RG2
    } elseif {$switchPosition == "RG1"} {
	set gunChoice RG1
    } else {
	APSAlertBox [APSUniqueName .] -errorMessage "Switch Position: $switchPosition"
	exit 1
    }
    ResetEntries
    after 3000 {
	.userFrame.frame.run.button flash
	.userFrame.frame.run.button invoke
    }
}

APSApplication . \
    -name rfGunInterlock \
    -overview {This application is intended to monitor the rf gun for anomalous conditions.  It shuts the heater and rf power off if anything is detected.} -version $CVSRevisionAuthor

set mainStatus ""
set RG1maxHeaterPower 18
set RG1maxPressure 10e-7

set RG2maxHeaterPower 18
set RG2maxPressure 10e-7

set RG1minSectPwr -1e6
set RG1maxSafeSectPwr 12e6
set RG1maxSectPwr 13e6
set RG1minKlyPwr -1e6
set RG1maxSafeKlyPwr 12.5e6
set RG1maxKlyPwr 13e6

set RG2minSectPwr -1e6
set RG2maxSafeSectPwr 16.0e6
set RG2maxSectPwr 16.0e6
set RG2minKlyPwr -1e6
set RG2maxSafeKlyPwr 20e6
set RG2maxKlyPwr 20e6

set maxSafeKlyPowerStatus 0
set maxSafeSectPowerStatus 0
set minSafeKlyPowerStatus 0
set minSafeSectPowerStatus 0
set stopInterlocking 0

pack [frame .userFrame.frame] -fill x -expand false -side bottom
APSScrolledStatus .record \
    -parent .userFrame \
    -textVariable mainStatus \
    -width 80 \
    -height 8 \
    -packOption "-fill both -expand true" -withButtons 1
pack configure .userFrame.record.frame -fill both -expand true

APSLabeledEntry .heater \
    -parent .userFrame.frame \
    -label "Heater power upper limit (W): " \
    -textVariable RG2maxHeaterPower \
    -type real
APSLabeledEntry .press \
    -parent .userFrame.frame \
    -label "Pressure upper limit (Torr): " \
    -textVariable RG2maxPressure \
    -type real
#APSLabeledEntry .sectPwrLower \
#    -parent .userFrame.frame \
#    -label "L1 sector forward power lower limit (W): " \
#    -textVariable RG2minSectPwr \
#    -type real
APSLabeledEntry .sectPwrUpper \
    -parent .userFrame.frame \
    -label "L1 sector forward power upper limit (W): " \
    -textVariable RG2maxSectPwr \
    -type real
#APSLabeledEntry .klyPwrLower \
#    -parent .userFrame.frame \
#    -label "L1 Kly forward power lower limit (W): " \
#    -textVariable RG2minKlyPwr \
#    -type real
APSLabeledEntry .klyPwrUpper \
    -parent .userFrame.frame \
    -label "L1 Kly forward power upper limit (W): " \
    -textVariable RG2maxKlyPwr \
    -type real

APSButton .run \
    -parent .userFrame.frame \
    -text "Run" \
    -command { switchApplicationState 1; RunRFGunInterlock; switchApplicationState 0} \
    -contextHelp "Press to engage rf gun interlock."
APSButton .stop \
    -parent .userFrame.frame \
    -text "Stop" \
    -command {switchApplicationState 0; set stopInterlocking 1 ; bell; update}
APSDisableButton .userFrame.frame.stop.button
APSButton .info \
    -parent .userFrame.frame \
    -text "Info" \
    -command { 
	if $useRC {exec medm -x -attach -macro RCPV=L:RFGunInterlockRC ./sr/psApp/APSRunControlSingle.adl &}
    }
APSRadioButtonFrame .gunChoice \
    -parent .userFrame.frame \
    -label "   Gun Choice:" \
    -variable gunChoice \
    -buttonList "RG1 RG2" \
    -valueList "RG1 RG2" \
    -orientation horizontal \
    -commandList {ResetEntries ResetEntries}

if [pv linkw "$tclVarList switchPosition" "$pvList L1:RFG:RF:SW2:positionMI"] {
    APSAlertBox [APSUniqueName .] -errorMessage "CA problem:  $errorCode\nCan't run!" 
    exit 1
}
if {$switchPosition == "RG2"} {
    set gunChoice RG2
} elseif {$switchPosition == "RG1"} {
    set gunChoice RG1
} else {
    APSAlertBox [APSUniqueName .] -errorMessage "Switch Position: $switchPosition"
    exit 1
}
ResetEntries
after 200

#port 4580 is used to tell the rfGunInterlock to attempt to restart
if [catch {socket -server Restart 4580}] {
    APSSetVarAndUpdate mainStatus  "There appears to be another copy of this program already started"
}

.menu.file.menu entryconfigure 1 -command "exec $argv0 &; exit"
dp_atexit append ExitNicely

if {$start == "1"} {
    .userFrame.frame.run.button invoke
}
