#! Generated by VisualDCT v2.5
record(busy, "$(P)$(Q)Busy") {
}
record(bo, "$(P)$(Q)SetBusy") {
field(UDF, "0")
field(VAL, "1")
field(OUT, "$(P)$(Q)Busy PP")
field(OSV, "NO_ALARM")
}
# tweak
record(ao, "$(P)$(Q)TweakVal") {
field(PREC, "3")
field(DOL, "1")
}
record(transform, "$(P)$(Q)Tweak") {
field(CLCD, "a?c-e:b?c+e:c")
field(INPC, "$(P)$(Q)Ramp.VAL NPP NMS")
field(INPE, "$(P)$(Q)TweakVal.VAL NPP MS")
field(OUTD, "$(P)$(Q)Ramp.VAL PP MS")
field(OUTF, "$(P)$(Q)Tweak.A NPP NMS")
field(OUTG, "$(P)$(Q)Tweak.B NPP NMS")
field(PREC, "3")
}
record(calcout, "$(P)$(Q)RampStop") {
field(INPA, "$(P)$(Q)Ramp.VAL")
field(INPB, "$(P)$(Q)Ramp.OVAL")
field(CALC, "A#B")
field(OUT, "$(P)$(Q)Ramp.VAL PP")
field(OOPT, "When Non-zero")
field(DOPT, "Use OCAL")
field(OCAL, "B")
}
# If target value changes, and we didn't do it (Busy==0), then
# get the value and stuff in into Ramp
record(ao, "$(P)$(Q)SyncToTarget") {
field(SDIS, "$(P)$(Q)Busy")
field(OMSL, "closed_loop")
field(DOL, "$(P)$(Q)RampTestTarget.VAL CP")
field(OUT, "$(P)$(Q)Ramp.VAL PP")
field(FLNK,"$(P)$(Q)SyncOVAL")
}
# If we don't also sync OVAL, we won't ramp next time.
record(ao, "$(P)$(Q)SyncOVAL") {
field(SDIS, "$(P)$(Q)Busy")
field(OMSL, "closed_loop")
field(DOL, "$(P)$(Q)Ramp.VAL")
field(OUT, "$(P)$(Q)Ramp.OVAL")
}
# Users write to this field to move or ramp the target
record(ao, "$(P)$(Q)Ramp") {
field(OROC, ".1")
field(OUT, "$(P)$(Q)PutValue.DO2 PP")
field(PREC, "3")
}
# See if we need to process the Ramp record again to get it one step
# closer to the target value
record(calcout, "$(P)$(Q)RampCheckOutput") {
field(SDIS, "$(P)$(Q)RampStop.PACT")
field(INPA, "$(P)$(Q)Ramp.VAL")
field(INPB, "$(P)$(Q)Ramp.OVAL")
field(INPC, "$(P)$(Q)Ramp.OROC")
field(CALC, "abs(a-b)>C/2")
field(OOPT, "When Non-zero")
field(ODLY, "0.1")
field(OUT, "$(P)$(Q)Ramp.PROC CA")
field(PREC, "3")
}
# Put the value to the target record, and arrange the other things we need
# (set busy, wait until target finishes changing, see if target is at final
# destination, see if we're all done).
# Note that the LNK2 field will normally be overwritten with a PV specified
# by the user. Also, note that the user doesn't set LNK2 directly, because
# we need the link to have the "CA" attribute to wait for completion.
record(sseq, "$(P)$(Q)PutValue") {
field(SDIS, "$(P)$(Q)SyncToTarget.PACT")
field(STR1, "Busy")
field(LNK1, "$(P)$(Q)Busy PP")
field(LNK2, "$(P)$(Q)RampTestTarget CA")
field(WAIT2, "Wait")
field(LNK3, "$(P)$(Q)RampCheckOutput.PROC PP")
field(LNK4, "$(P)$(Q)RampCheckDone.PROC PP")
field(PREC, "3")
}
# If the target PV is less than half a step away from the target value,
# we're done. While Busy is TRUE, check periodically.
record(calcout, "$(P)$(Q)RampCheckDone") {
field(INPA, "$(P)$(Q)Ramp.VAL NPP")
field(INPB, "$(P)$(Q)Ramp.OVAL NPP")
field(INPC, "$(P)$(Q)Ramp.OROC")
field(CALC, "abs(a-b)>C/2")
field(OOPT, "When Zero")
field(ODLY, ".1")
field(OUT, "$(P)$(Q)Busy CA")
field(PREC, "3")
field(SCAN, "1 second")
field(DISV, "0")
field(SDIS, "$(P)$(Q)Busy.VAL")
}
# Dummy record, for the default case in which the user doesn't actually want
# to drive anything with the ramp, but just to ramp a number.
record(ao, "$(P)$(Q)RampTestTarget") {
field(PREC, "3")
}
record(ai, "$(P)$(Q)Readback") {
field(PREC, "3")
field(INP, "$(P)$(Q)RampTestTarget.VAL CP")
}
# This is where the user specifies the PV (in the AA field) that is to be
# ramped. Add the link attribute "CA", and shove the result into the PutValue
# record, which is the thing that does the actual writing to the target PV.
# We'll also have to update our sync section with the new PV name.
record(scalcout, "$(P)$(Q)PutLinkCalc") {
field(AA, "$(P)$(Q)RampTestTarget")
field(CALC, "aa+' CA'")
field(OUT, "$(P)$(Q)PutValue.LNK2 CA")
field(FLNK, "$(P)$(Q)SyncLinkCalc")
}
# Get the user's new target PV name, and make SyncToTarget monitor that PV.
record(scalcout, "$(P)$(Q)SyncLinkCalc") {
field(INAA, "$(P)$(Q)PutLinkCalc.AA")
field(CALC, "aa+' CP'")
field(OUT, "$(P)$(Q)SyncToTarget.DOL CA")
}
# Get the user's new target PV name, and make Readback monitor that PV.
record(scalcout, "$(P)$(Q)ReadLinkPVCalc") {
field(CALC, "aa+' CP'")
field(INAA, "$(P)$(Q)PutLinkCalc.AA CP")
field(OUT, "$(P)$(Q)Readback.INP CA")
}
# We may have to initialize this database with a user specified PV name that
# was restored by autosave. If so, we could construct the link text at PINI
# time, but we can't actually write the resulting link, because link fields
# must be written by channel access, and channel access is not functioning
# at PINI time. An easy way to wait for channel access is to wait for the
# periodic scan tasks to start. However, we only want to process once, so
# we reset our own SCAN field to 0 after we've done our job.
# Another thing we have to do at init time is initialize *Ramp.OVAL to
# *Ramp.VAL, because the ao record needs OVAL to be right, or its OROC
# calculation will break.
record(seq, "$(P)$(Q)Init") {
field(SCAN, "1 second")
field(LNK1, "$(P)$(Q)PutLinkCalc.PROC")
field(DOL2, "$(P)$(Q)Ramp.VAL")
field(LNK2, "$(P)$(Q)Ramp.OVAL")
field(DO3, "0")
field(LNK3, "$(P)$(Q)Init.SCAN CA")
}