EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  <20222023  2024  Index 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  <20222023  2024 
<== Date ==> <== Thread ==>

Subject: Re: [EXTERNAL] Creating a database record
From: "Vodopivec, Klemen via Tech-talk" <tech-talk at aps.anl.gov>
To: EPICS Tech Talk <tech-talk at aps.anl.gov>
Date: Wed, 9 Feb 2022 16:36:35 +0000
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 <tech-talk at aps.anl.gov> wrote:
>
> On Thu, 3 Feb 2022 at 21:01, Dudley, David via Tech-talk <tech-talk at aps.anl.gov> 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. 


References:
Creating a database record Dudley, David via Tech-talk
Re: Creating a database record Ralph Lange via Tech-talk

Navigate by Date:
Prev: RE: Compilation of IOC using OPC UA device support DESMARCHELIER Gabriel via Tech-talk
Next: Connecting Basler camera with areaDetector on Windows Sullivan,Bryan via Tech-talk
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  <20222023  2024 
Navigate by Thread:
Prev: Re: Creating a database record Ralph Lange via Tech-talk
Next: RE: Creating a database record Dudley, David via Tech-talk
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  <20222023  2024 
ANJ, 14 Sep 2022 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·