#!/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)]
APSDebugPath

set includeLTP 0
set includeLinac 0
set includeLinacRf 0
set includeLinacPhase 0
set includeBoosterDirInj 0
set includeBTS 0
set includePTB 0
set includeLEUTL 0
set includeLEA 0
set includePAR 0
set includeRateButtons 0
set includeBoosterSingleTurn 0
set args $argv
APSStrictParseArguments {includeLTP includeLinac includeBTS includePTB includeLEUTL includeLinacRf includeLinacPhase includeBoosterDirInj includeRateButtons includePAR includeBoosterSingleTurn includeLEA}

if $includeLEUTL {
    set includeLEA 1
}

if {!$includeLTP && !$includeLinac && !$includeBTS && !$includePTB && !$includeLEA && !$includeLinacRf && !$includeLinacPhase && !$includeBoosterDirInj && !$includePAR && !$includeBoosterSingleTurn} {
    APSAlertBox .ab -errorMessage "LinacLTPSetpointTransfer: Must include one of linac, LTP, PAR, PTB, BTS, or LEUTL!"
    exit
}

set nameSuffixList ""
set chargePV ""
set checkReadback 0
if {$includeLEA} {
    lappend nameSuffixList "LEA BPMs"
    set chargePV L5:CM1:measCurrentCM
    set checkReadback 1
}

if $includeLinac {
    lappend nameSuffixList "Linac BPMs"
    set chargePV L5:CM1:measCurrentCM
    set checkReadback 1
}
if $includeLTP {
    lappend nameSuffixList "LTP BPMs"
    set chargePV LTP:FCM:measCurrentCM.CVAL
    set checkReadback 1
}

if $includePTB {
    lappend nameSuffixList "PTB BPMs"
    set chargePV PTB:CM:measCurrentCM.CVAL
    set checkReadback 1
}

if $includeBTS {
    lappend nameSuffixList "BTS BPMs" 
    set chargePV BTS:BESOCM:A:DATA:Beam:QM
    set checkReadback 1
}


if $includeLinacRf {
    lappend nameSuffixList "Linac Rf Powers/Phases"
}
if $includeLinacPhase {
    lappend nameSuffixList "Linac Beam-to-Rf Phases"
}
if $includeBoosterDirInj {
    lappend nameSuffixList "Booster Dir. Inj. BPMs" 
}
if $includePAR {
    lappend nameSuffixList "PAR BPMs"
}

set CVSRevisionAuthor "\$Revision: 1.31 $ \$Author: soliday $"
APSApplication . -name "SetpointTransfer: [join $nameSuffixList {+ }]" -version $CVSRevisionAuthor 

set nameList ""
set labelList ""
set readbackList ""
set setpointList ""
set groupList ""
set includeRateList ""
set rcPVList ""

proc addToLists {args} {
    set name ""
    set label ""
    set readback ""
    set setpoint ""
    set group ""
    set includeRate 0
    set rcPV ""
    APSStrictParseArguments {name label readback setpoint group includeRate rcPV} 

    global nameList labelList readbackList setpointList groupList includeRateList
    if [lsearch -exact $nameList $name]!=-1 return

    lappend nameList $name
    global $name 
    set $name 0
    lappend labelList $label
    lappend readbackList $readback
    lappend setpointList $setpoint
    lappend groupList $group
    lappend includeRateList $includeRate
    lappend rcPV $rcPV
}

proc Toggle {args} {
    set group ""
    APSStrictParseArguments {group}

    global nameList groupList
    foreach name $nameList group0 $groupList {
        if [string compare $group $group0]==0 {
            global $name
            if [set $name] {
                set $name 0
            } else {
                set $name 1
            }
        }
    }
}

set numberIncluded 0
if $includeLTP {
    foreach item {1 2 3 4} {
        addToLists \
          -name LTP:PH${item} \
          -label LTP:PH${item} \
          -readback LTP:PH${item}:AdjustedCC \
          -setpoint LTP:PH${item}:SetpointAO \
          -group LTP
    }
    foreach item {1 2 3 4} {
        addToLists \
          -name LTP:PV${item} \
          -label LTP:PV${item} \
          -readback LTP:PV${item}:AdjustedCC \
          -setpoint LTP:PV${item}:SetpointAO \
          -group LTP
    }
    incr numberIncluded
}
if $includePAR {
    foreach sector {1 2 3 4} {
        foreach item {1 2 3 4} {
            set root P${sector}P${item}
            foreach plane {x y} {
                addToLists \
                  -name $root:$plane \
                  -label $root:$plane \
                  -readback $root:$plane \
                  -setpoint $root:$plane:SetpointAO
            }
        }
    }
}
if $includeLinacRf {
      foreach index {1 2 3 4 5} {
          addToLists \
            -name L${index}Phase \
            -label L${index}Phase \
            -readback L${index}:AUTO:PH:measuredPhaseAI \
            -setpoint L${index}:AUTO:PH:SetpointAO \
            -group LinacRf
      }
    foreach sector {1 2 3 4 5} \
      meas {L1:KY:DC2ARF.VAL L-K2:LLRF:SD:Fwd_PkPwrRemoteM L3:KY:DC2ARF.VAL \
              L4:SD:DC1ARF.VAL L-K5:LLRF:SD:Fwd_PkPwrRemoteM}  \
      sp {L1:KY:DC2ARF:SetpointP L2:SD:DC1ARF:SetpointP L3:KY:DC2ARF:SetpointP \
            L4:SD:DC1ARF:SetpointP L5:SD:DC1ARF:SetpointP} \
        rcPV {L:L1Stabilizer:SDDS L:L2Stabilizer:SDDS L:L3Stabilizer:SDDS L:L4Stabilizer:SDDS \
                L:L5Stabilizer:SDDS} {
                addToLists \
                  -name L${sector}Power \
                  -label L${sector}Power \
                  -readback $meas \
                  -setpoint $sp \
                  -group LinacRf \
                  -rcPV $rcPV \
                  -includeRate $includeRateButtons
            }
    incr numberIncluded
}
if $includeLinac {
    set tmpFile /tmp/[APSTmpString]
    foreach plane {H V} {
        if [catch {exec sddsprocess /home/helios/oagData/controllaw/bpmList.sdds -pipe=out \
                     -match=param,Beamline=LINAC,Plane=$plane,& -match=col,BPMPVs=*ErrorCC \
                     -match=column,BPMs=L?:* \
                     -edit=column,Setpoint,BPMPVs,%/ErrorCC/SetpointAO/ \
                     -edit=column,Measurement,BPMPVs,%/:ErrorCC/:AdjustedCC/ \
                     | sddsconvert -pipe=in $tmpFile -delete=column,BPMPVs
            sdds load $tmpFile BPMData} result] {
            return -code error $result
        }
        foreach BPM [lindex $BPMData(Column.BPMs) 0] \
          Setpoint [lindex $BPMData(Column.Setpoint) 0] \
          Measurement [lindex $BPMData(Column.Measurement) 0] {
#              if {![string match *$plane* $BPM]} {
#                  append BPM :$plane
#              }
              addToLists \
                -name $BPM \
                -label $BPM \
                -readback $Measurement \
                -setpoint $Setpoint \
                -group LinacBPM
          }
    }
    incr numberIncluded
}   
if $includeLinacPhase {
    foreach phaseDetector {L:BPD:L1P1:RFGUN1 L:BPD:L1P1:RFGUN2 L:BPD:L1P1:L2AS1 L:BPD:L3P3:L4AS1 L:BPD:L4P1:L5AS1 L:BPD:L0P2:L1AS1 } phaseDetectorLabel {"(RG1) L:BPD:L1P1:RFGUN1" "(RG2) L:BPD:L1P1:RFGUN2" "(L2)  L:BPD:L1P1:L2AS1" "(L4)  L:BPD:L3P3:L4AS1" "(L5)  L:BPD:L4P1:L5AS1" "(For PCGun Operations)\nL:BPD:L0P2:L1AS1      "} {
        addToLists \
          -name $phaseDetector \
          -label $phaseDetectorLabel \
          -readback ${phaseDetector}:AdjustedCC \
          -setpoint ${phaseDetector}:SetpointAO \
          -group LinacPhase
    }
}   

if $includeBoosterDirInj {
    foreach BPM {LTP:PH4 PB:PH1 PB:PH4 PTB:SB:PH0 PTB:SB:PH1 PTB:SB:PH2} {
        addToLists \
          -name $BPM \
          -label $BPM \
          -readback ${BPM}:AdjustedCC \
          -setpoint ${BPM}:SetpointAO \
          -group PTB
    }
    foreach BPM {LTP:PV4 PB:PV1 PB:PV4 PTB:SB:PV0 PTB:SB:PV1 PTB:SB:PV2} {
        addToLists \
          -name $BPM \
          -label $BPM \
          -readback ${BPM}:AdjustedCC \
          -setpoint ${BPM}:SetpointAO \
          -group PTB
    }
    incr numberIncluded
}

if {$includeLEA} {
    set tmpFile /tmp/[APSTmpString]
    foreach plane {H V} {
        if [catch {exec sddsprocess /home/helios/oagData/controllaw/bpmList.sdds -pipe=out \
                     -match=param,Beamline=LEUTL,Plane=$plane,& -match=col,BPMPVs=*ErrorCC \
                     -match=col,BPMs=L?:*,! \
                     -edit=column,Setpoint,BPMPVs,%/ErrorCC/SetpointAO/ \
                     -edit=column,Measurement,BPMPVs,%/:ErrorCC/:AdjustedCC/ \
                     | sddsconvert -pipe=in $tmpFile -delete=column,BPMPVs
            sdds load $tmpFile BPMData} result] {
            return -code error $result
        }
        foreach BPM [lindex $BPMData(Column.BPMs) 0] \
          Setpoint [lindex $BPMData(Column.Setpoint) 0] \
          Measurement [lindex $BPMData(Column.Measurement) 0] {
#              if {![string match *$plane* $BPM]} {
#                  append BPM :$plane
#              }
              addToLists \
                -name $BPM \
                -label $BPM \
                -readback $Measurement \
                -setpoint $Setpoint \
                -group LEUTL
          }
    }
    incr numberIncluded
}   
if $includePTB {
    foreach BPM {PTB:PH1 PTB:PH2 PTB:PH3 PTB:PH4 PTB:PH5} {
        addToLists \
          -name $BPM \
          -label $BPM \
          -readback ${BPM}:AdjustedCC \
          -setpoint ${BPM}:SetpointAO \
          -group PTB
    }
    foreach BPM {PTB:PV1 PTB:PV2 PTB:PV3 PTB:PV4 PTB:PV5} {
        addToLists \
          -name $BPM \
          -label $BPM \
          -readback ${BPM}:AdjustedCC \
          -setpoint ${BPM}:SetpointAO \
          -group PTB
    }
    incr numberIncluded
}
if $includeBTS {
    set BTSBPMList [list BTS:APH1 BTS:APH2 BTS:APH3 BTS:APV1 BTS:APV2 BTS:APV3 BTS:BPH1 BTS:BPH2 BTS:BPH3 BTS:BPH4 BTS:BPH5 BTS:BPH6 BTS:BPH7 BTS:BPV1 BTS:BPV2 BTS:BPV3 BTS:BPV4 BTS:BPV5 BTS:BPV6 BTS:BPV7 BTS:CPH1 BTS:CPH2 BTS:CPV1 BTS:CPV2 BTS:DPH1 BTS:DPH2 BTS:DPV1 BTS:DPV2]
    foreach BPM $BTSBPMList {
        addToLists \
          -name $BPM \
          -label $BPM \
          -readback ${BPM}:AdjustedM \
          -setpoint ${BPM}:SetpointC \
          -group BTS
    }
    exec cavput -list=[join $BTSBPMList ,] -list=:SetpointC -list=.DRVH=10e3,.DRVL=-10e3
    incr numberIncluded
}

if $includeBoosterSingleTurn {
    set pvList [exec sddsprocess /home/helios/oagData/SCR/requestFiles/Booster.req -match=col,ControlName=*:singleTurn:*setpointAO -pipe=out | \
                  sdds2stream -pipe -col=ControlName]
    foreach pv $pvList {
        set BPM [regsub "setpointAO" $pv ""]
        set readback ${BPM}position
        addToLists \
          -name $BPM \
          -label $BPM \
          -readback $readback \
          -setpoint $pv \
          -group BoosterSingleTurn
    }
    incr numberIncluded
}
proc ViewRate {} {
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddsmonitor -step=1 /home/helios/oagData/controllaw/linacRf/rfPowerRate.mon $tmpRoot.sdds
        exec sddscollect $tmpRoot.sdds -pipe=out \
                 -collect=suffix=.INTR -collect=suffix=.AVER -collect=suffix=.GAIN \
                 | sddsprintout -pipe=in $tmpRoot.print \
                 -column=Rootname -column=.GAIN,format=%10.4f,label=Gain \
                 "-column=.INTR,format=%14.4f,label=Interval (s)" \
                 "-column=.AVER,format=%14.0f,label=Num. to Ave."}  result] {
        return -code error "$result"
    }
    file delete -force $tmpRoot.sdds
    APSFileDisplayWindow [APSUniqueName .] -fileName $tmpRoot.print -width 80 -deleteOnClose 1
}

proc SwitchRate {args} {
    set mode low
    APSStrictParseArguments {mode}

    if [lsearch -exact [list low high] $mode]==-1 {
        return -code error "SwitchRate: unknown rate: $mode"
    }
    global nameList 
    eval global $nameList
    set switchList ""
    foreach item $nameList {
        if ![set $item] continue
        if [string match L?Power $item] {
            lappend switchList [os editstring 2fD $item]
        } else {
            return -code error "Can't switch rate for $item"
        }
    }
    if [catch {LMOCS_PowerControlLawSetup -deviceList $switchList -mode $mode} result] {
      setStatus "Problem changing rates: $result"
    } else {
        setStatus "Set rate to $mode for [join $switchList ,]"
    }
}

proc setStatus {message} {
    global status
    set status $message
    update
}

set status ""
APSScrolledStatus .status -parent .userFrame -textVariable status \
  -height 8 -width 65 -packOption {-side top}

if $includeLinacPhase {
    set  limitPerRow 5
} else {
    set limitPerRow [expr [llength $nameList]/4]
}
APSCheckButtonFrame .cbs -parent .userFrame -limitPerRow $limitPerRow \
  -label "Control Point Choices" \
  -orientation vertical -variableList $nameList \
  -buttonList $labelList -allNone 1 -contextHelp \
  "Select the readbacks for which you want to transfer the present value to the setpoint.  This will allow controllaw programs to maintain the present value."

set averageNumber 10
set readingInterval 1
APSLabeledEntry .le1 -parent .userFrame -textVariable averageNumber \
  -label "Number of readings to average: " 
APSLabeledEntry .le2 -parent .userFrame -textVariable readingInterval \
  -label "Time between readings (seconds): " 

if $numberIncluded>1 {
    if $includeLTP {
        APSButton .ltp -parent .userFrame -text "Toggle LTP" -command "Toggle -group LTP"
    }
    if $includeLinacRf {
        APSButton .linacrf -parent .userFrame -text "Toggle Linac Rf" -command "Toggle -group LinacRf"
    }
    if $includeLinac {
        APSButton .linac -parent .userFrame -text "Toggle Linac BPMs" -command "Toggle -group LinacBPM"
    }
    if $includeLinacPhase {
        APSButton .linacPhase -parent .userFrame -text "Toggle Linac Phase Detectors" -command "Toggle -group LinacPhase"
    }
    if $includeLEA {
        APSButton .leutl -parent .userFrame -text "Toggle LEUTL" -command "Toggle -group LEUTL"
    }
    if $includePTB {
        APSButton .ptb -parent .userFrame -text "Toggle PTB" -command "Toggle -group PTB"
    }
    if $includeBTS {
        APSButton .bts -parent .userFrame -text "Toggle BTS" -command "Toggle -group BTS"
    }
}

proc ZeroSetpoints {} {
    global nameList setpointList
    eval global $nameList $setpointList
    set setList ""
    foreach item $nameList setpoint $setpointList {
        if [set $item] {
            lappend setList $setpoint=0
        }
    }
    if [llength $setList] {
        if [catch {exec cavput -list=[join $setList ,]} result] {
            return -code error "$result"
        }
    }
}

proc Transfer {args} {
    global averageNumber readingInterval nameList readbackList setpointList includePAR env chargePV checkReadback
    
    if [string length $chargePV] {
	#charge if beam > 0.1 before transfeer
	if [catch {exec cavget -list=$chargePV -pend=10 -printError} charge] {
            setStatus "Error reading beam charge: $charge"
            return
        }
	if {$charge<0.1} {
	    if ![APSYesNoPopUp "Warning the beam charge is less than 0.1nC, do you still want to transfer?"] {
                setStatus "The beam charge is less than 0.1nC, abort transfer bpm setpoint."
                return
            }
        }
    }
    if {$includePAR} {
        #check par beam >0.5A and the orbit rms <0.25nC before transfer
        if [catch {exec cavget -list=P:bpmSum:ChargeM -pend=10 -printError} charge] {
            setStatus "Error reading par charge: $charge"
            return
        }
        if {$charge<0.5} {
            setStatus "The par charge is less than 0.5nC, abort transfer par bpm setpoint."
            return
        }
        #check orbit rms
        if [catch {exec cavget -list=P -range=begin=1,end=4 -list=P -range=begin=1,end=4 -list=:x,:y \
                     -repeat=number=5,pause=1,average -label } readingList] {
            setStatus "Error reading par orbit: $readingList"
            return
        }
        set num [llength $readingList]
        set xorbitList ""
        set yorbitList ""
        for {set i 0} {$i<$num} {incr i 2} {
            set pv [lindex $readingList $i]
            if [regexp {x} $pv] {
                lappend xorbitList [lindex $readingList [expr $i+1]]
            } else {
                lappend yorbitList [lindex $readingList [expr $i+1]]
            }
        }
       
        if [catch {exec sddsmakedataset -pipe=out -col=xorbit,type=double -data=[join $xorbitList ,]\
                     -col=yorbit,type=double  -data=[join $yorbitList ,] \
                     | sddsprocess -pipe -process=xorbit,rms,xRMS -process=yorbit,rms,yRMS \
                     | sdds2stream -pipe -par=xRMS,yRMS } rmsList] {
            setStatus "Error processing par orbit rms: $rmsList"
            return
        }
        set xrms [lindex $rmsList 0]
        set yrms [lindex $rmsList 1]
        if {[regexp ":x" $nameList] && $xrms>0.25} {
	    if ![APSYesNoPopUp "Warning Par x orbit rms ($xrms) > 0.25, do you still want to transfer?"] {
		setStatus "Par x orbit rms ($xrms) > 0.25, abort x plane transfer."
		return
	    }
        }
        if {[regexp ":y" $nameList] && $yrms>0.25} {
	     if ![APSYesNoPopUp "Warning Par y orbit rms ($xrms) > 0.25, do you still want to transfer?"] {
		 setStatus "Par y orbit rms ($yrms) > 0.25, abort y plane transfer."
		 return
	     }
	}
    }
    catch {exec logMessage -sourceId=linacLTPSetpointTransfer \
             -tag=User $env(USER) \
             -tag=Host $env(HOST) \
             -tag=flagList [join $nameList ,] \
             -tag=readbackList [join $readbackList ,] \
             -tag=setpointList [join $setpointList ,] }
    if [catch {APSCAAverageAndTransfer -average $averageNumber \
		   -interval $readingInterval \
		   -flagList $nameList -readbackList $readbackList \
		   -setpointList $setpointList \
		   -checkReadback $checkReadback \
		   -statusCallback setStatus } result] {
        setStatus "Error transfer setpoint: $result"
        return
    }
    setStatus "done."
    
}
APSButton .run -parent .userFrame -text "Transfer" \
  -command {Transfer} \
  -contextHelp \
  "Averages readings from the readback PVs and transfers the results to the setpoints."
APSButton .zero -parent .userFrame -text "Zero" \
    -command ZeroSetpoints

if $includeRateButtons {
    APSButton .lowrate -parent .userFrame -text "Low Gain" \
      -command "SwitchRate -mode low"
    APSButton .highrate -parent .userFrame -text "High Gain" \
      -command "SwitchRate -mode high"
    APSButton .viewrate -parent .userFrame -text "View Gain & Rate" \
      -command ViewRate
}

setStatus Ready.
