#
# $Log: not supported by cvs2svn $
# Revision 1.21  2003/12/17 18:31:30  soliday
# timeouts of zero now convert to 30 seconds for linking and asynchronous pv put calls.
#
# Revision 1.20  2003/12/17 04:32:47  soliday
# Changed timeout to 30 seconds because multiple timeouts have occured today.
#
# Revision 1.19  2001/09/04 17:33:45  soliday
# Made a generic procedure to connect to various device config PVs.
#
# Revision 1.18  2001/02/06 19:44:27  soliday
# Fixed some tcl warning messages found with procheck
#
# Revision 1.17  2000/08/29 00:26:43  borland
# Sets missingPV list properly for devices with multiple PVs.
#
# Revision 1.16  2000/06/12 19:03:00  soliday
# Added cavput option for APSDevSend
#
# Revision 1.15  2000/06/12 18:37:15  borland
# Added some more debugging printouts.
#
# Revision 1.14  2000/05/02 19:56:57  borland
# Improved debug printouts.
#
# Revision 1.13  2000/05/02 19:43:56  borland
# Added APSDevSendDebug flag.
#
# Revision 1.12  2000/05/02 15:42:15  soliday
# Added nq for a inverse query command.
#
# Revision 1.11  2000/03/02 18:46:54  soliday
# It now checks for a pvTable.tcl file to source in. This increases the loading
# speed.
#
# Revision 1.10  1999/11/15 20:44:04  borland
# Temporary files are now cleaned up using APSAddToTmpFileList.
#
# Revision 1.9  1999/08/26 19:39:57  soliday
# releaseLinks defaults to 0
#
# Revision 1.8  1999/08/26 19:34:42  borland
# Final version with -releaseLInks option for APSDevSend.
#
# Revision 1.7  1999/08/26 17:06:26  borland
# Added APSDevSendHelp.
#
# Revision 1.6  1999/08/26 16:59:42  borland
# Added -returnPVList option to APSDevSend.
#
# Revision 1.5  1999/08/23 19:04:51  borland
# Added comments to explain the array used for storing device info.
#
# Revision 1.4  1999/08/23 16:53:36  borland
# Output operations now work with pv linking just before putting.
#
# Revision 1.3  1999/08/23 15:56:21  borland
# Temporary fix for problems with link just before get/put.
#
# Revision 1.2  1999/08/06 19:04:58  borland
# Added timeout control.  Now does groups of puts if several PVs are listed
# for a device.
#
# Revision 1.1  1999/08/04 18:00:38  borland
# First version of APSDevSend and related procedures.
#
#

set APSDevSendDebug 0

set apsDeviceConfigDir /home/helios/oagData/deviceConfig
proc APSLinkToDeviceConfigPVs {args} {
    global apsDeviceConfigDir
    set device linac
    APSStrictParseArguments {device}
    set fileList [glob -nocomplain $apsDeviceConfigDir/${device}/*.pvTable] 
    if {[file exists [file join $apsDeviceConfigDir ${device} pvTable.tcl]]} {
        set modTime [file mtime [file join $apsDeviceConfigDir ${device} pvTable.tcl]]
        set upToDate 1
        foreach file $fileList {
            set link 1
            while {$link} {
                if {[file type $file] == "link"} {
                    set file [file join [file dirname $file ] [file readlink $file]]
                } else {
                    set link 0
                }
            }
            if {[file mtime $file] > $modTime} {
                set upToDate 0
                break
            }
        }
        if {$upToDate} {
            if [catch {source [file join $apsDeviceConfigDir ${device} pvTable.tcl]} result] {
                return -code error "APSLinkToDeviceConfigPVs: $result"
            }
            return
        }
    }
    if [llength $fileList] {
        if [catch {APSLinkToDevicePVs -fileList $fileList} result] {
            return -code error "APSLinkToDeviceConfigPVs: $result"
        }
    }
}

proc APSLinkToLINACPVs {} {
    if [catch {APSLinkToDeviceConfigPVs -device linac} result] {
        return -code error "APSLinkToLINACPVs: $result"
    }
}

proc APSLinkToPTBPVs {} {
    if [catch {APSLinkToDeviceConfigPVs -device ptb} result] {
        return -code error "APSLinkToPTBPVs: $result"
    }
}

# Do a comparison that is sensitive to whether the data is 
# numerical or not.  Like string compare, returns 0 if the
# values are equivalent.

proc APSPVValueCompare {value1 value2} {
    set n1 [scan $value1 %f%s v1 s1]
    set n2 [scan $value2 %f%s v2 s2]
    if {$n1==1 && $n2==1} {
        return [expr $value1!=$value2]
    }
    return [string compare $value1 $value2]
}

#
# Procedure to create links between PVs and Tcl variables.
# Sets up data structures used by APSDevSend for sending/getting
# values and other device-based operations.
# Uses SDDS files having the following contents:
# Parameter DeviceType: must be unique across all files
# string columns:
# DeviceName   name of the device
# Operation    name of the operation
# ControlName  process variable name for this operation on this device
# Direction    either 'i' or 'o' for input (read from IOC) or output (write to IOC)
# ValueString  if not blank, used with 'o' operations or for comparisons in queries.
#

set apsLinkToDevicePVsFileList {}
proc APSLinkToDevicePVs {args} {
    set fileList ""
    APSStrictParseArguments {fileList}

    set tmpOps /tmp/[APSTmpString]
    set tmpDevs /tmp/[APSTmpString]
    set tmpID [APSUniqueName tmpID]
    APSAddToTmpFileList -ID $tmpID -fileList [list $tmpOps $tmpDevs]

    set deviceTypeList ""
    global apsLinkToDevicePVsFileList
    foreach file $fileList {
        if [lsearch -exact $apsLinkToDevicePVsFileList $file]!=-1 continue
        lappend apsLinkToDevicePVsFileList $file
        if [catch {exec sddssort -unique $file $tmpOps -column=Operation
            exec sddssort -unique $file $tmpDevs -column=DeviceName} result] {
            APSDeleteTmpFileList -ID $tmpID
            return -code error "APSLLinkToPVs: $result"
        }
        if [catch {sdds load $file pvData
            sdds load $tmpOps opData
            sdds load $tmpDevs devData} result] {
            APSDeleteTmpFileList -ID $tmpID
            return -code error "APSLLinkToPVs: $result"
        }
        set pages [llength $pvData(Parameter.DeviceType)]
        set varList {}
        set pvList {}
        for {set page 0} {$page<$pages} {incr page} {
            set deviceType [lindex $pvData(Parameter.DeviceType) $page]
            if [llength [info globals $deviceType]]!=0 {
                global $deviceType
                APSDeleteTmpFileList -ID $tmpID
                return -code error "APSLLinkToPVs: duplicate device type: $deviceType in file $file and [set ${deviceType}(Filename)]"
            }
            global $deviceType
            # For each device type, an array is created with the following elements:
            # Filename  
            #           name of the file from which data is loaded. 
            # Operation, Direction, DeviceName
            #           data from same-named columns of the file
            # <operation>,ValueListLength   
            #           number of values given for the operation.  Used only to keep track of
            #           whether or not there are any values.
            # <device>,<operation>,ValueString
            #           value supplied for performing a specific operation on a device
            # <device>,<operation>,VariableList
            #           list of Tcl variables associated with a device for an operation
            # <device>,<operation>,Variables
            #           number of Tcl variables associated with a device for an operation
            # <device>,<operation>,PVList
            #           list of PVs associated with a device for an operation
            # <device>,<operation>,IsLinked
            #           whether PVs are linked for this operation on this device.  Used to
            #           flag linking when before first operation is done.
            # <operation>,DeviceList
            #           list of devices that support an operation
            # <device>,OperationList
            #           list of operations associated with a device

            set ${deviceType}(Filename) $file
            set ${deviceType}(Operation) [lindex $opData(Column.Operation) $page]
            set ${deviceType}(Direction) [lindex $opData(Column.Direction) $page]
            set ${deviceType}(DeviceName) [lindex $devData(Column.DeviceName) $page]
            set rows [llength [lindex $pvData(Column.DeviceName) $page]]
            set valueList ""
            foreach operation [set ${deviceType}(Operation)] {
                set ${deviceType}($operation,ValueListLength) 0
            }
            for {set row 0} {$row<$rows} {incr row} {
                set devName [lindex [lindex $pvData(Column.DeviceName) $page] $row]
                set devOp   [lindex [lindex $pvData(Column.Operation) $page] $row]
                set devPVList [split [lindex [lindex $pvData(Column.ControlName) $page] $row] ,]
                set devPVCount [llength $devPVList]
                set devValue [string trim [lindex [lindex $pvData(Column.ValueString) $page] $row]]
                set index 0
                set newVarList ""
                foreach device $devPVList {
                    lappend newVarList ${deviceType}($devName,$devOp,$index)
                    incr index
                }
                set ${deviceType}($devName,$devOp,VariableList) $newVarList
                set ${deviceType}($devName,$devOp,PVList) $devPVList
                set ${deviceType}($devName,$devOp,IsLinked) 0
                set ${deviceType}($devName,$devOp,Variables) [llength $newVarList]
                eval lappend varList $newVarList
                eval lappend pvList $devPVList
                lappend ${deviceType}($devOp,DeviceList) $devName
                if [string length $devValue] {
                    incr ${deviceType}($devOp,ValueListLength) 
                    set ${deviceType}($devName,$devOp,ValueString) $devValue
                }
                lappend ${deviceType}($devName,OperationList) $devOp
            }
            set index 0
            # If any operations have value lists, 
            # 1. Check that number of values is same as number of devices.
            # 2. If operation is "i", then convert to "q" (query).
            foreach operation [set ${deviceType}(Operation)] {
                if [set ${deviceType}($operation,ValueListLength)] {
                    if [set ${deviceType}($operation,ValueListLength)]!=[llength [set ${deviceType}($operation,DeviceList)]] {
                        APSDeleteTmpFileList -ID $tmpID
                        return -code error \
                          "APSDevSend: ValueString data is invalid for $deviceType operation $operation."
                    }
                }
                if {[string compare [lindex [set ${deviceType}(Direction)] $index] "i"]==0 && \
                      [set ${deviceType}($operation,ValueListLength)]} {
                    # query-type operation involves comparison to value strings
                    set ${deviceType}(Direction) \
                      [lreplace [set ${deviceType}(Direction)] $index $index q]
                }
                incr index
            }
            lappend deviceTypeList $deviceType
        }
    }
    APSDeleteTmpFileList -ID $tmpID
    return $deviceTypeList
}


proc APSDevSendHelp {} {
    return {Usage: APSDevSend -group <name> [-operation <name> [-deviceList <list> [{-valueList <list> | -value <item>}] [-forceRead 1] [-blunderAhead 1] [-timeout <secs>] [-returnPVList 1] [-releaseLinks 1]]]}
}

proc APSDevSend {args} {
    set group ""
    set operation ""
    set deviceList ""
    set valueList ""
    set value ""
    set forceRead 0
    set returnPVList 0
    set blunderAhead 0
    set timeout 30
    set releaseLinks 0
    set cavput 0
    APSStrictParseArguments {group operation deviceList valueList value forceRead blunderAhead timeout returnPVList releaseLinks cavput}
    global APSDevSendDebug
    
    if {$timeout == 0} {
        set pvtimeout 30
    } else {
        set pvtimeout $timeout
    }

    if [string length $group]==0 {
        return -code error "APSDevSend: no group specified"
    }
    if [llength [info global $group]]==0 {
        return -code error "APSDevSend: device group $group not found"
    }
    if {[string length $value] && [llength $valueList]} {
        return -code error "APSDevSend: error: specify value or valueList, not both."
    }
    global $group
    if [string length $operation]==0 {
        # no operation named, so return list of operations for this group
        return [list [set ${group}(Operation)] [set ${group}(Direction)]]
    }
    if [llength $deviceList]==0 {
        # no devices named, so return list of devices that support this operation
        return [set ${group}($operation,DeviceList)]
    }
    if !$returnPVList {
        if {$forceRead} {
            set direction i
        } else {
            if [set opIndex [lsearch -exact [set ${group}(Operation)] $operation]]==-1 {
                return -code error "APSDevSend: $group has no operation $operation"
            }
            set direction [lindex [set ${group}(Direction)] $opIndex]
        }
    } else {
        set direction i
    }
    set PVLinkList ""
    set VarLinkList ""
    switch $direction {
        i -
        q -
        nq {
            # input or readback
            if [llength $valueList] {
                return -code error "APSDevSend: value list given for readback operation $operation"
            }
            # Functions of this loop:
            # 1. check for support of operation by listed devices.
            #    list missingPV has 0/1 for supported/unsupported devices
            # 2. check for unlinked PVs.  PVLinkList and VarLinkList are for passing
            #    to pv linkw.  LinkVarToSetList is a list of variables to set to 1 to
            #    indicate that pvs have been linked.
            # 3. make list of variables for use in pv getw.
            foreach device $deviceList {
                if [lsearch -exact [set ${group}($operation,DeviceList)] $device]==-1 {
                    eval lappend missingPV 0
                    if $blunderAhead continue
                    return -code error "APSDevSend: $device in $group does not support operation $operation"
                }
                if [set ${group}($device,$operation,IsLinked)]==0 {
                    eval lappend PVLinkList [set ${group}($device,$operation,PVList)]
                    eval lappend VarLinkList [set ${group}($device,$operation,VariableList)]
                    lappend LinkVarToSetList ${group}($device,$operation,IsLinked)
                }
                eval lappend missingPV [APSReplicateItem -item 0 -number \
                                          [set ${group}($device,$operation,Variables)]]
                eval lappend varList [set ${group}($device,$operation,VariableList)]
                eval lappend pvList [set ${group}($device,$operation,PVList)]
                lappend pvReturnList [set ${group}($device,$operation,PVList)]
            }
            if $returnPVList {
                return $pvReturnList
            }
            # link to PVs as needed 
            if [llength $PVLinkList] {
                if [pv linkw $VarLinkList $PVLinkList $pvtimeout] {
                    global errorCode
                    return -code error "APSDevSend: error linking to PVs: $errorCode"
                }
                foreach var $LinkVarToSetList {
                    set $var 1
                }
            }
            # get the values
            if !$timeout {
                return -code error "APSDevSend: timeout can't be zero for read operations"
            }
            if [pv getw $varList $pvtimeout] {
                global errorCode
                return -code error "APSDevSend: pv getw error: $errorCode"
            }
            # make a list of values for return to caller
            if $APSDevSendDebug {
                foreach item $varList device $deviceList {
                    puts stderr "$device: [set $item]  [set ${group}($device,$operation,PVList)]"
                }
            }
            switch $direction {
                i {
                    # simple input or input/output on forced read
                    # just return the values
                    foreach item $varList missing $missingPV {
                        if $missing {
                            lappend valueList ?
                        } else {
                            lappend valueList [set $item]
                        }
                    }
                }
                q {
                    # query input.  Return 1/0 for match/nonmatch to supplied value
                    foreach item $varList device $deviceList missing $missingPV {
                        if $missing {
                            lappend valueList ?
                        } else {
                            set compValue [set ${group}($device,$operation,ValueString)]
                            lappend valueList [expr ![APSPVValueCompare $compValue [set $item]]]
                        }
                    }
                }
                nq {
                    # query input.  Return 1/0 for match/nonmatch to supplied value
                    foreach item $varList device $deviceList missing $missingPV {
                        if $missing {
                            lappend valueList ?
                        } else {
                            set compValue [set ${group}($device,$operation,ValueString)]
                            lappend valueList [expr [APSPVValueCompare $compValue [set $item]]]
                        }
                    }
                }
            }
            if {$releaseLinks && [llength $PVLinkList]} {
                if [pv unlink $VarLinkList] {
                    global errorCode
                    return -code error "APSDevSend: error linking to PVs: $errorCode"
                }
                foreach var $LinkVarToSetList {
                    set $var 0
                }
            }
            return $valueList
        }
        o {
            # output or setpoint
            if [set ${group}($operation,ValueListLength)] {
                # use predefined values for this operation
                # valueList is a list of values for each device
                if {[llength $valueList] || [string length $value]} {
                    return -code error "APSDevSend: $group operation $operation accepts no values."
                }
                foreach device $deviceList {
                    lappend valueList [set ${group}($device,$operation,ValueString)]
                }
            } else {
                # use caller's values for this operation
                # compose a valueList with the right number of elements
                if [string length $value] {
                    set valueList [APSReplicateItem -item $value -number [llength $deviceList]]
                } elseif ![llength $valueList] {
                    return -code error "APSDevSend: value list missing for readback operation $operation"
                } elseif [llength $valueList]!=[llength $deviceList] {
                    return -code error "APSDevSend: value list and device list are different lengths"
                }
            }
            # make list of variables and their values 
            # varList is the list of variables
            # fullValueList is the list of values for each variable
            # pvList is the list of PVs (for error reporting).
            foreach device $deviceList value $valueList {
                if [lsearch -exact [set ${group}($operation,DeviceList)] $device]==-1 {
                    if $blunderAhead continue
                    return -code error "APSDevSend: $device in $group does not support operation $operation"
                }
                if [set ${group}($device,$operation,IsLinked)]==0 {
                    eval lappend PVLinkList [set ${group}($device,$operation,PVList)]
                    eval lappend VarLinkList [set ${group}($device,$operation,VariableList)]
                    lappend LinkVarToSetList ${group}($device,$operation,IsLinked)
                }
                eval lappend varList [set ${group}($device,$operation,VariableList)]
                eval lappend pvList [set ${group}($device,$operation,PVList)]
                eval lappend fullValueList [APSReplicateItem -item $value \
                                              -number [set ${group}($device,$operation,Variables)]]
            }
            # link to PVs as needed 
            if [llength $PVLinkList] {
                if [pv linkw $VarLinkList $PVLinkList $pvtimeout] {
                    global errorCode
                    return -code error "APSDevSend: error linking to PVs: $errorCode"
                }
                foreach variable $LinkVarToSetList {
                    set $variable 1
                }
            }
            # set values in variables
            foreach variable $varList value $fullValueList {
                set $variable $value
            }
            # put the values

            if {$cavput} {
                set cavVarList ""
                foreach var $varList pvname $pvList {
                    lappend cavVarList "$pvname=[set $var]"
                }
                set cavVarList [join $cavVarList ,]
                if {[catch {exec cavput -pend=$pvtimeout -list=$cavVarList} result]} {
                    return -code error "APSDevSend: cavput error: $result: pvs are $pvList"
                }
            } else {
                if $timeout {
                    if $APSDevSendDebug {
                        puts stderr "Using pv putw"
                        foreach variable $varList {
                            puts stderr "Putting $variable = [set $variable] to pv [lindex $PVLinkList [lsearch $VarLinkList $variable] ]"
                        }
                    }
                    if [pv putw $varList $pvtimeout] {
                        global errorCode
                        return -code error "APSDevSend: pv putw error: $errorCode: pvs are $pvList"
                    }
                } else {
                    if $APSDevSendDebug {
                        puts stderr "Using pv put"
                        foreach variable $varList {
                            puts stderr "Putting $variable = [set $variable] to pv [lindex $PVLinkList [lsearch $VarLinkList $variable] ]"
                        }
                    }
                    if [pv put $varList] {
                        global errorCode
                        return -code error "APSDevSend: pv put error: $errorCode: pvs are $pvList"
                    }
                }
            }
            if {$releaseLinks && [llength $PVLinkList]} {
                if [pv unlink $VarLinkList] {
                    global errorCode
                    return -code error "APSDevSend: error linking to PVs: $errorCode"
                }
                foreach var $LinkVarToSetList {
                    set $var 0
                }
            }
        }
    }
}

proc APSGetMagnetPVNamesAndInfoHelp {} {
    return {Usage: APSGetMagnetPVNamesAndInfo [-arrayName <variable>]\n\
              [-magnet <magnet>]\n\
              [-beamline <beamline>]\n\
              [-sector <sector>]\n\
              [-type <type>]\n\n\
Sets the array variable with magnet PV names from /home/helios/oagData/deviceConfig/magnets.sdds\n\
Returns the list of magnets}
}

proc APSGetMagnetPVNamesAndInfo {args} {
    set arrayName magnetPVs
    set magnet ""
    set beamline ""
    set sector ""
    set type ""
    APSStrictParseArguments {arrayName magnet beamline sector type}
    upvar 1 $arrayName magnetPVs
    set requestedMagnet $magnet
    set requestedBeamline $beamline
    set requestedSector $sector
    set requestedType $type

    if {[catch {sdds load /home/helios/oagData/deviceConfig/magnets.sdds data} results]} {
        return -code error $results
    }

    set magnets ""
    foreach magnet [lindex $data(Column.MagnetName) 0] \
      beamline [lindex $data(Column.Beamline) 0] \
      sector [lindex $data(Column.Sector) 0] \
      type [lindex $data(Column.Type) 0] \
      statusPV [lindex $data(Column.OnOffStatusPV) 0] \
      statusOnValue [lindex $data(Column.StatusOnValue) 0]\
      turnOnPV [lindex $data(Column.TurnOnPV) 0] \
      turnOnValue [lindex $data(Column.TurnOnValue) 0] \
      turnOffPV [lindex $data(Column.TurnOffPV) 0] \
      turnOffValue [lindex $data(Column.TurnOffValue) 0] \
      resetPV [lindex $data(Column.ResetPV) 0] \
      resetValue [lindex $data(Column.ResetValue) 0] \
      faultPV [lindex $data(Column.FaultPV) 0] \
      noFaultValue [lindex $data(Column.NoFaultValue) 0] \
      setCurrentPV [lindex $data(Column.SetCurrentPV) 0] \
      readCurrentPV [lindex $data(Column.ReadCurrentPV) 0] \
      readDCCTCurrentPV [lindex $data(Column.ReadDCCTCurrentPV) 0] \
      readDacCurrentPV [lindex $data(Column.ReadDacCurrentPV) 0] \
      readDCCTSlowCurrentPV [lindex $data(Column.ReadDCCTSlowCurrentPV) 0] \
      setVoltagePV [lindex $data(Column.SetVoltagePV) 0] \
      readVoltagePV [lindex $data(Column.ReadVoltagePV) 0] \
      readDacVoltagePV [lindex $data(Column.ReadDacVoltagePV) 0] \
      startConditioningPV [lindex $data(Column.StartConditioningPV) 0] \
      setConditioningCyclesPV [lindex $data(Column.SetConditioningCyclesPV) 0] \
      setConditioningFinishPV [lindex $data(Column.SetConditioningFinishPV) 0] \
      readTempPV [lindex $data(Column.ReadTempPV) 0] \
      rateDividerPV [lindex $data(Column.RateDividerPV) 0] \
      resistancePV [lindex $data(Column.ResistancePV) 0] {

          if {[llength $requestedMagnet]} {
              if {[string match -nocase $requestedMagnet $magnet] != 1} {
                  continue
              }
          }
          if {[llength $requestedBeamline]} {
              if {[string match -nocase $requestedBeamline $beamline] != 1} {
                  continue
              }
          }
          if {[llength $requestedSector]} {
              if {[string match -nocase $requestedSector $sector] != 1} {
                  continue
              }
          }
          if {[llength $requestedType]} {
              if {[string match -nocase $requestedType $type] != 1} {
                  continue
              }
          }

          lappend magnets $magnet
          set magnetPVs(${magnet}.beamline) $beamline
          set magnetPVs(${magnet}.sector) $sector
          set magnetPVs(${magnet}.type) $type

          if {$statusPV != ""} {
              set statusPV ${magnet}$statusPV
          }
          if {$turnOnPV != ""} {
              set turnOnPV ${magnet}$turnOnPV
          }
          if {$turnOffPV != ""} {
              set turnOffPV ${magnet}$turnOffPV
          }
          if {$resetPV != ""} {
              set resetPV ${magnet}$resetPV
          }
          if {$faultPV != ""} {
              set faultPV ${magnet}$faultPV
          }
          if {$setCurrentPV != ""} {
              set setCurrentPV ${magnet}$setCurrentPV
          }
          if {$readCurrentPV != ""} {
              set readCurrentPV ${magnet}$readCurrentPV
          }
          if {$readDCCTCurrentPV != ""} {
              set readDCCTCurrentPV ${magnet}$readDCCTCurrentPV
          }
          if {$readDacCurrentPV != ""} {
              set readDacCurrentPV ${magnet}$readDacCurrentPV
          }
          if {$readDCCTSlowCurrentPV != ""} {
              set readDCCTSlowCurrentPV ${magnet}$readDCCTSlowCurrentPV
          }
          if {$setVoltagePV != ""} {
              set setVoltagePV ${magnet}$setVoltagePV
          }
          if {$readVoltagePV != ""} {
              set readVoltagePV ${magnet}$readVoltagePV
          }
          if {$readDacVoltagePV != ""} {
              set readDacVoltagePV ${magnet}$readDacVoltagePV
          }
          if {$startConditioningPV != ""} {
              set startConditioningPV ${magnet}$startConditioningPV
          }
          if {$setConditioningCyclesPV != ""} {
              set setConditioningCyclesPV ${magnet}$setConditioningCyclesPV
          }
          if {$setConditioningFinishPV != ""} {
              set setConditioningFinishPV ${magnet}$setConditioningFinishPV
          }
          if {$readTempPV != ""} {
              set readTempPV ${magnet}$readTempPV
          }
          if {$rateDividerPV != ""} {
              set rateDividerPV ${magnet}$rateDividerPV
          }
          if {$resistancePV != ""} {
              set resistancePV ${magnet}$resistancePV
          }

          set magnetPVs(${magnet}.statusPV) $statusPV
          set magnetPVs(${magnet}.statusOnValue) $statusOnValue
          set magnetPVs(${magnet}.turnOnPV) $turnOnPV
          set magnetPVs(${magnet}.turnOnValue) $turnOnValue
          set magnetPVs(${magnet}.turnOffPV) $turnOffPV
          set magnetPVs(${magnet}.turnOffValue) $turnOffValue
          set magnetPVs(${magnet}.resetPV) $resetPV
          set magnetPVs(${magnet}.resetValue) $resetValue
          set magnetPVs(${magnet}.faultPV) $faultPV
          set magnetPVs(${magnet}.noFaultValue) $noFaultValue
          set magnetPVs(${magnet}.setCurrentPV) $setCurrentPV
          set magnetPVs(${magnet}.readCurrentPV) $readCurrentPV
          set magnetPVs(${magnet}.readDCCTCurrentPV) $readDCCTCurrentPV
          set magnetPVs(${magnet}.readDacCurrentPV) $readDacCurrentPV
          set magnetPVs(${magnet}.readDCCTSlowCurrentPV) $readDCCTSlowCurrentPV
          set magnetPVs(${magnet}.setVoltagePV) $setVoltagePV
          set magnetPVs(${magnet}.readVoltagePV) $readVoltagePV
          set magnetPVs(${magnet}.readDacVoltagePV) $readDacVoltagePV
          set magnetPVs(${magnet}.startConditioningPV) $startConditioningPV
          set magnetPVs(${magnet}.setConditioningCyclesPV) $setConditioningCyclesPV
          set magnetPVs(${magnet}.setConditioningFinishPV) $setConditioningFinishPV
          set magnetPVs(${magnet}.readTempPV) $readTempPV
          set magnetPVs(${magnet}.rateDividerPV) $rateDividerPV
          set magnetPVs(${magnet}.resistancePV) $resistancePV
      }
    return $magnets
}
