#!/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.3 $ \$Author: borland $"

APSApplication . -name SRLifetimeVsIDs -version $CVSRevisionAuthor -overview \
    {Measures SR beam lifetime as a function of the number of IDs closed.}

set status Ready.
APSScrolledStatus .status -parent .userFrame -textVariable status -width 80 -height 8

set outputDirectory [pwd]
set timeToWait 60
set rootname LifetimeVsIDs
set outputDir ""
set retriesToUse 100
set IDString [join [APSIDSectorList] ,]
set gapToUse 12
set startingGap 60
set runIndex 1

APSLabeledEntry .dir -parent .userFrame -label "Directory: " \
    -textVariable outputDirectory -width 70 -contextHelp  \
    "Directory in which to put data files."
APSLabeledEntry .root -parent .userFrame -label "Rootname: " \
    -textVariable rootname -width 70 -contextHelp  \
    "Rootname to use for constructing filenames."
APSLabeledEntry .index -parent .userFrame -label "Index: " -textVariable runIndex -width 10 \
    -numberButtons 1 -contextHelp \
    "The index of the run.  The file rootname will be ${rootname}-<Index> ."

APSLabeledEntry .timeToWait -parent .userFrame -label "Time to wait (s): " \
  -textVariable timeToWait -width 10 -contextHelp \
  "Time to wait for data collection at each frequency."
APSLabeledEntry .gapToUse -parent .userFrame -label "Gap to use (mm): " \
  -textVariable gapToUse -width 10 -contextHelp \
  "Enter the gap in mm to use for all IDs."
APSLabeledEntry .startGap -parent .userFrame -label "Starting gap (mm): " \
  -textVariable startingGap -width 10 -contextHelp \
  "Enter starting the gap in mm to use for all IDs.  This should be large enough that the ID fields are still weak."
APSLabeledEntry .idList -parent .userFrame -label "IDs to use: " \
  -textVariable IDString -width 70 -contextHelp \
  "Comma-separated list of ID sectors to use.  E.g., 1,2ds,5,12"

APSButton .run -parent .userFrame -text Run -command \
  {APSDisableButton .userFrame.run.button
      APSEnableButton .userFrame.abort.button
     RunIDLifetimeMeasurement -index $runIndex -outputDir $outputDirectory \
     -IDList [split $IDString ,] -gapToUse $gapToUse -timeToWait $timeToWait \
     -startingGap $startingGap \
     -retriesToUse $retriesToUse -rootname $rootname \
     -statusCallback "APSSetVarAndUpdate status" \
     -errorCallback "APSEnableButton .userFrame.run.button; APSDisableButton .userFrame.abort.button"
      APSEnableButton .userFrame.run.button; APSDisableButton .userFrame.abort.button
      bell; bell; bell
      } 
set abortIDLifetimeMeasurement 0
APSButton .abort -parent .userFrame -text Abort -command \
  {APSSetVarAndUpdate status "Aborting..."; set abortIDLifetimeMeasurement 1}
APSDisableButton .userFrame.abort.button

proc RunIDLifetimeMeasurement {args} {
    set index 0
    set statusCallback APSNoOp
    set errorCallback APSNoOp
    set outputDir ""
    set timeToWait 30
    set retriesToUse 10
    set IDList ""
    set gapToUse 12
    set abortVariable ""
    set rootname ""
    set startingGap 100
    APSStrictParseArguments {index statusCallback errorCallback outputDir timeToWait \
                               IDList gapToUse abortVariable rootname retriesToUse \
                               startingGap}

    if [string length $abortVariable] {
        global $abortVariable
        set $abortVariable 0
    }
    if ![string length $rootname] {
        eval $errorCallback
        return -code error "No rootname given."
    }

    scan $index "%ld" index
    set index [format "%02ld" $index]
    set outputRoot $outputDir/${rootname}-$index

    set newIDList ""
    foreach ID $IDList {
        set suffix ""
        if [string first us $ID]!=-1 {
            set suffix us
        }
        if [string first ds $ID]!=-1 {
            set suffix ds
        }
        if [scan $ID %ld ID]!=1 continue
        lappend newIDList [format %02ld $ID]$suffix
    }
    set IDList $newIDList

    if [catch {exec cavget -num -list=ID:AccessSecurity} lastSecurity] {
        eval $errorCallback
        return -code error "Problem getting access security mode."
    }
    if [catch {exec cavput "-list=ID:AccessSecurity=Machine Physics"} result] {
        eval $errorCallback
        return -code error "Problem setting access security mode to Machine Physics"
    }
    eval $statusCallback {"Opening IDs to maximum gap."}
    if [catch {APSIDMoveGapsToMaximum -IDList $IDList -maximum $startingGap} result] {
        eval $errorCallback
        catch {exec cavput -list=ID:AccessSecurity$lastSecurity}
        return -code error "Problem moving gaps to $startingGap: $result"
    }
    eval $statusCallback {"Done."}

    if {![file exists $outputRoot]} {
        set tmpRoot /tmp/[APSTmpString]

        eval $statusCallback {"Starting sddsmonitor job."}
        set smPID [exec sddsmonitor /home/helios/oagData/sr/gapScans/inputFiles/IDs.mon \
                     $outputRoot -interval=1,s \
                     -time=1,h -precision=single -erase &]
        eval $statusCallback {"sddsmonitor job started."}
        if [catch {exec kill -STOP $smPID} result] {
            catch {exec cavput -list=ID:AccessSecurity=$lastSecurity}
            catch {exec kill -KILL $smPID}
            eval $errorCallback
            return -code error $result
        }

        foreach ID $IDList {
            if {[string length $abortVariable] && [subst \$$abortVariable]} {
                break
            }
            set IDName ID$ID
            eval $statusCallback {"Working on ID $IDName"}
            if [catch {exec cavget -list=$IDName:DeviceLimit} commisLimit] {
                catch {exec cavput -list=ID:AccessSecurity=$lastSecurity}
                eval $errorCallback
                catch {exec kill -STOP $smPID}
                return -code error "$commisLimit"
            }
            if $commisLimit>$gapToUse {
                eval $statusCallback {"$IDName has commissioning limit of $commisLimit mm,"}
                eval $statusCallback {"which is larger than your gap.  Skipping this ID."}
                eval $errorCallback
                continue
            }
            if [catch {exec cavput -pend=5 -list=$IDName:GapSet=$gapToUse} result] {
                eval $statusCallback {"Can't move $IDName: $result.  Skipping this ID."}
                continue
            }
            after 2000
            if {[catch {exec cavput -pend=5 -list=${IDName}:Start=1} result]} {
                catch {exec cavput -list=ID:AccessSecurity=$lastSecurity}
                eval $errorCallback
                catch {exec kill -STOP $smPID}
                return -code error "$result"
            }
            set retries $retriesToUse
            catch {exec cavget -list=$IDName:Gap} lastGap
            while {$retries} {
                incr retries -1
                catch {exec cavput -pend=5 -list=${IDName}:Start=1}
                APSWaitWithUpdate -waitSeconds 5 -updateInterval 1
                if [catch {exec cavget -pend=5 -list=$IDName:Gap} gapNow] {
                    catch {exec cavput -list=ID:AccessSecurity=$lastSecurity}
                    eval $errorCallback
                    catch {exec kill -KILL $smPID}
                    return -code error "$gapNow"
                }
                if {[string length $abortVariable] && [subst \$$abortVariable]} {
                    eval $statusCallback {"Aborting measurement of $IDName"}
                    set $abortVariable 0
                    break
                }
                if [expr abs($gapNow-$gapToUse)<0.01] {
                    break
                }
                if [expr abs($lastGap-$gapNow)<0.1] {
                    # must move at least 0.1mm in 5 seconds
                    set retries 0
                }
                set lastGap $gapNow
            }
            if !$retries {
                eval $statusCallback {"$IDName didn't move or didn't close in the allotted time."}
                eval $statusCallback {"Will assume that it is nonfunctional."}
                if [catch {exec cavput -list=$IDName:GapSet=$startingGap
                    after 1000
                    exec cavput -list=$IDName:Start=1} result] {
                    catch {exec cavput -list=ID:AccessSecurity=$lastSecurity}
                    eval $errorCallback
                    catch {exec kill -KILL $smPID}
                    return -code error "Unable to open $IDName: $result"
                }
            } else {
                if [catch {exec kill -CONT $smPID} result] {
                    catch {exec cavput -list=ID:AccessSecurity=$lastSecurity}
                    eval $errorCallback
                    catch {exec kill -KILL $smPID}
                    return -code error $result
                }
                eval $statusCallback {"Taking data..."}
                APSWaitWithUpdate -waitSeconds $timeToWait -updateInterval 1
                eval $statusCallback {"Data taking done for $IDName."}
                catch {exec kill -STOP $smPID}
            }
        }
        if {[string length $abortVariable] && [subst \$$abortVariable]} {
            eval $statusCallback {"Measurement aborted."}
        } else {
            eval $statusCallback {"Measurement done."}
        }
    } else {
        eval $statusCallback {"Data already exists with that name."}
    }
    catch {exec kill -KILL $smPID}
    if [catch {exec cavput -list=ID:AccessSecurity=$lastSecurity} result] {
        eval $errorCallback
        catch {exec kill -KILL $smPID}
        return -code error "Unable to return access security to previous mode ($lastSecurity): $result"
    }
}

proc APSIDMoveGapsToMaximum {args} {
    set IDList ""
    set retriesToUse 30
    set maximum 0
    APSStrictParseArguments {IDList returnAbove retriesToUse maximum}

    # open gaps
    if [catch {exec cavget -pend=5 -list=ID -list=[join $IDList ,] \
                 -list=:FullOpenGap -label \
                 | sed -e s/FullOpenGap/GapSet/} fullGapList] {
        return -code error "$result"
    }
    set maxIndex [llength $fullGapList]
    set IDList ""
    set maxGapList ""
    for {set index 0} {$index<$maxIndex} {incr index 2} {
        set name [lindex $fullGapList $index]
        set value [lindex $fullGapList [expr $index+1]]
        if [string compare $value ?]==0 continue
        if {$maximum!=0} {
            set value $maximum
        } 
        lappend maxGapList $value
        regsub FullOpenGap $name GapSet name
        lappend gapSetList $name=$value
        regsub :GapSet $name "" name
        regsub ID $name "" name
        lappend IDList $name
    }
    if [catch {exec cavput -list=[join $gapSetList ,] 
        exec cavput -pend=5 -list=ID -list=[join $IDList ,] \
                 -list=:Start=1} result] {
        return -code error "$result"
    }
    
    # wait for gaps to exceed $returnAbove
    set first 1
    set index -1
    foreach ID $IDList {
        incr index 1
        lappend cawaitOption -waitFor=ID${ID}:Gap,above=[expr [lindex $maxGapList $index]-0.01]
        if !$first {
            lappend cawaitOption -and
        }
        set first 0
    }
    set retries $retriesToUse
    while {$retries} {
        incr retries -1
        APSWaitWithUpdate -waitSeconds 10 -updateInterval 1
        if ![catch {eval exec cawait $cawaitOption} result] {
            return 
        }
        catch {exec cavput -pend=5 -list=ID -list=[join $IDList ,] -list=:Start=1}
    }
    return -code error "Gaps didn't open in allotted time."
}

