#!/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)]
APSApplication . -name MeasureRGKickerLeakage

set setupDir /home/helios/oagData/linac/gunKickerValidation

set tmpRoot /tmp/[APSTmpString]
set runControlPV APS:RunControlSlot4RC

proc SetWidgets {args} {
    global mainFrame
    set mode ""
    APSStrictParseArguments {mode}

    switch $mode {
        config {
            APSDisableButton $mainFrame.stop.button
            APSDisableButton $mainFrame.config1.button
            APSDisableButton $mainFrame.config2.button
            APSDisableButton $mainFrame.run.button
            APSDisableButton $mainFrame.limit.button
            APSDisableButton $mainFrame.test.button
            APSDisableButton $mainFrame.testreview.button
        }
        ready {
            APSDisableButton $mainFrame.stop.button
            APSEnableButton $mainFrame.config1.button
            APSEnableButton $mainFrame.config2.button
            APSEnableButton $mainFrame.run.button
            APSEnableButton $mainFrame.limit.button
            APSEnableButton $mainFrame.test.button
            APSEnableButton $mainFrame.testreview.button
        }
        run {
            APSEnableButton $mainFrame.stop.button
            APSDisableButton $mainFrame.config1.button
            APSDisableButton $mainFrame.config2.button
            APSDisableButton $mainFrame.run.button
            APSDisableButton $mainFrame.limit.button
            APSDisableButton $mainFrame.test.button
            APSDisableButton $mainFrame.testreview.button
        }
        test {
            APSDisableButton $mainFrame.stop.button
            APSDisableButton $mainFrame.config1.button
            APSDisableButton $mainFrame.config2.button
            APSDisableButton $mainFrame.run.button
            APSDisableButton $mainFrame.limit.button
            APSDisableButton $mainFrame.test.button
            APSDisableButton $mainFrame.testreview.button
        }
    }
    update
}

proc setStatus {text} {
    APSSetVarAndUpdate status "[clock format [clock seconds] -format %T]: $text"
}

proc PlotData {args} {
    set last 0
    set column Leakage
    APSStrictParseArguments {last column}
    global setupDir gun
    set dataFile [lindex [lsort [glob -nocomplain $setupDir/${gun}Data/Log-????-???-????.????]] end]
    if ![string length $dataFile] {
        setStatus "No data!"
        return
    }
    if $last<=0 {
        # plot everything
        exec sddsplot $dataFile -column=Time,$column -ticks=xtime &
    } else {
        # plot last N minutes, roughly, using 3s per point
        set clip [expr int($last/3.0)]
        exec sddsplot $dataFile -column=Time,$column -ticks=xtime -clip=0,$clip,invert &
    }
}

proc StopBeam {text} {
    APSSetVarAndUpdate status "[clock format [clock seconds] -format %T]: $text"
    APSLogScriptAction -procedure StopBeam -action "Stop beam: $text" \
        -parameters "?" -state ok
    catch {exec cavput -list=L1:GV2:closeCmdBO=1,LI:FL:FS1:Act1InC=1,L2:LL:lockRfOffBO=1 -pend=30}
    after 2000
    catch {exec cavput -list=L1:GV2:closeCmdBO=1,LI:FL:FS1:Act1InC=1,L2:LL:lockRfOffBO=1 -pend=30}
    after 2000
}

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

proc GetWaveforms {args} {
    set fileName ""
    set gun RG2
    APSStrictParseArguments {fileName gun}
    global setupDir L1CM2Calibration RGCMCalibration
    set calFactor $L1CM2Calibration($gun)
    set rgCal $RGCMCalibration($gun)

    if [catch {exec cavput -list=L1:SCOPE1:stopReadRunSQ.SCAN=Passive
        after 500
        exec cavput -list=L1:SCOPE1:stopReadRunSQ.VAL=1
        after 500
        exec sddswmonitor $fileName -erase -steps=1 \
                 -scalars=$setupDir/L1Scope1Scalars.sdds \
                 -pvname=L1:SCOPE1:scaledTimeAxisWF,L1:SCOPE1:chan2ScaledWaveWF,L1:SCOPE1:chan4ScaledWaveWF
        exec sddsprocess -nowarning $fileName \
                 "-define=column,t,L1:SCOPE1:scaledTimeAxisWF,units=ns" \
                 "-define=column,L1CM2,L1:SCOPE1:chan2ScaledWaveWF Chan2VPerDiv * Chan2Offset + chs 1e3 * $calFactor *,units=mA" \
                 "-define=column,GunCM,L1:SCOPE1:chan4ScaledWaveWF Chan4VPerDiv * Chan4Offset + chs 1e3 * $rgCal *,units=mA"
        file delete $fileName~ } result] {
        APSLogScriptAction -procedure GetWaveforms -action "Error: $result" \
          -parameters "?" -state error
    }
}

set logFID ""
set logFileString ""

proc SendToLogFile {} {
    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] {
            setStatus "$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
}


proc ConfigureScope {args} {
    set configuration 1
    APSStrictParseArguments {configuration}

    global setupDir
    APSLogScriptAction -procedure ConfigureScope -action "Configuring L1:SCOPE1" \
        -parameters "?" -state ok
    setStatus "Configuring scope..."
    if [catch {exec cavput -list=L1:SCOPE1:stopBO=1} result] {
        return -code error "$result"
    }
    set burtwbFile $setupDir/L1Scope1RGSetup${configuration}.snap
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddsbreak $burtwbFile -pipe=out -rowlimit=10 \
                 | sddssplit -pipe=in -binary -rootname=$tmpRoot} result] {
        return -code error "$result"
    }
    foreach file [lsort [glob -nocomplain ${tmpRoot}*.sdds]] {
        if [catch {exec sddscasr -restore $file} result] {
            return -code error "$result"
        }
        after 2000
        update
    }
    eval file delete [lsort [glob -nocomplain ${tmpRoot}*.sdds]]
    if [catch {exec putScopeSetup L1:SCOPE1 $setupDir/L1Scope1RGSetup${configuration}.sdds} result] {
        APSLogScriptAction -procedure ConfigureScope -action "Error: $result" \
          -parameters "?" -state error
        return -code error "$result"
    } 
    APSWaitWithUpdate -waitSeconds 10 -updateInterval 1
    exec cavput -list=L1:SCOPE1:stopReadRunSQ.VAL=1
    setStatus "Ready."
}

proc ProcessWaveforms {args} {
    set fileName ""
    set gun ""
    set nameList ""
    APSStrictParseArguments {fileName gun nameList}

    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 ProcessWaveforms -action "Error: $dataList" \
          -parameters "?" -state error
        return -code error "ProcessWaveforms: $dataList"
    }
    return "$dataList"
}

proc ReviewTestCapture {} {
    global nameList logFID unitsList logFileString setupDir status badOnesLeft formatList unitsList
    global gunHeaterPowerThreshold tmpRoot gun
    eval global $nameList

    set gun [exec cavget -list=L1:RFG:RF:SW2:positionMI]

    set oldDir [pwd]
    cd $setupDir/${gun}Data
    set fileList [lsort [glob -nocomplain Test-*.proc]]
    cd $oldDir

    set choice [APSChooseItemFromList -name ChooseFile \
                  -itemList $fileList -returnIndices 1 -multiItem 0]
    if $choice<0 return

    set fileName $setupDir/${gun}Data/[lindex $fileList $choice]
    exec sddsplot \
      -layout=1,2 -title=@TimeStamp \
      -same=x,global -graph=line,vary -factor=yMultiplier=-1 \
      -column=t,GunCM $fileName -end \
      -column=t,L1CM2 -filter=col,t2,-1e6,0 $fileName \
      -column=t,L1CM2 -filter=col,t1,-1e6,0  $fileName &
}

proc TestCapture {} {
    global nameList logFID unitsList logFileString setupDir status badOnesLeft formatList unitsList
    global gunHeaterPowerThreshold tmpRoot gun
    eval global $nameList

    APSLogScriptAction -procedure TestCapture -action "Testing L1:SCOPE1 capture" \
        -parameters "?" -state ok

    set gun [exec cavget -list=L1:RFG:RF:SW2:positionMI]
    APSDateBreakDown -dayVariable day -monthVariable month -julianDayVariable jday \
      -yearVariable year -twoDigitYear 0 -leadingZeros 0
    set fileName [APSNextGenerationedName -name \
                    $setupDir/${gun}Data/Test-[format %04d-%03d-%02d%02d $year $jday $month $day].0000 \
                    -newFile 1 -separator .]
    GetWaveforms -fileName $fileName -gun $gun
    if [catch {ProcessWaveforms -fileName $fileName -gun $gun \
                 -nameList $nameList } dataList] {
        setStatus "TestCapture: Problem acquiring data: $dataList"
        ClearValues
        bell
    } else {
        exec sddsplot \
          -layout=1,2 -title=@TimeStamp \
          -same=x,global -graph=line,vary -factor=yMultiplier=-1 \
          -column=t,GunCM $fileName.proc -end \
          -column=t,L1CM2 -filter=col,t2,-1e6,0 $fileName.proc \
          -column=t,L1CM2 -filter=col,t1,-1e6,0  $fileName.proc &
    }
}

set changeLogPID ""

proc RunLoop {args} {
    set limit 1
    APSStrictParseArguments {limit}

    APSLogScriptAction -procedure RunLoop -action "start" \
        -parameters "limit:$limit" -state ok

    global nameList logFID unitsList logFileString setupDir status badOnesLeft formatList unitsList pvList
    global gunHeaterPowerThreshold tmpRoot gun  changeLogPID runControlPV LeakageMax
    eval global $nameList
    global abortLoop

    catch {APSRunControlExit}
    after 2000
    if $limit {
        setStatus "Starting gun leakage limiter."
        set description "GunLeakageLimiter"
    } else {
        setStatus "Starting gun leakage monitor."
        set description "GunLeakageMonitor"
    }
    if {[catch {APSRunControlInit -pv $runControlPV -description $description \
                  -timeout 60000} result]} {
        setStatus "Unable to get runControl access: $result"
        # StopBeam
        return
    }

    set lastKickerState -1
    set badOnesLeft 3
    set abortLoop 0

    if [catch {exec cavget -list=L1:RFG:RF:SW2:positionMI} gun] {
        setStatus "RunLoop: Problem acquiring data: $dataList"
        APSLogScriptAction -procedure RunLoop -action "Error: $gun" \
          -parameters "?" -state ok
        ClearValues
        bell
    }

    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 RunLoop -action "Running leakage monitoring" \
        -parameters "?" -state ok
    
    while {!$abortLoop} {
        if {$limit && $badOnesLeft<=0} {
            setStatus "Too many problems.  Stopping beam."
            StopBeam
            set badOnesLeft 3
        }
        APSWaitWithUpdate -waitSeconds 1 -updateInterval 1
        
        if [catch {APSRunControlPing} result] {
            break
        }
        if [catch {GetWaveforms -fileName $tmpRoot.sdds -gun $gun} result] {
            setStatus "RunLoop: Problem acquiring data: $result (GetWaveforms)"
            ClearValues
            bell
            incr badOnesLeft -1
            continue
        }
        if [catch {ProcessWaveforms -fileName $tmpRoot.sdds -gun $gun \
                    -nameList $nameList } dataList] {
            setStatus "RunLoop: Problem acquiring data: $dataList"
            ClearValues
            bell
            incr badOnesLeft -1
            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 {$lastKickerState==-1 || $lastKickerState!=$KickerEnabled} {
            # if kick just changed state, retake data as it might be bad
            set lastKickerState $KickerEnabled
            ClearValues
            bell
            continue
        }
        
        if {$L1KlystronPower<2e6} {
            setStatus "L1 klystron power < 2 MW"
            bell
            SendToLogFile
            continue
        }
        if {$HeaterPower<$gunHeaterPowerThreshold($gun)} {
            setStatus "$gun heater power < $gunHeaterPowerThreshold($gun) W"
            bell
            SendToLogFile
            continue
        }
        
        if {$GunCMMax<0.05} {
            setStatus "Insufficient current seen from gun.  Scope problem?"
            SendToLogFile
            bell
            incr badOnesLeft -1
            continue
        } 
        if {$Leakage>$LeakageMax} {
            set LeakageMax $Leakage
        }
        if {$Leakage>3.0} {
            setStatus "Leakage is > 3%."
            bell
            bell
            bell
            SendToLogFile
            incr badOnesLeft -1
            continue
        }
        setStatus "All checks satisfied."
        SendToLogFile
    }
    setStatus "Aborted."
    catch {exec kill $changeLogPID}
    catch {APSRunControlExit}
    set changeLogPID ""
}


set status ""
APSScrolledStatus .status -parent .userFrame -textVariable status \
        -width 80 -withButtons 1 -height 20
.userFrame.status.frame.fg.top.text tag configure RED_FG -foreground red
.userFrame.status.frame.fg.top.text insert end "Note: Activities performed with this script are recorded\n" RED_FG
.userFrame.status.frame.fg.top.text insert end "and subject to audit.\n" RED_FG

set gunHeaterPowerThreshold(RG1) 21
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 nameList [list HeaterPower KickerEnabled \
                L1KlystronPower GunCMMax L1CM2Max GunCMInteg2 L1CM2Integ1 L1CM2Integ2 Leakage]
set pvList [list "" "" "" "" "" L1:RFG:VLD:GunCMInt2 L1:RFG:VLD:L1CM2Int1 L1:RFG:VLD:L1CM2Int2 L1:RFG:VLD:LeakageCC]

set unitsList [list W "binary" W mA mA mA*ns mA*ns mA*ns "%"]
set formatList [list %.5f %.0f %.3g %.4f %.4f %.4f %.4f %.4f %.4f]
foreach item $nameList units $unitsList {
    APSLabeledOutput .w$item -parent .userFrame \
      -label "$item ($units)" -textVariable $item -width 15
}

APSLabeledOutput .wLeakageMax -parent .userFrame \
      -label "LeakageMax (%)" -textVariable LeakageMax -width 15
APSButton .reset -parent .userFrame.wLeakageMax -text "Reset" \
    -command "set LeakageMax 0" -size small
set LeakageMax 0

proc AbortLoop {} {
    global abortLoop logFID changeLogPID
    setStatus "Stopping..."
    set abortLoop 1
    catch {close $logFID}
    set logFID ""
    catch {exec kill $changeLogPID}
    set changeLogPID ""
    APSLogScriptAction -procedure AbortLoop -action "Aborting leakage monitoring" \
        -parameters "?" -state ok
}

set abortLoop 0
APSFrame .bf1 -parent .userFrame -relief flat 
set w .userFrame.bf1.frame
set mainFrame $w
APSButton .config1 -parent $w -text "CONFIG1"  \
    -command "SetWidgets -mode config; ConfigureScope -configuration 1; SetWidgets -mode ready" \
    -contextHelp "Set the scope to configuration 1."
APSButton .config2 -parent $w -text "CONFIG2"  \
    -command "SetWidgets -mode config; ConfigureScope -configuration 2; SetWidgets -mode ready" \
    -contextHelp "Set the scope to configuration 2."
APSButton .test -parent $w -text "TEST"  \
    -command "SetWidgets -mode test; TestCapture; SetWidgets -mode ready" \
    -contextHelp "Acquire and display waveforms to verify operation."
APSButton .testreview -parent $w -text "TEST REVIEW" \
    -command "SetWidgets -mode test; ReviewTestCapture; SetWidgets -mode ready" \
    -contextHelp "Review waveforms captured with TEST button."
APSButton .run -parent $w -text "MONITOR"  \
    -command "SetWidgets -mode run; RunLoop -limit 0; SetWidgets -mode ready" \
    -contextHelp "Continuously acquire waveforms and compute leakage." 
APSButton .limit -parent $w -text "LIMIT"  \
    -command "SetWidgets -mode run; RunLoop -limit 1; SetWidgets -mode ready" \
    -contextHelp "Continuously acquire waveforms and compute leakage.  Take action to stop beam if leakage exceeds 3%." 
APSButton .stop -parent $w -text "STOP"  \
    -command AbortLoop \
    -contextHelp "Stop monitoring or limiting."
APSButton .rc -parent $w -text "INFO" -command \
    "exec medm -attach -x -macro RCPV=$runControlPV ./sr/psApp/APSRunControlSingle.adl" \
    -contextHelp "Launch MEDM screen for run control."
APSButton .enable -parent $w -text "ENABLE" \
    -command "SetWidgets -mode ready" \
    -contextHelp "Enable script buttons (use in event of errors)."

APSFrame .bf2 -parent .userFrame -relief flat
set w .userFrame.bf2.frame
APSButton .plot2 -parent $w -text "Plot Last 2 Minutes" \
    -command "PlotData -last 120" 
APSButton .plot10 -parent $w -text "Plot Last 10 Minutes" \
    -command "PlotData -last 600" 
APSButton .plot -parent $w -text "Plot All Data" \
    -command "PlotData" 

set gun [exec cavget -list=L1:RFG:RF:SW2:positionMI]
SetWidgets -mode ready

