RRM 3-13 Subroutine

From EPICSWIKI
Revision as of 22:53, 1 September 2005 by AndrewJohnson (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

EPICS Record Reference Manual


sub - Subroutine

The subroutine record is used to call a C initialization routine and a recurring scan routine. There is no device support for this record.

Parameter Fields

The fields fall into several categories:

  • scan parameters
  • read parameters
  • subroutine connection parameters
  • operator display parameters
  • alarm parameters
  • monitor parameters
  • run-time parameters.

Scan Parameters

The subroutine record has the standard fields for specifying under what circumstances it will be processed. These fields are listed in Scan Fields. In addition, Scanning Specification explains how these fields are used.

Read Parameters

The subroutine record has twelve input links (INPA-INPL), each of which has a corresponding value field (A-L). These fields are used to retrieve and store values that can be passed to the subroutine that the record calls.

The input links can be either channel access or database links, or constants. When constants, the corresponding value field for the link is initialized with the constant value and the field's value can be changed at run-time via dbPuts. Otherwise, the values for (A-F) are fetched from the input links when the record is processed. See Address Specification for information on specifying links.


FieldSummaryTypeDCTInitialAccessModifyRec Proc MonitorPP
INPAInput AINLINKYes0NoNoN/ANo
INPBInput BINLINKYes0NoNoN/ANo
INPCInput CINLINKYes0NoNoN/ANo
INPDInput DINLINKYes0NoNoN/ANo
INPEInput EINLINKYes0NoNoN/ANo
INPFInput FINLINKYes0NoNoN/ANo
INPGInput GINLINKYes0NoNoN/ANo
INPHInput HINLINKYes0NoNoN/ANo
INPIInput FINLINKYes0NoNoN/ANo
INPJInput HINLINKYes0NoNoN/ANo
INPKInput KINLINKYes0NoNoN/ANo
INPLInput LINLINKYes0NoNoN/ANo
AValue for ADOUBLENo0YesYes/NoYesYes
BB ValueDOUBLENo0YesYes/NoYesYes
CC ValueDOUBLENo0YesYes/NoYesYes
DD ValueDOUBLENo0YesYes/NoYesYes
EE ValueDOUBLENo0YesYes/NoYesYes
FF ValueDOUBLENo0YesYes/NoYesYes
GG ValueDOUBLENo0YesYes/NoYesYes
HH ValueDOUBLENo0YesYes/NoYesYes
II ValueDOUBLENo0YesYes/NoYesYes
JJ ValueDOUBLENo0YesYes/NoYesYes
KK ValueDOUBLENo0YesYes/NoYesYes
LL ValueDOUBLENo0YesYes/NoYesYes


Subroutine Connection

These fields are used to connect to the C subroutine. The name of the subroutine should be entered in the SNAM field.


FieldSummaryTypeDCTInitialAccessModifyRec Proc MonitorPP
INAMInitialization Name STRING [16]YesNullYesNoNoNo
SNAMSubroutine NameSTRING [16]YesNullYesNoNoNo


Operator Display Parameters

These parameters are used to present meaningful data to the operator. They display the value and other parameters of the subroutine either textually or graphically.

EGU is a string of up to 16 characters that could describe any units used by the subroutine record. It is retrieved by the get_units record support routine.

The HOPR and LOPR fields set the upper and lower display limits for the VAL, A-L, LA-LL, HIHI, LOLO, LOW, and HIGH fields. Both the get_graphic_double and get_control_double record support routines retrieve these fields.

The PREC field determines the floating point precision with which to display VAL. It is used whenever the get_precision record support routine is called.

See Fields Common to All Record Types for more on the record name (NAME) and description (DESC) fields.


FieldSummaryTypeDCTInitialAccessModifyRec Proc MonitorPP
EGUEngineering UnitsSTRING [16]YesnullYesYesNoNo
HOPRHigh Operating RangeFLOATYes0YesYesNoNo
LOPRLow Operating RangeFLOATYes0YesYesNoNo
PRECDisplay PrecisionSHORTYes0YesYesNoNo
NAMERecord NameSTRING [29]Yes0YesNoNoNo
DESCDescriptionSTRING [29]YesNullYesYesNoNo


Alarm Parameters

The possible alarm conditions for subroutine records are the SCAN, READ, limit alarms, and an alarm that can be triggered if the subroutine returns a negative value. The SCAN and READ alarms are called by the record or device support routines. The limit alarms are configured by the user in the HIHI, LOLO, HIGH, and LOW fields using numerical values. They apply to the VAL field. For each of these fields, there is a corresponding severity field which can be either NO_ALARM, MINOR, or MAJOR.

The BRSV field is where the user can set the alarm severity in case the subroutine returns a negative value. See Alarm Specification for a complete explanation of alarms and these fields. Alarm Fields lists other fields related to a alarms that are common to all record types.


FieldSummaryTypeDCTInitialAccessModifyRec Proc MonitorPP
HIHIHihi Alarm LimitFLOATYes0YesYesNoYes
HIGHHigh Alarm LimitFLOATYes0YesYesNoYes
LOWLow Alarm LimitFLOATYes0YesYesNoYes
LOLOLolo Alarm LimitFLOATYes0YesYesNoYes
HHSVHihi Alarm SeverityGBLCHOICEYes0YesYesNoYes
HSVHigh Alarm SeverityGBLCHOICEYes0YesYesNoYes
LSVLow Alarm SeverityGBLCHOICEYes0YesYesNoYes
LLSVLolo Alarm SeverityGBLCHOICEYes0YesYesNoYes
BRSVSeverity for a subroutine return value less than 0.GBLCHOICEYes0YesYesNoYes
HYSTAlarm DeadbandDOUBLEYes0YesYesNoNo


Monitor Parameters

These parameters are used to determine when to send monitors placed on the VAL field. The appropriate monitors are invoked when VAL differs from the values in the ALST and MLST run-time fields, i.e., when the value of VAL changes by more than the deadband specified in these fields. The ADEL and MDEL fields specify a minimum delta which the change must surpass before the value-change monitors are invoked. If these fields have a value of zero, everytime the value changes, a monitor will be triggered; if they have a value of -1, everytime the record is processed, monitors are triggered. The ADEL field is used by archive monitors and the MDEL field for all other types of monitors. See Monitor Specification for a complete explanation of monitors and deadbands.


FieldSummaryTypeDCTInitialAccessModifyRec Proc MonitorPP
ADELArchive DeadbandDOUBLEYes0YesYesNoNo
MDELMonitor, i.e. value change, DeadbandDOUBLEYes0YesYesNoNo


Run-time Parameters

These parameters are used by the run-time code for processing the subroutine record. They are not configured using a database configuration tool. They represent the current state of the record. Many of them are used by the record processing routines or the monitors.

VAL should be set by the subroutine. SADR holds the subroutine address and is set by the record processing routine. STYP, the subroutine symbol type, is also set by the record processing routine.

The rest of these fields--LALM, ALST, MLST, and the LA-LL fields--are used to implement the monitors. For example, when LA is not equal to A, the value-change monitors are called for that field.


FieldSummaryTypeDCTInitialAccessModifyRec Proc MonitorPP
VALValue FieldDOUBLENo0YesYesYesYes
SADRSubroutine Address NOACCESSNo0NoNoNo 
STYPSubroutine Symbol TypeSHORTNo0YesNoNoNo
LALMLast Alarm Monitor Trigger ValueDOUBLENo0YesNoNoNo
ALSTLast Archiver Monitor Trigger ValueDOUBLENo0YesNoNoNo
MLSTLast Value Change Monitor Trigger ValueDOUBLENo0YesNoNoNo
LALast A ValueDOUBLENo0YesNoNoNo
LBLast B ValueDOUBLENo0YesNoNoNo
LCLast C ValueDOUBLENo0YesNoNoNo
LDLast D ValueDOUBLENo0YesNoNoNo
LELast E ValueDOUBLENo0YesNoNoNo
LFLast F ValueDOUBLENo0YesNoNoNo
LGLast G ValueDOUBLENo0YesNoNoNo
LHLast H ValueDOUBLENo0YesNoNoNo
LILast I ValueDOUBLENo0YesNoNoNo
LJLast J ValueDOUBLENo0YesNoNoNo
LKLast K ValueDOUBLENo0YesNoNoNo
LLLast L ValueDOUBLENo0YesNoNoNo


Record Support

Record Support Routines

init_record

For each constant input link, the corresponding value field is initialized with the constant value. For each input link that is of type PV_LINK, a channel access link is created.

If an initialization subroutine is defined, it is located and called.

The processing subroutine is located and its address and type stored in SADR and STYP.

process

See next section.

get_value

Fills in the values of struct valueDes so that they refer to VAL.

get_units

Retrieves EGU.

get_precision

Retrieves PREC when VAL is the field being referenced. Otherwise, calls recGblGetPrec().

get_graphic_double

Sets the upper display and lower display limits for a field. If the field is VAL, A-L, LA-LL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR, else if the field has upper and lower limits defined they will be used, else the upper and lower maximum values for the field type will be used.

get_control_double

Sets the upper control and the lower control limits for a field. If the field is VAL, A-L, LA-LL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR, else if the field has upper and lower limits defined they will be used, else the upper and lower maximum values for the field type will be used.

get_alarm_double

Sets the following values:

upper_alarm_limit = HIHI
upper_warning_limit = HIGH
lower_warning_limit = LOW
lower_alarm_limit = LOLO


Record Processing

Routine process implements the following algorithm:

  1. If PACT is FALSE then fetch all arguments.
  2. Call the subroutine and check return value.
    • Call subroutine
    • Set PACT TRUE
    • If return value is 1, return
  3. Check alarms. This routine checks to see if the new VAL causes the alarm status and severity to change. If so, NSEV, NSTA and LALM are set. It also honors the alarm hysteresis factor (HYST). Thus the value must change by more than HYST before the alarm status and severity is lowered.
  4. Check to see if monitors should be invoked.
    • Alarm monitors are invoked if the alarm status or severity has changed.
    • Archive and value change monitors are invoked if ADEL and MDEL conditions are met.
    • Monitors for A-L are invoked if value has changed.
    • NSEV and NSTA are reset to 0.
  5. Scan forward link if necessary, set PACT FALSE, and return.

Example Synchronous Subroutine

This is an example subroutine that merely increments VAL each time process is called.

#include <vxWorks.h>
#include <types.h>
#include <stdioLib.h>
#include <dbDefs.h>
#include <subRecord.h>
#include <dbCommon.h>
#include <recSup.h>

long subInit(struct subRecord *psub)
{
    printf("subInit was called\n");
    return(0);
}

long subProcess(struct subRecord *psub)
{
    psub->val++;
    return(0);
}

Example Asynchronous Subroutine

This example shows an asynchronous subroutine. It uses (actually misuses) fields A and B. Field A is taken as the number of seconds until asynchronous completion. Field B is a flag to decide if messages should be printed. Lets assume A > 0 and B = 1. The following sequence of actions will occcur:


  1. subProcess is called with pact FALSE. It performs the following steps.
    • Computes, from A, the number of ticks until asynchronous completion should occur.
    • Prints a message stating that it is requesting an asynchronous callback.
    • Calls the vxWorks watchdog start routine.
    • Sets pact TRUE and returns a value of 0. This tells record support to complete without checking alarms, monitors, or the forward link.
  2. When the time expires, the system wide callback task calls myCallback. myCallback locks the record, calls process, and unlocks the record.
  3. Process again calls subProcess, but now pact is TRUE. Thus the following is done:
    • VAL is incremented.
    • A completion message is printed.
    • subProcess returns 0. The record processing routine will complete record processing.
#include   <vxWorks.h>
#include   <types.h>
#include   <stdioLib.h>
#include   <wdLib.h>
#include   <callback.h>
#include   <dbDefs.h>
#include   <dbAccess.h>
#include   <subRecord.h>

/* control block for callback*/
struct callback {
    CALLBACK   callback;
    struct dbCommon *precord;
    WDOG_ID wd_id;
};

void myCallback(struct callback *pcallback)
{
    struct dbCommon *precord=pcallback->precord;
    struct rset  *prset=(struct rset *)(precord->rset);
    dbScanLock(precord);
    (*prset->process)(precord);
    dbScanUnlock(precord);
}

long subInit(struct subRecord *psub)
{
    struct callback *pcallback;
    pcallback = (struct callback *)(calloc(1,sizeof(struct callback)));
    psub->dpvt = (void *)pcallback;
    callbackSetCallback(myCallback,pcallback);
    pcallback->precord = (struct dbCommon *)psub;
    pcallback->wd_id = wdCreate();
    printf("subInit was called\n");
    return 0;
}

long subProcess(struct subRecord *psub)
{
    struct callback *pcallback=(struct callback *)(psub->dpvt);
    /* sub.inp must be a CONSTANT*/
    if (psub->pact) {
        psub->val++;
        if (psub->b)
        printf("%s subProcess Completed\n", psub->name);
        return 0;
    } else {
        int wait_time = (long)(psub->a * vxTicksPerSecond);
        if (wait_time <= 0){
            if (psub->b)
                printf("%s subProcess sync processing\n", psub->name);
            psub->pact = TRUE;
            return 0;
        }
        if (psub->b){
            callbackSetPriority(psub->prio, pcallback);
            printf("%s Starting async processing\n", psub->name);
            wdStart(pcallback->wd_id, wait_time, callbackRequest, (int)pcallback);
            return 1;
        }
    }
    return 0;
}




EPICS Record Reference Manual - 19 MAY 1998