4. Database Builder Support¶
The functionality documented here is designed to create EPICS databases alongside an IOC developed using the EPICS Device C API. The database building process uses the EPICS database builder, which is a separate support module and documented elsewere.
Importing epics_device
will automatically import and initialise
epicsdbbuilder
. By default the version configured in
configure/SITE_CONFIG
of epics_device
will be used, but this can be
overridden by setting the environment variable EPICSDBBUILDER
before
importing epics_device
.
A database building script will normally be invoked from the EPICS build
environment. This will have already exported the environment variable
EPICS_BASE
, which must be set before importing epics_device
. If
EPICS_DEVICE
has also been configured in configure/RELEASE
then this can
be exported from the make file and then the following example script will work:
# Configure path using environment
import sys, os
sys.path.append(os.environ['EPICS_DEVICE'])
# Import and initialise EPICS device
from epics_device import *
# Configure an appropriate record naming convention
SetTemplateRecordNames()
# Now create records, eg
aOut('RECORD', DESC = 'This is a record')
# Finally write the records, here the filename is sys.argv
WriteRecords(sys.argv[1])
Invoking a Python script of this form will write a valid EPICS database file.
With this script the following lines added to the Db/Makefile
after
include $(TOP)/configure/RULES
will build the database as required:
export EPICS_DEVICE
$(COMMON_DIR)/%.db: ../%.py
$(PYTHON) $< $@
4.1. Creating EPICS Records¶
The methods exported by epics_device
provide helper functions for
creating EPICS records of each of the eleven basic types. A particular coding
style is supported by these calls, if the default behaviour is not felt to be
appropriate then records can be created directly by calling the appropriate
methods of EpicsDevice
.
A number of defaults and naming conventions are applied by the functions below.
4.1.1. Record Address¶
By default the name used to look up the record in IOC support, as published by
PUBLISH()
and allies, is the name argument as passed to the appropriate
record construct documented below, before any name processing occurs. This can
be modified in two ways:
Firstly, every record creation function listed below takes an optional keyword argument address, which can be used to specify an address other than the record name.
Secondly, a prefix can be prepended to every address and name by calling the functions
push_name_prefix()
andpop_name_prefix()
.
-
epics_device.
push_name_prefix
(prefix)¶ -
epics_device.
pop_name_prefix
()¶ These two functions mirror the action of
push_record_name_prefix()
andpop_record_name_prefix()
, and affect both the record name and the associated address.
-
epics_device.
set_name_separator
(separator)¶ By default component of the prefix and the record name are separated by ‘:’, but this function can be used to change the separator.
-
class
epics_device.
name_prefix
(prefix)[source]¶ This is a context manager for a name prefix, wrapping
push_name_prefix()
andpop_name_prefix()
into a single action. This can be used thus:with name_prefix('PREFIX'): aIn('AIN')
4.1.2. In Records¶
Input records are created by the following functions. Processing must be arranged for each record. The options are:
Setting
SCAN
to a delay interval and allowing EPICS to trigger processing.Setting
SCAN = 'I/O Intr'
and callingtrigger_record()
from within the driver.Leaving
SCAN
as'Passive'
and ensuring that the record is processed in response toFLNK
from some other record. In particular seeTrigger()
for this.
-
epics_device.
aIn
(name, LOPR=None, HOPR=None, EGU=None, PREC=None, **fields)[source]¶ -
epics_device.
longIn
(name, LOPR=None, HOPR=None, EGU=None, **fields)[source]¶ For
ai
andlongin
records theMDEL
field is set by default to -1 to ensure that all ticks are generated.
-
epics_device.
boolIn
(name, ZNAM=None, ONAM=None, **fields)[source]¶ For
boolIn()
the two optional arguments are the strings associated with boolean valuesfalse
andtrue
respectively.
-
epics_device.
mbbIn
(name, *options, **fields)[source]¶ For
mbbIn
*options represents a sequence of up to 16 enumeration assignments. Each assignment is either a string or else a tuple of two values, in which case the first value is the option name and the second is the severity option.In all cases the underlying values are assigned by default in ascending order from 0.
For example:
status = mbbIn('STATUS', 'Ok', ('Failing', 'MINOR'), ('Failed', 'MAJOR'), DESC = 'Status pv')
This creates a PV with value 0, 1 or 2, and with increasing severity.
-
epics_device.
set_MDEL_default
(default)[source]¶ Normally the
MDEL
field forai
andlongin
records defaults to 0. This means that record updates which don’t change the published value aren’t transmitted over channel access. In some applications this is inconvenient, in which case this function can be called with default set to -1 to ensure that all updates are transmitted.
4.1.3. Out Records¶
For all “out” records OMSL
is set to supervisory
and PINI
is set to
YES
. As “out” records are normally used for device configuration they
should be left with SCAN
set to 'Passive'
, the default.
The name passed to each of these functions is the internal address, but the
record name can be modified by invoking set_out_name()
.
-
epics_device.
aOut
(name, DRVL=None, DRVH=None, EGU=None, PREC=None, **fields)[source]¶ -
epics_device.
longOut
(name, DRVL=None, DRVH=None, EGU=None, **fields)[source]¶ By default for
ao
andlongout
records theLOPR
andHOPR
fields are set equal toDRVL
andDRVH
respectively.
-
epics_device.
boolOut
(name, ZNAM=None, ONAM=None, **fields)[source]¶ See
boolIn()
for the optional arguments.
-
epics_device.
mbbOut
(name, *options, **fields)[source]¶ See
mbbIn()
for options. An example control PV might be:mbbOut('SETUP', 'Normal', 'Unusual', 'Special', DESC = 'Configure setup control')
-
epics_device.
set_out_name
(function)[source]¶ This hook can be used to implement a special naming convention for out records: the record name for all out records is first processed by this function before being passed through to normal
epicsdbbuilder
processing.For example, all output records can be named with a trailing
_S
suffix with the following call:set_out_name(lambda name: name + '_S')
4.1.4. Waveform Records¶
For waveform records the direction of data flow is determined by driver support rather than by EPICS or the device layer.
-
epics_device.
Waveform
(name, length, FTVL='LONG', **fields)[source]¶ Defines a waveform record with the given name. The number of points in the waveform must be specified as length, and if a field type other than
'LONG'
(which really means 32-bit integer) is wanted this must be explicitly specified.
-
epics_device.
WaveformOut
(name, length, FTVL='LONG', **fields)[source]¶ This is used for defining a waveform specialised for output. Functionally this is identicial to
Waveform()
except for two differences:The associated record name is passed through the
set_out_name()
hook.The
'PINI'
field is set to'YES'
.
4.1.5. Raw Record Creation¶
The functions listed above are all helper functions with a number of hard-wired
defaults and actions. A more direct approach to record creation can be taken by
invoking the record creation methods for EpicsDevice
and
epicsdbbuilder.records
directly.
-
epics_device.
EpicsDevice
[source]¶ This Python object has a method for each record type supported by EPICS Device, namely
ai
,bi
,longin
,mbbi
,stringin
,ao
,bo
,longout
,mbbo
,stringout
,waveform
. Each method has the following signature:-
EpicsDevice.
record
(name, address=None, **fields)¶ Creates an EPICS record of type record with the given name. The record is configured with EPICS Device support, and by default the EPICS Device binding address is also name, but a different value can be specified by setting address. Keyword arguments can be used to specify any EPICS field.
This method automatically initialises the
DTYP
andINP
orOUT
fields as appropriate, and is otherwise just a wrapper around the corresponding method ofepicsdbbuilder.records
.
-
4.2. Helper Functions¶
These functions are designed to assist in the generation of databases. The
Trigger()
function is the most complex one, designed for record sets which
update on driver internal events.
-
epics_device.
Trigger
(prefix, *pvs, set_time = False)[source]¶ This function generates two records with names prefix
:TRIG
and prefix:DONE
together with as many fanout records as necessary to ensure that all of the PVs in pvs are processed in turn when the:TRIG
record is processed. This function is designed to be used with theepics_interlock
API to implement coherent updating of all the linked PVs.If the set_time field is set then
create_interlock()
should be called with its set_time field set totrue
and a valid timestamp should be passed tointerlock_signal()
. In this case the driver is responsible for timestamping the records.For example, the database definition:
Trigger('UPDATE', aIn('V1'), aIn('V2'), aIn('V3'), Waveform('WF', 1000))
can be combined with the following C code to trigger simultaneous and coherent updates of the three named PVs:
static struct epics_interlock *update; static double v1, v2, v3; static int wf[1000]; static void compute_update( double *v1, double *v2, double *v3, int wf[]) { ... } // Called in response to some internal or external action void trigger_update(void) { interlock_wait(update); compute_update(&v1, &v2, &v3, wf); interlock_signal(update, NULL); } // Publish the PVs void publish_pvs(void) { update = create_interlock("UPDATE", false); PUBLISH_READ_VAR(ai, "V1", v1); PUBLISH_READ_VAR(ai, "V2", v2); PUBLISH_READ_VAR(ai, "V3", v3); PUBLISH_WF_READ_VAR(int, "WF", 1000, wf); }
The key principle here is that the variables containing the values of the PVs are only written while the interlock (
update
) is held, so that EPICS see a consistent update of all PVs. This is of particular importance when waveforms are involved.
-
epics_device.
Action
(name, **fields)[source]¶ Creates an “action” PV. This is a
bo
record configured not to start during IOC initialisation.
-
epics_device.
ForwardLink
(name, desc, *pvs, **fields)[source]¶ A helper function for triggering internal processing after any PV in the list pvs is processed. Creates an action PV by calling
Action()
and forward links each passed PV to the new action PV. The created PV is returned.This is designed to be used to trigger common processing after any of a set of “out” records have been updated.
-
epics_device.
AggregateSeverity
(name, description, recs)[source]¶ For up to 12 records, passed as list recs, generates a
calc
record with the given name and description with severity set to the aggregated severity of the input records. The value of the generated record is 1.The returned record must be processed, typically after processing the given list of records. For example:
pvs = [ aIn('PV1', HIGH = 1, HSV = 'MINOR'), bIn('PV2', 'Ok', 'Bad', OSV = 'MAJOR')] pvs.append(AggregateSeverity('ALL', 'Health', pvs)) Trigger('UPDATE', *pvs)
Note that in this example the aggregation PV must be processed after the PVs it aggregates.
4.3. Functions from EPICS Db Builder¶
The following functions are reexported from epicsdbbuilder
and are
useful for database building. For fuller documentation see the documentation
for that module, but a selection of useful functions is listed here for
reference.
-
epicsdbbuilder.
records
¶ This is part of the IOC builder framework, not documented here. There is a method for each record type supported by EPICS, ie
ai
,ao
,calc
, etc, with the following signature:-
records.
record_type
(name, **fields)¶ Creates an EPICS record of type record_type with the given name and with other fields as specified. These records by default have no EPICS Device support configured.
For example:
-
records.
calc
(name, **fields)¶ This creates a
calc
record with the given name (as modified by the appropriateSetRecordNames()
setup).
-
-
epicsdbbuilder.
PP
(record)[source]¶ -
epicsdbbuilder.
CP
(record)[source]¶ -
epicsdbbuilder.
MS
(record)[source]¶ -
epicsdbbuilder.
NP
(record)[source]¶ When generating internal record links these add the appropriate link annotation.
-
epicsdbbuilder.
create_fanout
(name, *records, **kargs)[source]¶ -
epicsdbbuilder.
create_dfanout
(name, *records, **kargs)[source]¶ Creates processing and data fanouts to an arbitrary list of records.
-
epicsdbbuilder.
SetRecordNames
(names)[source]¶ -
epicsdbbuilder.
SetTemplateRecordNames
([prefix] [,separator])[source]¶ These two functions are used to establish how the full record name written to the generated database is derived from the short form record name passed to the appropriate
records
method.