Trigger a Device with the EPICS record .PROC field#

The EPICS .PROC field is one of the fields common to all EPICS records. It tells the IOC’s database to execute the standard actions for that record’s data. When the record is in Passive scan mode, sending a 1 value to the .PROC field processes the record.

EPICS record processing is similar to the ophyd trigger() method which tells the Device to run its data acquisition method.

[1]:
from ophyd import Component, Device, EpicsSignal

Let’s make a custom ophyd Device, limiting our attention only to the fields of interest for this howto guide.

field

description

.A

The a value.

.CLCA

The calculation to produce a new A value when the record is processed.

.PROC

Send a 1 to this field to process the record.

.SCAN

The record’s scan mode selection.

Here, we add the trigger_value keyword argument. This is how we send a 1 to the .PROC field when the Device is triggered.

It is worth commenting about the kind keyword value. The kind attribute is the means to identify a signal that is relevant for handling by a callback.

kind

usage

hinted

attribute should be reported by .read()

config

value is metadata, should be reported by .read_configuration()

omitted

value is not reportable

[2]:
class Transform(Device):
    a = Component(EpicsSignal, ".A", kind="hinted")
    calc_a = Component(EpicsSignal, ".CLCA", kind="config", string=True)
    process_record = Component(EpicsSignal, ".PROC", kind="omitted", trigger_value=1)
    scan_mode = Component(EpicsSignal, ".SCAN", kind="config", string=True)

Create an ophyd object and connect it with EPICS.

[3]:
xform = Transform("gp:userTran11", name="xform")
xform.wait_for_connection()

Print the summary ophyd of the Device.

[4]:
xform.summary()
data keys (* hints)
-------------------
*xform_a

read attrs
----------
a                    EpicsSignal         ('xform_a')

config keys
-----------
xform_calc_a
xform_scan_mode

configuration attrs
-------------------
calc_a               EpicsSignal         ('xform_calc_a')
scan_mode            EpicsSignal         ('xform_scan_mode')

unused attrs
------------
process_record       EpicsSignal         ('xform_process_record')

Show the values as they exist now using the .read() method.

[5]:
print(f"{xform.read()=}")
xform.read()=OrderedDict([('xform_a', {'value': 2.0, 'timestamp': 1714336346.373808})])

Tell ophyd to trigger the Device (which tells the transform record to process) using the .trigger() method.

Note that only the a value is reported. All other attributes are either configuration or not reportable (such as process_record).

[6]:
xform.trigger()
print(f"{xform.read()=}")
xform.read()=OrderedDict([('xform_a', {'value': 3.0, 'timestamp': 1714337169.963434})])

Reset the Device before we demonstrate.

[7]:
xform.calc_a.put("")
xform.a.put(0)
xform.scan_mode.put("Passive")
print(f"{xform.read()=}")
xform.read()=OrderedDict([('xform_a', {'value': 0.0, 'timestamp': 1714337169.970021})])

Define the calculation to run (increment a) each time the record is processed.

[8]:
xform.calc_a.put("A+1")

Print the value before triggering (processing), trigger the, then print the value afterwards. We expect the value will increment by 1.

[9]:
print(f"{xform.read()=}")
xform.trigger()
print(f"{xform.read()=}")
xform.read()=OrderedDict([('xform_a', {'value': 0.0, 'timestamp': 1714337169.970021})])
xform.read()=OrderedDict([('xform_a', {'value': 1.0, 'timestamp': 1714337169.982637})])

Let’s do the same thing in a bluesky plan. First, we need some parts from the bluesky package. These are the most basic parts:

[10]:
from bluesky import RunEngine
from bluesky import plan_stubs as bps

RE = RunEngine()

Define the bluesky plan. Instead of calling the Device’s .trigger() method directly, we let the RunEngine handle that task (with bps.trigger()), in case the device takes some time to complete its trigger action(s).

[11]:
def plan():
    print(f"{xform.read()=}")
    yield from bps.trigger(xform)
    print(f"{xform.read()=}")

Run the plan.

[12]:
RE(plan())
xform.read()=OrderedDict([('xform_a', {'value': 1.0, 'timestamp': 1714337169.982637})])
xform.read()=OrderedDict([('xform_a', {'value': 2.0, 'timestamp': 1714337170.147542})])
[12]:
()