#!/bin/sh
# \
exec oagwish8.5 "$0" "$@"

# $Log: not supported by cvs2svn $
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 args $argv
set allowAllSectors 0
set timeDebug 0
set ignoreLock 0
APSStrictParseArguments {allowAllSectors ignoreLock}
set CVSRevisionAuthor "\$Revision: 1.0 $ \$Author: shang $"

#if [regexp {.0} $env(DISPLAY)] {
#    set otherDisplay :0.1
#} else {
    set otherDisplay :0.0
#}

APSApplication . -name APSUIDSteering \
  -overview "provides convenience controls for ID steering."

set tcl_precision 6

set IDSteeringStatus Ready.
APSScrolledStatus .status -parent .userFrame -width 60\
        -textVariable IDSteeringStatus 

proc SetIDSteeringStatus {text} {
    global IDSteeringStatus
    set IDSteeringStatus "[clock format [clock seconds] -format %H:%M:%S]: $text"
    update
#    bell
}

proc EnableDisableSectors {args} {
    global IDSteering allowAllSectors

    for {set sector 1} {$sector<=40} {incr sector} {
	set sectorf [format %02d $sector]
	if [lsearch -exact $IDSteering(sectorList) $sector]<0 {
	    if !$allowAllSectors {
		APSDisableButton $IDSteering(S$sectorf.button)
	    } else {
		APSEnableButton $IDSteering(S$sectorf.button)
	    }
	}
    }
}

proc MakeSectorsWidget {widget args} {
    global IDSteering allowAllSectors

    set parent ""
    APSParseArguments {parent}
    
    set IDSteering(deltaLimit) 5
    set IDSteering(waitTime) 1
   
    set w $parent$widget
    APSFrame $widget -parent $parent \
      -label "Storage Ring ID selection for steering." \
      -contextHelp {ID selection frame} 

    if !$allowAllSectors {
        set sectorList $IDSteering(sectorList)
    }
    
    for {set quad 1} {$quad<5} {incr quad} {
        set start [expr ($quad-1)*10+1]
        set end   [expr $start+9]
        set buttonList {}
        set valueList {}
        APSFrame .sector$quad -parent $w.frame 
        $w.frame.sector$quad.frame configure -relief flat
        for {set sector $start} {$sector<=$end} {incr sector} {
            set cbLabel $sector
            if {$sector<10} {set cbLabel "0$sector"}
            APSButton .sector$sector -parent $w.frame.sector$quad.frame \
              -text "$cbLabel" \
              -command "IDSteeringDialog -sector $sector" \
              -contextHelp "Brings up dialog box for ID$cbLabel steering."
	    set IDSteering(S[format %02d $sector].button) $w.frame.sector$quad.frame.sector$sector.button
            if !$allowAllSectors {
                if [expr -1 == [lsearch $sectorList $sector]] {
                    APSDisableButton $w.frame.sector$quad.frame.sector$sector.button
                }
            }
        }
    }
    global allowAllSectors
    APSRadioButtonFrame .all -parent $parent -label "Allow all sectors?" -buttonList {Yes No} -orientation horizontal \
	-valueList {1 0} -variable allowAllSectors -commandList {EnableDisableSectors EnableDisableSectors}
    set width 10
 #   APSLabeledEntry .delta -parent $parent -label "Corrector change limit(A):" -width $width -textVariable IDSteering(deltaLimit)
   # APSLabeledEntry .waittime -parent $parent -label "Wait time between steps in changing correctors (seconds):" \
#	-textVariable IDSteering(waitTime) -width $width
    APSFrame .adt -parent $parent
    APSButton .adt -parent $parent.adt.frame -text "SR BPM AdjustedCC ADT (difference mode)" \
	-command "exec adt -f /home/helios/OAG/oagData/ADTFiles/srBpm/sr.bpm.lowPass1s.adjusted.pv -a /home/helios/OAG/oagData/ADTFiles/srBpm -z 3 -d  &"
    
}


set tmpRoot /tmp/[APSTmpString]
proc IDSteeringDialog {args} {
    global IDSteering timeDebug otherDisplay errorCode tmpRoot

    set sector ""
    APSParseArguments {sector}
    if ![string length $sector] {
        APSAlertBox [APSUniqueName .] -errorMessage \
          "No sector variable specified in IDSteeringDialog"
        return 1
    }
    set sectorf [format %02d $sector]
    
    if !$IDSteering(S$sectorf.configLoaded) {
	if [catch {LoadIDSteeringConfig -sector $sector} result] {
	    APSAlertBox .alert -errorMessage "Error loading config for S$sectorf: $result"
	    exit
	}
	set IDSteering(S$sectorf.configLoaded)  1
    }
    set border 2
    set dialogFrame .dialogID$sector.userFrame
    APSDialogBox .dialogID$sector  \
	-name "ID$sector Dialog" \
	-contextHelp "Dialog box for steering in ID$sector." 
    
    
    APSFrame .parameters -parent $dialogFrame 
    $dialogFrame.parameters.frame configure -relief flat
    
    set w $dialogFrame.parameters.frame
    APSFrameGrid .grid -parent $w -xList {x1 x2}
    set w1 $w.grid.x1
    set w2 $w.grid.x2
    set width 15
    foreach plane {x y} win [list $w1 $w2] {
	APSLabel .l1 -parent $win -text "     $plane plane bpm setpoint"
	set i  0
	foreach bpm $IDSteering(S$sectorf.$plane.bpmList) {
	    APSLabeledOutput .bpm$i -parent $win -label "[format %10s $bpm] setpoint(um)  " -width $width \
		-textVariable IDSteering(S$sectorf.$plane.$bpm.var) 
	    incr i
	}
	APSLabel .l -parent $win -text ""
	APSLabel .l2 -parent $win -text "     $plane plane corr setpoint"
	set i 0
	foreach corr $IDSteering(S$sectorf.$plane.corrList) {
	    APSLabeledOutput .corr$i -parent $win -label "[format %10s $corr] setpoint(A)  " -width $width \
		-textVariable IDSteering(S$sectorf.$plane.$corr.var) 
	    incr i
	}
    }
    
    APSFrame .exec -parent $dialogFrame -label "Steering(Knob) execution"
    set w $dialogFrame.exec.frame
    APSLabel .t -parent $w -text "                                               Status     StepSize     SteeredValue  LowLimit   HighLimit"
    foreach type {x xp y yp} units {um urad um urad} {
	set label "$type ($units):"
	set IDSteering(S$sectorf.$type.steerButtons) ""
	#APSLabeledOutput .$type -parent $w -label "[format %20s $label]" -textVariable IDSteering(S$sectorf.x.knobAccu) -width $width
	
	APSLabeledEntryFrame .$type -parent $w -label "[format %20s $label]" -orientation horizontal -variableList \
	    [list IDSteering(S$sectorf.$type.status) IDSteering(S$sectorf.$type.StepSize) IDSteering(S$sectorf.$type.readback) IDSteering(S$sectorf.$type.llimit) IDSteering(S$sectorf.$type.hlimit)] -width 12
															
	APSButton .add -parent $w.$type -packOption "-side right" -text "->" -command "ChangeKnob -value 1 -sector $sector -type $type" \
	    -contextHelp "steer $type by 1 $units"
	lappend IDSteering(S$sectorf.$type.steerButtons) $w.$type.add.button
	APSButton .zero -parent $w.$type -packOption "-side right" -text "zero" -command "ChangeKnob -value zero -sector $sector -type $type"
	lappend IDSteering(S$sectorf.$type.steerButtons) $w.$type.zero.button
	APSButton .minus -parent $w.$type -packOption "-side right" -text "<-" -command "ChangeKnob -value -1  -sector $sector -type $type" \
	    -contextHelp "steer $type by -1 $units"
	lappend IDSteering(S$sectorf.$type.steerButtons) $w.$type.minus.button
	APSButton .show -parent $w.$type -packOption "-side right" -text "$IDSteering(S$sectorf.$type.knobName)"  -highlight 1 -highlightColor blue  \
	    -command "ShowKnob -sector $sector -type $type" -contextHelp "display the knob structure."
    }
}


proc LoadIDSteeringConfig {args} {
    set sector ""
    APSParseArguments {sector}
    global IDSteering tmpRoot errorCode
    set sectorf [format %02d $sector]
    set IDSteering(S$sectorf.configFile) /home/helios/oagData/sr/knobs/IDbump/lattices/default/ID${sectorf}.cokn
    SetIDSteeringStatus "Loading S$sectorf config... "
    SetIDSteeringStatus "Loading S$sectorf config (file $IDSteering(S$sectorf.configFile) )... "
    set file $IDSteering(S$sectorf.configFile)
    set pages [exec sdds2stream -npages=bar $file]
    set parnames [exec sddsquery -par $file]
    set otherPVList ""
    set otherVarList ""
    for {set page 1} {$page<=$pages} {incr page} {
	set type [exec sdds2stream -page=$page -par=KnobType $file]
	if [catch {exec sddsconvert $file -pipe=out -from=$page -to=$page \
		       | tee $tmpRoot.S$sectorf.$type.config \
		       | sddsprintout -pipe=in $tmpRoot.S$sectorf.$type.print \
		       -par=ControlName,label=KnobName -par=KnobType,label=SteeringType \
		       -col=ControlName,format=%30s -col=Weight,format=%15.6f } result] {
	    return -code error "Error printing file: $result"
	}
	APSAddToTmpFileList -ID idstring -fileList "$tmpRoot.S$sectorf.$type.print $tmpRoot.S$sectorf.$type.config"
	if [lsearch -exact "Gain" $parnames]>=0 {
	    IDSteering(S$sectorf.$type.gain) [exec sdds2stream -par=Gain -page=$page $file]
	} else {
	    set IDSteering(S$sectorf.$type.Gain) 1.0
	}
	if [lsearch -exact  $parnames "StepSize"]>=0 {
	    set IDSteering(S$sectorf.$type.StepSize) [format %.1f [exec sdds2stream -par=StepSize -page=$page $file]]
	} else {
	    set IDSteering(S$sectorf.$type.StepSize) 5.0
	}
	
	set IDSteering(S$sectorf.$type.config) $tmpRoot.S$sectorf.$type.config
	set IDSteering(S$sectorf.$type.setPV) [exec sdds2stream -par=SetValuePV -page=$page $file]
	set IDSteering(S$sectorf.$type.readbackPV) [exec sdds2stream -par=SetRbvPV -page=$page $file]
	set IDSteering(S$sectorf.$type.statusPV) [exec sdds2stream -par=SetStatusPV -page=$page $file]
	set IDSteering(S$sectorf.$type.modePV) [exec sdds2stream -par=SetModePV -page=$page $file]
	set IDSteering(S$sectorf.$type.knobName) [exec sdds2stream -par=ControlName -page=$page $file]
	set IDSteering(S$sectorf.$type.deltaPV) [exec sdds2stream -par=SetValueLimitPV -page=$page $file]
	lappend otherPVList $IDSteering(S$sectorf.$type.setPV)
	lappend otherVarList IDSteering(S$sectorf.$type.set)
	lappend otherPVList $IDSteering(S$sectorf.$type.readbackPV)
	lappend otherVarList IDSteering(S$sectorf.$type.readback)
	lappend otherPVList $IDSteering(S$sectorf.$type.statusPV)
	lappend otherVarList IDSteering(S$sectorf.$type.status)
	lappend otherPVList $IDSteering(S$sectorf.$type.modePV)
	lappend otherVarList IDSteering(S$sectorf.$type.mode)
	lappend otherPVList $IDSteering(S$sectorf.$type.deltaPV)
	lappend otherVarList IDSteering(S$sectorf.$type.delta)
#	set IDSteering(S$sectorf.$type.knobAccu) 0
	
	set IDSteering(S$sectorf.$type.print) $tmpRoot.S$sectorf.$type.print
	set IDSteering(S$sectorf.$type.pvList) [join [exec sdds2stream -col=ControlName -page=$page $file]]
	set IDSteering(S$sectorf.$type.weightList) [join [exec sdds2stream -col=Weight -page=$page $file]]
	set deviceList [join [exec sdds2stream -col=DeviceName -page=$page $file]]
	set IDSteering(S$sectorf.$type.deviceList) [lsort $deviceList]
	#x and xp use the same pvs, but different coefficients
	#y and yp use the same pvs, but different coefficients
	foreach device $deviceList weight $IDSteering(S$sectorf.$type.weightList) {
	    set IDSteering(S$sectorf.$type.$device.weight) $weight
	}
	
	if {$type=="x" || $type=="y"} {
	    set varList ""
	    set bpmList ""
	    set corrList ""
	    foreach pv $IDSteering(S$sectorf.$type.pvList) device $deviceList {
		lappend varList IDSteering(S$sectorf.$type.$device.var)
		if [regexp "CurrentC" $pv] {
		    lappend corrList $device
		} else {
		    lappend bpmList $device
		}
	    }
	    set IDSteering(S$sectorf.$type.bpmList) $bpmList
	    set IDSteering(S$sectorf.$type.corrList) $corrList
	    set IDSteering(S$sectorf.$type.varList) $varList
	    if [pv linkw $varList $IDSteering(S$sectorf.$type.pvList) 30] {
		return -code error "Error link pvs: $errorCode"
	    }
	    pv getw $varList
	}
    }
    
    foreach plane {x y} {
	if {$IDSteering(S$sectorf.$plane.deviceList)!=$IDSteering(S$sectorf.${plane}p.deviceList)} {
	    return -code error "Error the device list of $plane and ${plane}p are not the same: $result"
	}
    }
     foreach plane {x y} {
	foreach bpm $IDSteering(S$sectorf.$plane.bpmList) {
	    if [pv umon IDSteering(S$sectorf.$plane.$bpm.var)]!=0 {
		APSAlertBox .alert -errorMessage "umon error $errorCode"
		exit
	    }
	}
	foreach corr $IDSteering(S$sectorf.$plane.corrList) {
	    if [pv umon IDSteering(S$sectorf.$plane.$corr.var)]!=0 {
		APSAlertBox .alert -errorMessage "umon error $errorCode"
		exit
	    }
	}
    }
    
   # pv linkw $otherVarList $otherPVList 
    set errorCode ""
    if [pv linkw $otherVarList $otherPVList 30] {
	APSAlertBox .alert -errorMessage "pv linkw error: $errorCode; you need check if the steering server is started for sector $sectorf."
	SetIDSteeringStatus "Knob creating for S$sectorf failed, you need check if the steering server is started for sector $sectorf."
        puts stderr "pv linkw error: $errorCode; you need check if the steering server is started for sector $sectorf."
        puts stderr "doing some cavget"
        puts stderr "[exec cavget -list=[join $otherPVList ,] -label]"
    } else {
	SetIDSteeringStatus "set knob mode to delta mode..."
	foreach type {x xp y yp} {
	    set IDSteering(S$sectorf.$type.mode) add
	    set IDSteering(S$sectorf.$type.mode) 0
	    pv putw IDSteering(S$sectorf.$type.mode)
	    if [pv umon IDSteering(S$sectorf.$type.readback)]!=0 {
		APSAlertBox .alert -errorMessage "umon error for IDSteering(S$sectorf.$type.readback)  $errorCode"
		exit
	    }
	    if [pv umon IDSteering(S$sectorf.$type.status)]!=0 {
		APSAlertBox .alert -errorMessage "umon error for IDSteering(S$sectorf.$type.status)  $errorCode"
		exit
	    }
	    set hLimit [exec cavget -list=$IDSteering(S$sectorf.$type.readbackPV).DRVH -pend=10]
	    set lLimit [exec cavget -list=$IDSteering(S$sectorf.$type.readbackPV).DRVL -pend=10]
	    set IDSteering(S$sectorf.$type.hlimit) $hLimit
	    set IDSteering(S$sectorf.$type.llimit) $lLimit
	    
	}
    }
    #reading steering limit
    
    SetIDSteeringStatus "S$sectorf config loaded"
    set IDSteering(S$sectorf.configLoaded) 1
}


proc ShowKnob {args} {
    set sector ""
    set type ""
    APSParseArguments {sector type} 
    global IDSteering
    set sectorf [format %02d $sector]
    set file $IDSteering(S$sectorf.$type.print)
     APSFileDisplayWindow [APSUniqueName .] \
      -fileName $file -deleteOnClose 0 -height 15 \
      -comment "$IDSteering(S$sectorf.$type.knobName) structure"
}


proc EnableDisableSteerButton {args} {
    set sector ""
    set type ""
    set disable 0
    APSParseArguments {sector type disable}
    global IDSteering
    set sectorf [format %02d $sector]
    foreach button $IDSteering(S$sectorf.$type.steerButtons) {
	if $disable {
	    APSDisableButton $button
	} else {
	    APSEnableButton $button
	}
    }
}

proc ChangeKnob {args} {
    set sector ""
    set type ""
    set value ""
    APSParseArguments {sector type value}

    EnableDisableSteerButton -sector $sector -type $type -disable 1
    global IDSteering
    set sectorf [format %02d $sector]
    pv getw IDSteering(S$sectorf.$type.readback)
    set hLimit $IDSteering(S$sectorf.$type.hlimit)
    set lLimit $IDSteering(S$sectorf.$type.llimit)
    
    set value0 $IDSteering(S$sectorf.$type.readback)
    if {$value=="zero"} {
	#remove all changes, zero steering
	set value [expr -1.0*$value0]
    } else {
	set value [expr $IDSteering(S$sectorf.$type.Gain)*$IDSteering(S$sectorf.$type.StepSize)*$value]
    }
    set newValue [expr $value0 + $value]
    if {$newValue<$lLimit || $newValue > $hLimit} {
	SetIDSteeringStatus "Steering request for Sector $sector $type is out of range! Only partial steering will be performed"
	set waitfor 3
	set waitfor "all good"
    } else {
	set waitfor "all good"
    }
    set IDSteering(S$sectorf.$type.set) $value
    pv putw IDSteering(S$sectorf.$type.set)
    after 3000
    update
    #wait for status
   # puts "wait for status : $waitfor"
   # exec cawait  -timeLimit=20 -waitFor=$IDSteering(S$sectorf.$type.statusPV),equalTo=$waitfor
    pv getw IDSteering(S$sectorf.$type.delta)
    update
    
    for {set i 0} {$i<300} {incr i} {
	pv getw IDSteering(S$sectorf.$type.status)
	SetIDSteeringStatus "$IDSteering(S$sectorf.$type.status)"
	update
	if {$IDSteering(S$sectorf.$type.status)==$waitfor} {
	    break
	}
	if {$IDSteering(S$sectorf.$type.status)=="updating"} {
	    after 1000
	    update
	} else {
	    break
	}
    }
    pv getw IDSteering(S$sectorf.$type.readback)
    pv getw IDSteering(S$sectorf.$type.status)
    update
    set value1 [expr $IDSteering(S$sectorf.$type.readback)-$value0]
    SetIDSteeringStatus "steering S$sectorf $type status: $IDSteering(S$sectorf.$type.status)"
    if {$waitfor==0 && $value!=$value1} {
	SetIDSteeringStatus "S$sector $type steering failed: setpoint and readback do not agree"
	APSAlertBox .alert -errorMessage "S$sector $type steering failed: setpoint and readback do not agree"
    } else {
	#set IDSteering(S$sectorf.$type.knobAccu) [expr $IDSteering(S$sectorf.$type.knobAccu) + $value]
	if [regexp {p} $type] {
	    set unit urad
	} else {
	    set unit um
	}
	SetIDSteeringStatus "S$sectorf $type has been steered for $IDSteering(S$sectorf.$type.readback) $unit now."
    }
    EnableDisableSteerButton -sector $sector -type $type -disable 0
    return
   
}



set IDSteering(sectorList) ""
if !$allowAllSectors {
    set sectorList  [join [exec sdds2stream -col=Sector /home/helios/oagData/sr/IDs/sectors.sdds]]
    lappend sectorList 28
    lappend sectorList 29   
    set IDSteering(sectorList) [lsort -integer $sectorList]
}

for {set sector 1} {$sector<=40} {incr sector} {
    set sectorf [format %02d $sector]
    set IDSteering(S$sectorf.configLoaded) 0
    if $allowAllSectors {
	lappend IDSteering(sectorList) $sector
    }
}


MakeSectorsWidget .sectors -parent .userFrame


return
