Merge branch '7.0' into PSI-7.0
This commit is contained in:
@@ -43,7 +43,7 @@ static long init_record(dbCommon *pcommon)
|
||||
{
|
||||
long status=0;
|
||||
|
||||
/* dont convert */
|
||||
/* don't convert */
|
||||
status=2;
|
||||
return status;
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl)
|
||||
break;
|
||||
|
||||
case dbfl_type_ref:
|
||||
must_lock = !pfl->u.r.dtor;
|
||||
must_lock = !pfl->dtor;
|
||||
if (must_lock) {
|
||||
dbScanLock(dbChannelRecord(chan));
|
||||
dbChannelGetArrayInfo(chan, &pSource, &nSource, &offset);
|
||||
@@ -123,9 +123,9 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl)
|
||||
offset = (offset + start) % pfl->no_elements;
|
||||
dbExtractArray(pSource, pTarget, pfl->field_size,
|
||||
nTarget, pfl->no_elements, offset, my->incr);
|
||||
if (pfl->u.r.dtor) pfl->u.r.dtor(pfl);
|
||||
if (pfl->dtor) pfl->dtor(pfl);
|
||||
pfl->u.r.field = pTarget;
|
||||
pfl->u.r.dtor = freeArray;
|
||||
pfl->dtor = freeArray;
|
||||
pfl->u.r.pvt = my->arrayFreeList;
|
||||
}
|
||||
/* adjust no_elements (even if zero elements remain) */
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <chfPlugin.h>
|
||||
#include <recGbl.h>
|
||||
#include <epicsExit.h>
|
||||
#include <db_field_log.h>
|
||||
#include <dbAccess.h>
|
||||
#include <epicsExport.h>
|
||||
|
||||
typedef struct myStruct {
|
||||
@@ -81,8 +81,8 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
|
||||
status = dbFastGetConvertRoutine[pfl->field_type][DBR_DOUBLE]
|
||||
(localAddr.pfield, (void*) &val, &localAddr);
|
||||
if (!status) {
|
||||
send = 0;
|
||||
recGblCheckDeadband(&my->last, val, my->hyst, &send, 1);
|
||||
send = pfl->mask & ~(DBE_VALUE|DBE_LOG);
|
||||
recGblCheckDeadband(&my->last, val, my->hyst, &send, pfl->mask & (DBE_VALUE|DBE_LOG));
|
||||
if (send && my->mode == 1) {
|
||||
my->hyst = val * my->cval/100.;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "freeList.h"
|
||||
#include "db_field_log.h"
|
||||
#include "chfPlugin.h"
|
||||
#include "epicsExit.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
typedef struct myStruct {
|
||||
@@ -102,17 +103,20 @@ static chfPluginIf pif = {
|
||||
NULL /* channel_close */
|
||||
};
|
||||
|
||||
static void decShutdown(void *ignore)
|
||||
{
|
||||
if (myStructFreeList)
|
||||
freeListCleanup(myStructFreeList);
|
||||
myStructFreeList = NULL;
|
||||
}
|
||||
|
||||
static void decInitialize(void)
|
||||
{
|
||||
static int firstTime = 1;
|
||||
|
||||
if (!firstTime) return;
|
||||
firstTime = 0;
|
||||
|
||||
if (!myStructFreeList)
|
||||
freeListInitPvt(&myStructFreeList, sizeof(myStruct), 64);
|
||||
|
||||
chfPluginRegister("dec", &pif, opts);
|
||||
epicsAtExit(decShutdown, NULL);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(decInitialize);
|
||||
|
||||
@@ -1,59 +1,214 @@
|
||||
=head1 Channel Filters
|
||||
=title Field Modifiers and Channel Filters
|
||||
|
||||
Channel Filters can be applied to Channel Access channels by a client, using
|
||||
a JSON Field Modifier to select the filter and any parameters.
|
||||
The following filters are available in this release:
|
||||
=head2 Contents
|
||||
|
||||
=over
|
||||
|
||||
=item * L<TimeStamp|/"TimeStamp Filter ts">
|
||||
=item * L<Introduction
|
||||
|/"Introduction">
|
||||
|
||||
=item * L<Deadband|/"Deadband Filter dbnd">
|
||||
=item * L<Using Field Modifiers and Channel Filters
|
||||
|/"Using Field Modifiers and Channel Filters">
|
||||
|
||||
=item * L<Array|/"Array Filter arr">
|
||||
=item * L<Example Filters
|
||||
|/"Example Filters">
|
||||
|
||||
=item * L<Synchronize|/"Synchronize Filter sync">
|
||||
=item * L<Field Modifier Reference
|
||||
|/"Field Modifier Reference">
|
||||
|
||||
=item * L<Decimation|/"Decimation Filter dec">
|
||||
=over
|
||||
|
||||
=item * L<UTag|/"UTag Filter utag">
|
||||
=item * L<Long String Modifier C<$>
|
||||
|/"Long String Field Modifier $">
|
||||
|
||||
=item * L<Subarray Modifier C<<< [E<hellip>] >>>
|
||||
|/"Subarray Field Modifier [start:increment:end]">
|
||||
|
||||
=back
|
||||
|
||||
=head2 Using Filters
|
||||
=item * L<JSON5 Channel Filters
|
||||
|/"JSON5 Channel Filters">
|
||||
|
||||
Channel filters can be added to any Channel Access channel name.
|
||||
There can be more than one filter applied to the same channel, in which case the
|
||||
order that they are specified will control the order in which they are applied
|
||||
to the resulting data-stream.
|
||||
The filter specification must appear after the field name, or if the default
|
||||
(VAL) field is used after a dot C<.> appended to the record name.
|
||||
With the exception of the array short-hand which is described below, all filters
|
||||
must appear inside a pair of braces C< {} > after the dot expressed as a JSON
|
||||
(L<JavaScript Object Notation|http://www.json.org/>) object, which allows filter
|
||||
parameters to be included as needed.
|
||||
=over
|
||||
|
||||
Each filter is given as a name/value pair. The filter name (given in parentheses
|
||||
in the titles below) is a string, and must be enclosed inside double-quotes C<">
|
||||
characters as per the JSON specification.
|
||||
Parameters to that filter are provided as the value part of the name/value pair,
|
||||
and will normally appear as a child JSON object consisting of name/value pairs
|
||||
inside a nested pair of braces C< {} >.
|
||||
=item * L<TimeStamp Filter C<<< {ts:{}} >>>
|
||||
|/"TimeStamp Filter ts">
|
||||
|
||||
=head4 Example Filter
|
||||
=item * L<Deadband Filter C<<< {dbnd:{E<hellip>}} >>>
|
||||
|/"Deadband Filter dbnd">
|
||||
|
||||
Given a record called C<test:channel> the following would apply a filter C<f> to
|
||||
the VAL field of that record, giving the filter two numeric parameters named
|
||||
C<lo> and C<hi>:
|
||||
=item * L<Array Filter C<<< {arr:{E<hellip>}} >>>
|
||||
|/"Array Filter arr">
|
||||
|
||||
test:channel.{"f":{"lo":0,"hi":10}}
|
||||
=item * L<Synchronize Filter C<<< {sync:{E<hellip>}} >>>
|
||||
|/"Synchronize Filter sync">
|
||||
|
||||
Note that due to the required presence of the double-quote characters in the
|
||||
JSON strings in the name string, it will usually be necessary to enclose a
|
||||
filtered name within single-quotes C<< ' ... ' >> when typing it as an
|
||||
argument to a Unix shell command.
|
||||
=item * L<Decimation Filter C<<< {dec:{E<hellip>}} >>>
|
||||
|/"Decimation Filter dec">
|
||||
|
||||
=head2 Filter Reference
|
||||
=item * L<User Tag Filter C<<< {utag:{E<hellip>}} >>>
|
||||
|/"User Tag Filter utag">
|
||||
|
||||
=back
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Introduction
|
||||
|
||||
A Field Modifier is a string that is appended to the field name part of a
|
||||
Channel Access or PV Access channel name of an IOC-based server.
|
||||
The IOC currently recognizes 3 different kinds of field modifier, which are
|
||||
described below.
|
||||
|
||||
A Channel Filter is an IOC plugin that can be attached to an IOC process
|
||||
variable channel using a field modifier, and can alter the data updates that are
|
||||
served to the client that requested the filtering.
|
||||
Clients that use a channel filter have no effect on other clients connected to
|
||||
the same PV.
|
||||
Filters can only modify or drop monitor events that the IOC posts; introducing
|
||||
extra monitor events (in between the events posted by the IOC itself) is not
|
||||
currently possible.
|
||||
|
||||
Most Channel Filters are configured by a field modifier that uses JSON5
|
||||
syntax to select the type of filter and provide any parameters it accepts.
|
||||
|
||||
|
||||
=head2 Using Field Modifiers and Channel Filters
|
||||
|
||||
Modifiers can be added to any Channel Access or PV Access channel name.
|
||||
There can be more than one modifier or filter applied to a channel.
|
||||
Modifiers must appear immediately after the field name if one is included in the
|
||||
channel name.
|
||||
If no field is named because the default (VAL) field is the target, the
|
||||
modifiers must come immediately after a dot C<.> appended to the record name.
|
||||
|
||||
The order that modifiers and filters are specified controls the order in which
|
||||
they are applied to the resulting data-stream.
|
||||
If used, the Long String and Subarray field modifiers must appear first and in
|
||||
that order, followed by any channel filters inside a pair of braces C< {} > that
|
||||
form a JSON5 (L<JavaScript Object Notation|https://spec.json5.org/>) map, which
|
||||
allows filters and their parameters to be specified as needed.
|
||||
|
||||
Each JSON5 filter is specified as a name:value pair.
|
||||
The filter name is a map key that may be an unquoted identifier name (which all
|
||||
of the filter names given below are), or a string enclosed inside either single-
|
||||
or double-quote characters C<'> or C<"> as per the JSON5 specification.
|
||||
Parameters to the filter are provided in the value part of the key:value pair
|
||||
after the colon C<:> character, and will normally be an embedded JSON5 map
|
||||
containing zero or more key/value pairs inside a nested pair of braces C< {} >.
|
||||
|
||||
Unless included inside a quoted string, white space characters are ignored and
|
||||
skipped over by the JSON5 parser between other token characters.
|
||||
This includes horizontal and vertical tabs, line feed/form feed/carriage return,
|
||||
space and the non-breaking space character C< \xA0 >.
|
||||
Within a quoted string, line breaks may escaped with a backslash C<\> to be
|
||||
omitted from the parsed string.
|
||||
|
||||
An IOC Channel Access link can include filters in its channel name, but it is
|
||||
important to not include any spaces at all in the filter specification.
|
||||
If a filter name or parameter must contain a space it will be necessary to
|
||||
express that space character as an escaped character C<\x20> or C<\u0020> inside
|
||||
a quoted string, otherwise the space will mark the end of the channel name to
|
||||
the link parsing code inside the IOC.
|
||||
|
||||
=head4 Example Filters
|
||||
|
||||
Given a record called C<test:channel> the following would all apply a channel
|
||||
filter C<f> to the VAL field of that record, giving the filter two numeric
|
||||
parameters named C<lo> and C<hi>:
|
||||
|
||||
test:channel.{f:{lo:0,hi:10}}
|
||||
test:channel.{"f":{"lo":0, "hi":10}}
|
||||
test:channel.{'f': {'lo':0, 'hi':10} }
|
||||
|
||||
When typing a filtered channel name as an argument to a Unix shell command, if
|
||||
quote characters are used for keys or values in JSON strings within the channel
|
||||
name string it may be necessary to enclose the name within quotes C<'> or C<">
|
||||
or to use back-slash escapes before them.
|
||||
Quotes may not be required when the Long String modifier C<$> is used at the end
|
||||
of a field name with nothing following it, but will be necessary for a square
|
||||
bracketted Subarray filter or if a dollar sign is followed by something else.
|
||||
|
||||
Hal$ caget test:channel.{f:{lo:0,hi:10}}
|
||||
...
|
||||
Hal$ caget 'test:channel.{"f":{"lo":0, "hi":10}}'
|
||||
...
|
||||
Hal$ caget -S calc:record.CALC$
|
||||
...
|
||||
Hal$ caget -S 'test:channel.NAME$[0:4]'
|
||||
test:channel.NAME$[0:4] test
|
||||
|
||||
=head2 Field Modifier Reference
|
||||
|
||||
The two built-in field modifiers use a simplified syntax following the record
|
||||
field name.
|
||||
|
||||
=head3 Long String Field Modifier C<$>
|
||||
|
||||
Appending a dollar sign C<$> to the name of a C<DBF_STRING> field causes the IOC
|
||||
to change the representation of that field into an array of characters, which
|
||||
allows strings longer than 40 character to be transported through Channel
|
||||
Access.
|
||||
Long strings are particularly useful for the CALC fields of a calculation or
|
||||
calcout record, which can hold up to 80 characters, or the VAL fields of an lsi
|
||||
(Long String Input) or lso (Long String Output) record which can be any length
|
||||
as chosen by the database designer.
|
||||
|
||||
Hal$ cainfo test:channel.NAME
|
||||
test:channel.NAME
|
||||
State: connected
|
||||
Host: 10.234.56.78:5064
|
||||
Access: read, no write
|
||||
Native data type: DBF_STRING
|
||||
Request type: DBR_STRING
|
||||
Element count: 1
|
||||
Hal$ cainfo test:channel.NAME$
|
||||
test:channel.NAME$
|
||||
State: connected
|
||||
Host: 10.234.56.78:5064
|
||||
Access: read, no write
|
||||
Native data type: DBF_CHAR
|
||||
Request type: DBR_CHAR
|
||||
Element count: 61
|
||||
|
||||
A CA client accessing a channel that uses the Long String field modifier will
|
||||
have to be specifically configured to treat the data as a string instead of the
|
||||
array of C<DBF_CHAR> that it looks like.
|
||||
CA clients should not attempt to parse the channel name themselves to recognize
|
||||
this field modifier in the name.
|
||||
All long string values returned by the IOC should include a trailing zero byte
|
||||
in their data as is standard for strings in the C language.
|
||||
For the catools programs provided with Base, the flag C<-S> indicates that a
|
||||
channel containing a character array should be treated as a long string.
|
||||
|
||||
Hal$ caget test:channel.NAME
|
||||
test:channel.NAME test:channel
|
||||
Hal$ caget test:channel.NAME$
|
||||
test:channel.NAME$ 61 116 101 115 116 58 99 104 97 110 110 101 108 0 0 ...
|
||||
Hal$ caget -S test:channel.NAME$
|
||||
test:channel.NAME$ test:channel
|
||||
|
||||
|
||||
=head3 Subarray Field Modifier C<[start:increment:end]>
|
||||
|
||||
This square-bracket field modifier syntax gets translated within the IOC into
|
||||
calls to the L<Array Filter|/"Array Filter arr">, see that section below for
|
||||
details of this shorthand.
|
||||
|
||||
The subarray field modifier syntax can immediately follow a Long String field
|
||||
modifier, which permits fetching various kinds of substrings from the field.
|
||||
This syntax cannot appear after a JSON filter specification though, the JSON
|
||||
"arr" filter syntax must be used to apply an array filter after any other JSON
|
||||
filter type.
|
||||
|
||||
Hal$ caget -S 'test:channel.NAME$[0:4]'
|
||||
test:channel.NAME$[0:4] test
|
||||
Hal$ caget -S 'test:channel.NAME$[5:-1]'
|
||||
test:channel.NAME$[5:-1] channel
|
||||
|
||||
|
||||
=head2 JSON5 Channel Filters
|
||||
|
||||
=cut
|
||||
|
||||
@@ -61,11 +216,11 @@ registrar(tsInitialize)
|
||||
|
||||
=head3 TimeStamp Filter C<"ts">
|
||||
|
||||
This filter is used to set the timestamp of the value fetched through
|
||||
the channel to the time the value was fetched (or an update was sent),
|
||||
rather than the time the record last
|
||||
processed which could have been days or even weeks ago for some records, or set
|
||||
to the EPICS epoch if the record has never processed.
|
||||
This filter replaces the timestamp in the data fetched through the channel with
|
||||
the time the value was fetched (or an update was sent). The record's timestamp
|
||||
indicates when the record last processed, which could have been days or even
|
||||
weeks ago for some records, or set to the EPICS epoch if the record has never
|
||||
processed.
|
||||
|
||||
=head4 Parameters
|
||||
|
||||
@@ -125,7 +280,7 @@ The default mode is C<abs> if no mode parameter is included.
|
||||
test:channel 2012-09-01 22:10:23.601023 5
|
||||
test:channel 2012-09-01 22:10:24.601136 6 HIGH MINOR
|
||||
^C
|
||||
Hal$ camonitor 'test:channel.{"dbnd":{"abs":1.5}}'
|
||||
Hal$ camonitor 'test:channel.{"dbnd":{"d":1.5}}'
|
||||
test:channel.{"dbnd":{"d":1.5}} 2012-09-01 22:11:49.613341 1 LOLO MAJOR
|
||||
test:channel.{"dbnd":{"d":1.5}} 2012-09-01 22:11:51.613615 3 LOW MINOR
|
||||
test:channel.{"dbnd":{"d":1.5}} 2012-09-01 22:11:53.613804 5
|
||||
@@ -144,16 +299,21 @@ subarrays).
|
||||
|
||||
=head4 Parameters
|
||||
|
||||
Note: Negative index numbers address from the end of the array, with C<-1> being the last element.
|
||||
|
||||
=over
|
||||
|
||||
=item Square bracket notation C<[start:increment:end]> (shorthand)
|
||||
|
||||
The common square bracket notation which can be used in place of JSON.
|
||||
This much shorter square bracket notation can be used in place of JSON.
|
||||
Any parameter may be omitted (keeping the colons) to use the default value.
|
||||
If only one colon is included, this means C<[start:end]> with an increment of 1.
|
||||
If only a single parameter is used C<[index]> the filter returns one element.
|
||||
If only one colon is included, it means C<[start:end]> with an increment of 1.
|
||||
If only a single parameter is given C<[index]> the filter returns one element.
|
||||
|
||||
Index numbers for the start and end parameters must be integers, with the first
|
||||
array element being found at index C<0>.
|
||||
The value of an index may be negative, in which case the indexing is counted
|
||||
backwards from the end of the array, with C<-1> being the last element.
|
||||
If the start index selects an element that comes after the end index element,
|
||||
the subarray returned will always be empty.
|
||||
|
||||
=item Start index C<"s">
|
||||
|
||||
@@ -161,8 +321,8 @@ Index of the first original array element to retrieve.
|
||||
|
||||
=item Increment C<"i">
|
||||
|
||||
Index increment between retrieved elements of the original array; must be
|
||||
a positive number.
|
||||
The stride or increment to apply between elements of the original array to be
|
||||
retrieved. This value must be a positive integer.
|
||||
|
||||
=item End index C<"e">
|
||||
|
||||
@@ -176,9 +336,9 @@ C<s=0> (first element), C<i=1> (fetch all elements), C<e=-1>
|
||||
|
||||
=head4 Example
|
||||
|
||||
Hal$ caget test:channel 'test:channel.{"arr":{"s":2,"i":2,"e":8}}' test:channel.[3:5] test:channel.[3:2:-3]
|
||||
Hal$ caget test:channel 'test:channel.{"arr":{s:2,i:2,e:8}}' test:channel.[3:5] test:channel.[3:2:-3]
|
||||
test:channel 10 0 1 2 3 4 5 6 7 8 9
|
||||
test:channel.{"arr":{"s":2,"i":2,"e":8}} 4 2 4 6 8
|
||||
test:channel.{"arr":{s:2,i:2,e:8}} 4 2 4 6 8
|
||||
test:channel.[3:5] 3 3 4 5
|
||||
test:channel.[3:2:-3] 3 3 5 7
|
||||
|
||||
@@ -202,13 +362,14 @@ C<dbStateSet()>.
|
||||
=item Mode+State
|
||||
|
||||
Mode and state can be specified in one definition (shorthand).
|
||||
The desired mode is given as parameter name (C<"before"> / C<"first"> /
|
||||
C<"while"> / C<"last"> / C<"after"> / C<"unless">), with the state name
|
||||
(enclosed in double quotes C<">) as value.
|
||||
The desired mode is given as the parameter name (C<"before"> / C<"first"> /
|
||||
C<"while"> / C<"last"> / C<"after"> / C<"unless"> which may be unquoted), with
|
||||
the state name (enclosed in single or double quotes C<"> or C<'>) as the value.
|
||||
|
||||
=item Mode C<"m">
|
||||
|
||||
A single word from the list below, enclosed in double quotes C<">.
|
||||
A single word from the list below, enclosed in single or double quotes C<'> or
|
||||
C<">.
|
||||
This controls how the state value should affect the monitor stream.
|
||||
|
||||
=over
|
||||
@@ -235,7 +396,7 @@ as the state is false.
|
||||
|
||||
=item State C<"s">
|
||||
|
||||
The name of a state variable, enclosed in double quotes C<">.
|
||||
The name of a state variable, enclosed in single or double quotes C<"> or C<'>.
|
||||
|
||||
=back
|
||||
|
||||
@@ -245,7 +406,7 @@ Assuming there is a system state called "blue", that is being controlled by
|
||||
some other facility such as a timing system, updates could be restricted to
|
||||
periods only when "blue" is true by using
|
||||
|
||||
Hal$ camonitor 'test:channel' 'test:channel.{"sync":{"while":"blue"}}'
|
||||
Hal$ camonitor 'test:channel' 'test:channel.{sync:{while:"blue"}}'
|
||||
...
|
||||
|
||||
=cut
|
||||
@@ -283,17 +444,18 @@ client connects.
|
||||
To sample a 60Hz channel at 1Hz, a 10Hz channel every 6 seconds or a 1Hz channel
|
||||
once every minute:
|
||||
|
||||
Hal$ camonitor 'test:channel' 'test:channel.{"dec":{"n":60}}'
|
||||
Hal$ camonitor 'test:channel' 'test:channel.{dec:{n:60}}'
|
||||
...
|
||||
|
||||
=cut
|
||||
|
||||
registrar(utagInitialize)
|
||||
|
||||
=head3 UTag Filter C<"utag">
|
||||
=head3 User Tag Filter C<"utag">
|
||||
|
||||
This filter applies a test UTAG&M==V to the value taken from the UTAG record field
|
||||
and drops those updates which evaluate as false.
|
||||
This filter applies a test C< (UTAG & M) == V > to the value of the record's
|
||||
UTAG field at the time each monitor event is posted, and drops all updates for
|
||||
which this expression is false.
|
||||
|
||||
=head4 Parameters
|
||||
|
||||
@@ -301,12 +463,19 @@ and drops those updates which evaluate as false.
|
||||
|
||||
=item Mask C<"M">
|
||||
|
||||
Bit mask.
|
||||
An integer to be used as a bit mask.
|
||||
|
||||
=item Value C<"V">
|
||||
|
||||
Required value.
|
||||
The integer value to be matched after applying the mask to the UTAG value.
|
||||
|
||||
=back
|
||||
|
||||
=head4 Example
|
||||
|
||||
To read a channel only when the UTAG value is even (bit 0 is 0):
|
||||
|
||||
Hal$ camonitor 'test:channel' 'test:channel.{utag:{m:1, v:0}}'
|
||||
...
|
||||
|
||||
=cut
|
||||
|
||||
@@ -35,7 +35,7 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
|
||||
|
||||
/* If reference and not already copied,
|
||||
must make a copy (to ensure coherence between time and data) */
|
||||
if (pfl->type == dbfl_type_ref && !pfl->u.r.dtor) {
|
||||
if (pfl->type == dbfl_type_ref && !pfl->dtor) {
|
||||
void *pTarget = calloc(pfl->no_elements, pfl->field_size);
|
||||
void *pSource = pfl->u.r.field;
|
||||
if (pTarget) {
|
||||
@@ -46,7 +46,7 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
|
||||
dbExtractArray(pSource, pTarget, pfl->field_size,
|
||||
nSource, pfl->no_elements, offset, 1);
|
||||
pfl->u.r.field = pTarget;
|
||||
pfl->u.r.dtor = freeArray;
|
||||
pfl->dtor = freeArray;
|
||||
pfl->u.r.pvt = pvt;
|
||||
dbScanUnlock(dbChannelRecord(chan));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
=head1 Extensible Links
|
||||
=title Extensible IOC Database Links
|
||||
|
||||
The extensible link mechanism allows new kinds of record links to be created,
|
||||
using JSON for the link address syntax.
|
||||
@@ -24,13 +24,11 @@ The following additional link types are available in this release:
|
||||
=head2 Using JSON Links
|
||||
|
||||
When setting a record link field to a JSON link address, the link specification
|
||||
must appear inside a pair of braces C< {} > expressed as a JSON (L<JavaScript
|
||||
Object Notation|http://www.json.org/>) object, which allows link parameters to
|
||||
be defined as needed by the particular link type. When link fields are set from
|
||||
an IOC database file at initialization time, the field definitions may take
|
||||
advantage of a "relaxed JSON" syntax that reduces the number of double-quote
|
||||
characters required and maintains backwards compatibility with the older
|
||||
database file syntax.
|
||||
must appear inside a pair of braces C< {} > expressed as a JSON5 (L<JavaScript
|
||||
Object Notation|https://spec.json5.org/>) object, which allows link parameters
|
||||
to be defined as needed by the particular link type. When link fields are set in
|
||||
an IOC database file, the field value may take advantage of the JSON5 syntax to
|
||||
reduce the number of double-quote characters required.
|
||||
|
||||
|
||||
=head2 Link Type Reference
|
||||
@@ -68,10 +66,10 @@ results in an error.
|
||||
{const: "Pi"}
|
||||
{const: [1, 2.718281828459, 3.14159265358979]}
|
||||
{const: ["One", "e", "Pi"]}
|
||||
{const:[Inf, -Inf]})
|
||||
|
||||
The JSON syntax does not support Infinity or NaN values when parsing numbers,
|
||||
but (for scalars) it is possible to provide these in a string which will be
|
||||
converted to the desired double value at initialization, for example:
|
||||
The newer JSON5 syntax supports Infinity values when parsing numbers, so it is
|
||||
no longer necessary to quote these in a string, although that still works:
|
||||
|
||||
field(INP, {const:"Inf"})
|
||||
|
||||
|
||||
@@ -275,8 +275,11 @@ static long fetch_values(aSubRecord *prec)
|
||||
|
||||
/* Get the input link values */
|
||||
for (i = 0; i < NUM_ARGS; i++) {
|
||||
DBLINK *plink = &(&prec->inpa)[i];
|
||||
long nRequest = (&prec->noa)[i];
|
||||
status = dbGetLink(&(&prec->inpa)[i], (&prec->fta)[i], (&prec->a)[i], 0,
|
||||
if(dbLinkIsConstant(plink))
|
||||
continue;
|
||||
status = dbGetLink(plink, (&prec->fta)[i], (&prec->a)[i], 0,
|
||||
&nRequest);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
@@ -736,6 +736,10 @@ The choices can be found by following the link to the menuFtype definition.
|
||||
|
||||
These fields specify how many array elements the input value fields may hold.
|
||||
|
||||
Note that access to the C<NOT> field from C code must use the field name in
|
||||
upper case, e.g. C<< prec->NOT >> since the lower-case C<not> is a reserved
|
||||
word in C++ and cannot be used as an identifier.
|
||||
|
||||
=fields NOA, NOB, NOC, NOD, NOE, NOF, NOG, NOH, NOI, NOJ, NOK, NOL, NOM, NON, NOO, NOP, NOQ, NOR, NOS, NOT, NOU
|
||||
|
||||
=cut
|
||||
@@ -2349,10 +2353,12 @@ value, you would either delete the NOA specification, or specify it as "1".
|
||||
The associated subroutine code that uses the A field might look like this:
|
||||
|
||||
static long my_asub_routine(aSubRecord *prec) {
|
||||
long i, *a;
|
||||
long i;
|
||||
epicsInt32 *a;
|
||||
|
||||
double sum=0;
|
||||
...
|
||||
a = (long *)prec->a;
|
||||
a = (epicsInt32 *)prec->a;
|
||||
for (i=0; i<prec->noa; i++) {
|
||||
sum += a[i];
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "special.h"
|
||||
#include "cantProceed.h"
|
||||
#include "menuYesNo.h"
|
||||
#include "menuOmsl.h"
|
||||
|
||||
#define GEN_SIZE_OFFSET
|
||||
#include "aaoRecord.h"
|
||||
@@ -92,6 +93,7 @@ rset aaoRSET={
|
||||
epicsExportAddress(rset,aaoRSET);
|
||||
|
||||
static void monitor(aaoRecord *);
|
||||
static long fetchValue(aaoRecord *, int);
|
||||
static long writeValue(aaoRecord *);
|
||||
|
||||
static long init_record(struct dbCommon *pcommon, int pass)
|
||||
@@ -142,7 +144,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
|
||||
recGblRecordError(S_dev_missingSup, prec, "aao: init_record");
|
||||
return S_dev_missingSup;
|
||||
}
|
||||
return 0;
|
||||
return fetchValue(prec, 1);
|
||||
}
|
||||
|
||||
static long process(struct dbCommon *pcommon)
|
||||
@@ -161,8 +163,11 @@ static long process(struct dbCommon *pcommon)
|
||||
if ( !pact ) {
|
||||
prec->udf = FALSE;
|
||||
|
||||
if(!!(status = fetchValue(prec, 0)))
|
||||
return status;
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
* will be up to date if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
@@ -339,6 +344,34 @@ static void monitor(aaoRecord *prec)
|
||||
db_post_events(prec, &prec->val, monitor_mask);
|
||||
}
|
||||
|
||||
static long fetchValue(aaoRecord *prec, int init)
|
||||
{
|
||||
int isConst;
|
||||
long status;
|
||||
long nReq = prec->nelm;
|
||||
|
||||
if(prec->omsl!=menuOmslclosed_loop)
|
||||
return 0;
|
||||
|
||||
isConst = dbLinkIsConstant(&prec->dol);
|
||||
|
||||
if(init && isConst) {
|
||||
status = dbLoadLinkArray(&prec->dol, prec->ftvl, prec->bptr, &nReq);
|
||||
|
||||
} else if(!init && !isConst) {
|
||||
status = dbGetLink(&prec->dol, prec->ftvl, prec->bptr, 0, &nReq);
|
||||
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!status) {
|
||||
prec->nord = nReq;
|
||||
prec->udf = FALSE;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static long writeValue(aaoRecord *prec)
|
||||
{
|
||||
aaodset *pdset = (aaodset *) prec->dset;
|
||||
@@ -357,7 +390,7 @@ static long writeValue(aaoRecord *prec)
|
||||
case menuYesNoYES: {
|
||||
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
|
||||
if (prec->pact || (prec->sdly < 0.)) {
|
||||
/* Device suport is responsible for buffer
|
||||
/* Device support is responsible for buffer
|
||||
which might be write-only so we may not be
|
||||
allowed to call dbPutLink on it.
|
||||
Maybe also device support has an advanced
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
=title Array Analog Output (aao)
|
||||
|
||||
The array analog output record type is used to write array data. The array data
|
||||
can contain any of the supported data types. The record is in many ways similar to
|
||||
the waveform record but outputs arrays instead of reading them. It also allows the
|
||||
device support to allocate the array storage.
|
||||
can contain any of the supported data types. The record is in many ways similar
|
||||
to the waveform record but outputs arrays instead of reading them. It also
|
||||
allows the device support to allocate the array storage.
|
||||
|
||||
=recordtype aao
|
||||
|
||||
@@ -32,28 +32,30 @@ The record-specific fields are described below, grouped by functionality.
|
||||
=head3 Scan Parameters
|
||||
|
||||
The array analog output record has the standard fields for specifying under what
|
||||
circumstances the record will be processed. These fields are listed in L<Scan
|
||||
Fields>. In addition, L<Scanning Specification> explains how these fields are
|
||||
used. I/O event scanning is only available when supported by device support.
|
||||
circumstances the record will be processed.
|
||||
These fields are described in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
|
||||
=fields SCAN, PHAS, EVNT, PRIO, PINI
|
||||
|
||||
=head3 Write Parameters
|
||||
|
||||
These fields are configurable by the user to specify how and where to the record
|
||||
writes its data. The OUT field determines where the array analog output writes its
|
||||
output. It can be a hardware address, a channel access or database link, or a
|
||||
constant. Only in records that use soft device support can the OUT field be a
|
||||
channel access link, a database link, or a constant. Otherwise, the OUT field must
|
||||
be a hardware address. See L<Address Specification> for information on the format
|
||||
of hardware addresses and database links.
|
||||
writes its data. The OUT field determines where the array analog output writes
|
||||
its output. It can be a hardware address, a channel access or database link, or
|
||||
a constant. Only in records that use soft device support can the OUT field be a
|
||||
channel access link, a database link, or a constant. Otherwise, the OUT field
|
||||
must be a hardware address. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on the format of hardware addresses and database links.
|
||||
|
||||
=head4 Fields related to array writing
|
||||
|
||||
The DTYP field must contain the name of the appropriate device support module. The
|
||||
values in the array referenced by are written to the location specified in the OUT
|
||||
field. (If the OUT link is a constant, no data are written.) NELM specifies the
|
||||
maximum number of elements that the array can hold, while FTVL specifies the data
|
||||
type of the elements (follow the link in the table below for a list of the
|
||||
available choices).
|
||||
The DTYP field must contain the name of the appropriate device support module.
|
||||
The values in the array referenced by are written to the location specified in
|
||||
the OUT field. (If the OUT link is a constant, no data are written.) NELM
|
||||
specifies the maximum number of elements that the array can hold, while FTVL
|
||||
specifies the data type of the elements (follow the link in the table below for
|
||||
a list of the available choices).
|
||||
|
||||
=fields DTYP, OUT, NELM, FTVL
|
||||
|
||||
@@ -117,13 +119,34 @@ These parameters are used by the run-time code for processing the array analog
|
||||
output record. They are not configured using a configuration tool. Only the VAL
|
||||
field is modifiable at run-time.
|
||||
|
||||
VAL references the array where the array analog output record stores its data. The
|
||||
BPTR field holds the address of the array.
|
||||
VAL references the array where the array analog output record stores its data.
|
||||
The BPTR field holds the address of the array.
|
||||
|
||||
The NORD field holds a counter of the number of elements that have been written to
|
||||
the output,
|
||||
The NORD field holds a counter of the number of elements that have been written
|
||||
to the output,
|
||||
|
||||
=fields VAL, BPTR, NORD
|
||||
=fields VAL, BPTR, NORD, OMSL, DOL
|
||||
|
||||
The following steps are performed in order during record processing.
|
||||
|
||||
=head4 Fetch Value
|
||||
|
||||
The OMSL menu field is used to determine whether the DOL link
|
||||
field should be used during processing or not:
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
If OMSL is C<supervisory> the DOL field are not used.
|
||||
The new output value is taken from the VAL field, which may have been set from
|
||||
elsewhere.
|
||||
|
||||
=item *
|
||||
If OMSL is C<closed_loop> the DOL link field is read to obtain a value.
|
||||
|
||||
=back
|
||||
|
||||
Note: The OMSL and DOL fields were added to the aaoRecord in Base 7.0.7.
|
||||
|
||||
=head3 Simulation Mode Parameters
|
||||
|
||||
@@ -325,6 +348,17 @@ Scan forward link if necessary, set PACT FALSE, and return.
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Link")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
field(OMSL,DBF_MENU) {
|
||||
prompt("Output Mode Select")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
menu(menuOmsl)
|
||||
}
|
||||
field(EGU,DBF_STRING) {
|
||||
prompt("Engineering Units")
|
||||
promptgroup("80 - Display")
|
||||
@@ -438,9 +472,9 @@ Scan forward link if necessary, set PACT FALSE, and return.
|
||||
=head3 Fields Of Interest To Device Support
|
||||
|
||||
Each array analog output record record must have an associated set of device
|
||||
support routines. The primary responsibility of the device support routines is to
|
||||
write the array data value whenever C<write_aao()> is called. The device support
|
||||
routines are primarily interested in the following fields:
|
||||
support routines. The primary responsibility of the device support routines is
|
||||
to write the array data value whenever C<write_aao()> is called. The device
|
||||
support routines are primarily interested in the following fields:
|
||||
|
||||
=fields PACT, DPVT, NSEV, NSTA, OUT, NELM, FTVL, BPTR, NORD
|
||||
|
||||
@@ -490,7 +524,8 @@ provided for any device type that can use the ioEvent scanner.
|
||||
|
||||
long write_aao(dbCommon *precord)
|
||||
|
||||
This routine must write the array data to output. It returns the following values:
|
||||
This routine must write the array data to output. It returns the following
|
||||
values:
|
||||
|
||||
=over
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
#undef GEN_SIZE_OFFSET
|
||||
#include "epicsExport.h"
|
||||
|
||||
/* Hysterisis for alarm filtering: 1-1/e */
|
||||
/* Hysteresis for alarm filtering: 1-1/e */
|
||||
#define THRESHOLD 0.6321
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
|
||||
@@ -45,8 +45,9 @@ hardware address information that the device support uses to determine where the
|
||||
input data should come from.
|
||||
The format for the INP field value depends on the device support layer that is
|
||||
selected by the DTYP field.
|
||||
See L<Address Specification|...> for a description of the various hardware
|
||||
address formats supported.
|
||||
See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for a description of the various hardware address formats supported.
|
||||
|
||||
=head3 Units Conversion
|
||||
|
||||
@@ -157,6 +158,10 @@ They do not affect the functioning of the record at all.
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
NAME is the record's name, and can be useful when the PV name that a client
|
||||
knows is an alias for the record.
|
||||
|
||||
=item *
|
||||
DESC is a string that is usually used to briefly describe the record.
|
||||
|
||||
@@ -175,7 +180,10 @@ DOUBLE fields.
|
||||
|
||||
=back
|
||||
|
||||
=fields DESC, EGU, HOPR, LOPR, PREC
|
||||
See L<Fields Common to All Record Types|dbCommonRecord/Operator Display
|
||||
Parameters> for more about the record name (NAME) and description (DESC) fields.
|
||||
|
||||
=fields NAME, DESC, EGU, HOPR, LOPR, PREC
|
||||
|
||||
=head3 Alarm Limits
|
||||
|
||||
@@ -198,6 +206,11 @@ positive number of seconds will delay the record going into or out of a minor
|
||||
alarm severity or from minor to major severity until the input signal has been
|
||||
in the alarm range for that number of seconds.
|
||||
|
||||
See L<Alarm Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#alarm-specification>
|
||||
for a complete explanation of record alarms and of the standard fields.
|
||||
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related
|
||||
to alarms that are common to all record types.
|
||||
|
||||
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST, AFTC, LALM
|
||||
|
||||
=head3 Monitor Parameters
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#include "recGbl.h"
|
||||
#include "menuConvert.h"
|
||||
#include "menuOmsl.h"
|
||||
#include "menuYesNo.h"
|
||||
#include "menuSimm.h"
|
||||
#include "menuIvoa.h"
|
||||
|
||||
#define GEN_SIZE_OFFSET
|
||||
@@ -188,7 +188,7 @@ static long process(struct dbCommon *pcommon)
|
||||
if(!status) convert(prec, value);
|
||||
prec->udf = isnan(prec->val);
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
* will be up to date if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
@@ -561,14 +561,20 @@ static long writeValue(aoRecord *prec)
|
||||
}
|
||||
|
||||
switch (prec->simm) {
|
||||
case menuYesNoNO:
|
||||
case menuSimmNO:
|
||||
status = pdset->write_ao(prec);
|
||||
break;
|
||||
|
||||
case menuYesNoYES: {
|
||||
case menuSimmYES:
|
||||
case menuSimmRAW:
|
||||
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
|
||||
if (prec->pact || (prec->sdly < 0.)) {
|
||||
status = dbPutLink(&prec->siol, DBR_DOUBLE, &prec->oval, 1);
|
||||
if (prec->simm == menuSimmYES)
|
||||
/* don't convert */
|
||||
status = dbPutLink(&prec->siol, DBR_DOUBLE, &prec->oval, 1);
|
||||
else /* prec->simm == menuSimmRAW*/
|
||||
/* convert */
|
||||
status = dbPutLink(&prec->siol, DBR_LONG, &prec->rval, 1);
|
||||
prec->pact = FALSE;
|
||||
} else { /* !prec->pact && delay >= 0. */
|
||||
epicsCallback *pvt = prec->simpvt;
|
||||
@@ -580,7 +586,6 @@ static long writeValue(aoRecord *prec)
|
||||
prec->pact = TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
|
||||
|
||||
@@ -161,9 +161,9 @@ The analog output record sends its desired output to the address in the
|
||||
OUT field. For analog outputs that write their values to devices, the
|
||||
OUT field must specify the address of the I/O card. In addition, the
|
||||
DTYP field must contain the name of the device support module. Be aware
|
||||
that the address format differs according to the I/O bus used. See
|
||||
Address Specification for information on the format of hardware
|
||||
addresses.
|
||||
that the address format differs according to the I/O bus used. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on the format of hardware addresses.
|
||||
|
||||
For soft records the output link can be a database link, a channel
|
||||
access link, or a constant value. If the link is a constant, no output
|
||||
@@ -263,8 +263,9 @@ processing.
|
||||
|
||||
The following fields are used to operate the record in simulation mode.
|
||||
|
||||
If SIMM (fetched through SIML) is YES, the record is put in SIMS
|
||||
If SIMM (fetched through SIML, if populated) is YES, the record is put in SIMS
|
||||
severity and the value is written through SIOL, without conversion.
|
||||
If SIMM is RAW, the value is converted and RVAL is written.
|
||||
SSCN sets a different SCAN mechanism to use in simulation mode.
|
||||
SDLY sets a delay (in sec) that is used for asynchronous simulation
|
||||
processing.
|
||||
@@ -307,7 +308,7 @@ for more information on simulation mode and its fields.
|
||||
interest(1)
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
prompt("Desired Output Link")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
@@ -557,7 +558,7 @@ for more information on simulation mode and its fields.
|
||||
prompt("Simulation Mode")
|
||||
special(SPC_MOD)
|
||||
interest(1)
|
||||
menu(menuYesNo)
|
||||
menu(menuSimm)
|
||||
}
|
||||
field(SIMS,DBF_MENU) {
|
||||
prompt("Simulation Mode Severity")
|
||||
|
||||
@@ -37,6 +37,8 @@ The binary input record has the standard fields for specifying under what
|
||||
circumstances the record will be processed.
|
||||
These fields are described in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
|
||||
=fields SCAN, PHAS, EVNT, PRIO, PINI
|
||||
|
||||
=head3 Read and Convert Parameters
|
||||
|
||||
The read and convert fields determine where the binary input gets its
|
||||
@@ -44,14 +46,15 @@ input from and how to convert the raw signal to engineering units. The INP
|
||||
field contains the address from where device support retrieves the value.
|
||||
If the binary input record gets its value from hardware, the address of the
|
||||
card must be entered in the INP field, and the name of the device support
|
||||
module must be entered in the DTYP field. See L<Address Specification> for
|
||||
information on the format of the hardware address. Be aware that the format
|
||||
differs between types of cards.
|
||||
module must be entered in the DTYP field. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on the format of the hardware address.
|
||||
|
||||
For records that specify C<Soft Channel> or C<Raw Soft Channel> device
|
||||
support routines, the INP field can be a channel or a database link, or a
|
||||
constant. If a constant, VAL can be changed directly by dbPuts. See
|
||||
L<Address Specification> for information on the format of database and
|
||||
constant. If a constant, VAL can be changed directly by dbPuts. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on the format of database and
|
||||
channel access addresses. Also, see L<Device Support for Soft Records> in
|
||||
this chapter for information on soft device support.
|
||||
|
||||
@@ -102,9 +105,10 @@ C<MAJOR>. The ZSV field holds the severity for the zero state; OSV, for
|
||||
the one state. COSV causes an alarm whenever the state changes between
|
||||
0 and 1 and the severity is configured as MINOR or MAJOR.
|
||||
|
||||
See L<Alarm Specification> for a complete explanation of the discrete alarm
|
||||
states. L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related to alarms that are
|
||||
common to all record types.
|
||||
See L<Alarm Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#alarm-specification>
|
||||
for a complete explanation of record alarms and of the standard fields.
|
||||
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related
|
||||
to alarms that are common to all record types.
|
||||
|
||||
=fields ZSV, OSV, COSV
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "special.h"
|
||||
#include "menuIvoa.h"
|
||||
#include "menuOmsl.h"
|
||||
#include "menuYesNo.h"
|
||||
#include "menuSimm.h"
|
||||
|
||||
#define GEN_SIZE_OFFSET
|
||||
#include "boRecord.h"
|
||||
@@ -211,7 +211,7 @@ static long process(struct dbCommon *pcommon)
|
||||
} else prec->rval = (epicsUInt32)prec->val;
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
* will be up to date if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
@@ -427,14 +427,18 @@ static long writeValue(boRecord *prec)
|
||||
}
|
||||
|
||||
switch (prec->simm) {
|
||||
case menuYesNoNO:
|
||||
case menuSimmNO:
|
||||
status = pdset->write_bo(prec);
|
||||
break;
|
||||
|
||||
case menuYesNoYES: {
|
||||
case menuSimmYES:
|
||||
case menuSimmRAW:
|
||||
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
|
||||
if (prec->pact || (prec->sdly < 0.)) {
|
||||
status = dbPutLink(&prec->siol, DBR_USHORT, &prec->val, 1);
|
||||
if (prec->simm == menuSimmYES)
|
||||
status = dbPutLink(&prec->siol, DBR_USHORT, &prec->val, 1);
|
||||
else /* prec->simm == menuSimmRAW */
|
||||
status = dbPutLink(&prec->siol, DBR_ULONG, &prec->rval, 1);
|
||||
prec->pact = FALSE;
|
||||
} else { /* !prec->pact && delay >= 0. */
|
||||
epicsCallback *pvt = prec->simpvt;
|
||||
@@ -446,7 +450,6 @@ static long writeValue(boRecord *prec)
|
||||
prec->pact = TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
|
||||
|
||||
@@ -15,29 +15,6 @@ values into other records via database or channel access links. This record
|
||||
can implement both latched and momentary binary outputs depending on how
|
||||
the HIGH field is configured.
|
||||
|
||||
=head2 Parameter Fields
|
||||
|
||||
The binary output's fields fall into the following categories:
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
scan parameters
|
||||
|
||||
=item *
|
||||
convert and write parameters
|
||||
|
||||
=item *
|
||||
operator display parameters
|
||||
|
||||
=item *
|
||||
alarm parameters
|
||||
|
||||
=item *
|
||||
run-time parameters
|
||||
|
||||
=back
|
||||
|
||||
=recordtype bo
|
||||
|
||||
=cut
|
||||
@@ -47,13 +24,10 @@ recordtype(bo) {
|
||||
=head3 Scan Parameters
|
||||
|
||||
The binary output record has the standard fields for specifying under what
|
||||
circumstances the record will be processed. The fields are listed in
|
||||
circumstances the record will be processed.
|
||||
These fields are described in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
|
||||
L<Scan Fields|dbCommonRecord/Scan Fields>. In addition, L<Scanning Specification> explains how these
|
||||
fields are used. Note that I/O event scanning is only supported for those card
|
||||
types that interrupt.
|
||||
|
||||
=fields SCAN
|
||||
=fields SCAN, PHAS, EVNT, PRIO, PINI
|
||||
|
||||
=head3 Desired Output Parameters
|
||||
|
||||
@@ -65,14 +39,14 @@ output mode select (OMSL) field, which can have two possible values:
|
||||
C<losed_loop> or C<supervisory>. If C<supervisory> is specified, the value
|
||||
in the VAL field can be set externally via dbPuts at run-time. If
|
||||
C<closed_loop> is specified, the VAL field's value is obtained from the
|
||||
address specified in the desired output location (DOL) field which can be a
|
||||
address specified in the Desired Output Link (DOL) field which can be a
|
||||
database link or a channel access link, but not a constant. To achieve
|
||||
continuous control, a database link to a control algorithm record should be
|
||||
entered in the DOL field.
|
||||
|
||||
L<Address Specification> presents more information on database addresses
|
||||
and links. L<Scanning Specification> explaines the effect of database
|
||||
linkage on scanning.
|
||||
See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on hardware addresses and links.
|
||||
|
||||
=fields DOL, OMSL
|
||||
|
||||
@@ -130,15 +104,17 @@ The OUT field specifies where the binary output record writes its output.
|
||||
It must specify the address of an I/O card if the record sends its output
|
||||
to hardware, and the DTYP field must contain the corresponding device
|
||||
support module. Be aware that the address format differs according to the
|
||||
I/O bus used. See L<Address Specification> for information on the format of
|
||||
hardware addresses.
|
||||
I/O bus used. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on the format of hardware addresses.
|
||||
|
||||
Otherwise, if the record is configured to use the soft device support
|
||||
modules, then it can be either a database link, a channel access link, or a
|
||||
constant. Be aware that nothing will be written when OUT is a constant. See
|
||||
L<Address Specification> for information on the format of the database and
|
||||
channel access addresses. Also, see L<Device Support For Soft Records> in
|
||||
this chapter for more on output to other records.
|
||||
Otherwise, if the record is configured to use the soft device support modules,
|
||||
then it can be either a database link, a channel access link, or a constant. Be
|
||||
aware that nothing will be written when OUT is a constant. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on the format of the database and channel access addresses.
|
||||
Also, see L<Device Support For Soft Records> in this chapter for more on output
|
||||
to other records.
|
||||
|
||||
=head3 Operator Display Parameters
|
||||
|
||||
@@ -206,8 +182,9 @@ The WPDT field is a private field for honoring seconds to hold HIGH.
|
||||
|
||||
The following fields are used to operate the record in simulation mode.
|
||||
|
||||
If SIMM (fetched through SIML) is YES, the record is put in SIMS
|
||||
severity and the value is written through SIOL.
|
||||
If SIMM (fetched through SIML, if populated) is YES, the record is put
|
||||
in SIMS severity and the unconverted value is written through SIOL.
|
||||
If SIMM is RAW, the value is converted and RVAL is written.
|
||||
SSCN sets a different SCAN mechanism to use in simulation mode.
|
||||
SDLY sets a delay (in sec) that is used for asynchronous simulation
|
||||
processing.
|
||||
@@ -242,7 +219,7 @@ for more information on simulation mode and its fields.
|
||||
menu(menuOmsl)
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
prompt("Desired Output Link")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
@@ -352,7 +329,7 @@ for more information on simulation mode and its fields.
|
||||
prompt("Simulation Mode")
|
||||
special(SPC_MOD)
|
||||
interest(1)
|
||||
menu(menuYesNo)
|
||||
menu(menuSimm)
|
||||
}
|
||||
field(SIMS,DBF_MENU) {
|
||||
prompt("Simulation Mode Severity")
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#undef GEN_SIZE_OFFSET
|
||||
#include "epicsExport.h"
|
||||
|
||||
/* Hysterisis for alarm filtering: 1-1/e */
|
||||
/* Hysteresis for alarm filtering: 1-1/e */
|
||||
#define THRESHOLD 0.6321
|
||||
|
||||
/* Create RSET - Record Support Entry Table */
|
||||
|
||||
@@ -28,8 +28,9 @@ recordtype(calc) {
|
||||
|
||||
The Calc record has the standard fields for specifying under what
|
||||
circumstances the record will be processed.
|
||||
These fields are listed in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
These fields are described in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
|
||||
=fields SCAN, PHAS, EVNT, PRIO, PINI
|
||||
|
||||
=head3 Read Parameters
|
||||
|
||||
@@ -40,8 +41,9 @@ channel access link. If they are constants, they will be initialized with
|
||||
the value they are configured with and can be changed via C<dbPuts>. They
|
||||
cannot be hardware addresses.
|
||||
|
||||
See L<Address Specification> for information on how to specify database
|
||||
links.
|
||||
See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on how to specify database links.
|
||||
|
||||
=fields INPA, INPB, INPC, INPD, INPE, INPF, INPG, INPH, INPI, INPJ, INPK, INPL
|
||||
|
||||
@@ -155,6 +157,9 @@ CEIL: Ceiling (unary)
|
||||
=item *
|
||||
FLOOR: Floor (unary)
|
||||
|
||||
=item *
|
||||
FMOD: Floating point modulo (binary) Added in UNRELEASED
|
||||
|
||||
=item *
|
||||
LOG: Log base 10 (unary)
|
||||
|
||||
@@ -453,9 +458,12 @@ The following alarm parameters which are configured by the user, define the
|
||||
limit alarms for the VAL field and the severity corresponding to those
|
||||
conditions.
|
||||
|
||||
The HYST field defines an alarm deadband for each limit. See L<Alarm Specification>
|
||||
for a complete explanation of alarms of these fields. L<Alarm Fields|dbCommonRecord/Alarm Fields>
|
||||
lists other fields related to alarms that are common to all record types.
|
||||
The HYST field defines an alarm deadband for each limit.
|
||||
|
||||
See L<Alarm Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#alarm-specification>
|
||||
for a complete explanation of record alarms and of the standard fields.
|
||||
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related
|
||||
to alarms that are common to all record types.
|
||||
|
||||
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST
|
||||
|
||||
|
||||
@@ -245,7 +245,7 @@ static long process(struct dbCommon *pcommon)
|
||||
|
||||
if ( !pact ) {
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
* will be up to date if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStamp(prec);
|
||||
}
|
||||
/* check for output link execution */
|
||||
|
||||
@@ -183,6 +183,9 @@ CEIL: Ceiling (unary)
|
||||
=item *
|
||||
FLOOR: Floor (unary)
|
||||
|
||||
=item *
|
||||
FMOD: Floating point modulo (binary) Added in UNRELEASED
|
||||
|
||||
=item *
|
||||
LOG: Log base 10 (unary)
|
||||
|
||||
@@ -535,13 +538,13 @@ the user and which describes the values being operated upon. The string is
|
||||
retrieved whenever the routine C<get_units()> is called. The EGU string is
|
||||
solely for an operator's sake and does not have to be used.
|
||||
|
||||
The HOPR and LOPR fields on;y refer to the limits if the VAL, HIHI, HIGH,
|
||||
The HOPR and LOPR fields only refer to the limits of the VAL, HIHI, HIGH,
|
||||
LOW, and LOLO fields. PREC controls the precision of the VAL field.
|
||||
|
||||
=head4 Menu calcoutINAV
|
||||
|
||||
The INAV-INLV fields indicate the status of the link to the PVs specified
|
||||
in the INPA-INPL fields, respectfully. These field can have four possible
|
||||
in the INPA-INPL fields respectively. These fields can have four possible
|
||||
values:
|
||||
|
||||
=menu calcoutINAV
|
||||
@@ -568,7 +571,7 @@ The OUTV field indicates the status of the OUT link. If has the same
|
||||
possible values as the INAV-INLV fields.
|
||||
|
||||
The CLCV and OLCV fields indicate the validity of the expression in the
|
||||
CALC and OCAL fields respectfully. If the expression in invalid, the field
|
||||
CALC and OCAL fields respectively. If the expression in invalid, the field
|
||||
is set to one.
|
||||
|
||||
The DLYA field is set to one during the delay specified in ODLY.
|
||||
@@ -590,10 +593,12 @@ The following alarm parameters, which are configured by the user, define the
|
||||
limit alarms for the VAL field and the severity corresponding to those
|
||||
conditions.
|
||||
|
||||
The HYST field defines an alarm deadband for each limit. See
|
||||
L<Alarm Specification> for a complete explanation of alarms and these
|
||||
fields. C<Alarm Fields> lists other fields related to alarms that are
|
||||
common to all record types.
|
||||
The HYST field defines an alarm deadband for each limit.
|
||||
|
||||
See L<Alarm Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#alarm-specification>
|
||||
for a complete explanation of record alarms and of the standard fields.
|
||||
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related
|
||||
to alarms that are common to all record types.
|
||||
|
||||
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST
|
||||
|
||||
@@ -1218,7 +1223,7 @@ honors the alarm hysteresis factor (HYST). Thus the value must change by at
|
||||
least HYST before the alarm status and severity changes.
|
||||
|
||||
=item 4.
|
||||
Determine if the Output Execution Option (OOPT) is met. If it met, either
|
||||
Determine if the Output Execution Option (OOPT) is met. If met, either
|
||||
execute the output link (and output event) immediately (if ODLY = 0), or
|
||||
schedule a callback after the specified interval. See the explanation for
|
||||
the C<execOutput()> routine below.
|
||||
|
||||
@@ -67,11 +67,12 @@ The record-specific fields are described below, grouped by functionality.
|
||||
=head3 Scanning Parameters
|
||||
|
||||
The compression record has the standard fields for specifying under what
|
||||
circumstances the record will be processed. These fields are listed in
|
||||
circumstances the record will be processed. Since the compression record
|
||||
supports no direct interfaces to hardware, its SCAN field cannot be set to C<<<
|
||||
I/O Intr >>>.
|
||||
These fields are described in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
|
||||
L<Scan Fields|dbCommonRecord/Scan Fields>. In addition, L<Scanning Specification>
|
||||
explains how these fields are used. Since the compression record supports no
|
||||
direct interfaces to hardware, its SCAN field cannot specify C<<< I/O Intr >>>.
|
||||
=fields SCAN, PHAS, EVNT, PRIO, PINI
|
||||
|
||||
=head3 Algorithms and Related Parameters
|
||||
|
||||
@@ -88,9 +89,11 @@ The following fields determine what channel to read and how to compress the data
|
||||
|
||||
As stated above, the ALG field specifies which algorithm to be performed on the data.
|
||||
|
||||
The INP should be a database or channel access link. Though INP can be a constant,
|
||||
the data compression algorithms are supported only when INP is a database link. See
|
||||
L<Address Specification> for information on specifying links.
|
||||
The INP should be a database or channel access link. Though INP can be a
|
||||
constant, the data compression algorithms are supported only when INP is a
|
||||
database link. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on specifying links.
|
||||
|
||||
|
||||
IHIL and ILIL can be set to provide an initial value filter on the input array.
|
||||
@@ -209,18 +212,26 @@ described in L<Alarm Fields|dbCommonRecord/Alarm Fields>.
|
||||
|
||||
These parameters are used by the run-time code for processing the data
|
||||
compression algorithm. They are not configurable by the user, though some are
|
||||
accessible at run-time. They can represent the current state of the waveform or
|
||||
accessible at run-time. They can represent the current state of the algorithm or
|
||||
of the record whose field is referenced by the INP field.
|
||||
|
||||
=fields NUSE, OUSE, BPTR, SPTR, WPTR, CVB, INPN, INX
|
||||
|
||||
NUSE and OUSE hold the current and previous number of elements stored in VAL.
|
||||
|
||||
BPTR is a pointer that refers to the buffer referenced by VAL.
|
||||
BPTR points to the buffer referenced by VAL.
|
||||
|
||||
SPTR points to an array that is used for array averages.
|
||||
|
||||
WPTR is used by the dbGetlinks routines.
|
||||
WPTR points to the buffer containing data referenced by INP.
|
||||
|
||||
CVB stores the current compressed value for C<<< N to 1 >>> algorithms when INP
|
||||
references a scalar.
|
||||
|
||||
INPN is updated when the record processes; if INP references an array and the
|
||||
size changes, the WPTR buffer is reallocated.
|
||||
|
||||
INX counts the number of readings collected.
|
||||
|
||||
=head2 Record Support
|
||||
|
||||
@@ -479,7 +490,7 @@ Scan forward link if necessary, set PACT FALSE, and return.
|
||||
interest(3)
|
||||
}
|
||||
field(INX,DBF_ULONG) {
|
||||
prompt("Compressed Array Inx")
|
||||
prompt("Current number of readings")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ originates, i.e., the data which is to be fowarded to the records in its
|
||||
output links. The output mode select (OMSL) field determines whether the
|
||||
output originates from another record or from run-time database access.
|
||||
When set to C<closed_loop>, the desired output is retrieved from the link
|
||||
specified in the desired output (DOL) field, which can specify either a
|
||||
specified in the Desired Output Link (DOL) field, which can specify either a
|
||||
database or a channel access link, and placed into the VAL field. When set
|
||||
to C<supervisory>, the desired output can be written to the VAL field via
|
||||
dbPuts at run-time.
|
||||
@@ -59,8 +59,9 @@ undergoes no conversions before it is sent out to the output links.
|
||||
=head3 Write Parameters
|
||||
|
||||
The OUTA-OUTH fields specify where VAL is to be sent. Each field that is to
|
||||
forward data must specify an address to another record. See
|
||||
L<Address Specification> for information on specifying links.
|
||||
forward data must specify an address to another record. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on specifying links.
|
||||
|
||||
The SELL, SELM, and SELN fields specify which output links are to be
|
||||
used.
|
||||
@@ -71,42 +72,57 @@ SELM is a menu, with three choices:
|
||||
|
||||
=menu dfanoutSELM
|
||||
|
||||
If SELM=="All", then all output links are used, and the values of
|
||||
If SELM is C<All>, then all output links are used, and the values of
|
||||
SELL and SELN are ignored.
|
||||
|
||||
If SELM=="Specified", then the value of SELN is used to specify a single
|
||||
If SELM is C<Specified>, then the value of SELN is used to specify a single
|
||||
link which will be used. If SELN==0, then no link will be used; if SELN==1,
|
||||
then OUTA will be used, and so on.
|
||||
|
||||
SELN can either have its value set directly, or have its values retrieved
|
||||
from another EPICS PV. If SELL is a valid PV link, then SELN will be set to
|
||||
the values of the linked PV.
|
||||
SELN can either have its value set directly, or have it retrieved from
|
||||
another EPICS PV. If SELL is a valid PV link, then SELN will be read from
|
||||
the linked PV.
|
||||
|
||||
If SELM=="Mask", then SELN will be treated as a bit mask. If bit one of
|
||||
SELN is set, then OUTA will be used, if bit two is set, OUTB will be used.
|
||||
Thus if SELN==5, OUTC and OUTA will be used.
|
||||
If SELM is C<Mask>, then SELN will be treated as a bit mask. If bit zero
|
||||
(the LSB) of SELN is set, then OUTA will be written to; if bit one is set,
|
||||
OUTB will be written to, and so on. Thus when SELN==5, both OUTC and OUTA
|
||||
will be written to.
|
||||
|
||||
=fields OUTA, OUTB, OUTC, OUTD, OUTE, OUTF, OUTG, OUTH
|
||||
=fields SELL, SELM, SELN, OUTA, OUTB, OUTC, OUTD, OUTE, OUTF, OUTG, OUTH
|
||||
|
||||
=head3 Operator Display Parameters
|
||||
|
||||
These parameters are used to present meaningful data to the operator. They
|
||||
display the value and other parameters of the data fanout record either
|
||||
textually or graphically.
|
||||
These parameters are used to present meaningful data to the operator.
|
||||
They do not affect the functioning of the record at all.
|
||||
|
||||
The EGU field can contain a string of up to 16 characters describing the
|
||||
value on the VAL field.
|
||||
=over
|
||||
|
||||
The HOPR and LOPR fields determine the upper and lower display limits for
|
||||
graphic displays and the upper and lower control limits for control
|
||||
displays. They apply to the VAL, HIHI, HIGH, LOW, and LOLO fields. The
|
||||
record support routines C<get_graphic_double()> and C<get_control_double()>
|
||||
retrieve HOPR and LOPR.
|
||||
=item *
|
||||
NAME is the record's name, and can be useful when the PV name that a client
|
||||
knows is an alias for the record.
|
||||
|
||||
=item *
|
||||
DESC is a string that is usually used to briefly describe the record.
|
||||
|
||||
=item *
|
||||
EGU is a string of up to 16 characters naming the engineering units that the VAL
|
||||
field represents.
|
||||
|
||||
=item *
|
||||
The HOPR and LOPR fields set the upper and lower display limits for the VAL,
|
||||
HIHI, HIGH, LOW, and LOLO fields.
|
||||
|
||||
=item *
|
||||
The PREC field determines the floating point precision (i.e. the number of
|
||||
digits to show after the decimal point) with which to display VAL and the other
|
||||
DOUBLE fields.
|
||||
|
||||
=back
|
||||
|
||||
See L<Fields Common to All Record Types|dbCommonRecord/Operator Display
|
||||
Parameters> for more on the record name (NAME) and description (DESC) fields.
|
||||
Parameters> for more about the record name (NAME) and description (DESC) fields.
|
||||
|
||||
=fields EGU, HOPR, LOPR, NAME, DESC
|
||||
=fields NAME, DESC, EGU, HOPR, LOPR, PREC
|
||||
|
||||
=head3 Alarm Parameters
|
||||
|
||||
@@ -119,9 +135,10 @@ in the corresponding field (HHSV, LLSV, HSV, LSV) and can be either
|
||||
NO_ALARM, MINOR, or MAJOR. In the hysteresis field (HYST) can be entered a
|
||||
number which serves as the deadband on the limit alarms.
|
||||
|
||||
See L<Alarm Specification> for a complete explanation of alarms and these
|
||||
fields. L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related to alarms that are
|
||||
common to all record types.
|
||||
See L<Alarm Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#alarm-specification>
|
||||
for a complete explanation of record alarms and of the standard fields.
|
||||
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related
|
||||
to alarms that are common to all record types.
|
||||
|
||||
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST
|
||||
|
||||
@@ -211,7 +228,7 @@ hysteresis factors for monitor callbacks.
|
||||
interest(1)
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
prompt("Desired Output Link")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
|
||||
@@ -37,10 +37,10 @@ recordtype(event) {
|
||||
=head3 Scan Parameters
|
||||
|
||||
The event record has the standard fields for specifying under what circumstances
|
||||
it will be processed. If the SCAN field specifies C<I/O Intr>, then device
|
||||
support will provide an interrupt handler, posting an event number when an I/O
|
||||
interrupt occurs.
|
||||
These fields are listed in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
it will be processed.
|
||||
These fields are described in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
|
||||
=fields SCAN, PHAS, EVNT, PRIO, PINI
|
||||
|
||||
=head3 Event Number Parameters
|
||||
|
||||
@@ -73,8 +73,9 @@ The device support routines use the address in this record to obtain input. For
|
||||
records that provide an interrupt handler, the INP field should specify the
|
||||
address of the I/O card, and the DTYP field should specify a valid device
|
||||
support module. Be aware that the address format differs according to the card
|
||||
type used. See L<Address Specification> for information on the format of
|
||||
hardware addresses and specifying links.
|
||||
type used. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on the format of hardware addresses and specifying links.
|
||||
|
||||
For soft records, the INP field can be a constant, a database link, or a channel
|
||||
access link. For soft records, the DTYP field should specify C<Soft Channel>.
|
||||
|
||||
@@ -160,7 +160,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
|
||||
prec->bptr = calloc(prec->nelm, sizeof(epicsUInt32));
|
||||
}
|
||||
|
||||
/* calulate width of array element */
|
||||
/* calculate width of array element */
|
||||
prec->wdth = (prec->ulim - prec->llim) / prec->nelm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
#undef GEN_SIZE_OFFSET
|
||||
#include "epicsExport.h"
|
||||
|
||||
/* Hysterisis for alarm filtering: 1-1/e */
|
||||
/* Hysteresis for alarm filtering: 1-1/e */
|
||||
#define THRESHOLD 0.6321
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
#define report NULL
|
||||
|
||||
@@ -146,7 +146,7 @@ static long process(dbCommon *pcommon)
|
||||
if (!status) convert(prec,value);
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
* will be up to date if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ monitoring deadband functionality.
|
||||
interest(1)
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
prompt("Desired Output Link")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#undef GEN_SIZE_OFFSET
|
||||
#include "epicsExport.h"
|
||||
|
||||
/* Hysterisis for alarm filtering: 1-1/e */
|
||||
/* Hysteresis for alarm filtering: 1-1/e */
|
||||
#define THRESHOLD 0.6321
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
#define report NULL
|
||||
|
||||
@@ -81,10 +81,14 @@ rset longoutRSET={
|
||||
};
|
||||
epicsExportAddress(rset,longoutRSET);
|
||||
|
||||
#define DONT_EXEC_OUTPUT 0
|
||||
#define EXEC_OUTPUT 1
|
||||
|
||||
static void checkAlarms(longoutRecord *prec);
|
||||
static void monitor(longoutRecord *prec);
|
||||
static long writeValue(longoutRecord *prec);
|
||||
static void convert(longoutRecord *prec, epicsInt32 value);
|
||||
static long conditional_write(longoutRecord *prec);
|
||||
|
||||
static long init_record(struct dbCommon *pcommon, int pass)
|
||||
{
|
||||
@@ -119,6 +123,9 @@ static long init_record(struct dbCommon *pcommon, int pass)
|
||||
prec->mlst = prec->val;
|
||||
prec->alst = prec->val;
|
||||
prec->lalm = prec->val;
|
||||
prec->pval = prec->val;
|
||||
prec->outpvt = EXEC_OUTPUT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -148,7 +155,7 @@ static long process(struct dbCommon *pcommon)
|
||||
if (!status) convert(prec,value);
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
* will be up to date if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
@@ -210,6 +217,14 @@ static long special(DBADDR *paddr, int after)
|
||||
recGblCheckSimm((dbCommon *)prec, &prec->sscn, prec->oldsimm, prec->simm);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Detect an output link re-direction (change) */
|
||||
if (dbGetFieldIndex(paddr) == longoutRecordOUT) {
|
||||
if ((after) && (prec->ooch == menuYesNoYES))
|
||||
prec->outpvt = EXEC_OUTPUT;
|
||||
return(0);
|
||||
}
|
||||
|
||||
default:
|
||||
recGblDbaddrError(S_db_badChoice, paddr, "longout: special");
|
||||
return(S_db_badChoice);
|
||||
@@ -381,7 +396,6 @@ static void monitor(longoutRecord *prec)
|
||||
|
||||
static long writeValue(longoutRecord *prec)
|
||||
{
|
||||
longoutdset *pdset = (longoutdset *) prec->dset;
|
||||
long status = 0;
|
||||
|
||||
if (!prec->pact) {
|
||||
@@ -391,7 +405,7 @@ static long writeValue(longoutRecord *prec)
|
||||
|
||||
switch (prec->simm) {
|
||||
case menuYesNoNO:
|
||||
status = pdset->write_longout(prec);
|
||||
status = conditional_write(prec);
|
||||
break;
|
||||
|
||||
case menuYesNoYES: {
|
||||
@@ -421,10 +435,61 @@ static long writeValue(longoutRecord *prec)
|
||||
|
||||
static void convert(longoutRecord *prec, epicsInt32 value)
|
||||
{
|
||||
/* check drive limits */
|
||||
/* check drive limits */
|
||||
if(prec->drvh > prec->drvl) {
|
||||
if (value > prec->drvh) value = prec->drvh;
|
||||
else if (value < prec->drvl) value = prec->drvl;
|
||||
}
|
||||
prec->val = value;
|
||||
}
|
||||
|
||||
/* Evaluate OOPT field to perform the write operation */
|
||||
static long conditional_write(longoutRecord *prec)
|
||||
{
|
||||
struct longoutdset *pdset = (struct longoutdset *) prec->dset;
|
||||
long status = 0;
|
||||
int doDevSupWrite = 0;
|
||||
|
||||
switch (prec->oopt)
|
||||
{
|
||||
case longoutOOPT_On_Change:
|
||||
/* Forces a write op if a change in the OUT field is detected OR is first process */
|
||||
if (prec->outpvt == EXEC_OUTPUT) {
|
||||
doDevSupWrite = 1;
|
||||
} else {
|
||||
/* Only write if value is different from the previous one */
|
||||
doDevSupWrite = (prec->val != prec->pval);
|
||||
}
|
||||
break;
|
||||
|
||||
case longoutOOPT_Every_Time:
|
||||
doDevSupWrite = 1;
|
||||
break;
|
||||
|
||||
case longoutOOPT_When_Zero:
|
||||
doDevSupWrite = (prec->val == 0);
|
||||
break;
|
||||
|
||||
case longoutOOPT_When_Non_zero:
|
||||
doDevSupWrite = (prec->val != 0);
|
||||
break;
|
||||
|
||||
case longoutOOPT_Transition_To_Zero:
|
||||
doDevSupWrite = ((prec->val == 0)&&(prec->pval != 0));
|
||||
break;
|
||||
|
||||
case longoutOOPT_Transition_To_Non_zero:
|
||||
doDevSupWrite = ((prec->val != 0)&&(prec->pval == 0));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (doDevSupWrite)
|
||||
status = pdset->write_longout(prec);
|
||||
|
||||
prec->pval = prec->val;
|
||||
prec->outpvt = DONT_EXEC_OUTPUT; /* reset status */
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,15 @@ limits.
|
||||
|
||||
=cut
|
||||
|
||||
menu(longoutOOPT) {
|
||||
choice(longoutOOPT_Every_Time,"Every Time")
|
||||
choice(longoutOOPT_On_Change,"On Change")
|
||||
choice(longoutOOPT_When_Zero,"When Zero")
|
||||
choice(longoutOOPT_When_Non_zero,"When Non-zero")
|
||||
choice(longoutOOPT_Transition_To_Zero,"Transition To Zero")
|
||||
choice(longoutOOPT_Transition_To_Non_zero,"Transition To Non-zero")
|
||||
}
|
||||
|
||||
recordtype(longout) {
|
||||
|
||||
=head2 Parameter Fields
|
||||
@@ -38,10 +47,10 @@ The record must specify where the desired output originates, i.e., the 32 bit
|
||||
integer value it is to write. The output mode select (OMSL) field determines
|
||||
whether the output originates from another record or from database access. When
|
||||
set to C<<< closed_loop >>>, the desired output is retrieved from the link
|
||||
specified in the desired output (DOL) field (which can specify either a database
|
||||
or channel access link) and placed into the VAL field. When set to C<<<
|
||||
supervisory >>>, the desired output can be written into the VAL field via dpPuts
|
||||
at run-time.
|
||||
specified in the Desired Output Link (DOL) field (which can specify either a
|
||||
database or channel access link) and placed into the VAL field. When set to
|
||||
C<<< supervisory >>>, the desired output can be written into the VAL field via
|
||||
dpPuts at run-time.
|
||||
|
||||
A third type of value for the DOL field is a constant in which case, when the
|
||||
record is initialized, the VAL field will be initialized with this constant
|
||||
@@ -68,10 +77,54 @@ For soft records, the OUT output link can be a constant, a database link, or a
|
||||
channel access link. If the link is a constant, the result is no output. The
|
||||
DTYP field must then specify the C<<< Soft Channel >>> device support routine.
|
||||
|
||||
See L<Address Specification> for information on the format of hardware addresses
|
||||
and database links.
|
||||
See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on the format of hardware addresses and database links.
|
||||
|
||||
=fields OUT, DTYP
|
||||
=fields OUT, DTYP, OOPT, OOCH
|
||||
|
||||
=head4 Menu longoutOOPT
|
||||
|
||||
The OOPT field was added in EPICS UNRELEASED.
|
||||
|
||||
It determines the condition that causes the output link to be
|
||||
written to. It's a menu field that has six choices:
|
||||
|
||||
=menu longoutOOPT
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
C<Every Time> -- write output every time record is processed. (DEFAULT)
|
||||
|
||||
=item *
|
||||
C<On Change> -- write output every time VAL changes.
|
||||
|
||||
=item *
|
||||
C<When Zero> -- when record is processed, write output if VAL is zero.
|
||||
|
||||
=item *
|
||||
C<When Non-zero> -- when record is processed, write output if VAL is
|
||||
non-zero.
|
||||
|
||||
=item *
|
||||
C<Transition To Zero> -- when record is processed, write output only if VAL
|
||||
is zero and the last value was non-zero.
|
||||
|
||||
=item *
|
||||
C<Transition To Non-zero> -- when record is processed, write output only if
|
||||
VAL is non-zero and last value was zero.
|
||||
|
||||
=back
|
||||
|
||||
=head4 Changes in OUT field when OOPT = On Change
|
||||
|
||||
The OOCH field was added in EPICS UNRELEASED.
|
||||
|
||||
If OOCH is C<YES> (its default value) and the OOPT field is C<On Change>,
|
||||
the record will write to the device support the first time the record gets
|
||||
processed after its OUT link is modified, even when the output value has
|
||||
not actually changed.
|
||||
|
||||
=cut
|
||||
|
||||
@@ -93,11 +146,12 @@ and database links.
|
||||
}
|
||||
field(OUT,DBF_OUTLINK) {
|
||||
prompt("Output Specification")
|
||||
special(SPC_MOD)
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
prompt("Desired Output Link")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
@@ -172,13 +226,17 @@ record's output. The IVOA field specifies the action to take in this case.
|
||||
|
||||
The limit alarms are configured by the user in the HIHI, LOLO, HIGH, and LOW
|
||||
fields using floating-point values. For each of these fields, there is a
|
||||
corresponding severity field which can be either NO_ALARM, MINOR, or MAJOR. The
|
||||
HYST field contains the alarm deadband around each limit alarm.
|
||||
corresponding severity field which can be either NO_ALARM, MINOR, or MAJOR.
|
||||
|
||||
See L<Alarm Specification> for a complete explanation of alarms and
|
||||
these fields. For an explanation of the IVOA and IVOV fields, see L<Output
|
||||
Records>. L<Alarm Fields|dbCommonRecord/Alarm Fields> lists the fields related to
|
||||
alarms that are common to all record types.
|
||||
The HYST field sets an alarm deadband around each limit alarm.
|
||||
|
||||
For an explanation of the IVOA and IVOV fields, see
|
||||
L<Invalid Output Action Fields|dbCommonOutput/Invalid Output Action Fields>.
|
||||
|
||||
See L<Alarm Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#alarm-specification>
|
||||
for a complete explanation of record alarms and of the standard fields.
|
||||
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related
|
||||
to alarms that are common to all record types.
|
||||
|
||||
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST, IVOA, IVOV
|
||||
|
||||
@@ -360,7 +418,7 @@ for more information on simulation mode and its fields.
|
||||
prompt("Sim. Mode Private")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("epicsCallback *simpvt")
|
||||
extra("epicsCallback *simpvt")
|
||||
}
|
||||
field(IVOA,DBF_MENU) {
|
||||
prompt("INVALID output action")
|
||||
@@ -373,6 +431,29 @@ for more information on simulation mode and its fields.
|
||||
promptgroup("50 - Output")
|
||||
interest(2)
|
||||
}
|
||||
field(PVAL,DBF_LONG) {
|
||||
prompt("Previous Value")
|
||||
}
|
||||
field(OUTPVT,DBF_NOACCESS) {
|
||||
prompt("Output Write Control Private")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("epicsEnum16 outpvt")
|
||||
}
|
||||
field(OOCH,DBF_MENU) {
|
||||
prompt("Output Exec. On Change (Opt)")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
menu(menuYesNo)
|
||||
initial("1")
|
||||
}
|
||||
field(OOPT,DBF_MENU) {
|
||||
prompt("Output Execute Opt")
|
||||
promptgroup("50 - Output")
|
||||
interest(1)
|
||||
menu(longoutOOPT)
|
||||
initial("0")
|
||||
}
|
||||
|
||||
|
||||
=begin html
|
||||
|
||||
@@ -31,21 +31,21 @@ These fields are listed in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
|
||||
The long string output record must specify from where it gets its desired output
|
||||
string. The first field that determines where the desired output originates is
|
||||
the output mode select (OMSL) field, which can have two possible value:
|
||||
C<closed_loop> or C<supervisory>. If C<supervisory> is specified, DOL is
|
||||
ignored, the current value of VAL is written, and VAL can be changed externally
|
||||
via dbPuts at run-time. If C<closed_loop> is specified, the VAL field's value is
|
||||
obtained from the address specified in the desired output location field (DOL)
|
||||
which can be either a database link or a channel access link.
|
||||
the output mode select (OMSL) field, which can have two possible values:
|
||||
C<closed_loop> or C<supervisory>. If C<closed_loop> is specified, the VAL
|
||||
field's value is fetched from the address specified in the Desired Output Link
|
||||
field (DOL) which can be either a database link or a channel access link. If
|
||||
C<supervisory> is specified, DOL is ignored, the current value of VAL is
|
||||
written, and VAL can be changed externally via dbPuts at run-time.
|
||||
|
||||
The maximum number of characters in VAL is given by SIZV, and cannot be larger
|
||||
than 65535.
|
||||
|
||||
DOL can also be a constant in addition to a link, in which case VAL is
|
||||
initialized to the constant value. Your string constant, however, may be
|
||||
interpreted as a CA link name. If you want to initialize your string output
|
||||
record, it is therefore best to use the VAL field. Note that if DOL is a
|
||||
constant, OMSL cannot be C<closed_loop>.
|
||||
DOL can also be a constant instead of a link, in which case VAL is initialized
|
||||
to the constant value. Most simple string constants are likely to be interpreted
|
||||
as a CA link name though. To initialize a string output record it is simplest
|
||||
to set the VAL field directly; alternatively use a JSON constant link type in
|
||||
the DOL field.
|
||||
|
||||
=fields VAL, SIZV, DOL, OMSL
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ an array of 32 unsigned characters, each representing a bit of the word.
|
||||
These fields (B0-B9, BA-BF, B10-B19, B1A-B1F) are set to 1 if the corresponding
|
||||
bit is set, and 0 if not.
|
||||
|
||||
This record's operation is similar to that of the multi-bit binary input record,
|
||||
This record's operation is similar to that of the
|
||||
L<multi-bit binary input record|mbbiRecord>,
|
||||
and it has many fields in common with it. This record also has two available
|
||||
soft device support modules: C<Soft Channel> and C<Raw Soft Channel>.
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
#undef GEN_SIZE_OFFSET
|
||||
#include "epicsExport.h"
|
||||
|
||||
/* Hysterisis for alarm filtering: 1-1/e */
|
||||
/* Hysteresis for alarm filtering: 1-1/e */
|
||||
#define THRESHOLD 0.6321
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
@@ -177,7 +177,7 @@ static long process(struct dbCommon *pcommon)
|
||||
|
||||
if (prec->sdef) {
|
||||
pstate_values = &(prec->zrvl);
|
||||
prec->val = 65535; /* Initalize to unknown state*/
|
||||
prec->val = 65535; /* Initialize to unknown state*/
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (*pstate_values == rval) {
|
||||
prec->val = i;
|
||||
|
||||
@@ -413,9 +413,12 @@ The change of state severity (COSV) field triggers an alarm when any change of
|
||||
state occurs, if set to MAJOR or MINOR.
|
||||
|
||||
The other fields, when set to MAJOR or MINOR, trigger an alarm when VAL equals
|
||||
the corresponding state. See the See L<Alarm Specification> for a complete
|
||||
explanation of discrete alarms and these fields. L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other
|
||||
fields related to a alarms that are common to all record types.
|
||||
the corresponding state.
|
||||
|
||||
See L<Alarm Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#alarm-specification>
|
||||
for a complete explanation of record alarms and of the standard fields.
|
||||
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related
|
||||
to alarms that are common to all record types.
|
||||
|
||||
=fields UNSV, COSV, ZRSV, ONSV, TWSV, THSV, FRSV, FVSV, SXSV, SVSV, EISV, NISV, TESV, ELSV, TVSV, TTSV, FTSV, FFSV
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "special.h"
|
||||
#include "menuOmsl.h"
|
||||
#include "menuIvoa.h"
|
||||
#include "menuYesNo.h"
|
||||
#include "menuSimm.h"
|
||||
|
||||
#define GEN_SIZE_OFFSET
|
||||
#include "mbboDirectRecord.h"
|
||||
@@ -88,6 +88,14 @@ static long writeValue(mbboDirectRecord *);
|
||||
|
||||
#define NUM_BITS 32
|
||||
|
||||
static
|
||||
void bitsFromVAL(mbboDirectRecord *prec)
|
||||
{
|
||||
unsigned i;
|
||||
for(i=0; i<NUM_BITS; i++)
|
||||
(&prec->b0)[i] = !!(prec->val&(1u<<i));
|
||||
}
|
||||
|
||||
static long init_record(struct dbCommon *pcommon, int pass)
|
||||
{
|
||||
struct mbboDirectRecord *prec = (struct mbboDirectRecord *)pcommon;
|
||||
@@ -131,16 +139,21 @@ static long init_record(struct dbCommon *pcommon, int pass)
|
||||
status = 0;
|
||||
}
|
||||
|
||||
if (!prec->udf &&
|
||||
prec->omsl == menuOmslsupervisory) {
|
||||
/* Set initial B0 - B1F from VAL */
|
||||
epicsUInt32 val = prec->val;
|
||||
if (!prec->udf)
|
||||
bitsFromVAL(prec);
|
||||
else {
|
||||
/* Did user set any of the B0-B1F fields? */
|
||||
epicsUInt8 *pBn = &prec->b0;
|
||||
epicsUInt32 val = 0, bit = 1;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_BITS; i++) {
|
||||
*pBn++ = !! (val & 1);
|
||||
val >>= 1;
|
||||
for (i = 0; i < NUM_BITS; i++, bit <<= 1)
|
||||
if (*pBn++)
|
||||
val |= bit;
|
||||
|
||||
if (val) { /* Yes! */
|
||||
prec->val = val;
|
||||
prec->udf = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,29 +187,18 @@ static long process(struct dbCommon *pcommon)
|
||||
}
|
||||
prec->val = val;
|
||||
}
|
||||
else if (prec->omsl == menuOmslsupervisory) {
|
||||
epicsUInt8 *pBn = &prec->b0;
|
||||
epicsUInt32 val = 0;
|
||||
epicsUInt32 bit = 1;
|
||||
int i;
|
||||
|
||||
/* Construct VAL from B0 - B1F */
|
||||
for (i = 0; i < NUM_BITS; i++, bit <<= 1)
|
||||
if (*pBn++)
|
||||
val |= bit;
|
||||
prec->val = val;
|
||||
}
|
||||
else if (prec->udf) {
|
||||
recGblSetSevr(prec, UDF_ALARM, prec->udfs);
|
||||
recGblSetSevrMsg(prec, UDF_ALARM, prec->udfs, "UDFS");
|
||||
goto CONTINUE;
|
||||
}
|
||||
|
||||
prec->udf = FALSE;
|
||||
bitsFromVAL(prec);
|
||||
/* Convert VAL to RVAL */
|
||||
convert(prec);
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
* will be up to date if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
@@ -234,6 +236,9 @@ CONTINUE:
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
/* update bits to reflect any change made by dset */
|
||||
bitsFromVAL(prec);
|
||||
|
||||
monitor(prec);
|
||||
|
||||
/* Wrap up */
|
||||
@@ -255,60 +260,37 @@ static long special(DBADDR *paddr, int after)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!after)
|
||||
return 0;
|
||||
|
||||
switch (paddr->special) {
|
||||
case SPC_MOD: /* Bn field modified */
|
||||
if (prec->omsl == menuOmslsupervisory) {
|
||||
/* Adjust VAL corresponding to the bit changed */
|
||||
epicsUInt8 *pBn = (epicsUInt8 *) paddr->pfield;
|
||||
epicsUInt32 bit = 1 << (pBn - &prec->b0);
|
||||
|
||||
if (*pBn)
|
||||
prec->val |= bit;
|
||||
else
|
||||
prec->val &= ~bit;
|
||||
|
||||
prec->udf = FALSE;
|
||||
convert(prec);
|
||||
if(after==0 && fieldIndex >= mbboDirectRecordB0 && fieldIndex <= mbboDirectRecordB1F) {
|
||||
if(prec->omsl == menuOmslclosed_loop) {
|
||||
/* To avoid confusion, reject changes to bit fields while in closed loop.
|
||||
* Not a 100% solution as confusion can still arise if dset overwrites VAL.
|
||||
*/
|
||||
return S_db_noMod;
|
||||
}
|
||||
break;
|
||||
|
||||
case SPC_RESET: /* OMSL field modified */
|
||||
if (prec->omsl == menuOmslclosed_loop) {
|
||||
/* Construct VAL from B0 - B1F */
|
||||
epicsUInt8 *pBn = &prec->b0;
|
||||
epicsUInt32 val = 0, bit = 1;
|
||||
int i;
|
||||
} else if(after==1 && fieldIndex >= mbboDirectRecordB0 && fieldIndex <= mbboDirectRecordB1F) {
|
||||
/* Adjust VAL corresponding to the bit changed */
|
||||
epicsUInt8 *pBn = (epicsUInt8 *) paddr->pfield;
|
||||
epicsUInt32 bit = 1 << (pBn - &prec->b0);
|
||||
|
||||
for (i = 0; i < NUM_BITS; i++, bit <<= 1)
|
||||
if (*pBn++)
|
||||
val |= bit;
|
||||
prec->val = val;
|
||||
/* Because this is !(VAL and PP), dbPut() will always post a monitor on this B* field
|
||||
* after we return. We must keep track of this change separately from MLST to handle
|
||||
* situations where VAL and B* are changed prior to next monitor(). eg. by dset to
|
||||
* reflect bits actually written. This is the role of OBIT.
|
||||
*/
|
||||
|
||||
if (*pBn) {
|
||||
prec->val |= bit;
|
||||
prec->obit |= bit;
|
||||
} else {
|
||||
prec->val &= ~bit;
|
||||
prec->obit &= ~bit;
|
||||
}
|
||||
else if (prec->omsl == menuOmslsupervisory) {
|
||||
/* Set B0 - B1F from VAL and post monitors */
|
||||
epicsUInt32 val = prec->val;
|
||||
epicsUInt8 *pBn = &prec->b0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_BITS; i++, pBn++, val >>= 1) {
|
||||
epicsUInt8 oBn = *pBn;
|
||||
|
||||
*pBn = !! (val & 1);
|
||||
if (oBn != *pBn)
|
||||
db_post_events(prec, pBn, DBE_VALUE | DBE_LOG);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
recGblDbaddrError(S_db_badChoice, paddr, "mbboDirect: special");
|
||||
return S_db_badChoice;
|
||||
prec->udf = FALSE;
|
||||
convert(prec);
|
||||
}
|
||||
|
||||
prec->udf = FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -330,8 +312,21 @@ static void monitor(mbboDirectRecord *prec)
|
||||
events |= DBE_VALUE | DBE_LOG;
|
||||
prec->mlst = prec->val;
|
||||
}
|
||||
if (events)
|
||||
if (events) {
|
||||
db_post_events(prec, &prec->val, events);
|
||||
}
|
||||
{
|
||||
unsigned i;
|
||||
epicsUInt32 bitsChanged = prec->obit ^ (epicsUInt32)prec->val;
|
||||
|
||||
for(i=0; i<NUM_BITS; i++) {
|
||||
/* post bit when value or alarm severity changes */
|
||||
if((events&~(DBE_VALUE|DBE_LOG)) || (bitsChanged&(1u<<i))) {
|
||||
db_post_events(prec, (&prec->b0)+i, events | DBE_VALUE | DBE_LOG);
|
||||
}
|
||||
}
|
||||
prec->obit = prec->val;
|
||||
}
|
||||
|
||||
events |= DBE_VALUE | DBE_LOG;
|
||||
if (prec->oraw != prec->rval) {
|
||||
@@ -364,14 +359,18 @@ static long writeValue(mbboDirectRecord *prec)
|
||||
}
|
||||
|
||||
switch (prec->simm) {
|
||||
case menuYesNoNO:
|
||||
case menuSimmNO:
|
||||
status = pdset->write_mbbo(prec);
|
||||
break;
|
||||
|
||||
case menuYesNoYES: {
|
||||
case menuSimmYES:
|
||||
case menuSimmRAW:
|
||||
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
|
||||
if (prec->pact || (prec->sdly < 0.)) {
|
||||
status = dbPutLink(&prec->siol, DBR_ULONG, &prec->val, 1);
|
||||
if (prec->simm == menuSimmYES)
|
||||
status = dbPutLink(&prec->siol, DBR_LONG, &prec->val, 1);
|
||||
else /* prec->simm == menuSimmRAW */
|
||||
status = dbPutLink(&prec->siol, DBR_ULONG, &prec->rval, 1);
|
||||
prec->pact = FALSE;
|
||||
} else { /* !prec->pact && delay >= 0. */
|
||||
epicsCallback *pvt = prec->simpvt;
|
||||
@@ -383,7 +382,6 @@ static long writeValue(mbboDirectRecord *prec)
|
||||
prec->pact = TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
|
||||
|
||||
@@ -9,11 +9,14 @@
|
||||
|
||||
=title Multi-Bit Binary Output Direct Record (mbboDirect)
|
||||
|
||||
The mbboDirect record performs the opposite function to that of the mbbiDirect
|
||||
record. It accumulates bits (in the fields B0 - BF) as unsigned characters, and
|
||||
converts them to a word which is then written out to hardware. If a bit field is
|
||||
non-zero, it is interpreted as a binary 1. On the other hand, if it is zero, it
|
||||
is interpreted as a binary 0.
|
||||
The mbboDirect record performs roughly the opposite function to that of the
|
||||
L<mbbiDirect record|mbbiDirectRecord>.
|
||||
|
||||
It can accept boolean values in its 32 bit fields (B0-B9, BA-BF, B10-B19 and
|
||||
B1A-B1F), and converts them to a 32-bit signed integer in VAL which is provided
|
||||
to the device support. A zero value in a bit field becomes a zero bit in VAL, a
|
||||
non-zero value in a bit field becomes a one bit in VAL, with B0 being the least
|
||||
signficant bit and B1F the MSB/sign bit.
|
||||
|
||||
=recordtype mbboDirect
|
||||
|
||||
@@ -31,50 +34,86 @@ The mbboDirect record has the standard fields for specifying under what
|
||||
circumstances it will be processed.
|
||||
These fields are listed in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
|
||||
=fields SCAN, PHAS, EVNT, PRIO, PINI
|
||||
|
||||
=head3 Desired Output Parameters
|
||||
|
||||
The mbboDirect record, like all output records, must specify where its output
|
||||
originates. The output mode select field (OMSL) determines whether the output
|
||||
originates from another record or from database access. When set to C<<<
|
||||
closed_loop >>>, the desired output is retrieved from the link specified in the
|
||||
desired output (DOL) field--which can specify either a database or channel
|
||||
access link--and placed into the VAL field. When set to C<<< supervisory >>>,
|
||||
the DOL field is ignored and the current value of VAL is used. The desired
|
||||
output can be written into the VAL field via dpPuts at run-time when the record
|
||||
is in C<<< supervisory >>> mode. DOL can also be a constant, in which case VAL
|
||||
is initialized to the constant value. Note that OMSL cannot be C<<< closed_loop
|
||||
>>> when DOL is a constant.
|
||||
Like all output records, the mbboDirect record must specify where its output
|
||||
should originate when it gets processed. The Output Mode SeLect field (OMSL)
|
||||
determines whether the output value should be read from another record or not.
|
||||
When set to C<<< closed_loop >>>, a 32-bit integer value (the "desired output")
|
||||
will be read from a link specified in the Desired Output Link (DOL) field and
|
||||
placed into the VAL field.
|
||||
|
||||
VAL is then converted to RVAL in the routine described in the next section.
|
||||
However, the C<<< Soft Channel >>> device support module for the mbboDirect
|
||||
record writes the VAL field's value without any conversion.
|
||||
When OMSL is set to C<<< supervisory >>>, the DOL field is ignored during
|
||||
processing and the contents of VAL are used. A value to be output may thus be
|
||||
written direcly into the VAL field from elsewhere as long as the record is in
|
||||
C<<< supervisory >>> mode.
|
||||
|
||||
=fields OMSL, DOL, VAL
|
||||
|
||||
=head4 Bit Fields
|
||||
|
||||
The fields B0 through BF and B10 through B1F provide an alternative way to set
|
||||
the individual bits of the VAL field when the record is in C<<< supervisory >>>
|
||||
mode. Writing to one of these fields will then modify the corresponding bit in
|
||||
VAL, and writing to VAL will update these bit fields from that value.
|
||||
|
||||
The VAL field is signed so it can be accessed through Channel Access as an
|
||||
integer; if it were made unsigned (a C<DBF_ULONG>) its representation through
|
||||
Channel Access would become a C<double>, which could cause problems with some
|
||||
client programs.
|
||||
|
||||
Prior to the EPICS 7.0.6.1 release the individual bit fields were not updated
|
||||
while the record was in C<<< closed_loop >>> mode with VAL being set from the
|
||||
DOL link, and writing to the bit fields in that mode could cause the record to
|
||||
process but the actual field values would not affect VAL at all. Changing the
|
||||
OMSL field from C<<< closed_loop >>> to C<<< supervisory >>> would set the bit
|
||||
fields from VAL at that time and trigger a monitor event for the bits that
|
||||
changed at that time. At record initialization if VAL is defined and the OMSL
|
||||
field is C<<< supervisory >>> the bit fields would be set from VAL.
|
||||
|
||||
From EPICS 7.0.6.1 the bit fields get updated from VAL during record processing
|
||||
and monitors are triggered on them in either mode. Attempts to write to the bit
|
||||
fields while in C<<< closed_loop >>> mode will be rejected by the C<special()>
|
||||
routine which may trigger an error from the client that wrote to them. During
|
||||
initialization if the record is still undefined (UDF) after DOL has been read
|
||||
and the device support initialized but at least one of the B0-B1F fields is
|
||||
non-zero, the VAL field will be set from those fields and UDF will be cleared.
|
||||
|
||||
=fields B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, BA, BB, BC, BD, BE, BF, B10, B11, B12, B13, B14, B15, B16, B17, B18, B19, B1A, B1B, B1C, B1D, B1E, B1F
|
||||
|
||||
=head3 Convert and Write Parameters
|
||||
|
||||
For records that are to write values to hardware devices, the OUT output link
|
||||
must contain the address of the I/O card, and the DTYP field must specify
|
||||
the proper device support module. Be aware that the address format differs
|
||||
according to the I/O bus used. See L<Address Specification> for information
|
||||
on the format of hardware addresses.
|
||||
according to the I/O bus used. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on the format of hardware addresses.
|
||||
|
||||
If the mbboDirect record does not use the C<<< Soft Channel >>> device support
|
||||
module, then VAL is converted to RVAL, and RVAL is the actual 16-bit word sent
|
||||
out. RVAL is set equal to VAL and then shifted left by the number of bits
|
||||
specified in the SHFT field (the SHFT value is set by device support and is not
|
||||
configurable by the user). RVAL is then sent out to the location specified in
|
||||
the OUT field.
|
||||
During record processing VAL is converted into RVAL, which is the actual 32-bit
|
||||
word to be sent out. RVAL is set to VAL shifted left by the number of bits
|
||||
specified in the SHFT field (SHFT is normally set by device support). RVAL is
|
||||
then sent out to the location specified in the OUT field.
|
||||
|
||||
For mbboDirect records that specify a database link, a channel access link, or a
|
||||
constant, the DTYP field must specify either one of two soft device support
|
||||
routines--{Soft Channel} or C<<< Raw Soft Channel >>>. The difference between
|
||||
the two is that C<<< Soft Channel >>> writes the desired output value from VAL
|
||||
directly to the output link while C<<< Raw Soft Channel >>> writes the value
|
||||
from RVAL to the output link after it has undergone the conversion described
|
||||
above.
|
||||
The fields NOBT and MASK can be used by device support to force some of the
|
||||
output bits written by that support to be zero. By default all 32 bits can be
|
||||
sent, but the NOBT field can be set to specify a smaller number of contiguous
|
||||
bits, or MASK can specify a non-contiguous set of bits. When setting MASK it is
|
||||
often necessary to set NOBT to a non-zero value as well, although in this case
|
||||
the actual value of NOBT may be ignored by the device support. If a device
|
||||
support sets the SHFT field it will also left-shift the value of MASK at the
|
||||
same time.
|
||||
|
||||
=fields OUT, RVAL, SHFT, B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, BA, BB, BC, BD, BE, BF
|
||||
For mbboDirect records writing to a link instead of to hardware, the DTYP field
|
||||
must select one of the soft device support routines C<<< Soft Channel >>> or
|
||||
C<<< Raw Soft Channel >>>. The C<<< Soft Channel >>> support writes the contents
|
||||
of the VAL field to the output link. The C<<< Raw Soft Channel >>> support
|
||||
allows SHFT to be set in the DB file, and sends the result of ANDing the shifted
|
||||
MASK with the RVAL field's value.
|
||||
|
||||
=fields OUT, RVAL, SHFT, MASK, NOBT
|
||||
|
||||
=head3 Operator Display Parameters
|
||||
|
||||
@@ -105,7 +144,6 @@ Parameters> for more on the record name (NAME) and description (DESC) fields.
|
||||
field(OMSL,DBF_MENU) {
|
||||
prompt("Output Mode Select")
|
||||
promptgroup("50 - Output")
|
||||
special(SPC_RESET)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
menu(menuOmsl)
|
||||
@@ -117,7 +155,7 @@ Parameters> for more on the record name (NAME) and description (DESC) fields.
|
||||
interest(1)
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
prompt("Desired Output Link")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
@@ -155,6 +193,11 @@ Parameters> for more on the record name (NAME) and description (DESC) fields.
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(OBIT,DBF_LONG) {
|
||||
prompt("Last Bit mask Monitored")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(SHFT,DBF_USHORT) {
|
||||
prompt("Shift")
|
||||
promptgroup("50 - Output")
|
||||
@@ -167,11 +210,13 @@ These parameters are used by the run-time code for processing the mbbo Direct
|
||||
record.
|
||||
|
||||
MASK is used by device support routine to read the hardware register. Record
|
||||
support sets low order NOBT bits. Device support can shift this value.
|
||||
support sets the low order NOBT bits of MASK at initialization, and device
|
||||
support is allowed to shift this value.
|
||||
|
||||
MLST holds the value when the last monitor for value change was triggered.
|
||||
OBIT has a similar role for bits held in the B0-B1F fields.
|
||||
|
||||
=fields NOBT, ORAW, MASK, MLST
|
||||
=fields NOBT, ORAW, MASK, MLST, OBIT
|
||||
|
||||
=head3 Simulation Mode Parameters
|
||||
|
||||
@@ -179,6 +224,7 @@ The following fields are used to operate the record in simulation mode.
|
||||
|
||||
If SIMM (fetched through SIML) is YES, the record is put in SIMS
|
||||
severity and the value is written through SIOL, without conversion.
|
||||
If SIMM is RAW, the value is converted and RVAL is written.
|
||||
SSCN sets a different SCAN mechanism to use in simulation mode.
|
||||
SDLY sets a delay (in sec) that is used for asynchronous simulation
|
||||
processing.
|
||||
@@ -204,7 +250,7 @@ for more information on simulation mode and its fields.
|
||||
prompt("Simulation Mode")
|
||||
special(SPC_MOD)
|
||||
interest(1)
|
||||
menu(menuYesNo)
|
||||
menu(menuSimm)
|
||||
}
|
||||
field(SIMS,DBF_MENU) {
|
||||
prompt("Simulation Mode Severity")
|
||||
@@ -242,17 +288,21 @@ for more information on simulation mode and its fields.
|
||||
=head3 Alarm Parameters
|
||||
|
||||
The possible alarm conditions for mbboDirect records are the SCAN, READ, and
|
||||
INVALID alarms. The SCAN and READ alarms are not configurable by the user since
|
||||
they are always of MAJOR severity. See L<Alarm Specification> for a complete
|
||||
explanation of Scan and Read alarms.
|
||||
INVALID alarms.
|
||||
|
||||
The IVOA field specifies an action to take when the INVALID alarm is triggered.
|
||||
The IVOA field specifies an action to take when an INVALID alarm is triggered.
|
||||
There are three possible actions: C<<< Continue normally >>>, C<<< Don't drive
|
||||
outputs >>>, or C<<< Set output to IVOV >>>. When C<<< Set output to IVOV >>> is
|
||||
specified and a INVALID alarm is triggered, the record will write the value in
|
||||
the IVOV field to output. See L<Invalid Output Action Fields|dbCommonOutput/Invalid Output Action Fields> for more
|
||||
information. L<Alarm Fields|dbCommonRecord/Alarm Fields> lists the fields related to
|
||||
alarms that are common to all record types.
|
||||
the IVOV field to the output.
|
||||
|
||||
See L<Invalid Output Action Fields|dbCommonOutput/Invalid Output Action Fields>
|
||||
for more information about IVOA and IVOV.
|
||||
|
||||
See L<Alarm Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#alarm-specification>
|
||||
for a complete explanation of record alarms and of the standard fields.
|
||||
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related
|
||||
to alarms that are common to all record types.
|
||||
|
||||
=fields IVOA, IVOV
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#include "special.h"
|
||||
#include "menuOmsl.h"
|
||||
#include "menuIvoa.h"
|
||||
#include "menuYesNo.h"
|
||||
#include "menuSimm.h"
|
||||
|
||||
#define GEN_SIZE_OFFSET
|
||||
#include "mbboRecord.h"
|
||||
@@ -151,7 +151,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
|
||||
epicsUInt32 *pstate_values = &prec->zrvl;
|
||||
int i;
|
||||
|
||||
prec->val = 65535; /* initalize to unknown state */
|
||||
prec->val = 65535; /* initialize to unknown state */
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (*pstate_values == rval) {
|
||||
prec->val = i;
|
||||
@@ -217,7 +217,7 @@ static long process(struct dbCommon *pcommon)
|
||||
convert(prec);
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
* will be up to date if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
@@ -448,14 +448,18 @@ static long writeValue(mbboRecord *prec)
|
||||
}
|
||||
|
||||
switch (prec->simm) {
|
||||
case menuYesNoNO:
|
||||
case menuSimmNO:
|
||||
status = pdset->write_mbbo(prec);
|
||||
break;
|
||||
|
||||
case menuYesNoYES: {
|
||||
case menuSimmYES:
|
||||
case menuSimmRAW:
|
||||
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
|
||||
if (prec->pact || (prec->sdly < 0.)) {
|
||||
status = dbPutLink(&prec->siol, DBR_USHORT, &prec->val, 1);
|
||||
if (prec->simm == menuSimmYES)
|
||||
status = dbPutLink(&prec->siol, DBR_USHORT, &prec->val, 1);
|
||||
else /* prec->simm == menuSimmRAW */
|
||||
status = dbPutLink(&prec->siol, DBR_ULONG, &prec->rval, 1);
|
||||
prec->pact = FALSE;
|
||||
} else { /* !prec->pact && delay >= 0. */
|
||||
epicsCallback *pvt = prec->simpvt;
|
||||
@@ -467,7 +471,6 @@ static long writeValue(mbboRecord *prec)
|
||||
prec->pact = TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
|
||||
|
||||
@@ -165,8 +165,9 @@ for converting VAL to RVAL.
|
||||
|
||||
The following fields are used to operate the record in simulation mode.
|
||||
|
||||
If SIMM (fetched through SIML) is YES, the record is put in SIMS
|
||||
If SIMM (fetched through SIML, if populated) is YES, the record is put in SIMS
|
||||
severity and the value is written through SIOL, without conversion.
|
||||
If SIMM is RAW, the value is converted and RVAL is written.
|
||||
SSCN sets a different SCAN mechanism to use in simulation mode.
|
||||
SDLY sets a delay (in sec) that is used for asynchronous simulation
|
||||
processing.
|
||||
@@ -197,7 +198,7 @@ for more information on simulation mode and its fields.
|
||||
#=write Yes
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
prompt("Desired Output Link")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
@@ -657,7 +658,7 @@ for more information on simulation mode and its fields.
|
||||
prompt("Simulation Mode")
|
||||
special(SPC_MOD)
|
||||
interest(1)
|
||||
menu(menuYesNo)
|
||||
menu(menuSimm)
|
||||
}
|
||||
field(SIMS,DBF_MENU) {
|
||||
prompt("Simulation Mode Severity")
|
||||
|
||||
@@ -25,7 +25,9 @@ recordtype(printf) {
|
||||
|
||||
The printf record has the standard fields for specifying under what
|
||||
circumstances it will be processed.
|
||||
These fields are listed in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
These fields are described in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
|
||||
=fields SCAN, PHAS, EVNT, PRIO, PINI
|
||||
|
||||
=head3 String Generation Parameters
|
||||
|
||||
@@ -144,7 +146,8 @@ which type of the data is requested through the appropriate input link. As with
|
||||
C<printf()> a C<*> character may be used in the format to specify width and/or
|
||||
precision instead of numeric literals, in which case additional input links are
|
||||
used to provide the necessary integer parameter or parameters. See L<Address
|
||||
Specification> for information on specifying links.
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on specifying links.
|
||||
|
||||
The formatted string is written to the VAL field. The maximum number of
|
||||
characters in VAL is given by SIZV, and cannot be larger than 65535. The LEN
|
||||
|
||||
@@ -79,7 +79,7 @@ for each desired output link. Only those that are defined are used.
|
||||
When the sequence record is processed, it uses a selection algorithm similar to
|
||||
that of the selection record to decide which links to process.The select
|
||||
mechanism field (SELM) has three algorithms to choose from: C<<< All >>>,
|
||||
C<<<Specified >>> or C<<< Mask >>>.
|
||||
C<<< Specified >>> or C<<< Mask >>>.
|
||||
|
||||
=head4 Record fields related to the Selection Algorithm
|
||||
|
||||
@@ -102,24 +102,26 @@ process can be dynamically changed by the record pointed by SELL.
|
||||
|
||||
B<SELN - Link Selection>
|
||||
|
||||
When B<C<SELM = Specified>> this is the index number of the link that will be
|
||||
processed, used in combination with the C<OFFS> field:
|
||||
When B<SELM> has the value C<Specified> the B<SELN> field sets the index number
|
||||
of the link that will be processed, after adding the B<OFFS> field:
|
||||
|
||||
SELN = SELN + OFFS
|
||||
=over
|
||||
|
||||
LNKI<n> where I<n> = C<SELN + OFFS>
|
||||
|
||||
I<(By default, the OFFS is initalized to ZERO)>
|
||||
=back
|
||||
|
||||
When B<C<SELM = Mask>> this field is the bitmask that will be used to determine
|
||||
which links will be processed by the seq record,
|
||||
in combination with the C<SHFT> field:
|
||||
I<(If not set, the OFFS field is ZERO)>
|
||||
|
||||
When B<SELM> has the value C<Mask> the B<SELN> field provides the bitmask that
|
||||
determines which links will be processed, after shifting by B<SHFT> bits:
|
||||
|
||||
if (SHFT >= 0)
|
||||
SELN = SELN << -SHFT
|
||||
bits = SELN >> SHFT
|
||||
else
|
||||
SELN = SELN >> SHFT
|
||||
bits = SELN << -SHFT
|
||||
|
||||
I<(By default, the SHFT is initalized to -1)>
|
||||
I<(If not set, the SHFT field is -1 so bits from SELN are shifted left by 1)>
|
||||
|
||||
=head4 B<Note about SHFT and OFFS fields>
|
||||
|
||||
@@ -131,7 +133,7 @@ The SHFT and OFFS fields were introduced to keep compatibility of old databases
|
||||
that used seq records with links indexed from one.
|
||||
|
||||
B<To use the DO0, DOL0, LNK0, DLY0 fields when SELM = Mask, the SHFT field must
|
||||
be set to ZERO>
|
||||
be explicitly set to ZERO>
|
||||
|
||||
=head4 Selection Algorithms Description
|
||||
|
||||
@@ -208,29 +210,37 @@ Routine process implements the following algorithm:
|
||||
=item 1.
|
||||
|
||||
First, PACT is set to TRUE, and the link selection is fetched. Depending on the
|
||||
selection mechanism, the link selection output links are processed in order from
|
||||
LNK0 to LNKF. When LNKI<x> is processed, the corresponding DLYI<x> value is
|
||||
used to generate a delay via watchdog timer.
|
||||
selection mechanism chosen, the appropriate set of link groups will be
|
||||
processed. If multiple link groups need to be processed they are done in
|
||||
increasing numerical order, from LNK0 to LNKF.
|
||||
|
||||
=item 2.
|
||||
|
||||
After DLYI<x> seconds have expired, the input value is fetched from DOI<x> (if
|
||||
DOLI<x> is constant) or DOLI<x> (if DOLI<x> is a database link or channel
|
||||
access link) and written to LNKI<x>.
|
||||
When LNKI<x> is to be processed, the corresponding DLYI<x> value is first used
|
||||
to generate the requested time delay, using the IOC's Callback subsystem to
|
||||
perform subsequent operations. This means that although PACT remains TRUE, the
|
||||
lockset that the sequence record belongs to will be unlocked for the duration of
|
||||
the delay time (an unlock occurs even when the delay is zero).
|
||||
|
||||
=item 3.
|
||||
|
||||
When all links are completed, an asynchronous completion call back to dbProcess
|
||||
is made (see the Application Developer's Guide for more information on
|
||||
asynchronous processing.)
|
||||
After DLYI<x> seconds have expired, the value in DOI<x> is saved locally and a
|
||||
new value is read into DOI<x> through the link DOLI<x> (if the link is valid).
|
||||
Next the record's timestamp is set, and the value in DOI<x> is written through
|
||||
the LNKI<x> output link. If the value of DOI<x> was changed when it was read in
|
||||
a monitor event is triggered on that field.
|
||||
|
||||
=item 4.
|
||||
|
||||
Then UDF is set to FALSE.
|
||||
If any link groups remain to be processed, the next group is selected and the
|
||||
operations for that group are executed again from step 2 above.
|
||||
|
||||
If the last link group has been processed, UDF is set to FALSE and the record's
|
||||
timestamp is set.
|
||||
|
||||
=item 5.
|
||||
|
||||
Monitors are checked.
|
||||
Monitors are posted on VAL and SELN.
|
||||
|
||||
=item 6.
|
||||
|
||||
@@ -238,12 +248,11 @@ The forward link is scanned, PACT is set FALSE, and the process routine returns.
|
||||
|
||||
=back
|
||||
|
||||
For the delay mechanism to operate properly, the record is processed
|
||||
For the delay mechanism to operate properly, the record is normally processed
|
||||
asynchronously. The only time the record will not be processed asynchronously is
|
||||
when there are no non-NULL output links selected (i.e. when it has nothing to
|
||||
do.) The processing of the links is done via callback tasks at the priority set
|
||||
in the PRIO field in dbCommon (see the Application Developer's Guide for more
|
||||
information on call
|
||||
if it has nothing to do, because no link groups or only empty link groups are
|
||||
selected for processing (groups where both DOLI<x> and LNKI<x> are unset or
|
||||
contain only a constant value).
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ static long process(struct dbCommon *pcommon)
|
||||
}
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
* will be up to date if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
|
||||
if (prec->nsev < INVALID_ALARM )
|
||||
|
||||
@@ -65,8 +65,8 @@ the output mode select (OMSL) field, which can have two possible value: C<<<
|
||||
closed_loop >>> or C<<< supervisory >>>. If C<<< supervisory >>> is specified,
|
||||
DOL is ignored, the current value of VAL is written, and the VAL can be changed
|
||||
externally via dbPuts at run-time. If C<<< closed_loop >>> is specified, the VAL
|
||||
field's value is obtained from the address specified in the desired output
|
||||
location field (DOL) which can be either a database link or a channel access
|
||||
field's value is obtained from the address specified in the Desired Output
|
||||
Link field (DOL) which can be either a database link or a channel access
|
||||
link.
|
||||
|
||||
DOL can also be a constant, in which case VAL will be initialized to the
|
||||
@@ -80,7 +80,7 @@ cannot be C<<< closed_loop >>>.
|
||||
=cut
|
||||
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
prompt("Desired Output Link")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
|
||||
@@ -124,6 +124,7 @@ static long process(struct dbCommon *pcommon)
|
||||
struct waveformRecord *prec = (struct waveformRecord *)pcommon;
|
||||
wfdset *pdset = (wfdset *)(prec->dset);
|
||||
unsigned char pact=prec->pact;
|
||||
epicsUInt32 nord = prec->nord;
|
||||
long status;
|
||||
|
||||
if ((pdset==NULL) || (pdset->read_wf==NULL)) {
|
||||
@@ -143,6 +144,8 @@ static long process(struct dbCommon *pcommon)
|
||||
prec->udf = FALSE;
|
||||
recGblGetTimeStampSimm(prec, prec->simm, &prec->siol);
|
||||
|
||||
if (nord != prec->nord)
|
||||
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
|
||||
monitor(prec);
|
||||
|
||||
/* process the forward scan link record */
|
||||
@@ -206,7 +209,9 @@ static long put_array_info(DBADDR *paddr, long nNew)
|
||||
prec->nord = prec->nelm;
|
||||
|
||||
if (nord != prec->nord)
|
||||
{
|
||||
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -334,11 +339,7 @@ static long readValue(waveformRecord *prec)
|
||||
|
||||
switch (prec->simm) {
|
||||
case menuYesNoNO: {
|
||||
epicsUInt32 nord = prec->nord;
|
||||
|
||||
status = pdset->read_wf(prec);
|
||||
if (nord != prec->nord)
|
||||
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -353,7 +354,6 @@ static long readValue(waveformRecord *prec)
|
||||
|
||||
if (nRequest != prec->nord) {
|
||||
prec->nord = nRequest;
|
||||
db_post_events(prec, &prec->nord, DBE_VALUE | DBE_LOG);
|
||||
}
|
||||
prec->pact = FALSE;
|
||||
}
|
||||
|
||||
@@ -120,9 +120,18 @@ at run-time.
|
||||
VAL references the array where the waveform stores its data. The BPTR field
|
||||
holds the address of the array.
|
||||
|
||||
The NORD field holds a counter of the number of elements that have been read
|
||||
into the array. It is reset to 0 when the device is rearmed. The BUSY field
|
||||
indicates if the device is armed but has not yet been digitized.
|
||||
The NORD field indicates the number of elements that were read into the array.
|
||||
|
||||
The BUSY field permits asynchronous device support to collect array elements
|
||||
sequentially in multiple read cycles which may call the record's C<process()>
|
||||
method many times before completing a read operation. Such a device would set
|
||||
BUSY to TRUE along with setting PACT at the start of acquisition (it could also
|
||||
set NORD to 0 and use it to keep track of how many elements have been received).
|
||||
After receiving the last element the C<read_wf()> routine would clear BUSY which
|
||||
informs the record's C<process()> method that the read has finished. Note that
|
||||
CA clients that perform gets of the VAL field can see partially filled arrays
|
||||
when this type of device support is used, so the BUSY field is almost never used
|
||||
today.
|
||||
|
||||
=fields VAL, BPTR, NORD, BUSY
|
||||
|
||||
@@ -367,14 +376,14 @@ Other: Error.
|
||||
=head3 Device Support For Soft Records
|
||||
|
||||
The C<<< Soft Channel >>> device support module is provided to read values from
|
||||
other records and store them in arrays. If INP is a constant link, then read_wf
|
||||
does nothing. In this case, the record can be used to hold arrays written via
|
||||
dbPuts. If INP is a database or channel access link, the new array value is read
|
||||
from the link. NORD is set to the number of items in the array.
|
||||
other records and store them in the VAL field. If INP is a constant link, then
|
||||
C<read_wf()> does nothing. In this case, the record can be used to hold a fixed
|
||||
set of data or array values written from elsewhere. If INP is a valid link, the
|
||||
new array value is read from that link. NORD is set to the number of items
|
||||
received.
|
||||
|
||||
This module places a value directly in VAL.
|
||||
|
||||
If the INP link type is constant, then NORD is set to zero.
|
||||
If the INP link type is constant, VAL is set from it in the C<init_record()>
|
||||
routine and NORD is also set at that time.
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
@@ -114,7 +114,8 @@ void lazy_dbd(const std::string& dbd_file) {
|
||||
|
||||
if (verbose)
|
||||
std::cout<<"softIoc_registerRecordDeviceDriver(pdbbase)\n";
|
||||
softIoc_registerRecordDeviceDriver(pdbbase);
|
||||
errIf(softIoc_registerRecordDeviceDriver(pdbbase),
|
||||
"Failed to initialize database");
|
||||
registryFunctionAdd("exit", (REGISTRYFUNCTION) exitSubroutine);
|
||||
}
|
||||
|
||||
@@ -208,6 +209,9 @@ int main(int argc, char *argv[])
|
||||
lazy_dbd(dbd_file);
|
||||
xmacro = "IOC=";
|
||||
xmacro += optarg;
|
||||
if (verbose) {
|
||||
std::cout<<"dbLoadRecords(\""<<exit_file<<"\", \""<<xmacro<<"\")\n";
|
||||
}
|
||||
errIf(dbLoadRecords(exit_file.c_str(), xmacro.c_str()),
|
||||
std::string("Failed to load: ")+exit_file);
|
||||
loadedDb = true;
|
||||
|
||||
Reference in New Issue
Block a user