#!/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

APSApplication . -name "IEXcheckOut" \
  -overview "Collects IEX perturbation data for each selected mode to check it working status."

proc SetStatus {text} {
    global status
    set status $text
    update
}

proc DPRTFBOnOff {args} {
    APSParseArguments {mode}

    global apshpFilterCutoffVert apshpFilterCutoffHoriz apshpFilterInitialVert apshpFilterInitialHoriz
    global apshpFilterRampPoints apshpFilterRampInterval
#    APSMpSetRTFBGlobalParameters -readonly 1

    if {$mode==1} {set mode On}
    if {$mode==0} {set mode Off}
    switch $mode {
        On {
            set xstatus [exec caget -t -n S:RC:OrbitControlLawXC.RUN]
            set ystatus [exec caget -t -n S:RC:OrbitControlLawYC.RUN]
            if {!$xstatus || !$ystatus} {
                if [catch {exec cavput -list=S:RC:OrbitControlLaw -list=X,Y \
                             -list=C.SUSP=0 \
                         } result ] {
                    return -code error "$result"
                }
            }
            SetStatus "Done DPRTFBOnOff mode=$mode"
        }
        Off {
            if [catch {exec cavput -list=S:RC:OrbitControlLaw -list=X,Y -list=C.SUSP=1} result ] {
                return -code error "$result"
            }
            SetStatus "Done DPRTFBOnOff mode=$mode"
        }
    }
    after 1000
    return
}

proc FindGoodBpms {args} {
    set plane ""
    APSParseArguments {plane}
    set Plane [string toupper $plane]
    set statusFile /home/helios/oagData/sr/BPMStatus/config.sdds
    if [catch {exec sddsprocess $statusFile -pipe=out \
                   -match=col,DeviceName=S??\[ABC\]:P\[0123456\] \
                   -filter=col,Nonexistent$Plane,0,0,OkForDCOrbitCorrection$Plane,1,1,& \
                   | sdds2stream -pipe -col=DeviceName \
               } goodBpms] {
        return -code error $goodBpms
    }
    return $goodBpms
}

proc IEXMakeMonitor {} {
    global IEX
    cd $IEX(outputDir)
    exec sddsmakedataset -pipe=out -col=BPMName,type=string \
        -data=[join [FindGoodBpms -plane H] ,] \
        | sddsprocess -pipe=in xBPM.mon \
        -edit=col,ControlName,BPMName,ei/:x:LowPass1sErrorM/ \
        -edit=col,ReadbackName,BPMName,ei/:x:LowPass1sErrorM/
    exec sddsmakedataset -pipe=out -col=BPMName,type=string \
        -data=[join [FindGoodBpms -plane V] ,] \
        | sddsprocess -pipe=in yBPM.mon \
        -edit=col,ControlName,BPMName,ei/:y:LowPass1sErrorM/ \
        -edit=col,ReadbackName,BPMName,ei/:y:LowPass1sErrorM/
    if [catch {exec sddscombine $IEX(moniDir)/ID-IEX.mon \
                   $IEX(moniDir)/IEX-rms.mon \
                   xBPM.mon yBPM.mon $IEX(monifile) -merge -over \
               } result ] {
        return -code error "MakeMonitorFile: $result"
    }
    SetStatus "Done make IEX monitor."
    return
}

proc IEXSetup {args} {
    global IEX
    APSParseArguments {condition}

    #1 Turn off IEX, setup quasi, then turn it on
    if {[exec cavget -list=S29ID:QuasiRatio]==100} {
        set currState Off
        set value 85
    } else {
        set currState On
        set value 100
    }
    SetStatus "Set IEX to Quasi $IEX(Quasi)"
    if {![string match $currState $IEX(Quasi)] } {
        if {![exec cavget -numerical -list=S29ID:Main_on_offC]} {
            exec caput -w 3 S29ID:Main_on_offC 1
        }
        after 2000
#        SetStatus " Turn off IEX PS"
        exec cawait -interval=1 -waitFor=S29ID:feedbackM,sameAs=Ready
        exec cawait -interval=1 -waitFor=S29ID:BusyRecordM,sameAs=Done
        exec caput S29ID:QuasiRatioInC $value
        after 2000
#        SetStatus " Set IEX Quasi"
        exec cawait -interval=1 -waitFor=S29ID:feedbackM,sameAs=Ready
        exec cawait -interval=1 -waitFor=S29ID:BusyRecordM,sameAs=Done
    }

    SetStatus "Turn on IEX"
    exec caput S29ID:Main_on_offC 0
    after 2000
    #2 Set IEX to desired mode
    if [string match $IEX(Mode) C] {
        set IEX(Emin) 0.4
        set IEX(mode0) 0
        set IEX(mode1) 1
    } 
    if [string match $IEX(Mode) V] {
        set IEX(Emin) 0.44
        set IEX(mode0) 2
        set IEX(mode1) 2
    }
    if [string match $IEX(Mode) H] {
        set IEX(Emin) 0.25
        set IEX(mode0) 3
        set IEX(mode1) 4
    }
    SetStatus "Set IEX to desired mode"
    exec caput -w 3 S29ID:DesiredModeC $IEX(mode0)
    after 2000
    exec cawait -interval=1 -waitFor=S29ID:feedbackM,sameAs=Ready
    exec cawait -interval=1 -waitFor=S29ID:BusyRecordM,sameAs=Done

    #3 Set IEX to the desired beamline and quasi status
    SetStatus "Set IEX to desired beamline"
    switch $IEX(Beamline) {
        US {
            exec caput -w 3 S29ID:BeamlineC 0
        }
        DS {
            exec caput -w 3 S29ID:BeamlineC 1
        }
    }
       
    exec cavput -list=S29ID:BxStepLimitC=5,S29ID:ByStepLimitC=5
    IEXCondition -cycles $condition
    exec cavput -list=S29ID:BxStepLimitC=2,S29ID:ByStepLimitC=2
    return
}

proc WaitRampDone {} {
    set timeout 180
    set index 0
    while (1) {
        after 3000
        update
        if ([string match "*Done*" [exec cavget -list=S29ID:BusyRecordM]]) break
        incr index
        if {$index>$timeout} {
            return -code error "Something is wrong, aborted"
        }
    }
    return
}

proc IEXCondition {args} {
    global IEX
    APSParseArguments {cycles}

    SetStatus "Start IEX condition..."
    for {set i 0} {$i < $cycles} {incr i} {
        exec caput S29ID:EnergySetC $IEX(Emin)
        after 1000
        exec caput -w 3 S29ID:StartRampC 0
        exec caput -w 3 S29ID:StartRampC 1
        after 3000
        WaitRampDone
        exec caput S29ID:EnergySetC 2.735
        after 1000
        exec caput -w 3 S29ID:StartRampC 0
        exec caput -w 3 S29ID:StartRampC 1
        after 3000
        WaitRampDone
        if {![string match $IEX(Mode) V]} {
            exec caput -w 3 S29ID:DesiredModeC $IEX(mode1)
            after 2000
            exec cawait -interval=1 -waitFor=S29ID:feedbackM,sameAs=Ready
            exec cawait -interval=1 -waitFor=S29ID:BusyRecordM,sameAs=Done
            exec caput S29ID:EnergySetC $IEX(Emin)
            after 1000
            exec caput -w 3 S29ID:StartRampC 0
            exec caput -w 3 S29ID:StartRampC 1
            after 3000
            WaitRampDone
            # max energy at 6 GeV
            exec caput S29ID:EnergySetC 2.735
            after 1000
            exec caput -w 3 S29ID:StartRampC 0
            exec caput -w 3 S29ID:StartRampC 1
            after 3000
            WaitRampDone
            exec caput -w 3 S29ID:DesiredModeC $IEX(mode0)
            after 2000
            exec cawait -interval=1 -waitFor=S29ID:feedbackM,sameAs=Ready
            exec cawait -interval=1 -waitFor=S29ID:BusyRecordM,sameAs=Done            
        } else {
            # max energy at 6 GeV
            exec caput S29ID:EnergySetC 2.735
            after 1000
            exec caput -w 3 S29ID:StartRampC 0
            exec caput -w 3 S29ID:StartRampC 1
            after 3000
            WaitRampDone
        }
    } 
    SetStatus "Finish IEX condition."
    return
}

proc CollectData {args} {
    APSParseArguments {comment abortVar}
    global $abortVar IEX
    set dir [pwd]

#    set frame0 [lindex [exec caget S:VID1:numToAvgC] 1]
#    exec caput -w 3 S:VID1:numToAvg 30
    exec caput S29ID:AbortUtility_ 0

    cd $IEX(outputDir)
    if ![file exist $IEX(monifile)] {
        IEXMakeMonitor
    }

    set quasiList "$IEX(Quasi,Off) $IEX(Quasi,On)"
    set quasiStatusList "Off On"
    # IEX(Quasi) is unexpectedly a variable and not constants like the other array elements.
    foreach quasiV $quasiList IEX(Quasi) $quasiStatusList {
        if {!$quasiV} continue

        set modeList "$IEX(Mode,C) $IEX(Mode,V) $IEX(Mode,H)"
        set modeNameList "C V H"
        # IEX(Mode) is unexpectedly a variable and not constants like the other array elements.
        foreach modeV $modeList IEX(Mode) $modeNameList {
            if {!$modeV} continue

            # Step 0: Turn on DP/RTFB
            if [catch {DPRTFBOnOff -mode On} result] {
                return -code error "$result"
            }

            # Step 1: Condition IEX 2 cycles
            if [catch {IEXSetup -condition 2} result] {
                return -code error "$result"
            }

            # Step 2: Make measurement with DP/RTFB On
            set root $IEX(Mode)-$IEX(Beamline)-$IEX(Quasi)-DPOn
            SetStatus "Start taking data $root ..."
            if [catch {takeData -root $root -abortVar abortRun} result] {
                return -code error "$result"
            }
            SetStatus "Done taking data $root."

            # Step 3: Make measurement with DP/RTFB Off
            if [catch {DPRTFBOnOff -mode Off} result] {
                return -code error "$result"
            }
            set root $IEX(Mode)-$IEX(Beamline)-$IEX(Quasi)-DPOff
            SetStatus "Start taking data $root ..."
            if [catch {takeData -root $root -abortVar abortRun} result] {
                return -code error "$result"
            }
            SetStatus "Done taking data $root."
        }        
    }

    # Return to normal status
#    exec caput -w 3 S:VID1:numToAvgC $frame0
    if [catch {DPRTFBOnOff -mode On} result] {
        return -code error "$result"
    }
    if {![exec cavget -numerical -list=S29ID:Main_on_offC]} {
        exec caput -w 3 S29ID:Main_on_offC 1
    }
    exec cawait -interval=1 -waitFor=S29ID:feedbackM,sameAs=Ready
    exec cawait -interval=1 -waitFor=S29ID:BusyRecordM,sameAs=Done
    exec cavput -list=S29ID:BxStepLimitC=2,S29ID:ByStepLimitC=2
    exec caput S29ID:QuasiRatioInC 100
    cd $dir
    return
}

proc takeData {args} {
    APSParseArguments {root abortVar}
    global $abortVar IEX comment
    set waitSecond [expr 15*1000]

    exec cavput -list=S29ID:BxStepLimitC=2,S29ID:ByStepLimitC=2

    #1 Start measurement
    SetStatus "Launching sddsmonitor..."
    set description $root$comment
    if [catch {set pid [exec sddsmonitor $IEX(monifile) $root -daily \
                            -step=1200 -interval=1 \
                            "-comment=Comment,[APSMakeSafeQualifierString $description]" &] \
               } result ] {
        SetStatus $result
        return
    }
    SetStatus "sddsmonitor launched..."
    after $waitSecond

    #2 Ramp IEX Up to maximum value
    if {![set $abortVar] && ![lindex [exec caget -n S29ID:AbortUtility_] 1]} {
        SetStatus "IEX-Check: Step 1 - Ramp to maximum"
        exec caput S29ID:EnergySetC $IEX(Emin)
        after 1000
        exec caput -w 3 S29ID:StartRampC 0
        exec caput -w 3 S29ID:StartRampC 1
        after 3000
        WaitRampDone
    }
    after $waitSecond

    #3 Ramp IEX Down to zero
    if {![set $abortVar] && ![lindex [exec caget -n S29ID:AbortUtility_] 1]} {
        SetStatus "IEX-Check: Step 2 - Ramp to zero"
        exec caput S29ID:EnergySetC 2.735
        after 1000
        exec caput -w 3 S29ID:StartRampC 0
        exec caput -w 3 S29ID:StartRampC 1
        after 3000
        WaitRampDone
    }

    #4 For C and H modes

    if {![string match $IEX(Mode) V]} {
        exec caput -w 3 S29ID:DesiredModeC $IEX(mode1)
        after 2000
        exec cawait -interval=1 -waitFor=S29ID:feedbackM,sameAs=Ready
        exec cawait -interval=1 -waitFor=S29ID:BusyRecordM,sameAs=Done
        after $waitSecond
        if {![set $abortVar] && ![lindex [exec caget -n S29ID:AbortUtility_] 1]} {
            SetStatus "IEX-Check: Step 3 - Ramp to negative"
            exec caput S29ID:EnergySetC $IEX(Emin)
            after 1000
            exec caput -w 3 S29ID:StartRampC 0
            exec caput -w 3 S29ID:StartRampC 1
            after 3000
            WaitRampDone
        }
        after $waitSecond
        if {![set $abortVar] && ![lindex [exec caget -n S29ID:AbortUtility_] 1]} {
            SetStatus "IEX-Check: Step 4 - Ramp to zero"
            exec caput S29ID:EnergySetC 2.735
            after 1000
            exec caput -w 3 S29ID:StartRampC 0
            exec caput -w 3 S29ID:StartRampC 1
            after 3000
            WaitRampDone
        }
        exec caput -w 3 S29ID:DesiredModeC $IEX(mode0)
        after 2000
        exec cawait -interval=1 -waitFor=S29ID:feedbackM,sameAs=Ready
        exec cawait -interval=1 -waitFor=S29ID:BusyRecordM,sameAs=Done
    } else {
        exec caput S29ID:EnergySetC 2.735
        after 1000
        exec caput -w 3 S29ID:StartRampC 0
        exec caput -w 3 S29ID:StartRampC 1
        after 3000
        WaitRampDone
    }

    after $waitSecond
    SetStatus "Killing sddsmonitor..."
    if [catch {exec kill -KILL $pid} result] {
        SetStatus $result
    }
    SetStatus "Done collecting data $root"
    return
}

proc plotData {} {
    global Year Date IEX
    set dir [pwd]
    cd $IEX(outputDir)
    set fileList [lsort [glob -nocomplain *-$Year-???-$Date.????]]
    set dataList [APSChooseItemFromList \
                     -name "Data Set Selection" \
                     -itemList $fileList \
                     -returnList $fileList \
                     -returnIndices 0 \
                     -multiItem 1 \
                     -contextHelp "Select a file for plotting."]

    foreach file $dataList {
        APSSetVarAndUpdate status "Processing $file..."
        if ([string match "*DPOff*" $file]) {
            set options "-layout=1,2 -tick=xtime"
            exec sddsprocess $file -pipe=out \
              -process=S*:?:LowPass1sErrorM,first,%sFirst \
              -process=S*:?:LowPass1sErrorM,standarddeviation,%sStdDev \
              "-redef=col,%s,%s %sFirst -,sel=S*:?:LowPass1sErrorM" \
              | sddsrowstats -pipe=in \
              $file.rowstats \
              -standardDeviation=XOrbitRMS,S*:x:LowPass1sErrorM \
              -standardDeviation=YOrbitRMS,S*:y:LowPass1sErrorM 
            lappend options -col=Time,?OrbitRMS $file.rowstats \
              -topline=@Comment -file -factor=ymult=1e3 \
              {-ylabel=RMS Orbit (um)} -grap=line,vary -leg
            lappend options -col=Time,S29ID:?coilRdbk \
              $file.rowstats -topline=@Comment -file -ylabel=edit=ei/(A)/ \
              -grap=line,type=2 -yscale=id=2 -end
            lappend options -col=Time,*30HzBW $file \
              -topline=@Comment -file  {-ylabel=30 Hz (um)} -grap=line,vary -leg
            lappend options -col=Time,S29ID:?coilRdbk \
              $file -topline=@Comment -file -ylabel=edit=ei/(A)/ \
              -grap=line,type=2 -yscale=id=2 -end
            lappend options -col=Time,*VarBW $file \
              -topline=@Comment -file  {-ylabel=100 Hz (um)} -grap=line,vary -leg
            lappend options -col=Time,S29ID:?coilRdbk \
              $file -topline=@Comment -file -ylabel=edit=ei/(A)/ \
              -grap=line,type=2 -yscale=id=2 -end
            lappend options -col=Time,*FullBW $file \
              -topline=@Comment -file {-ylabel=Full Hz (um)} -grap=line,vary -leg
            lappend options -col=Time,S29ID:?coilRdbk \
              $file -topline=@Comment -file -ylabel=edit=ei/(A)/ \
              -grap=line,type=2 -yscale=id=2 -end
        }
        if ([string match "*DPOn*" $file]) {
            set options "-tick=xtime"
            lappend options -col=Time,Coupling $file -topline=@Comment -file \
              -grap=line,vary -leg -yscale=id=coup
            lappend options -col=Time,S29ID:?coilRdbk \
              $file -topline=@Comment -file -file -ylabel=edit=ei/(A)/ \
              -grap=line,type=2 -yscale=id=2 -end
        }
        if [catch {eval exec sddsplot \
                     $options & \
                 } result] {
            APSSetVarAndUpdate status "PlotData: $result"
            return
        }
    }

    APSSetVarAndUpdate status "Done."
    cd $dir
    return
}

set abortRun 0
set IEX(moniDir) /home/helios/oagData/sr/IDs/IEX/Monitor/
set IEX(outputDir) /home/helios/oagData/sr/IDs/IEX/Measurement
set IEX(monifile) IEX.mon

set IEX(Mode) ""
set IEX(Mode,C) 1
set IEX(Mode,V) 1
set IEX(Mode,H) 1
set IEX(Beamline) US
set IEX(Quasi) ""
set IEX(Quasi,Off) 1
set IEX(Quasi,On) 1
set IEX(Emin) 0.4
set IEX(mode0) 0
set IEX(mode1) 1
set systemTime [clock seconds]
set Year [clock format $systemTime -format %Y]
set Date [clock format $systemTime -format %m%d]
set comment ""

set status "Working..."
APSScrolledStatus .status -parent .userFrame -textVariable status -packOption "-expand yes -fill both"

APSLabeledEntry .outputDir -parent .userFrame \
  -label "Output directory:" -textVariable IEX(outputDir) \
  -contextHelp "Enter a name for the output file directory." -width 50
APSLabeledEntry .comment -parent .userFrame -label "Comment: " -textVariable comment \
  -width 55 \
  -contextHelp "Enter a comment to be written as a parameter to the output file."

APSCheckButtonFrame .mode -parent .userFrame -orientation horizontal \
  -label "IEX mode for measuring: " -contextHelp "Choose IEX mode for measurement." \
  -variableList {IEX(Mode,C) IEX(Mode,V) IEX(Mode,H)}  \
  -buttonList {C V H} 
APSCheckButtonFrame .quasi -parent .userFrame -orientation horizontal \
  -label "IEX Quasi On/Off: " -contextHelp "Choose IEX Quasi mode for measurement." \
  -variableList {IEX(Quasi,Off) IEX(Quasi,On)}  \
  -buttonList {Off On} 
APSLabeledEntry .year -parent .userFrame -label "Measurement Year\[yyyy\]: " -textVariable Year \
  -width 55 \
  -contextHelp "Enter the measurement year."
APSLabeledEntry .date -parent .userFrame -label "Measurement Date\[mmdd\]: " -textVariable Date \
  -width 55 \
  -contextHelp "Enter the measurement date."

APSButton .run -parent .userFrame -text Collect -command \
  { \
      APSDisableButton .userFrame.run.button 
      APSEnableButton .userFrame.stop.button
      catch {exec StripTool /home/helios/oagData/sr/IDs/IEX/stripPlot.mon &}
      catch {CollectData -comment $comment \
               -abortVar abortRun} status
      catch {exec play -q -v 3 /usr/local/oag/sounds/game_over.au}
      exec caput -w 3 S29ID:Main_on_offC 1
      update idletasks
      APSDisableButton .userFrame.stop.button
      APSEnableButton .userFrame.run.button
      SetStatus "Done with all checkout $abortRun"
  } \
  -contextHelp "Collects IEX perturbation data. Uses monitor file /home/helios/oagData/sr/IDs/IEX/IEX+orbit.mon"
APSButton .stop -parent .userFrame -text Abort -command \
  { set abortRun 1} \
  -contextHelp "Aborts run."

APSButton .plot -parent .userFrame -text Plot -command \
  { \
      catch {plotData} status
  } \
  -contextHelp "Plot Measurement Result"

set status "Ready."
update
APSInfoWindow .info -width 60 -name "IEX Checkout Procedure" -infoMessage "This window can be left open!!!\n\nStep 1: Inject many bunches for long lifetime into SR.\nStep 2: Run orbit correction in both plane.\nStep3: Hit the run button;\n       Watch the pop-up stripTools for IEX PS moving;\n       The program should do all the left for you, enjoy!\n\nIn case program aborted - Turn off IEX power supply." -modal 0
# Local Variables:
# mode: tcl
# indent-tabs-mode: nil
# End:
