#!/bin/sh  
# \
exec oagwish "$0" "$@"

# $Log: not supported by cvs2svn $
# Revision 1.14  2011/04/13 14:07:48  shang
# added 667 ns adjustment of time based on L1CM1 peak position comparing current data and previous data.
#
# Revision 1.13  2011/04/13 13:10:27  shang
# removed the waveform conversion since the EPICS waveform nows gives the actual voltage.
#
# Revision 1.12  2010/10/01 18:57:11  shang
# corrected the scale factor for timing, which should be 1e3 instead of 10e3
#
# Revision 1.11  2010/10/01 16:23:53  shang
# modified the time tranfser due to the units changed in the time waveform.
#
# Revision 1.10  2010/09/24 14:34:19  soliday
# Updated to reflect changes in PV names for the L1:SCOPE1
#
# Revision 1.9  2008/04/18 20:58:18  shang
# moved the checking kicker on/off state to scan script
#
# Revision 1.8  2008/04/18 20:13:47  shang
# added checking if the kicker is disabled during validation.
#
# Revision 1.7  2007/03/01 22:28:40  shang
# changed the RG1 gun heater threashold from 21 W to 14 W, and added popuping dialog box
# if the gun heater power less than its threashold.
#
# Revision 1.6  2007/02/27 16:34:14  shang
# sets the leakage to -100.0 at failed condition.
#
# Revision 1.5  2006/09/25 15:00:56  shang
# made changes to leakage computation.
#
# Revision 1.4  2006/03/02 18:53:16  shang
# changed the average range from head 150 to 50 for obtaining the baseline of RF gun current
# since the RF Gun current starts to have signal at head=80
#
# Revision 1.3  2006/03/02 18:08:59  shang
# fixed a typo
#
# Revision 1.2  2006/03/02 17:48:25  shang
# uses sddssmooth to remove the noise after waveform data is taken.
#
# Revision 1.1  2005/09/29 21:19:02  shang
# renamed from APSMonitorL1Leakage.tcl
#
# Revision 1.2  2005/03/04 14:58:19  shang
# removed shang's private libary path
#
# Revision 1.1  2005/03/04 01:00:09  shang
# first version of leakage monitor
#

wm withdraw .
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 args $argv
set gun ""
set limit 0
set runControlPV L:RFG:KickerLeakageRC
set rfFwdPowerLimit 6.0e6
APSParseArguments {gun limit runControlPV rfFwdPowerLimit}

switch $gun {
    RG1 {
	set rfFwdPowerLimit 6.0e6
    }
    RG2 {
	set rfFwdPowerLimit 6.5e6
    }
    default {
        puts stderr "Error: Invalid gun provided.!"
        exit
    }
}

set status ""
set gunHeaterPowerThreshold(RG1) 14
set gunHeaterPowerThreshold(RG2) 12
set L1CM2Calibration(RG1) 0.41
set L1CM2Calibration(RG2) 0.41
set RGCMCalibration(RG1) 1.1
set RGCMCalibration(RG2) 1.1
set setupDir /home/helios/oagData/linac/gunKickerValidation
set nameList [list HeaterPower KickerEnabled \
                L1KlystronPower GunCMMax L1CM2Max GunCMInteg2 L1CM2Integ1 L1CM2Integ2 Leakage]
set pvList [list "" L1:$gun:KIK:chargeTrigC "" "" "" L1:RFG:VLD:GunCMInt2 L1:RFG:VLD:L1CM2Int1 L1:RFG:VLD:L1CM2Int2 L1:RFG:VLD:LeakageCC]
set formatList [list %.5f %s %.3g %.4f %.4f %.4f %.4f %.4f %.4f]
set unitsList [list W "binary" W mA mA mA*ns mA*ns mA*ns "%"]
set changeLogPID ""
set logFID ""
set logFileString ""
set abortLoop 0
set LeakageMax 0
set asciiCharacters ""
for {set i 0} {$i < 256} {incr i} {
    lappend asciiCharacters [format %c $i]
}
proc SetStatus {text} {
    puts stderr "[clock format [clock seconds] -format %H:%M:%S] $text"
}
proc ConvertStringToNumbers {string length} {
    global asciiCharacters
    set string [split $string ""]
    set i 0
    set result ""
    foreach c $string {
        lappend result [lsearch -exact $asciiCharacters $c]
        incr i
    }
    for {set j $i} {$j < $length} {incr j} {
        lappend result 0
    }
    return $result
} 
proc APSGetScopeWaveforms {args} {
    set fileName ""
    set gun RG2
    set setupDir /home/helios/oagData/linac/gunKickerValidation
    set calFactor ""
    set rgCal ""
    set nameList ""
    APSStrictParseArguments {fileName gun setupDir calFactor rgCal nameList}
    
    global setScopeCommandVar setScopeCommandVar
    if {![string length $calFactor] } {
	set calFactor 0.41
    }
    if ![string length $rgCal] {
	set rgCal 1.1
    }
    
    set setScopeCommandVar [ConvertStringToNumbers ":ACQ:COUN 4" 256]
    pv putw setScopeCommandVar
    set setScopeCommandVar [ConvertStringToNumbers ":ACQ:COUN 16" 256]
    pv putw setScopeCommandVar
    APScavput -list=L1:SCOPE1:stopReadRunSQ.SCAN=Passive
    after 1000
    #compare to previous data /home/helios/oagData/linac/gunKickerValidation/RG2Data/Test-2005-272-0929.0000.proc
    #the time "t" has 667 ns difference from the peak position of L1CM2, so make this adjustment to make sure
    #the computation is the same as before, but do not know why. (HS)
    if [catch {APScavput -list=L1:SCOPE1:stopReadRunSQ.SCAN=Passive
        APScavput -list=L1:SCOPE1:stopReadRunSQ.VAL=1
        exec sddswmonitor $fileName -erase -steps=1 \
                 -scalars=$setupDir/L1Scope1Scalars.$gun.sdds \
                   -pvname=L1:SCOPE1:scaledTimeAxisWF,L1:SCOPE1:chan2ScaledWaveWF,L1:SCOPE1:chan4ScaledWaveWF
        exec sddssmooth $fileName -pipe=out -despike=pass=3 \
                   -col=L1:SCOPE1:chan2ScaledWaveWF,L1:SCOPE1:chan4ScaledWaveWF \
                   | sddsprocess -nowarning  -pipe \
                   "-define=column,t,L1:SCOPE1:scaledTimeAxisWF 1000 * 667 - ,units=ns" \
                   "-define=column,L1CM2,L1:SCOPE1:chan2ScaledWaveWF chs 1e3 * $calFactor *,units=mA" \
                   "-define=column,GunCM,L1:SCOPE1:chan4ScaledWaveWF chs 1e3 * $rgCal *,units=mA" \
                   | sddsprocess -pipe -process=*CM*,ave,%sBaseline,head=50 \
                   "-redefine=col,%s,%s %sBaseline -,select=*CM*,units=V" \
                   | sddsprocess -pipe \
                   -process=*CM*,max,%sMax \
                   -process=*CM*,max,%sMaxPos,func=t,position \
                   -process=t,spread,tSpread \
                   "-define=parameter,dt,tSpread n_rows 1 - /,units=ns" \
                   "-define=parameter,tCutoff1,GunCMMaxPos 100 - " \
                   "-define=column,t1,t tCutoff1 -" \
                   "-define=parameter,tCutoff2,GunCMMaxPos 100 + " \
                   "-define=column,t2,t tCutoff2 -" \
                   -process=L1CM2,sum,L1CM2Sum1,func=t1,lower=-700,upper=0 \
                   -process=L1CM2,sum,L1CM2Sum2,func=t2,lower=-900,upper=0 \
                   -process=GunCM,sum,GunCMSum2,func=t2,lower=-900,upper=0 \
                   "-define=parameter,L1CM2Integ1,L1CM2Sum1 dt *,units=V ns" \
                   "-define=parameter,L1CM2Integ2,L1CM2Sum2 dt *,units=V ns" \
                   "-define=parameter,GunCMInteg2,GunCMSum2 dt *,units=V ns" \
                   "-define=parameter,Leakage,L1CM2Integ1 GunCMInteg2 / 100 *,units=%" \
                   | tee $fileName.proc \
                   | sdds2stream -param=${gun}[join $nameList ,] -pipe} dataList] {
        APSLogScriptAction -procedure APSProcessScopeWaveforms -action "Error: $dataList" \
            -parameters "?" -state error
        return -code error "APSProcessWaveforms: $dataList"
    }
    return $dataList
}

proc APSProcessScopeWaveforms {args} {
    set fileName ""
    set gun ""
    set nameList ""
    APSStrictParseArguments {fileName gun nameList pvList}
    
    if [catch {exec sddsprocess $fileName -pipe=out \
                 -process=*CM*,ave,%sBaseline,head=150 \
                 "-redefine=col,%s,%s %sBaseline -,select=*CM*,units=V" \
                 | sddsprocess -pipe \
                 -process=*CM*,max,%sMax \
                 -process=*CM*,max,%sMaxPos,func=t,position \
                 -process=t,spread,tSpread \
                 "-define=parameter,dt,tSpread n_rows 1 - /,units=ns" \
                 "-define=parameter,tCutoff1,GunCMMaxPos 100 - " \
                 "-define=column,t1,t tCutoff1 -" \
                 "-define=parameter,tCutoff2,GunCMMaxPos 100 + " \
                 "-define=column,t2,t tCutoff2 -" \
                 -process=L1CM2,sum,L1CM2Sum1,func=t1,lower=-700,upper=0 \
                 -process=L1CM2,sum,L1CM2Sum2,func=t2,lower=-900,upper=0 \
                 -process=GunCM,sum,GunCMSum2,func=t2,lower=-900,upper=0 \
                 "-define=parameter,L1CM2Integ1,L1CM2Sum1 dt *,units=V ns" \
                 "-define=parameter,L1CM2Integ2,L1CM2Sum2 dt *,units=V ns" \
                 "-define=parameter,GunCMInteg2,GunCMSum2 dt *,units=V ns" \
                 "-define=parameter,Leakage,L1CM2Integ1 GunCMInteg2 / 100 *,units=%" \
                 | tee $fileName.proc \
                 | sdds2stream -param=${gun}[join $nameList ,] -pipe} dataList] {
        APSLogScriptAction -procedure APSProcessScopeWaveforms -action "Error: $dataList" \
          -parameters "?" -state error
        return -code error "APSProcessWaveforms: $dataList"
    }
    return "$dataList"
}

proc APSMonitorL1Leakage {args} {
    set limit 1
    set runControlPV ""
    set gun ""
    set rfFwdPowerLimit 9.0e6
    APSStrictParseArguments {limit runControlPV gun rfFwdPowerLimit}
    APSLogScriptAction -procedure APSMonitorL1Leakage -action "start" \
        -parameters "limit:$limit" -state ok

    global nameList logFID unitsList logFileString setupDir status badOnesLeft 
    global formatList unitsList pvList L1CM2Calibration RGCMCalibration
    global gunHeaterPowerThreshold changeLogPID LeakageMax 
    eval global $nameList
    global abortLoop

    catch {APSRunControlExit}
    after 2000
    if $limit {
        SetStatus "Starting gun leakage limiter."
        set status "Starting gun leakage limiter."
        set description "GunLeakageLimiter"
    } else {
        SetStatus "Starting gun leakage monitor."
        set status "Starting gun leakage monitor."
        set description "GunLeakageMonitor"
    }
    if [catch {APScavget -list=$runControlPV.RUN -pend=30} running] {
        return -code error $result
    }
    if $running {
        SetStatus "Leakage monitor is already running."
        exit
    }
    if [catch {APScavput -list=$runControlPV.CLR=1 -pend=30} result] {
        return -code error $result
    }
    if {[catch {APSRunControlInit -pv $runControlPV -description $description \
                  -timeout 60000} result]} {
        return -code error "APSMonitorL1Leakage: Unable to get runControl access: $result"
    }
    APSRunControlLogMessage -message "running" -severity 0
    set lastKickerState -1
    set badOnesLeft 3
    set abortLoop 0

    if [catch {APScavget -list=L1:RFG:RF:SW2:positionMI} gun1] {
        SetStatus "APSMonitorL1Leakage: $gun1"
        set status "APSMonitorL1Leakage: $gun1"
        catch {APSRunControlExit}
        exit
    }
    if {$gun1!=$gun} {
        SetStatus "APSMonitorL1Leakage: $gun is not in operation"
        set status "APSMonitorL1Leakage: $gun is not in operation"
        catch {APSRunControlExit}
        exit
    }
    if [string length $changeLogPID] {
        exec kill $changeLogPID
        set changeLogPID ""
    }
    APSDateBreakDown -dayVariable day -monthVariable month -julianDayVariable jday \
      -yearVariable year -twoDigitYear 0 -leadingZeros 0
    set changeLogPID [exec sddslogonchange $setupDir/L1Setpoints.mon \
                        $setupDir/${gun}Data/Changes-[format %04d-%03d-%02d%02d $year $jday $month $day] \
                        -generation \
                        -timeDuration=24,hour &]
    
    APSLogScriptAction -procedure APSMonitorL1Leakage -action "Running leakage monitoring" \
      -parameters "?" -state ok
    set tmpRoot /tmp/[APSTmpString]L1Leakage
    APSAddToTmpFileList -ID monitorL1Leakage -fileList "$tmpRoot.sdds $tmpRoot.sdds.proc"
    set calFactor $L1CM2Calibration($gun)
    set rgCal $RGCMCalibration($gun)
    while {!$abortLoop} {
        if [catch {APSRunControlPing} result] {
            break
        }
        if [catch {CheckLLRFTrip} result] {
            SetStatus "$result"
            if [catch {exec cavput -list=L1:RFG:VLD:LeakageCC=-100.0 -pend=30} result] {
                SetStatus $result
                bell 
                after 1000
            }
            after 1000
            continue
        }
        if [catch {APScavget -list=L1:SE:DC1ARF.VAL -pend=30 -printErrors} rfFwdPower] {
            SetStatus "$rfFwdPower"
            after 1000
            continue
        }
        if {$rfFwdPower<$rfFwdPowerLimit} {
            if {![winfo exist .rf]} {
                APSAlertBox .rf -name "RF gun feedforward power is low!" -type alert -name Alert \
                    -errorMessage "The RF gun feedforward power is less than $rfFwdPowerLimit." -modeless 1 -beep continuous
            }
            if [catch {exec cavput -list=L1:RFG:VLD:LeakageCC=-100.0 -pend=30} result] {
                SetStatus $result
                bell 
                after 1000
            }
            after 1000 
            continue
        } else {
            if [winfo exist .rf] {
                destroy .rf
            }
        }
        if {$limit && $badOnesLeft<=0} {
            SetStatus "Too many problems.  Stopping beam." 
            APSStopBeam "Too many problems.  Stopping beam."
            set badOnesLeft 3
        }
        #APSWaitWithUpdate -waitSeconds 1 -updateInterval 1
        if [catch {APSRunControlPing} result] {
            break
        }
	SetStatus  $tmpRoot.sdds
        if [catch {APSGetScopeWaveforms -fileName $tmpRoot.sdds -gun $gun \
                     -nameList $nameList \
                     -calFactor $calFactor -rgCal $rgCal} dataList] {
            SetStatus "APSMonitorL1Leakage: Problem acquiring data: $dataList" 
            if [catch {exec cavput -list=L1:RFG:VLD:LeakageCC=-100.0 -pend=30} result] {
                SetStatus $result
                bell 
                after 1000
            }
            after 1000
            #catch {APSRunControlExit}
            #exit
            continue
        }
	foreach item $nameList value $dataList format $formatList pvitem $pvList {
            set $item [format $format $value]
            if {[string length $pvitem]} {
                SetStatus "$item = [set $item]"
                catch {APScavput -list=${pvitem}=[set $item] -pend=30}
            }
        }
        if [catch {APSRunControlPing} result] {
            break
        }
        if {$lastKickerState==-1 || $lastKickerState!=$KickerEnabled} {
            # if kick just changed state, retake data as it might be bad
            set lastKickerState $KickerEnabled
            APSClearMonitorL1LeakageValues
            continue
        }
        
        if {$L1KlystronPower<2e6} {
            SetStatus "L1 klystron power < 2 MW"
            set status "L1 klystron power < 2 MW"
            if [catch {exec cavput -list=L1:RFG:VLD:LeakageCC=-100.0 -pend=30} result] {
                SetStatus $result
                bell 
                after 1000
            }
            APSSendToLogFile
            continue
        }
        if {$HeaterPower<$gunHeaterPowerThreshold($gun)} {
            SetStatus "$gun heater power < $gunHeaterPowerThreshold($gun) W"
            set status "$gun heater power < $gunHeaterPowerThreshold($gun) W"
            if ![winfo exist .lowpower] {
                APSAlertBox .lowpower -name "Gun Power Too Low!" -type alert -name Alert \
                    -errorMessage "$gun heater power is less than $gunHeaterPowerThreshold($gun) W" \
                    -modeless 1 -beep continuous
            }
            if [catch {exec cavput -list=L1:RFG:VLD:LeakageCC=-100.0 -pend=30} result] {
                SetStatus $result
                bell 
                after 1000
            }
            APSSendToLogFile
            continue
        } else {
            if [winfo exist .lowpower] {
                destroy .lowpower
            }
        }
        
        if {$GunCMMax<0.05} {
            SetStatus "Insufficient current seen from gun.  Scope problem?"
            set status "Insufficient current seen from gun.  Scope problem?"
            if [catch {exec cavput -list=L1:RFG:VLD:LeakageCC=-100.0 -pend=30} result] {
                SetStatus $result
                bell 
                after 1000
            }
            APSSendToLogFile
            incr badOnesLeft -1
            continue
        } 
        if {$Leakage>$LeakageMax} {
            set LeakageMax $Leakage
        }
        if {$Leakage>3.0} {
            SetStatus "Leakage is > 3%."
            set status "Leakage is > 3%."
            APSSendToLogFile
            incr badOnesLeft -1 
            if {![winfo exist .alert]} {
                APSAlertBox .alert -name "Leakage" -type alert -name Alert \
                    -errorMessage "The Leakage is greater than 3% now." -modeless 1 -beep continuous
            }
        } else {
            if [winfo exist .alert] {
                destroy .alert
            }
        }
        SetStatus "All checks satisfied, leakage now is $Leakage"
        #set status "All checks satisfied, leakage now is $Leakage"
        #APSSendToLogFile
        if [catch {APSRunControlPing} result] {
            break
        }
    }
    SetStatus "Monitor L1 leakage was aborted."
    set status "Monitor L1 leakage was aborted."
    catch {exec kill $changeLogPID}
    catch {APSRunControlExit}
    set changeLogPID ""
    if [string length $logFID] {
        close $logFID
    }
}

proc CheckLLRFTrip {args} {
    set leakageControlPV  L:RFG:KickerLeakageRC 
    APSParseArguments {leakageControlPV}
    
    if [catch {APScavget -list=L1:LL:readyCC -pend=30} trip] {
        return -code error $trip
    }
    if {$trip=="?"} {
        return -code error "Can not read value of L1:LL:readyCC."
    }
    if {$trip<1.0} {
        if {![winfo exist .trip]} {
            APSAlertBox .trip -name "LLRF tripped!" -type alert -name Alert \
                -errorMessage "LLRF tripped." -modeless 1 -beep continuous
        }
        return -code error "LLRF tripped."
    } else { 
        if [winfo exist .trip] {
            destroy trip
        }
    }
}

proc APSStopBeam {text} {
    SetStatus $text
  #  APSLogScriptAction -procedure APSStopBeam -action "Stop beam: $text" \
  #      -parameters "?" -state ok
  #  catch {APScavput -list=L1:GV2:closeCmdBO=1,LI:FL:FS1:Act1InC=1,L2:LL:lockRfOffBO=1 -pend=30}
  #  after 2000
  #  catch {APScavput -list=L1:GV2:closeCmdBO=1,LI:FL:FS1:Act1InC=1,L2:LL:lockRfOffBO=1 -pend=30}
    catch {APSRunControlExit}
    exit
}

proc APSClearMonitorL1LeakageValues {} {
    global nameList pvList
    eval global $nameList
    foreach item $nameList pvitem $pvList {
        set $item ?
        if {[string length $pvitem]} {
            catch {APScavput -list=${pvitem}=? -pend=30}
        }
    }
}

proc APSSendToLogFile {} {
    global nameList logFID unitsList logFileString setupDir status badOnesLeft gun
    eval global $nameList

    set oldLogFileString $logFileString
    APSDateBreakDown -dayVariable day -monthVariable month -julianDayVariable jday \
      -yearVariable year -twoDigitYear 0 -leadingZeros 0
    set logFileString $setupDir/${gun}Data/Log-[format %04d-%03d-%02d%02d $year $jday $month $day]
    
    if {[string compare $logFileString $oldLogFileString]!=0 && [string length $logFID]} {
        if [catch {close $logFID} result] {
            setStatus "$result"
        }
        set logFID ""
    }
    if {![string length $logFID]} {
        set index 0
        set fileName [APSNextGenerationedName -name $logFileString.0000 -newFile 1 -separator .]
        if [catch {open $fileName w} logFID] {
            set status "$logFID"
        }
        puts $logFID "SDDS1"
        puts $logFID "&column name=Time type=double units=s &end"
        puts $logFID "&column name=Status type=string &end"
        puts $logFID "&column name=BadOnesLeft type=long &end"
        foreach item $nameList units $unitsList {
            puts $logFID "&column name=$item type=double units=$units &end"
        }
        puts $logFID "&data mode=ascii no_row_counts=1 &end"
    }
    puts -nonewline $logFID "[clock seconds] \"$status\" $badOnesLeft "
    foreach item $nameList {
        puts -nonewline $logFID "[set $item] "
    }
    puts $logFID ""
    flush $logFID
}

SetStatus "setting up scope to average mode."
if [catch {APScavput -list=L1:SCOPE1:stopReadRunSQ.SCAN=Passive -pend=30
    after 500
    APScavput -list=L1:SCOPE1:stopReadRunSQ.VAL=1 -pend=30
    after 500 } result] {
    return -code error "GetL1ScopeWaveforms: $result"
}
if [catch {exec sendScopeCommand L1:SCOPE1 ":TIM:SAMP REP"
    exec sendScopeCommand L1:SCOPE1 ":ACQ:TYPE AVER"
    exec sendScopeCommand L1:SCOPE1 ":ACQ:COUN 16" } result] {
    puts stderr $result
    exit
}
if [pv linkw setScopeCommandVar L1:SCOPE1:sendCmdSO 30]==1 {
    puts stderr "Unable link to L1:SCOPE1:sendCmdSO"
    exit
}
if [pv linkw setScopeProcVar L1:SCOPE1:sendCmdSI.PROC 30]==1 {
    puts stderr "Unable link to L1:SCOPE1:sendCmdSI.PROC"
    exit
}

set setScopeProcVar 1
APSMonitorL1Leakage -gun $gun -runControlPV $runControlPV -limit $limit -rfFwdPowerLimit $rfFwdPowerLimit

exit
