#!/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
set CVSRevisionAuthor "\$Revision: 1.0 $ \$Author: shang $"
#mechinical motion system analysis
#remove the bpm error caused by mechinical motion by changing the bpm offsets

set status ""
proc SetStatus {text} {
    global status
    set status "[exec date] $text"
    update
}

set lastPing 0
set runControlPV OAG138RC
proc PingRunControl {args} {
    global lastPing runControlPV abort
    set sec [clock seconds]
    if {[expr $lastPing + 2] > $sec} {
        return
    } else {
        set lastPing $sec
    }
    
    catch {APSRunControlPing} status
    switch $status {
        RUNCONTROL_OK {}
        RUNCONTROL_ABORT {
            set abort 0
            return -code error "MMS-correction was aborted."
        }
        RUNCONTROL_TIMEOUT -
        RUNCONTROL_ERROR {
            set abort 0
            return -code error "Unable to ping runcontrol record of $runControlPV: $status."
        }
    }
}

set abort 0
proc Abort {args} {
    global runControlPV abort
    set abort 1
    if [catch {APSAbortSRControllaw -runControlPV $runControlPV} result] {
	return -code error $result
    }
    APSEnableButton .userFrame.start.button
    APSDisableButton .userFrame.abort.button
}

proc MMSCorrect {args} {
    set bpm ""
    set plane ""
    APSParseArguments {bpm plane}
    global offset cap0 cap hs0 hs errorCode offset0 hsDelta offsetDelta capDelta interval abort linked errorCode linkVarList
    global p0OffsetLimit gridOffsetLimit accumDelta suspend
  #  APSWaitWithUpdate -waitSeconds $interval  -updateInterval 1
   
    set delta_cap [expr $cap($bpm:$plane) - $cap0($bpm:$plane)]
    set capDelta($bpm:$plane) $delta_cap
    set delta_hs 0
    if {$plane=="y"} {
        set delta_hs [expr $hs($bpm:$plane) - $hs0($bpm:$plane)]
        set hsDelta($bpm:$plane) $delta_hs
    }
    
    set delta [expr $delta_cap + $delta_hs]
    set offsetDelta($bpm:$plane) [expr 1.0e-3 * $delta]
    set accumDelta($bpm:$plane) [expr $accumDelta($bpm:$plane) + $delta]
    if [regexp {ID} $bpm] {
        set limit $gridOffsetLimit
    } else {
        set limit $p0OffsetLimit
    }
    if {[expr abs($delta)]>$limit} {
        SetStatus "the accumulated offset change of $bpm $plane, exceeds the limit ($limit um), skip this change for this bpm."
        return
    }
    set offset($bpm:$plane) [expr $offset0($bpm:$plane) + $delta * 1.0e-3]
    if [pv putw offset($bpm:$plane)] {
        return -code error "Error changing $bpm:$plane offset by $delta: errorCode"
    }
   # SetStatus "change  $bpm $plane offset by $offsetDelta($bpm:$plane) mm"
}

set pvList ""
set varList ""
foreach bpm {S27B:P0 S28A:P0 S27ID:P1} \
  cap_pv {CAP:S27:BP0 CAP:S28:AP0 CAP:S27:GRID} \
  hs_pv {HS:S27:BP0 HS:S28:AP0 HS:S27:GRID} {
    foreach plane {x y} {
        lappend pvList ${bpm}:ms:$plane:OffsetAO
        lappend varList offset($bpm:$plane)
        if [catch {exec cavget -list=$bpm:ms:$plane:OffsetAO -pend=10} offset_val] {
            puts stderr "Error reading initial offset: $offset_val"
            exit 1
        }
        set offset0($bpm:$plane) $offset_val
        if [catch {exec cavget -list=$cap_pv:$plane -pend=10} cap_val] {
            puts stderr "Error reading $cap_pv:$plane : $cap_val"
            exit 1
        }
        set cap0($bpm:$plane) $cap_val
        lappend pvList $cap_pv:$plane
        lappend varList cap($bpm:$plane)
        set cappv($bpm:$plane) $cap_pv:$plane
        if {$plane=="y"} {
            #vertical has hs pv
            if [catch {exec cavget -list=$hs_pv:disp -pend=10} disp] {
                puts stderr "Error reading $hs_pv:$disp : $disp"
                exit 1
            }
            set hs0($bpm:$plane) $disp
            lappend pvList $hs_pv:disp
            lappend varList hs($bpm:$plane)
            set hspv($bpm:$plane)  $hs_pv:disp
        }
    }
}

if [pv linkw $varList $pvList 20] {
    puts stderr "Error link pvs: $errorCode"
    exit 1
}
set linkPVList $pvList
set linkVarList $varList
set linked 1
if [pv getw $varList] {
    puts stderr "Error reading pv values: $errorCode"
    exit 1
}

set abort 0
set pingTimeout 10
proc Start {args} {
    global abort checked interval linked cap hs errorCode linkPVList linkVarList offset offset0 cap0 cap hs0 hs
    global xOrbitCorrRun yOrbitCorrRun suspend runControlPV pingTimeout offsetDelta
    APSDisableButton .userFrame.start.button
    APSEnableButton .userFrame.abort.button
    
    SetStatus "Starting MMS correction..."
    set selected 0
    foreach plane {x y} {
        foreach bpm {S27B:P0 S28A:P0 S27ID:P1} {
            if {$checked($bpm:$plane)} {
                incr selected
            }
        }
    }
    if {!$selected} {
        SetStatus "no bpms were selected."
        APSDisableButton .userFrame.abort.button
        APSEnableButton .userFrame.start.button
        return
    }
    if [catch {APScavput -list=$runControlPV.CLR=1 -pend=20} result] {
        SetStatus $result
        return
    }
    if [catch {APSRunControlInit -pv $runControlPV \
		   -description "MMSCorrection" \
		   -timeout [expr $pingTimeout * 1000] } result] {
        SetStatus "Unable to initialize runcontrol for MMSCorrection, the runcontrol record may not be cleared, press the clear button on the medm screen to clear the record and restart: $result"
        return
    }
    if [catch {PingRunControl} result] {
	SetStatus "$result"
        APSDisableButton .userFrame.abort.button
        APSEnableButton .userFrame.start.button
	return
    }
    SetStatus "Started MMSCorrection every $interval seconds, but the status is updated every hour."
    set first 1
    set start0 [clock seconds]
    while {1} {
        if [pv getw $linkVarList] {
            SetStatus "Error reading pvs: $errorCode"
            APSDisableButton .userFrame.abort.button
            APSEnableButton .userFrame.start.button
            return
        }
        set writeStatus 0
        if $first {
            set writeStatus 1
            set first 0
        } elseif {[expr [clock seconds]-$start0]>=3600} {
            set writeStatus 1
            set start0 [clock seconds]
        }
        foreach plane {x y} {
            foreach bpm {S27B:P0 S28A:P0 S27ID:P1} {
                if {$checked($bpm:$plane)} {
                    if [catch {MMSCorrect -bpm $bpm -plane $plane} result] {
                        SetStatus "Error for $bpm $plane offset correction: $result"
                    } elseif {$writeStatus} {
                        SetStatus "$bpm $plane offset was changed by $offsetDelta($bpm:$plane) mm"
                    }
                }
            }
        }
        for {set i 0} {$i<$interval} {incr i} {
            if [catch {PingRunControl} result] {
                SetStatus "$result"
                APSDisableButton .userFrame.abort.button
                APSEnableButton .userFrame.start.button
                return
            }
            if $abort {
                SetStatus "Aborted."
                set abort 0
                return
            }
            APSWaitWithUpdate -waitSeconds 1 -updateInterval 1
        }
        if [catch {PingRunControl} result] {
            SetStatus "$result"
            APSDisableButton .userFrame.abort.button
            APSEnableButton .userFrame.start.button
            return
        }
    }
}
    

APSApplication . -name MMSCorrection -version $CVSRevisionAuthor \
  -overview {This interface provides a simple interface to correct the orbit due to mechanical system move.}
APSScrolledStatus .status  -parent .userFrame  -textVariable status -width 80 \
  -height 10 -withButtons 1 -packOption "-fill x"

APSFrame .f0 -parent .userFrame -packOption "-expand true -fill both"
APSFrame .f1 -parent .userFrame -packOption "-expand true -fill both"
APSFrame .f2 -parent .userFrame -packOption "-expand true -fill both"
set w1 .userFrame.f0.frame
set w2 .userFrame.f1.frame
set w3 .userFrame.f2.frame

APSLabel .label1 -parent $w1 -font bold -text "         PV                                        Initial                             Final                           Delta"  -packOption "-expand true -fill both"

set plane x
set buttonList ""
set varList ""
set colorList {red blue purple}
set wList [APSTabFrame .plane1 -parent $w1 -label "" -labelList {Horizontal Vertical} -width 900 -height 280 -packOption "-expand true"]
set wx [lindex $wList 0]
set wy [lindex $wList 1]
foreach plane {x y} {
    set parent [set w$plane]
    set index 0
    foreach bpm {S27B:P0 S28A:P0 S27ID:P1} {
        APSLabeledEntryFrame .offset$bpm  -parent $parent -label "$bpm:$plane offset (mm)" \
          -variableList [list offset0($bpm:$plane) offset($bpm:$plane) offsetDelta($bpm:$plane)] \
          -width 25 -orientation horizontal -bg [lindex $colorList $index] -labelColor [lindex $colorList $index]
        APSLabeledEntryFrame .cap$bpm  -parent $parent -label "$bpm:$plane cap(um)" \
          -variableList [list cap0($bpm:$plane) cap($bpm:$plane) capDelta($bpm:$plane)] \
          -width 25 -orientation horizontal 
        
        if {$plane=="y"} {
            APSLabeledEntryFrame .hs$bpm  -parent $parent -label "$bpm:$plane hs(um)" \
              -variableList [list hs0($bpm:$plane) hs($bpm:$plane) hsDelta($bpm:$plane)] \
              -width 25 -orientation horizontal 
        }
        lappend buttonList $bpm:$plane
        lappend varList checked($bpm:$plane)
        set checked($bpm:$plane) 1
        set accumDelta($bpm:$plane) 0
        set suspend($bpm:$plane) 0
        incr index
    }
}

set p0OffsetLimit 15
set gridOffsetLimit 15
set interval 5


APSFrameGrid .grid2 -parent $w2 -yList {x1 x2 x3} -packOption "-expand true -fill both -side left"
set parent $w2.grid2
APSLabeledEntry .interval -parent $parent.x1  -label "Interval (seconds): " -textVariable interval -width 15
APSLabeledEntry .interval -parent $parent.x2  -label "P0 offset change threashold (um): " -textVariable p0OffsetLimit -width 15 \
  -contextHelp "the maximum change threashold of P0 bpm offset, if the change exceeds this limit, the offset will not be applied."
APSLabeledEntry .interval -parent $parent.x3  -label "Grid offset change threashold (um): " -textVariable gridOffsetLimit -width 15 \
  -contextHelp "the maximum change threashold of grid bpm offset, if the change exceeds this limit, the offset will not be applied."


APSCheckButtonFrame .check -parent $w3 -allNone 1 -buttonList $buttonList -variableList $varList \
  -orientation horizontal -limitPerRow 3 -label "select bpm for correction:" -packOption "-expand true -fill both"


APSButton .start -parent .userFrame -text "Start" -command "Start"
APSButton .abort -parent .userFrame -text "Abort" -command "Abort"
APSButton .info -parent .userFrame -text "Info" -command "exec medm -x -attach -macro \"RCPV=$runControlPV\" ./sr/psApp/APSRunControlSingle.adl &"
APSDisableButton .userFrame.abort.button





