Files
detectortower/db/detectorTower.db
smathis 8eba612524
All checks were successful
Test And Build / Lint (push) Successful in 4s
Test And Build / Build (push) Successful in 15s
UDF state is not shown during initialization anymore
These changes process the AdjustOrigin record during initialization to
make sure its .STAT field does not show "UDF" anymore before the first
processing. The gate record makes sure that no command is send to the
underlying hardware during initial processing.
2025-07-09 11:43:31 +02:00

144 lines
5.6 KiB
Plaintext

# Read the position state of the axis:
# 0 = not ready
# 1 = ready (in working position)
# 2 = Moving from working to changer position or in changer position
# 3 = Moving from changer to working state
record(longin, "$(INSTR)$(M):PositionStateRBV")
{
field(DTYP, "asynInt32")
field(INP, "@asyn($(CONTROLLER),$(AXIS)) POSITION_STATE_RBV")
field(SCAN, "I/O Intr")
field(PINI, "NO")
}
# Set to 0 to move the tower into working state and to 1 to move into changer position.
# The PV "$(INSTR)$(M):ChangeStateRBV" can be used to check if starting the corresponding
# movement was successfull.
record(longout, "$(INSTR)$(M):ChangeState") {
field(DTYP, "asynInt32")
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) CHANGE_STATE")
field(PINI, "NO")
field(DRVH, "1")
field(DRVL, "0")
}
# When a value is written to the PV "$(INSTR)$(M):ChangeState", the tower needs to be
# idle (PositionState = 0), otherwise the state will not be changed. If the value
# of this PV is equal to "$(INSTR)$(M):ChangeState", starting a state change was
# successfull, otherwise not.
record(longin, "$(INSTR)$(M):ChangeStateRBV")
{
field(DTYP, "asynInt32")
field(INP, "@asyn($(CONTROLLER),$(AXIS)) CHANGE_STATE_RBV")
field(SCAN, "I/O Intr")
field(PINI, "NO")
}
# This PV combines the position state and the movement readback value from the
# motor record:
# - 0, if the tower is in working state or transitioning to change position
# - 1, If the tower is in change position or transitioning to working state
record(calc, "$(INSTR)$(M):ChangingStateRBV")
{
field(INPA, "$(INSTR)$(M):PositionStateRBV CP")
field(INPB, "$(INSTR)$(M).MOVN CP")
field(CALC, "((A == 2 && B == 0) || A == 3) ? 1 : 0")
}
# Convert the double value from the calc record to an integer value.
record(longout, "$(INSTR)$(M):ChangingStateRBV_int") {
field(DOL, "$(INSTR)$(M):ChangingStateRBV CP")
field(OMSL, "closed_loop")
}
# Read out the origin of the corresponding axis by the given value.
# This PV does nothing for "normal" Turbo PMAC axes.
record(ai, "$(INSTR)$(M):Origin") {
field(DTYP, "asynFloat64")
field(INP, "@asyn($(CONTROLLER),$(AXIS)) MOTOR_ORIGIN")
field(SCAN, "I/O Intr")
field(PINI, "NO")
}
# Shift the origin of the corresponding axis by the given value. The axis will move to this
# position and the hardware controller will internally set this position as the
# new "0" value. This PV does nothing for "normal" Turbo PMAC axes.
record(ao, "$(INSTR)$(M):AdjustOrigin") {
field(DTYP, "Raw Soft Channel")
field(PINI, "YES")
field(FLNK, "$(INSTR)$(M):ResetAO")
field(VAL, "0")
field(UDF, "FALSE")
field(SCAN, "Passive")
}
# Only forward nonzero inputs for the origin adjustment
record(calc, "$(INSTR)$(M):GateOrigin") {
field(CALC, "A!=0?A:VAL")
field(INPA, "$(INSTR)$(M):AdjustOrigin")
field(OUT, "$(INSTR)$(M):WriteAO.VAL PP") # Forward the value to the driver
field(PINI, "NO")
field(SCAN, "Passive")
}
# Reset the PV $(INSTR)$(M):AdjustOrigin to zero after it has been written to and
# forward the value to $(INSTR)$(M):WriteAO which does the actual writing.
record(seq, "$(INSTR)$(M):ResetAO") {
field(DESC, "Write value to hardware then reset to 0")
field(DOL1, "1") # Dummy value which is only here to trigger processing of LNK1
field(LNK1, "$(INSTR)$(M):GateOrigin.PROC PP")
field(DOL2, "0.0")
field(LNK2, "$(INSTR)$(M):AdjustOrigin.VAL PP") # Reset to zero
field(UDF, "FALSE")
}
# This record forwards the adjustment of the origin to the asyn driver.
record(ao, "$(INSTR)$(M):WriteAO") {
field(DTYP, "asynFloat64")
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) MOTOR_ADJUST_ORIGIN")
field(PINI, "NO")
field(VAL, "0")
}
# This record pair reads the parameter library value for "AdjustOriginHighLimitFromDriver_"
# and pushes it to the high limit field of the "$(INSTR)$(M):AdjustOrigin" PV.
# This can be used to read limits from the hardware and correspondingly update the motor record from the driver.
# The implementation strategy is taken from https://epics.anl.gov/tech-talk/2022/msg00464.php.
# This record is coupled to the parameter library via AdjustOriginHighLimitFromDriver_ -> MOTOR_AOHL_FROM_DRIVER.
record(ai, "$(INSTR)$(M):AOHL_RBV")
{
field(DTYP, "asynFloat64")
field(INP, "@asyn($(CONTROLLER),$(AXIS)) MOTOR_AOHL_FROM_DRIVER")
field(SCAN, "I/O Intr")
field(FLNK, "$(INSTR)$(M):PushAOHL2Field")
field(PINI, "NO")
}
# Abbreviated name because EPICS apparently has a maximum record name length
record(ao, "$(INSTR)$(M):PushAOHL2Field") {
field(DOL, "$(INSTR)$(M):AOHL_RBV NPP")
field(OUT, "$(INSTR)$(M):AdjustOrigin.DRVH")
field(OMSL, "closed_loop")
field(PINI, "NO")
}
# This record pair reads the parameter library value for "motorLowLimitFromDriver_"
# and pushes it to the low limit field of the "$(INSTR)$(M):AdjustOrigin" PV.
# This can be used to read limits from the hardware and correspondingly update the motor record from the driver.
# The implementation strategy is taken from https://epics.anl.gov/tech-talk/2022/msg00464.php.
# This record is coupled to the parameter library via AdjustOriginLowLimitFromDriver_ -> MOTOR_AOLL_FROM_DRIVER.
record(ai, "$(INSTR)$(M):AOLL_RBV")
{
field(DTYP, "asynFloat64")
field(INP, "@asyn($(CONTROLLER),$(AXIS)) MOTOR_AOLL_FROM_DRIVER")
field(SCAN, "I/O Intr")
field(FLNK, "$(INSTR)$(M):PushAOLL2Field")
field(PINI, "NO")
}
# Abbreviated name because EPICS apparently has a maximum record name length
record(ao, "$(INSTR)$(M):PushAOLL2Field") {
field(DOL, "$(INSTR)$(M):AOLL_RBV NPP")
field(OUT, "$(INSTR)$(M):AdjustOrigin.DRVL")
field(OMSL, "closed_loop")
field(PINI, "NO")
}