#!/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)]
set CVSRevisionAuthor "\$Revision: 2.0 $ \$Author: borland $"

APSApplication . -name "SRInjectionEnergy" -version $CVSRevisionAuthor \
  -overview "Provides a slider for moving the Booster beam energy and the BTS transfer line energy. Pulsed magnets are varied too."

set status Ready.
APSScrolledStatus .status -parent .userFrame -textVariable status \
  -width 50

proc MakeFrequencySlider {widget args} {
    APSStrictParseArguments {parent label}

    APSFrame $widget -parent $parent -label $label 
    set w $parent$widget.frame
    APSButton .down -parent $w -text "<-" -command "MoveFrequency -delta -1" \
      -contextHelp "Moves the frequency down by the increment." -fastClick 1
    APSButton .zero -parent $w -text "0" -command "MoveFrequency -zero 1 " \
      -contextHelp "Zero the frequency changes." -fastClick 1
    APSButton .up -parent $w -text "->" -command "MoveFrequency -delta 1" \
      -contextHelp "Moves the frequency up by the increment." -fastClick 1

    APSLabeledOutput .frequency -parent $w -label $label \
      -textVariable FrequencyOffset -width 16 \
      -contextHelp "Shows the relative frequency offset."
    APSLabeledEntry .incr -parent $w -label "Frequency step (Hz): " \
      -textVariable FrequencyIncrement -width 16 \
      -contextHelp "Sets the frequency step for each button press."
}

proc MakeEnergySlider {widget args} {
    APSStrictParseArguments {parent label}

    APSFrame $widget -parent $parent -label $label 
    set w $parent$widget.frame
    
    APSButton .down -parent $w -text "<-" -command "MoveEnergy -delta -1" \
      -contextHelp "Moves the energy down by the increment." -fastClick 1
    APSButton .zero -parent $w -text "0" -command "MoveEnergy -zero 1 " \
      -contextHelp "Zero the energy changes." -fastClick 1
    APSButton .up -parent $w -text "->" -command "MoveEnergy -delta 1" \
      -contextHelp "Moves the energy up by the increment." -fastClick 1

    APSLabeledOutput .energy -parent $w -label $label \
      -textVariable EnergyOffset -width 16 \
      -contextHelp "Shows the relative energy increment so far."
    APSLabeledEntry .incr -parent $w -label "Energy step (%): " \
      -textVariable EnergyIncrement -width 16 \
      -contextHelp "Sets the energy step for each button press."
    APSCheckButtonFrame .cb1 -parent $w -label "Include: " \
        -orientation horizontal \
        -buttonList "BRamp BPulsed BTSQ BTSB SPulsed" \
        -variableList {include(BRamp) include(BPulsed) include(BTSQ) include(BTSB) include(SPulsed)}
    global include
    foreach item [array names include] {
        set include($item) 1
    }
}

proc MakeMonitorFileWidget {widget args} {
    
    APSStrictParseArguments {parent label}

    APSFrame $widget -parent $parent -label "Monitor File"
    set w $parent$widget.frame
    APSLabeledEntry .dir -parent $w -label "Directory : " \
      -textVariable monitorDir -width 40 \
      -contextHelp "Sets the energy step for each button press."
    APSLabeledEntry .file -parent $w -label "File: " \
      -textVariable monitorFile -width 40 \
      -contextHelp "Sets the energy step for each button press."
    APSButton .gen -parent $w -text "Generate monitor file" \
      -command {MakeMonitorFile \
                  -monitorDir $monitorDir -monitorFile $monitorFile} \
      -contextHelp "Make monitor file from SRInjection monitor file and energy delta file." -fastClick 1

}

proc MakeReferenceWidget {widget args} {
    APSStrictParseArguments {parent label}
    global referenceDesc
    set referenceDesc "Save Present State as 0% state"
    APSFrame $widget -parent $parent -label "Save Reference"
    set w $parent$widget.frame
    APSLabeledEntry .desc -parent $w -label "Description:" -width 50 -textVariable referenceDesc
    APSButton .save -parent $w -text "Save Present State as 0% state" -command SaveReference
    APSButton .enery -parent $w -text "Make New Energy Delta File" -command MakeEnergyDeltaFile
}

proc SaveReference {args} {
    global referenceDesc status SRFile BoosterFile BoosterDipoleFile SCRdir
    if ![string length $referenceDesc] {
	set status "Please provide description!"
	return
    }
    set status "Doing SCR save for booster and SR..."
    update
    if [catch {APSSaveMachine -machine SR -description "$referenceDesc" } result1] {
	return -code error "Error doing SR SCR save: $result1"
    }
    set SRFile $SCRdir/SR/[lindex $result1 0]
    if [catch {APSSaveMachine -machine Booster -description "$referenceDesc" } result2] {
	return -code error "Error doing booster SCR save: $result2"
    }
    set BoosterFile $SCRdir/Booster/[lindex $result2 0]
    set BoosterDipoleFile $SCRdir/Booster/[lindex $result2 0]
    set status "reference saved."
    
    update
}

proc MoveEnergy {args} {
    set delta 0
    set zero 0
    if {[APSStrictParseArguments {delta zero}] || \
            ([expr $delta==0] && [expr $zero==0]) || \
            ([expr $delta!=0] && [expr $zero!=0])} {
        return -code error "MoveEnergy: invalid calling syntax."
    }

    global EnergyDeltaFile EnergyIncrement EnergyOffset include
    set matchOpt ""
    foreach item [array names include] {
        if $include($item) {
            if ![string length $matchOpt] {
                set matchOpt -match=col,Group=$item
            } else {
                append matchOpt ,Group=$item,|
            }
        }
    }
    #APSSetVarAndUpdate status "$matchOpt"
    if ![string length $matchOpt] {
        return -code error "Nothing selected for energy scaling"
    }
    
    if !$zero {
        # delta mode
        set EnergyOffset [expr $EnergyOffset + $delta * $EnergyIncrement]
        #puts stderr "EnergyOffset: $EnergyOffset   delta: $delta"
        if [catch {exec sddsprocess $matchOpt $EnergyDeltaFile -pipe=out \
                       "-redefine=col,Value,Value $EnergyOffset 100 / Coefficient * +" \
                       -reprint=col,ValueString,%le,Value \
                       | sddscasr -pipe=in -restore} result] {
            return -code error $result
        }
    } else {
        # zero mode
        APSSetVarAndUpdate status "Zero mode is disabled since it messes up IETS"
        return
        if [catch {exec sddsprocess $matchOpt $EnergyDeltaFile -pipe=out \
                     | sddscasr -pipe=in -restore } result] {
            return -code error $result
        }
        set EnergyOffset 0.0
    }
    return
}

proc MoveFrequency {args} {
    set delta 0
    set zero 0
    if {[APSStrictParseArguments {delta zero}] || \
            ([expr $delta==0] && [expr $zero==0]) || \
            ([expr $delta!=0] && [expr $zero!=0])} {
        return -code error "MoveFrequency: invalid calling syntax."
    }

    global FrequencyIncrement FrequencyOffset FrequencyOffset0
    if !$zero {
        # delta mode
        set FrequencyOffset [expr $FrequencyOffset + $delta * $FrequencyIncrement]
    } else {
        # zero mode
        set FrequencyOffset [expr $FrequencyOffset0]
    }
    if [pv putw FrequencyOffset] {
        return -code error "MoveFrequency: pv putw error"
    }
    return
}

set SCRdir /home/helios/oagData/SCR/snapshots/
set SRFile  $SCRdir/SR/SR-UserBeamPreferred.gz
set BoosterFile $SCRdir/Booster/Booster-UserBeamPreferred1Hz.gz
set BoosterDipoleFile $SCRdir/Booster/Booster-UserBeamPreferred1Hz.gz
proc MakeEnergyDeltaFile {} {
    global EnergyDeltaFile SRFile BoosterFile BoosterDipoleFile status

    set dataDir /home/helios/oagData/SCR/snapshots/
   # set SRFile $dataDir/SR/SR-UserBeamPreferred.gz
   # set BoosterFile $dataDir/Booster/Booster-UserBeamPreferred1Hz.gz
   # set BoosterDipoleFile $dataDir/Booster/Booster-UserBeamPreferred1Hz.gz

    set tmpRoot /tmp/[APSTmpString]
    if [regexp {UserBeamPrefer} $SRFile] {
	set status "Creating temporary energy delta file from SR and Booster UBOPs."
    } else {
	set status "Creating temporary energy delta file from present state."
    }
    update
    APSAddToTmpFileList -ID MakeEnergyDeltaFile \
        -fileList "$tmpRoot.SrPulsed $tmpRoot.BPulsed $tmpRoot.BTSQ $tmpRoot.BTSB $tmpRoot.BTSB $tmpRoot.BRamp"

    # match SR pulsed supplies
    if [catch {exec sddscombine $SRFile $BoosterFile -pipe=out -merge \
                   | sddsprocess -pipe \
                   -match=col,ControlName=S39-IES:*:VoltageC,ControlName=S39-IES:IS1:SetVoltageC,| \
                   -scan=col,Value,ValueString,%lf -print=col,Group,SPulsed \
                   = Assume linear, unsaturated response = \
                   "-define=col,Coefficient,Value" \
                   | sddssort -pipe -column=ControlName -unique \
                   | sddsconvert -pipe=in $tmpRoot.SrPulsed -retain=col,ControlName,Value,ValueString,Coefficient,Group} result] {
        return -code error "MakeEnergyDeltaFile (1): $result"
    }
    
    # match Booster pulsed supplies 
    if [catch {exec sddsprocess $BoosterFile -pipe=out \
                   -match=col,ControlName=B:ES?:VoltageSetSendAO,ControlName=B:EK:VoltageSetSendAO,| \
                   -scan=col,Value,ValueString,%lf -print=col,Group,BPulsed \
                   = Assume linear, unsaturated response = \
                   "-define=col,Coefficient,Value" \
                   | sddsconvert -pipe=in $tmpRoot.BPulsed -retain=col,ControlName,Value,ValueString,Coefficient,Group} result] {
        return -code error "MakeEnergyDeltaFile (2): $result"
    }

    # match BTS quadrupoles and dipoles
    # Use excitation curves to get coefficients
    if [catch {exec sddsprocess $BoosterFile -pipe=out \
                 -match=col,ControlName=BTS:*Q?:PS:SetCurrentC,ControlName=BTS:?B*:PS:SetCurrentC,|,ControlName=BTS:AB:CurrentAO,| \
                 | sdds2stream -pipe -column=ControlName} controlList] {
        return -code error "MakeEnergyDeltaFile (3): $controlList"
    }
    if [catch {exec sddsprocess $BoosterFile -pipe=out \
                   -match=col,ControlName=BTS:*Q?:PS:SetCurrentC,ControlName=BTS:?B*:PS:SetCurrentC,|,ControlName=BTS:AB:CurrentAO,| \
                   -edit=col,ElementName,ControlName,%/:PS:SetCurrentC//%/:CurrentAO// \
                   | sdds2stream -pipe -column=ElementName} elementList] {
        return -code error "MakeEnergyDeltaFile (3): $elementList"
    }
    if [catch {exec sddsprocess $BoosterFile -pipe=out \
                   -match=col,ControlName=BTS:*Q?:PS:SetCurrentC,ControlName=BTS:?B*:PS:SetCurrentC,|,ControlName=BTS:AB:CurrentAO,| \
                   | sdds2stream -pipe -column=ValueString} valueList] {
        return -code error "MakeEnergyDeltaFile (3.1): $valueList"
    }
    set coefList ""
    set groupList ""
    foreach element $elementList value $valueList control $controlList {
        if [string match BTS:?B* $element] {
            set BnLName B0L
            lappend groupList BTSB
        } else {
            set BnLName B1L
            lappend groupList BTSQ
        }
        if ![file exists [set excitFile /home/helios/oagData/bts/magnets/$element.excit]] {
            APSSetVarAndUpdate status "not found: $excitFile"
            return -code error "not found: $excitFile"
        }
        if [catch {exec sddsinterp $excitFile -pipe=out -column=Current,$BnLName -atValue=$value \
                       | sdds2stream -pipe -column=$BnLName} BnL] {
            APSSetVarAndUpdate status "Error: $BnL"
            return -code error "Error: $BnL"
        }
        if [catch {exec sddsderiv $excitFile -pipe=out -differ=$BnLName -versus=Current \
                       | sddsinterp -pipe -column=Current,${BnLName}Deriv -atValue=$value \
                       | sdds2stream -pipe -column=${BnLName}Deriv} dBnLdI] {
            APSSetVarAndUpdate status "Error: $dBnLdI"
            return -code error "Error: $dBnLdI"
        }
        lappend coefList [expr $BnL/$dBnLdI]
    }
    if [catch {exec sddsmakedataset $tmpRoot.BQ \
                 -column=ElementName,type=string -data=[join $elementList ,] \
                 -column=ControlName,type=string -data=[join $controlList ,] \
                 -column=Value,type=double -data=[join $valueList ,] \
                 -column=Coefficient,type=double -data=[join $coefList ,] \
                 -column=Group,type=string -data=[join $groupList ,]} result] {
           APSSetVarAndUpdate status "$result"
        return -code error "$result"
    }
    
    # energy per turn is 36.43 keV / booster turn or 109.292 keV / sr turn.
    set BoosterAcceleration 0.109292
    set SRenergy 6000
    # The value for the booster ramp turns is the number of
    # turns that give 100% in energy for the file created here.
    exec sddsprocess $BoosterFile -pipe=out -match=col,ControlName=Mt:BoosterRampTurnsAO \
         = Assume linear, unsaturated response = \
         -scan=col,Value,ValueString,%le \
        -define=col,Coefficient,[expr int($SRenergy / $BoosterAcceleration)] -print=col,Group,BRamp \
        | sddsconvert -pipe=in $tmpRoot.BRamp -retain=col,ControlName,Value,ValueString,Coefficient,Group

    exec sddscombine $tmpRoot.SrPulsed $tmpRoot.BPulsed $tmpRoot.BQ $tmpRoot.BRamp -merge -pipe=out \
         | sddsprocess -pipe=in $tmpRoot.all -reprint=col,ValueString,%21.15e,Value 
    APSDeleteTmpFileList -ID MakeEnergyDeltaFile  

    # Not deleted until application exits
    APSAddToTempFileList $tmpRoot.all

    puts stderr [exec sddsprintout -column=ControlName -column=ValueString $tmpRoot.all]
    set EnergyDeltaFile $tmpRoot.all
    puts stderr $EnergyDeltaFile
    set status "done."
    update
    return
}

proc MakeMonitorFile {args} {
    global EnergyDeltaFile
    set monitorDir .
    set monitorFile ""
    APSParseArguments {monitorDir monitorFile}
    set outfile $monitorDir/$monitorFile
    if ![string length $outfile] {
        return -code error "MakeMonitorFile: no monitorFile specified"
    }
    set origMonFile /home/helios/oagData/monitoring/SRInjection/SRInjection.mon
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddsprocess $origMonFile $tmpRoot -match=col,ControlName=*Rate,!} result] {
        return -code error "MakeMonitorFile: $result"
    }
    if [catch {exec sddscombine $tmpRoot $EnergyDeltaFile -pipe=out -merge \
                   | sddssort -pipe=in $outfile -col=ControlName -unique} result] {
        return -code error "MakeMonitorFile: $result"
    }
    # fix blank readback column
    if [catch {exec sddsprocess $outfile $tmpRoot.1 -match=col,ReadbackName= -reprint=col,ReadbackName,%s,ControlName
        exec sddsprocess $outfile $tmpRoot.2 -match=col,ReadbackName=,!
        exec sddscombine $tmpRoot.1 $tmpRoot.2 $outfile -merge -overwrite } result] {
        return -code error "MakeMonitorFile: $result"
    }
    APSSetVarAndUpdate status "Done."
    return
}

set EnergyOffset 0
set EnergyIncrement 0.025
MakeEnergySlider .slider -parent .userFrame -label "Relative Energy (%)"

#set status "Creating temporary energy delta file from SR and Booster UBOPs."
#update

set monitorDir .
set monitorFile SRInjection.mon
MakeMonitorFileWidget .monitor -parent .userFrame
MakeReferenceWidget .ref -parent .userFrame
update

if {[pv linkw FrequencyOffset A014-IETS:BTC:SROffsetFreqC] || [pv getw FrequencyOffset]} {
    APSSetVarAndUpdate status "$result"
} else {
    APSSetVarAndUpdate status "Present SR rf frequency: $FrequencyOffset Hz"
}
set FrequencyOffset0 $FrequencyOffset
set FrequencyIncrement 10.0
MakeFrequencySlider .fslider -parent .userFrame -label "Frequency offset (Hz)"


if [catch {MakeEnergyDeltaFile} result] {
    set status $result
}

# lists of PVs and corresponding tcl variables
set pvList {S6:WGS:modeSelect SRF:K1:PS1:Ch0 SRF:K2:PS1:Ch0 \
              SRF:K3:PS1:Ch0 SRF:K4:PS1:Ch0 BRF:S:PS1:Ch0_1AO}
set varList {WGSMode S1phase S2phase S3phase S4phase rfSBPhase}


if {[pv linkw $varList $pvList] || \
      [pv umon WGSMode ProcessWGSModeChange] || \
      [pv umon S1phase ProcessPhaseChange] || \
      [pv umon S2phase ProcessPhaseChange] || \
      [pv umon S3phase ProcessPhaseChange] || \
      [pv umon S4phase ProcessPhaseChange] || \
      [pv umon rfSBPhase ProcessPhaseChange] } {
    global errorCode
    APSAlertBox [APSUniqueName .] \
      -errorMessage "Unable to connect to $pvList: $errorCode"
    exit 1
}

proc ProcessPhaseChange {} {
    global varList
    eval global $varList rf3637Station rf40Station
    global rf3637Phase rf40Phase rfSBPhase
    foreach var $varList {
        set $var [subst \$$var]
    }
    set rf3637Phase [subst \$S${rf3637Station}phase]
    set rf40Phase [subst \$S${rf40Station}phase]
}

set LastWGSMode ""
proc ProcessWGSModeChange {} {
    global varList LastWGSMode status rf3637Station rf40Station
    eval global $varList
    set WGSMode $WGSMode
    if [string compare $LastWGSMode $WGSMode] {
        set LastWGSMode $WGSMode
        switch $WGSMode {
            "Mode 7" -
            "Mode 11" {
                set rf3637Station 2
                set rf40Station 4
                set status "Using K2 for 36/37 and K4 for 40"
            }
            "Mode 1" -
            "Mode 8" -
            "Mode 9" {
                set rf3637Station 2
                set rf40Station 1
                set status "Using K2 for 36/37 and K1 for 40"
            }
            "Mode 10" {
                set rf3637Station 3
                set rf40Station 4
                set status "Using K3 for 36/37 and K4 for 40"
            }
            "Mode 12" {
                set rf3637Station 3
                set rf40Station 1
                set status "Using K3 for 36/37 and K1 for 40"
            }
            default {
                APSAlertBox [APSUniqueName .] -errorMessage \
                  "Unknown rf mode: $WGSMode" 
                exit 1
            }
        }
    }
    ProcessPhaseChange
}

proc MovePhase {dir cavities} {
    global highLimits lowLimits
    if [lsearch -exact [list 3637 40] $cavities]!=-1 {
        global rf${cavities}Station varList rf${cavities}Increment
        eval global $varList
        set var S[subst \$rf${cavities}Station]phase
        set phase [subst \$S[subst \$rf${cavities}Station]phase]
        set delta [subst \$rf${cavities}Increment]
        set temp [expr $phase+$dir*$delta]
        if {($temp > $highLimits($var)) || ($temp < $lowLimits($var))} {
            APSSetVarAndUpdate status "Phase limit reached"
            bell
            return
        }
        set $var $temp
        if [pv putw $var] {
            global errorCode status
            set status $errorCode
            update
        }
        APSSetVarAndUpdate rf${cavities}Phase $temp
    } else {
        global rfSBIncrement rfSBPhase
        set temp [expr $rfSBPhase+$dir*$rfSBIncrement]
        if {($temp > $highLimits(rfSBPhase)) || ($temp < $lowLimits(rfSBPhase))} {
            APSSetVarAndUpdate status "Phase limit reached"
            bell
            return
        }
        set rfSBPhase $temp
        if [pv putw rfSBPhase] {
            global errorCode status
            set status $errorCode
            update
        }
    }
}

proc MakeRFSlider {widget args} {
    set parent ""
    set label ""
    set cavities ""
    set cavitiesLabel ""
    APSStrictParseArguments {parent label cavities cavitiesLabel}

    APSFrame $widget -parent $parent -label $label 
    
    set w $parent$widget.frame
    
    APSButton .down -parent $w -text "<-" -command "MovePhase -1 $cavities" \
      -contextHelp "Moves the phase for $label down by the increment." -fastClick 1
    APSButton .up -parent $w -text "->" -command "MovePhase 1 $cavities" \
      -contextHelp "Moves the phase for $label up by the increment." -fastClick 1
    global rf${cavities}Increment rf${cavities}Phase
    set rf${cavities}Increment 1
    set rf${cavities}Phase 0
    APSLabeledOutput .phase -parent $w -label " Phase: " \
      -textVariable rf${cavities}Phase -width 8 \
      -contextHelp "Shows the phase for $label"
    APSLabeledEntry .incr -parent $w -label "Phase increment: " \
      -textVariable rf${cavities}Increment -width 8 \
      -contextHelp "Sets the phase increment for $label"
}

proc getControlLimits {} {
    global varList lowLimits highLimits
    set lowList [pv info $varList drvl]
    set highList [pv info $varList drvh]
    foreach var $varList item $lowList item2 $highList {
        set lowLimits($var) [lindex $item 1]
        set highLimits($var) [lindex $item2 1]
    }
}

set status Working...

APSFrame .phase -parent .userFrame -label "Rf Phase"
set w .userFrame.phase.frame
APSLabeledOutput .wgsMode -parent $w -label "Present rf mode: " \
  -contextHelp "The presently selected rf switch mode." -textVariable WGSMode

MakeRFSlider .sliderSB -parent $w -label "SR/Booster" \
  -cavities SB
MakeRFSlider .slider3637 -parent $w -label "S36/37" \
  -cavities 3637 
MakeRFSlider .slider40 -parent $w -label "S40" \
  -cavities 40

getControlLimits

update
ProcessWGSModeChange
ProcessPhaseChange
set status "Ready."
