#!/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 CVSRevisionAuthor "\$Revision: 1.14 $ \$Author: borland $"

APSApplication . -name "SROrbitControllawBrief" -version $CVSRevisionAuthor \
        -overview "SROrbitControllawBrief provides convenience controls for executing sddscontrollaw for correcting the SR orbit. For an expert interface for SR orbit correction use SROrbitControllaw."

APSMenubarAddMenu .programs -text Programs -parent .menu
.menu.programs.menu add command -label SROrbitControllaw -underline 0 -command "exec SROrbitControllaw &"
.menu.programs.menu add command -label SROrbitControllawBrief -underline 0 -command "exec SROrbitControllawBrief &"

set SROrbitStatus "Initializing ..."
APSScrolledStatus .status -parent .userFrame -width 60 \
        -textVariable SROrbitStatus 

proc SetSROrbitStatus {text} {
    global SROrbitStatus
    set SROrbitStatus $text
    update
    bell
}
proc MakeOptionFrame {widget args} {
    global plane
    APSParseArguments {parent}

    APSFrame $widget -parent $parent \
      -contextHelp "Frame for containing options."
    $parent$widget.frame configure -relief flat
    APSRadioButtonFrame .plane -parent $parent$widget.frame \
      -buttonList {H/x V/y} \
      -variable plane \
      -valueList {x y} \
      -orientation Horizontal -label "" \
      -contextHelp "Selects the plane in effect when an action button is pressed."
    return
}

proc MakeActionWidget {widget args} {
    APSParseArguments {parent}

    set w $parent$widget
    APSFrame $widget -parent $parent \
      -contextHelp "Frame for containing action buttons."
    APSButton .startFine -parent $w.frame -text "FINE" \
      -command "ChangeControllaw -mode Fine"\
      -contextHelp "Starts or changes a sddscontrollaw command in the plane selected for accurate steering at light source points.\n\nMay be disabled if Fine correction shouldn't be used anymore."
    APSDisableButton $w.frame.startFine.button
    APSButton .startGlobal -parent $w.frame -text "GLOBAL" \
      -command "ChangeControllaw -mode Global"\
      -contextHelp "Starts or changes a sddscontrollaw command in the plane selected for global drift correction."
    APSButton .info -parent $w.frame -text INFO \
      -command "ControllawInfoButton" \
      -contextHelp "Displays an medm screen for the run control PV for the plane selected."
    APSButton .abort -parent $w.frame -text ABORT -command "AbortControllaw" -contextHelp \
      "Aborts the sddscontrollaw command through the ABORT run control mechanism or through the USR2 signal."
    APSButton .killAll -parent $w.frame -text "KILL ALL" -command "KillAllControllaws" -contextHelp \
      "Find all the SR orbit correction sddscontrollaw processes running on herema and phoenix and kills them."
    $w.frame configure -relief flat
}

proc ChangeControllaw {args} {
    global plane dataDir
    set mode ""
    APSParseArguments {mode}

    if [catch {CheckControllawRunning -plane $plane} checkResult] {
        SetSROrbitStatus "ChangeControllaw: $checkResult"
        return -code error "ChangeControllaw: $checkResult"
    }
# relink appropriate file.
    if [catch {APSUpdateSoftLink -file sr${mode}.${plane}.command -link $dataDir/sr.${plane}.newcommand \
             } result ] {
        return -code error "ChangeControllaw: $result"
    }
    if ![string compare $checkResult 0] {
        if [catch {StartControllaw -mode $mode -plane $plane \
                 } result ] {
            SetSROrbitStatus "ChangeControllaw: $result"
            return -code error "ChangeControllaw: $result"
        }
    } else {
        if [catch {SendSignal -signal USR1 -mode $mode -plane $plane \
                 } result ] {
            SetSROrbitStatus "ChangeControllaw: $result"
            return -code error "ChangeControllaw: $result"
        }
    }
    # setup BPM: averaging and InUse PVs
    if [catch {SetupBPM -mode $mode -plane $plane \
             } result ] {
        SetSROrbitStatus "ChangeControllaw: $result"
        return -code error "ChangeControllaw: $result"
    }
    # send value to PV
    if ![string compare $mode Fine] {
        if [catch {exec cavput -list=S:OrbitControlLaw[string toupper $plane]FineBO=1 \
                 } result ] {
            SetSROrbitStatus "ChangeControllaw: $result"
            return -code error "ChangeControllaw: $result"
        }
    } else {
        if [catch {exec cavput -list=S:OrbitControlLaw[string toupper $plane]FineBO=0 \
                 } result ] {
            SetSROrbitStatus "ChangeControllaw: $result"
            return -code error "ChangeControllaw: $result"
        }
    }
}

proc StartControllaw {args} {
    global startCommand
    set mode ""
    set plane ""
    APSParseArguments {mode plane}
    if {![string length $mode] || ![string length $plane]} {
        return -code error "StartControllaw: mode or plane not specified."
    }
    set Plane [string toupper $plane]
    set logDataDir /home/helios/oagData/controllaw/SRorbit/loggedData
    APSExecLog .sr${Plane}OrbitControllaw \
      -lineLimit 1024 \
      -name "SR ${Plane}-orbit Correction" \
      -unixCommand "$startCommand($mode,$plane) -controlLogFile=$logDataDir/sr${mode}.${plane}-[exec date +%Y-%m%d-%H%M%S].log" \
      -width 95
    return
}

proc AbortControllaw {args} {
    global plane
    if [catch {CheckControllawRunning -plane $plane} result] {
        SetSROrbitStatus "AbortControllaw: $result"
        return -code error "AbortControllaw: $result"
    }
    if ![string compare $result 0] {
        SetSROrbitStatus "No controllaw running in plane $plane."
        return
    } else {
        if [catch {SendSignal -signal USR2 -plane $plane \
                 } result ] {
            SetSROrbitStatus "AbortControllaw: $result"
            return -code error "AbortControllaw: $result"
        }
        if [catch {ClearInUsePVs -plane $plane \
                 } result ] {
            SetSROrbitStatus "AbortControllaw: $result"
            return -code error "AbortControllaw: $result"
        }
    }
}

proc KillAllControllaws {args} {
    foreach node {herema phoenix} {
        set tmpName /tmp/[APSTmpString]
        if [catch {exec rsh $node "ps -fed" > $tmpName \
                 } result ] {
            SetSROrbitStatus "KillAllControllaws: $result"
            return -code error "KillAllControllaws: $result"
        }
        if [catch {exec /usr/xpg4/bin/grep -s sddscontrollaw ${tmpName} \
                     | /usr/xpg4/bin/grep -e Global -e Fine \
                     > ${tmpName}.grep } result ] {
            continue
        }
        if [catch {open ${tmpName}.grep r} fileId] {
            SetSROrbitStatus "KillAllControllaws: Cannot open $tmpName.grep: $fileId"
            return -code error "KillAllControllaws: Cannot open $tmpName.grep: $fileId"
        } else {
            while {[gets $fileId line] >= 0 } {
                # pid number is the 2nd element of the ps output
                set pid [lindex $line 1]
                if [catch {exec rsh $node kill $pid} result ] {
                    SetSROrbitStatus "KillAllControllaws: $result"
                    return -code error "KillAllControllaws: $result"
                }
                SetSROrbitStatus "Killed pid $pid on $node"
            }
            close $fileId
            catch {exec rm $tmpName ${tmpName}.grep}
        }
    }
}

proc CheckControllawRunning {args} {
    set plane ""
    APSParseArguments {plane}
    if ![string length $plane] {
        return -code error "CheckControllawRunning: No plane given."
    }
    set Plane [string toupper $plane]
    set runControlPV "S:RC:OrbitControlLaw${Plane}C.RUN"
    return [exec cavget -list=$runControlPV]
}

proc SendSignal {args} {
    APSParseArguments {signal plane}
    if ![file exists pid${plane}.file] {
        set result "Can't find file pid${plane}.file"
        return -code error "SendSignal: $result"
    }
    set pid [getRunControlPid \
               -rcPV S:RC:OrbitControlLaw[string toupper ${plane}]C ]
    if [catch {exec kill -$signal $pid} result] {
        return -code error "SendSignal: $result"
    }
    return
}
    
proc ControllawInfoButton {args} {
    global plane
    set Plane [string toupper $plane]
    set runControlPV "S:RC:OrbitControlLaw${Plane}C"
    if {[catch {exec medm -attach -x  -macro "RCPV=$runControlPV" ./sr/psApp/APSRunControlSingle.adl & \
              } result ]} {
        SetSROrbitStatus "ControllawInfoButton: $result"
        return -code error "ControllawInfoButton: $result"
    }
    return
}

proc SetupBPM {args} {
    set mode ""
    set plane ""
    APSParseArguments {mode plane}
    if {![string length $mode] || ![string length $plane]} {
        return -code error "SetupBPM: mode or plane not specified."
    }
    if ![file exists sr${mode}.$plane.enables] {
        return -code error "SetupBPM: Can't find file sr${mode}.$plane.enables."
    }
    SetSROrbitStatus "Restoring BPM averaging enable PVs..."
    if {[catch {exec carestore -cawait 10 -sddsin sr${mode}.$plane.enables \
              } result ]} {
        SetSROrbitStatus "Problem with carestore: $result\nForging ahead..."
#        APSAlertBox .alert -errorMessage "$result"
#        return -code error $result
    }
    SetSROrbitStatus "Restoring BPM InUse PVs..."
    if ![file exists sr${mode}.$plane.InUse] {
        return -code error "SetupBPM: Can't find file sr${mode}.$plane.InUse."
    }
    if {[catch {exec carestore -cawait 10 -sddsin sr${mode}.$plane.InUse \
              } result ]} {
        SetSROrbitStatus "Problem with carestore: $result\nForging ahead..."
#        APSAlertBox .alert -errorMessage "$result"
#        return -code error $result
    }
}
    
proc ClearInUsePVs {args} {
    set plane ""
    APSParseArguments {plane}
    if ![string length $plane] {
        return -code error "ClearInUsePVs: No plane given."
    }
    if {[catch {exec cavput -list=S -range=beg=1,end=40 \
                  -list=A:P1,A:P2,A:P3,A:P4,B:P5,B:P4,B:P3,B:P2,B:P1 \
                  -list=:ms:${plane}:InUseBO=0 \
                  -pendIoTime=10 -blunder \
    } result ]} {
        return -code error "ClearInUsePVs: $result"
    }
    return
}

set dataDir /home/helios/oagData/sr/scorr
cd $dataDir
set logDataDir /home/helios/oagData/controllaw/SRorbit/loggedData
foreach mode {Fine Global} {
    foreach plane {x y} {
        set fileId [open sr$mode.$plane.command r]
        gets $fileId startCommand($mode,$plane)
        set startCommand($mode,$plane) "$startCommand($mode,$plane) -server=pid=pid${plane}.file,command=sr.${plane}.newcommand"
        close $fileId
    }
}

set plane x
MakeOptionFrame .options -parent .userFrame
MakeActionWidget .actions -parent .userFrame 
SetSROrbitStatus "Ready"
