![]() |
![]() ![]()
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 <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.
| ||||||||||||||
ANJ, 14 Sep 2022 |
![]() · Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing · |