
proc APSSRAcquireSlowHistories {args} {
    set startSector 1
    set endSector 40
    set sectorList ""
    set BPM B:P1
    set BPMList ""
    set historyBufferSize 4080 
    set acquisitionPlane *
    set outputFile ""
    set statusCallback APSNoOp
    set abortVariable ""
    set excludeScalars 0
    APSStrictParseArguments {sectorList startSector endSector BPM historyBufferSize acquisitionPlane outputFile \
                               statusCallback abortVariable BPMList excludeScalars}

    if {![llength [info commands blt::bgexec]]} {
	lappend auto_path $blt_library
	package require BLT
	global blt_library
    }
    if [string length [info command blt::bgexec]] {
        set execCmd "blt::bgexec dummy"
    } else {
        set execCmd exec
    }

    if [string length $abortVariable] {
        global $abortVariable
    }
    if ![string length $outputFile] {
        return -code error "APSSRAcquireSlowHistories: no output filename given"
    }
    if $historyBufferSize>4080 {
        set historyBufferSize 4080
    }
    if ![llength $BPMList] {
        if ![llength $sectorList] {
            if $startSector<1 {
                set startSector 1
            }
            if $endSector>40 {
                set endSector 40
            }
            if $startSector>$endSector {
                return -code error "APSSRAcquireSlowHistories: startSector>endSector"
            }
            for {set sector $startSector} {$sector<=$endSector} {incr sector} {
                lappend sectorList $sector
            }
        }
    }
    if {[string length $abortVariable] && [set $abortVariable]} {
        eval $statusCallback {"Aborting..."}
        return -code error "APSSRAcquireSlowHistories: aborted"
    }
    eval $statusCallback {"Configuring hardware..."}
    set setupDir /home/helios/oagData/monitorFiles/sr
    set RTFBScalars /home/helios/oagData/monitoring/RTFBStatus/RTFBStatus.mon
    set tmpRoot /tmp/[APSTmpString]

    # prepare lists for use with cavput commands, plus a file to use in
    # extracting PV names etc. from a sddswmonitor template file
    set SbpmList {}
    set targetList {}
    set selectionFile $tmpRoot.1 
    APSAddToTempFileList $tmpRoot.1
    set sFID [open $selectionFile w]
    puts $sFID "SDDS1\n&column name=BPMName type=string &end\n&data mode=ascii no_row_counts=1 &end"
    if ![llength $BPMList] {
        set BPMList {}
        foreach sector $sectorList {
            lappend SbpmList S:bpm$sector
            lappend BPMList S${sector}$BPM
            lappend targetList S:bpm${sector}=S${sector}$BPM
            # output twice to get x and y plane 
            puts $sFID "S${sector}$BPM"
            puts $sFID "S${sector}$BPM"
        }
    } else {
        foreach item $BPMList {
            scan $item "S%ld" sector
            lappend SbpmList S:bpm$sector
            lappend targetList S:bpm${sector}=$item
            lappend sectorList $sector
            # output twice to get x and y plane 
            puts $sFID $item
            puts $sFID $item
        }
    }
    flush $sFID    
    close $sFID
    
    # make the sddswmonitor input file 
    set inputFile $tmpRoot.2
    APSAddToTempFileList $tmpRoot.2
    if [catch {eval $execCmd sddsxref $selectionFile \
                 $setupDir/SRAcquireSlowHistory.xref -pipe=out \
                 -match=BPMName \
                 | sddsprocess -pipe=in $inputFile \
                 -match=column,Plane=$acquisitionPlane \
                 -define=param,WaveformLength,$historyBufferSize,type=long} result] {
        return -code error "APSSRAcquireSlowHistories: Problem making input file: $result"
    }

    # target the slow histories to the desired BPM
    if [catch {eval $execCmd cavput -list=[join $targetList ,] -list=:SlowBh:MI.VAL \
                 -pendIoTime=20} result] {
        return -code error "APSSRAcquireSlowHistories: $result"
    }

    # set the memory scanners and SCDUs
    if {[catch {eval $execCmd cavput -list=[join $BPMList ,] -list=:lock_bo=0 -pendIoTime=20} result] || \
          [catch {eval $execCmd cavput -list=S:bpm:memscan_wt_ao=11 \
                    -pendIoTime=20} result] || \
          [catch {eval $execCmd cavput -list=[join $BPMList ,] -list=:disablex_bo=0,:disabley_bo=0 \
                    -pendIoTime=20} result]} {
        return -code error "APSSRAcquireSlowHistories: $result"
    }

    # set up the history buffers and controls
    if {[catch {eval $execCmd cavput -list=[join $SbpmList ,] \
                  -list=:SlowBh: -list=modeBO=1,enableBO=1,sizeAO=$historyBufferSize \
                  -pendIoTime=20} result] } {
        return -code error "APSSRAcquireSlowHistories: $result"
    }

    # read the sample rate and units
    set Rate [eval $execCmd cavget -list=S:bpm[lindex $sectorList 0]:SlowBh \
                -list=:SampleRateAI,:SampleRateAI.EGU -delim=:]
    set RateUnits [lindex [split $Rate :] 1]
    set Rate [lindex [split $Rate :] 0]

    if {[string length $abortVariable] && [set $abortVariable]} {
        eval $statusCallback {"Aborting..."}
        return -code error "APSSRAcquireSlowHistories: aborted"
    }
    eval $statusCallback {"Triggering hardware...[join $SbpmList ,]"}
    # arm (trigger) the histories
    if [catch {eval $execCmd cavput -list=[join $SbpmList ,] \
                 -list=:SlowBh:ArmResetBO=1 -pend=20} result] {
        return -code error "APSSRAcquireSlowHistories: problem arming histories: $result"
    }

    # prepare a cawait command to wait for histories to fill
    set cawaitOption ""
    set first 1
    foreach element $SbpmList {
        set cawaitOption "$cawaitOption -waitFor=$element:SlowBh:xBF.BFUL,equalTo=1"
        if !$first {
            set cawaitOption "$cawaitOption -and"
        }
        set first 0
    }

    # wait for histories to fill
    set tryLimit 30
    for {set try 0} {$try<$tryLimit} {incr try} {
        eval $statusCallback {"Waiting for histories to fill....($try)"}
        if {[string length $abortVariable] && [set $abortVariable]} {
            eval $statusCallback {"Aborting..."}
            return -code error "APSSRAcquireSlowHistories: aborted"
        }
        if [catch {eval $execCmd cawait $cawaitOption -interval=1 -timeLimit=5} result] {
            continue
        } else {
            break
        }
    }
    if $try==$tryLimit {
        eval $statusCallback {"Timeout waiting for histories to fill."}
        return -code error "APSSRAcquireSlowHistories: Timeout waiting for histories to fill."
    }

    # acquire the data 
    set tmpFile $tmpRoot.3
    APSAddToTempFileList $tmpRoot.3
    set tryLimit 30
    if !$excludeScalars {
        set scalarsOption -scalar=$RTFBScalars
    } else {
        set scalarsOption ""
    }
    for {set try 0} {$try<$tryLimit} {incr try} {
        eval $statusCallback {"Trying to downloading data..."}
        if [catch {eval $execCmd sddswmonitor $inputFile $tmpFile -step=1 $scalarsOption \
                     -ezcaTiming=0.01,250 -erase \
                 } result] {
            eval $statusCallback {"APSSRAcquireSlowHistories: Problem acquiring: $result"}
            after 1000
        } else {
            break;
        }
    }
    if {$try==$tryLimit} {
        return -code error "APSSRAcquireSlowHistories: unable to download data after $tryLimit attempts."
    }
    if {[string length $abortVariable] && [set $abortVariable]} {
        eval $statusCallback {"Aborting..."}
        return -code error "APSSRAcquireSlowHistories: aborted"
    }

    # do some modest processing
    eval $statusCallback {"Data downloaded....postprocessing."}
    if [string compare $RateUnits Hz]==0 {
        set inverseRateUnits s
    } else {
        set inverseRateUnits 1/$RateUnits
    }
    if [catch {eval $execCmd sddsprocess $tmpFile $outputFile \
                 {"-define=param,Rate,$Rate,units=$RateUnits"} \
                 {"-define=column,t,Index Rate /,units=$inverseRateUnits,type=float"} \
                 -nowarning} result] {
        return -code error "APSSRAcquireSlowHistories: Problem postprocessing: $result"
    }
}

proc APSProcessSlowHistoryData {args} {
    set inputFile ""
    set outputFile ""
    set rmsOnly 0
    set useMedian 0
    APSStrictParseArguments {inputFile outputFile rmsOnly useMedian}
    
    if {![llength [info commands blt::bgexec]]} {
	lappend auto_path $blt_library
	package require BLT
	global blt_library
    }
    if [string length [info command blt::bgexec]] {
        set execCmd "blt::bgexec dummy"
    } else {
        set execCmd exec
    }

    if {![string length $inputFile] || ![file exists $inputFile]} {
        return -code error "APSProcessSlowHistoryData: no inputFile or nonexistent inputFile"
    }
    if ![string length $outputFile] {
        if !$rmsOnly {
            return -code error "APSProcessSlowHistoryData: no outputFile given"
        }
        set outputFile /tmp/[APSTmpString]
        APSAddToTempFileList $outputFile
    }
    set procMode mean
    if $useMedian {
        set procMode median
    }
    if [catch \
          {eval $execCmd sddsfft $inputFile -pipe=out -column=t,*:* -psd \
             -suppressaverage \
             | sddsconvert -pipe -delete=column,FFT* \
             | sddsxref -pipe $inputFile -leave=* -transfer=parameter,* \
             | sddsrowstats -pipe \
             -${procMode}=xPSD,PSD*x -${procMode}=yPSD,PSD*y \
             | sddsconvert -pipe -delete=column,PSD* \
             | sddsprocess -pipe=in $outputFile \
             -process=*PSD,sum,%sSum \
             {"-redefine=parameter,HLoopClosedGlobal,HLoopClosedGlobal"} \
             {"-redefine=parameter,VLoopClosedGlobal,VLoopClosedGlobal"} \
             {"-redefine=column,xPSD,xPSD,units=mm\$a2\$n/Hz,symbol="} \
             {"-redefine=column,yPSD,yPSD,units=mm\$a2\$n/Hz,symbol="} \
             {"-define=parameter,xRMS,xPSDSum fftFrequencySpacing * sqrt,units=mm"} \
             {"-define=parameter,yRMS,yPSDSum fftFrequencySpacing * sqrt,units=mm"} \
             {"-define=parameter,xRMSum,xRMS 1e3 *,units=um"} \
             {"-define=parameter,yRMSum,yRMS 1e3 *,units=mm"} \
             -print=parameter,xFBStatusString,%.0lf,HLoopClosedGlobal \
             -print=parameter,yFBStatusString,%.0lf,VLoopClosedGlobal \
             -reedit=parameter,xFBStatusString,%/0/Off/%/1/On/ \
             -reedit=parameter,yFBStatusString,%/0/Off/%/1/On/ \
             {"-print=parameter,xLabel,RMS x motion is %.3lfum  Feedback %s,xRMSum,xFBStatusString"} \
             {"-print=parameter,yLabel,RMS y motion is %.3lfum  Feedback %s,yRMSum,yFBStatusString"} \
         } result] {
        return -code error "APSProcessSlowHistoryData: $result"
    }
    if $rmsOnly {
        if [catch {eval $execCmd sdds2stream -parameter=xRMSum,yRMSum $outputFile} result] {
            return -code error "APSProcessSlowHistoryData: $result"
        }
        return $result
    }
}
