|
|
Experimental Physics and
| ||||||||||||||
|
|
Hi,
At SNS we have a software called pvMediator, that provides IOC shell functions to run before iocInit() which walk all the existing records in order to create new aggregated records dynamically. It uses regex to find PVs, and produces either aggregated read-back or fanout set-point records. The README is attached, we should be able to include it in ORNL EPICS repository if there’s interest. — Klemen > On Feb 4, 2022, at 3:48 AM, Ralph Lange via Tech-talk <[email protected]> wrote: > > On Thu, 3 Feb 2022 at 21:01, Dudley, David via Tech-talk <[email protected]> wrote: > Is it possible from with a device driver that before iocInit (or during some part of it) to programmatically build a database record for use in EPICS? > > > I know of a driver that does that, yes. > In the initialization of the driver (started by calls from the startup script) they detect the hardware and create a matching DB file in '/tmp', then load that file. Works fine. > > I don't like that for a production system for multiple reasons. Having no or little control over which records an IOC loads.... Broken cards that would just disappear from the name space with no trace.... > But I see the advantage for plug-and-play lab use. > > If you don't hard code the records into the driver code, but maybe blow up from templates that are part of your application, you would give the user at least some control. > > Cheers, > ~Ralph > reference: https://github.com/NDSv3/nds-epics/blob/46bf0bbf053a36be6140ef3d457519f8b56609a8/ndsSup/src/epicsInterfaceImpl.cpp#L170 > > > /* README
*
* Copyright (c) 2015 Oak Ridge National Laboratory.
* All rights reserved.
* See file LICENSE that is included with this distribution.
*
* @author Carl Lionberger
*/
pvMediator
The pvMediator support application provides four commands designed to be
called from the EPICS startup file st.cmd before the iocInit() call. Each
command makes and installs PVs that provide a more global connection to
multiple PVs already existing in the IOC; the pvMediator calls must be after
the PVs to which they are to connect are loaded.
All the commands use a pattern to find the existing PVs to connect to. The
pattern is matched using the POSIX regex standard with Extended Regular
Expression (ERE) handling enabled, but without back-substitution. The pattern
provided is wrapped in beginning and end specifiers "^<pattern>$" before
matching to ensure that matching of substrings of PV names does not occur. All
the commands use grouping PVs with limited numbers of inputs or outputs;
multiple instances of these are chained if necessary to handle the number of
matched PVs.
pvMediator supports an iocsh variable mediatorVerbosity. If this is set to 0,
each function will print how many pre-existing PVs it connected to and how many
additional PVs it generated. If set to 1, the names of the newly-composed
records are printed, and if set to 2 the entire records in the db-file format
will be printed.
The commands are designed to print error messages but allow startup to continue
if they get an error.
The Commands:
mediateSetpoint <recordType> <controlName> <pattern> [use ca links 0/1]
mediateSetpoint generates a single setpoint PV that drives its value to all the
PVs matched by the pattern. It generates a set of dfanout PVs and a soft
control PV that drives the dfanouts. The dfanout PVs drive all the PVs found in
the IOC that are of the type "recordType" and have names matching "pattern".
The recordType must be an output record type; this has been tested with bo,
mbbo, and ao but may work with any record with an "OUT" field.
The soft control PV will be named "controlName" and it is an error if already
exists. The control PV will be of the same type as the the matched PVs, and
will be patterned after the last one encountered; in fact all that will be
changed is that "OUT" will be set to drive a dfanout record and "DTYP" will be
set to "Soft Channel". This allows the control PV to be well presented in GUI
clients. It is assumed that auxiliary fields such as EGU and state names will
be the same in all the matched PVs. It can be argued that if this assumption is
violated it is not valid to send identical settings to the PVs as a group and
that mediateSetpoint should not be used.
The "use ca links" parameter should be set to 1 to use CA links for the outputs.
By default database links are used but this can create large database lock sets.
If that is a problem, use CA links.
mediateSetField <recordType> <controlName> <pattern> <fieldName>
MediateSetField() is very similar to mediateSetpoint, except that rather than
implicitly pointing to the VAL field, the field to be modified in each of the
selected set of PVs is set by the fieldName argument. The mediateSetpoint()
requirement that the selected records must be of type "output" is relaxed. The
controlName PV is an alias pointing to the last dfanout record produced. Putting
a value to that PV will cause it to be driven to the requested field of all the
matched PVs. The output links to matched PVs are of type CA.
mediateEquality <recordType> <resultName> <pattern> [setpoint] [tolerance]
mediateEquality generates a single result PV that indicates whether all the PVs
matched by "pattern" are of equal (+-tolerance) VAL and (optionally) match
"setpoint". The result PV is a bi record which reports the results of generated
subroutine records that get input from all PVs of "recordType" matching
"pattern". It is named "resultName" and will have a value of either "Equal" (1)
or "Not Equal" (0). It is an error if a PV "resultName" is already present.
"setpoint" can be either a literal numeric value or a PV link. If a PV link it
is essential it be given in the full link format, eg, "sepointPVName CPP MS",
in quotes as shown. If setpoint is omitted, the matched PVs will be compared
only to each other. If setpoint is set to "*", it is as if it is omitted; this
is provided only to allow setting tolerance without a setpoint.
"tolerance" is to be in double format and if omitted defaults to 0.001, a value
which will work in most cases including integer types.
The processing of this record is asynchronous so it is possible in a programmed
environment, such as sequencer code, that it could be checked before its value
has settled after database operations. A short delay may be needed in such
situations before reading the result PV.
mediateSeverity <recordType> <severityName> <pattern>
mediateSeverity generates a single severity PV that will have the highest
severity of all the PVs of type "recordType" matched by "pattern". The result
PV is a bi record whose VAL will be "0" ("Normal") if the severity is 0
(NO_ALARM) or "1" ("Alarm") otherwise. The anticipated use for this is to drive
either an alarm-sensitive summary indicator or a value-sensitive "LED"
indicator on a GUI.
Diagnostic Procedures
In a production situation it is recommended that there be a GUI that has an
overview of all the quantities being checked with mediateEquality or
mediateSeverity, so that finding which one is at fault is simple. This section
describes how to find the information about the mediateEquality inputs from the
iocsh. The general techniques should be useful with any of the pvMediator
commands and this section should give a more tangible idea of how these sets of
PVs are structured. Suppose you have run the command
mediateEquality("mbbi", "testMbbiG:Readback", "*Readback", "testMbboG:Setpoint
CPP MS")
in the startup file. Note that the syntax is different than in the command
descriptions above; either form will work with iocsh. This example is taken
from the test ioc that is part of the pvMediator app, and shows the state of
the PVs after the test sequencer runs at startup. The result PV is in the state
"Not Equal", or as seen from the iocsh:
epics> dbpr testMbbiG:Readback
ASG: DESC: result PV for EqualTest DISA: 0
DISP: 0 DISV: 1 NAME: testMbbiG:Readback
RVAL: 0 SEVR: MAJOR STAT: STATE SVAL: 0
TPRO: 0 VAL: 0
The first thing to do is find the PVs involved:
epics> dbgrep testMbbiG:Readback*
testMbbiG:Readback
testMbbiG:Readback0
testMbbiG:Readback1
testMbbiG:Readback2
epics>
The first PV on that list is the result PV and is of type mbbi; the others are
a chain of calc records that do the equality tests. Different records in the
chain have slightly different properties. The first task is to find which input
is different from the rest. First look at PV 0:
epics> dbpr testMbbiG:Readback0
A: 1 ASG: B: 1 C: 1
CALC: (A=B)&&(B=C)&&(C=D)&&(D=E)&&(E=F)&&(F=G)&&(G=H)&&(H=I)&&(I=J)&&(J=K)
D: 1 DESC: Check consistency DISA: 0
DISP: 0 DISV: 1 E: 1 F: 1
G: 1 H: 1 I: 1 J: 1
K: 1 L: 0 NAME: testMbbiG:Readback0
SEVR: NO_ALARM STAT: NO_ALARM TPRO: 0 VAL: 1
epics>
The first thing to notice is that the VAL is 1, meaning that all the inputs
this PV is looking at are equal. The "CALC" line shows the calculation this PV
performs; in this case we see that the values A through K are compared.
Examination will show they are all "1". Input L is not used because that would
make the CALC string longer than allowed.
Note that A will be set by the setpoint argument of the original command if it
is a link or a constant; if that argument is not given it will be the first
matched PV found.
We need to examine the subsequent PVs:
epics> dbpr testMbbiG:Readback1
A: 1 ASG: B: 1 C: 1
CALC: A&&(B=C)&&(C=D)&&(D=E)&&(E=F)&&(F=G)&&(G=H)&&(H=I)&&(I=J)&&(J=K)&&(K=L)
D: 1 DESC: Check consistency DISA: 0
DISP: 0 DISV: 1 E: 1 F: 1
G: 1 H: 1 I: 1 J: 1
K: 0 L: 1 NAME: testMbbiG:Readback1
SEVR: NO_ALARM STAT: NO_ALARM TPRO: 0 VAL: 0
First of all note that the CALC field is slightly different here; A is derived
from the previous PV, testMbbiG:Readback0. The VAL of this PV is 0, so a "Not
Equal" condition was found here. All the available inputs B through L are used;
inspection shows that K is 0 and must be the problem. By appending a "1" to the
same "dbpr" command we can get the information of where that value came from:
epics> dbpr testMbbiG:Readback1 1
A: 1 ADEL: 0 ASG: B: 1
BKPT: 00 C: 1
CALC: A&&(B=C)&&(C=D)&&(D=E)&&(E=F)&&(F=G)&&(G=H)&&(H=I)&&(I=J)&&(J=K)&&(K=L)
D: 1 DESC: Check consistency DISA: 0
DISP: 0 DISS: NO_ALARM DISV: 1 DTYP: <nil>
E: 1 EGU: EVNT: 0 F: 1
FLNK:CONSTANT 0 G: 1 H: 1 HHSV: NO_ALARM
HIGH: 0 HIHI: 0 HOPR: 0 HSV: NO_ALARM
HYST: 0 I: 1 INPA:CA_LINK testMbbiG:Readback0 CPP MS
INPB:CA_LINK testMbbi18:Readback CPP MS INPC:CA_LINK testMbbi19:Readback CPP MS
INPD:CA_LINK testMbbi1:Readback CPP MS INPE:CA_LINK testMbbi20:Readback CPP MS
INPF:CA_LINK testMbbi21:Readback CPP MS INPG:CA_LINK testMbbi22:Readback CPP MS
INPH:CA_LINK testMbbi2:Readback CPP MS INPI:CA_LINK testMbbi3:Readback CPP MS
INPJ:CA_LINK testMbbi4:Readback CPP MS INPK:CA_LINK testMbbi5:Readback CPP MS
INPL:CA_LINK testMbbi6:Readback CPP MS J: 1 K: 0
L: 1 LLSV: NO_ALARM LOLO: 0 LOPR: 0
LOW: 0 LSV: NO_ALARM MDEL: 0
NAME: testMbbiG:Readback1 PACT: 0 PHAS: 0
PINI: NO PREC: 0 PRIO: LOW PUTF: 0
RPRO: 0 SCAN: Passive SDIS:CONSTANT SEVR: NO_ALARM
STAT: NO_ALARM TPRO: 0 TSE: 0 TSEL:CONSTANT
UDF: 0 VAL: 0
epics>
The fields INPA through INPL are the input links for A through L. We can see
that INPK points to testMbbi5:Readback. Examination of that record shows it is
indeed 0:
epics> dbpr testMbbi5:Readback
ASG: DESC: DISA: 0 DISP: 0
DISV: 1 NAME: testMbbi5:Readback RVAL: 0
SEVR: NO_ALARM STAT: NO_ALARM SVAL: 0 TPRO: 0
VAL: 0
epics>
Here's what the third and last calc record looks like:
epics> dbpr testMbbiG:Readback2
A: 0 ASG: B: 1 C: 1
CALC: A&&(B=C)&&(C=D)&&(D=E) D: 1
DESC: Check consistency DISA: 0 DISP: 0
DISV: 1 E: 1 F: 0 G: 0
H: 0 I: 0 J: 0 K: 0
L: 0 NAME: testMbbiG:Readback2 SEVR: NO_ALARM
STAT: NO_ALARM TPRO: 0 VAL: 0
Note that it is giving a VAL of 0 because its input from the second calc record
is "0"; its own 4 inputs are all "1". Only testMbbi5:Readback is not equal to
the others and the setpoint.
| ||||||||||||||
| ANJ, 19 Mar 2026 |
·
Home
·
News
·
About
·
Talk
·
Base
·
Modules
·
Extensions
·
· Distributions · Download · Documents · Links · Licensing · |