#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
#     National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
#     Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************

=title Data Fanout Record (dfanout)

The Data Fanout or "dfanout" record is used to forward data to up to
16 other records. It's similar to the fanout record except that the
capability to forward data has been added to it. It has no associated
device support.

Since 7.0.10 the number of output links has been increased
from 8 to 16 and IVOA and IVOV fields have been added.

=head2 Parameter Fields

The record-specific fields are described below, grouped by functionality.

=recordtype dfanout

=cut

menu(dfanoutSELM) {
	choice(dfanoutSELM_All,"All")
	choice(dfanoutSELM_Specified,"Specified")
	choice(dfanoutSELM_Mask,"Mask")
}

recordtype(dfanout) {

=head3 Scan Parameters

The data fanout 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>.

=head3 Desired Output Parameters

The data fanout record must specify where the desired output value
originates, i.e., the data which is to be forwarded 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 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.

The DOL field can also be a constant in which case the VAL field is
initialized to the constant value.

Note that there are no conversion parameters, so the desired output value
undergoes no conversions before it is sent out to the output links.

=fields DOL, OMSL, VAL

=head3 Write Parameters

The OUTA-OUTP 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|https://docs.epics-controls.org/en/latest/process-database/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.

=head4 Menu dfanoutSELM

SELM is a menu, with three choices:

=menu dfanoutSELM

If SELM is C<All>, then all output links are used, and the values of
SELL and SELN are ignored.

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 it retrieved from
another EPICS PV. If SELL is a valid PV link, then SELN will be read from
the linked PV.

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 SELL, SELM, SELN, OUTA - OUTP

=head3 Operator Display Parameters

These parameters are used to present meaningful data to the operator.
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.

=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 about the record name (NAME) and description (DESC) fields.

=fields NAME, DESC, EGU, HOPR, LOPR, PREC

=head3 Alarm Parameters

The possible alarm conditions for data fanouts are the SCAN, READ, INVALID,
and limit alarms. The SCAN and READ alarms are called by the record
routines. The IVOA field specifies the action to take in this case.

For an explanation of the IVOA and IVOV fields, see
L<Invalid Output Action Fields|dbCommonOutput/Invalid Output Action Fields>.

The limit alarms are configured by the user in the HIHI, LOLO,
HIGH, and LOW fields using floating point values. The limit alarms apply 
only to the VAL field. The severity for each of these limits is specified
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|https://docs.epics-controls.org/en/latest/process-database/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

=head3 Monitor Parameters

These parameters are used to determine when to send monitors placed on the
VAL field. These monitors are sent when the value field exceeds the last
monitored fields by the specified deadband, ADEL for archivers monitors and
MDEL for all other types of monitors. If these fields have a value of zero,
every time the value changes, a monitor will be triggered; if they have a
value of -1, every time the record is scanned, monitors are triggered. See
L<Monitor Specification> for a complete explanation of monitors.

=fields ADEL, MDEL

=head3 Run-Time Parameters and Simulation Mode Parameters

These parameters are used by the run-time code for processing the data
fanout record. They are not configurable. They are used to implement the
hysteresis factors for monitor callbacks.

=fields LALM, ALST, MLST

=cut

	include "dbCommon.dbd" 
	field(VAL,DBF_DOUBLE) {
		prompt("Desired Output")
		promptgroup("40 - Input")
		asl(ASL0)
		pp(TRUE)
	}
	field(SELM,DBF_MENU) {
		prompt("Select Mechanism")
		promptgroup("30 - Action")
		interest(1)
		menu(dfanoutSELM)
	}
	field(SELN,DBF_USHORT) {
		prompt("Link Selection")
		interest(1)
		initial("1")
	}
	field(SELL,DBF_INLINK) {
		prompt("Link Selection Loc")
		promptgroup("30 - Action")
		interest(1)
	}
	field(OUTA,DBF_OUTLINK) {
		prompt("Output Spec A")
		promptgroup("50 - Output")
		interest(1)
	}
	field(OUTB,DBF_OUTLINK) {
		prompt("Output Spec B")
		promptgroup("50 - Output")
		interest(1)
	}
	field(OUTC,DBF_OUTLINK) {
		prompt("Output Spec C")
		promptgroup("50 - Output")
		interest(1)
	}
	field(OUTD,DBF_OUTLINK) {
		prompt("Output Spec D")
		promptgroup("50 - Output")
		interest(1)
	}
	field(OUTE,DBF_OUTLINK) {
		prompt("Output Spec E")
		promptgroup("50 - Output")
		interest(1)
	}
	field(OUTF,DBF_OUTLINK) {
		prompt("Output Spec F")
		promptgroup("50 - Output")
		interest(1)
	}
	field(OUTG,DBF_OUTLINK) {
		prompt("Output Spec G")
		promptgroup("50 - Output")
		interest(1)
	}
	field(OUTH,DBF_OUTLINK) {
		prompt("Output Spec H")
		promptgroup("50 - Output")
		interest(1)
	}
	field(OUTI,DBF_OUTLINK) {
		prompt("Output Spec I")
		promptgroup("50 - Output")
		interest(1)
	}
	field(OUTJ,DBF_OUTLINK) {
		prompt("Output Spec J")
		promptgroup("50 - Output")
		interest(1)
	}
	field(OUTK,DBF_OUTLINK) {
		prompt("Output Spec K")
		promptgroup("50 - Output")
		interest(1)
	}
	field(OUTL,DBF_OUTLINK) {
		prompt("Output Spec L")
		promptgroup("50 - Output")
		interest(1)
	}
	field(OUTM,DBF_OUTLINK) {
		prompt("Output Spec M")
		promptgroup("50 - Output")
		interest(1)
	}
	field(OUTN,DBF_OUTLINK) {
		prompt("Output Spec N")
		promptgroup("50 - Output")
		interest(1)
	}
	field(OUTO,DBF_OUTLINK) {
		prompt("Output Spec O")
		promptgroup("50 - Output")
		interest(1)
	}
	field(OUTP,DBF_OUTLINK) {
		prompt("Output Spec P")
		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")
		interest(1)
		size(16)
		prop(YES)		# get_units
	}
	field(PREC,DBF_SHORT) {
		prompt("Display Precision")
		promptgroup("80 - Display")
		interest(1)
		prop(YES)		# get_precision
	}
	field(HOPR,DBF_DOUBLE) {
		prompt("High Operating Range")
		promptgroup("80 - Display")
		interest(1)
		prop(YES)		# get_graphic_double, get_control_double
	}
	field(LOPR,DBF_DOUBLE) {
		prompt("Low Operating Range")
		promptgroup("80 - Display")
		interest(1)
		prop(YES)		# get_graphic_double, get_control_double
	}
	field(HIHI,DBF_DOUBLE) {
		prompt("Hihi Alarm Limit")
		promptgroup("70 - Alarm")
		pp(TRUE)
		interest(1)
		prop(YES)		# get_alarm_double
	}
	field(LOLO,DBF_DOUBLE) {
		prompt("Lolo Alarm Limit")
		promptgroup("70 - Alarm")
		pp(TRUE)
		interest(1)
		prop(YES)		# get_alarm_double
	}
	field(HIGH,DBF_DOUBLE) {
		prompt("High Alarm Limit")
		promptgroup("70 - Alarm")
		pp(TRUE)
		interest(1)
		prop(YES)		# get_alarm_double
	}
	field(LOW,DBF_DOUBLE) {
		prompt("Low Alarm Limit")
		promptgroup("70 - Alarm")
		pp(TRUE)
		interest(1)
		prop(YES)		# get_alarm_double
	}
	field(HHSV,DBF_MENU) {
		prompt("Hihi Severity")
		promptgroup("70 - Alarm")
		pp(TRUE)
		interest(1)
		prop(YES)		# get_alarm_double
		menu(menuAlarmSevr)
	}
	field(LLSV,DBF_MENU) {
		prompt("Lolo Severity")
		promptgroup("70 - Alarm")
		pp(TRUE)
		interest(1)
		prop(YES)		# get_alarm_double
		menu(menuAlarmSevr)
	}
	field(HSV,DBF_MENU) {
		prompt("High Severity")
		promptgroup("70 - Alarm")
		pp(TRUE)
		interest(1)
		prop(YES)		# get_alarm_double
		menu(menuAlarmSevr)
	}
	field(LSV,DBF_MENU) {
		prompt("Low Severity")
		promptgroup("70 - Alarm")
		pp(TRUE)
		interest(1)
		prop(YES)		# get_alarm_double
		menu(menuAlarmSevr)
	}
	field(HYST,DBF_DOUBLE) {
		prompt("Alarm Deadband")
		promptgroup("70 - Alarm")
		interest(1)
	}
	field(ADEL,DBF_DOUBLE) {
		prompt("Archive Deadband")
		promptgroup("80 - Display")
		interest(1)
	}
	field(MDEL,DBF_DOUBLE) {
		prompt("Monitor Deadband")
		promptgroup("80 - Display")
		interest(1)
	}
	field(LALM,DBF_DOUBLE) {
		prompt("Last Value Alarmed")
		special(SPC_NOMOD)
		interest(3)
	}
	field(ALST,DBF_DOUBLE) {
		prompt("Last Value Archived")
		special(SPC_NOMOD)
		interest(3)
	}
	field(MLST,DBF_DOUBLE) {
		prompt("Last Val Monitored")
		special(SPC_NOMOD)
		interest(3)
	}
	field(IVOA,DBF_MENU) {
		prompt("INVALID output action")
		promptgroup("50 - Output")
		interest(2)
		menu(menuIvoa)
	}
	field(IVOV,DBF_DOUBLE) {
		prompt("INVALID output value")
		promptgroup("50 - Output")
		interest(2)
	}

=head2 Record Support

=head3 Record Support Routines

=head2 C<init_record()>

This routine initializes all output links that are defined. Then it initializes
DOL if DOL is a constant or a PV_LINK. When initializing the output links
and the DOL link, a non-zero value is returned if an error occurs.

=head2 C<process()>

See next section.

=head2 C<get_units()>

The routine copies the string specified in the EGU field to the location
specified by a pointer which is passed to the routine.

=head2 C<get_graphic_double()>

If the referenced field is VAL, HIHI, HIGH, LOW, or LOLO, this routine sets
the C<upper_disp_limit> member of the C<dbr_grDouble> structure to the
HOPR and the C<lower_disp_limit> member to the LOPR. If the referenced
field is not one of the above fields, then C<recGblGetControlDouble()>
routine is called.

=head2 C<get_control_double()>

Same as the C<get_graphic_double()> routine except that it uses the
C<dbr_ctrlDouble> structure.

=head2 C<get_alarm_double()>

This sets the members of the C<dbr_alDouble> structure to the specified
alarm limits when the referenced field is VAL:

=over

upper_alarm_limit = HIHI

upper_warning_limit = HIGH

lower_warning_limit = LOW

lower_alarm_limit = LOLO

=back

If the referenced field is not VAL, the C<recGblGetAlarmDouble()> routine
is called.

=head3 Record Processing

=over

=item 1.

If OMSL is "closed_loop" and DOL is not a constant link read the new value
of VAL from DOL. If no errors occur, UDF is set to FALSE.

=item 2.

PACT is set TRUE and the record's timestamp is set.

=item 3.

A value is fetched from SELL and placed into SELN.

=item 4.

Alarms ranges are checked against the contents of the VAL field.

=item 5.

Check severity and then send the value through the OUTA-OUTP links, depending
on the setting of SELM and the value in SELN.

See L<Invalid Output Action Fields|dbCommonOutput/Invalid Output Action Fields>
for information on how INVALID alarms affect output records.

=item 6.

Value and archive monitors are posted on the VAL field if appropriate based on
the settings of MDEL and ADEL respectively.

=item 7.

Scan forward link if necessary, set PACT FALSE, and return.

=back

=cut
}
