Table of Contents Previous Chapter Chapter 37: sub - Subroutine

Chapter 37: sub - Subroutine

1. Introduction

The sub record provides a subroutine escape mechanism.

2. Field Summary

--------------------------------------------------------------
Field  Type       DCT  Initial  Access  Modify  Rec Proc   PP   
                                                Monitor         
--------------------------------------------------------------
VAL    DOUBLE     No   0        Yes     Yes     Yes        Yes  
INAM   STRING     Yes  Null     Yes     No                 No   
SNAM   STRING     Yes  Null     Yes     No                 No   
SADR   NOACCESS   No   0        No      No                 No   
STYP   SHORT      No   0        Yes     No      No         No   
INPA   INLINK     Yes  0        No      No      N/A        No   
INPB   INLINK     Yes  0        No      No      N/A        No   
INPC   INLINK     Yes  0        No      No      N/A        No   
INPD   INLINK     Yes  0        No      No      N/A        No   
INPE   INLINK     Yes  0        No      No      N/A        No   
INPF   INLINK     Yes  0        No      No      N/A        No   
INPG   INLINK     Yes  0        No      No      N/A        No   
INPH   INLINK     Yes  0        No      No      N/A        No   
INPI   INLINK     Yes  0        No      No      N/A        No   
INPJ   INLINK     Yes  0        No      No      N/A        No   
INPK   INLINK     Yes  0        No      No      N/A        No   
INPL   INLINK     Yes  0        No      No      N/A        No   
A      DOUBLE     No   0        Yes     Yes/No  Yes        Yes  
B      DOUBLE     No   0        Yes     Yes/No  Yes        Yes  
C      DOUBLE     No   0        Yes     Yes/No  Yes        Yes  
D      DOUBLE     No   0        Yes     Yes/No  Yes        Yes  
E      DOUBLE     No   0        Yes     Yes/No  Yes        Yes  
F      DOUBLE     No   0        Yes     Yes/No  Yes        Yes  
G      DOUBLE     No   0        Yes     Yes/No  Yes        Yes  
H      DOUBLE     No   0        Yes     Yes/No  Yes        Yes  
I      DOUBLE     No   0        Yes     Yes/No  Yes        Yes  
J      DOUBLE     No   0        Yes     Yes/No  Yes        Yes  
K      DOUBLE     No   0        Yes     Yes/No  Yes        Yes  
L      DOUBLE     No   0        Yes     Yes/No  Yes        Yes  
LA     DOUBLE     No   0        Yes     No      No         No   
LB     DOUBLE     No   0        Yes     No      No         No   
LC     DOUBLE     No   0        Yes     No      No         No   
LD     DOUBLE     No   0        Yes     No      No         No   
LE     DOUBLE     No   0        Yes     No      No         No   
LF     DOUBLE     No   0        Yes     No      No         No   
LG     DOUBLE     No   0        Yes     No      No         No   
LH     DOUBLE     No   0        Yes     No      No         No   
LI     DOUBLE     No   0        Yes     No      No         No   
LJ     DOUBLE     No   0        Yes     No      No         No   
LK     DOUBLE     No   0        Yes     No      No         No   
LL     DOUBLE     No   0        Yes     No      No         No   
PREC   SHORT      Yes  0        Yes     Yes     No         No   
EGU    STRING     Yes  Null     Yes     Yes     No         No   
HOPR   FLOAT      Yes  0        Yes     Yes     No         No   
LOPR   FLOAT      Yes  0        Yes     Yes     No         No   
HIHI   FLOAT      Yes  0        Yes     Yes     No         Yes  
LOLO   FLOAT      Yes  0        Yes     Yes     No         Yes  
HIGH   FLOAT      Yes  0        Yes     Yes     No         Yes  
LOW    FLOAT      Yes  0        Yes     Yes     No         Yes  
BRSV   GBLCHOICE  Yes  0        Yes     Yes     No         Yes  
HHSV   GBLCHOICE  Yes  0        Yes     Yes     No         Yes  
LLSV   GBLCHOICE  Yes  0        Yes     Yes     No         Yes  
HSV    GBLCHOICE  Yes  0        Yes     Yes     No         Yes  
LSV    GBLCHOICE  Yes  0        Yes     Yes     No         Yes  
HYST   DOUBLE     Yes  0        Yes     Yes     No         No   
ADEL   DOUBLE     Yes  0        Yes     Yes     No         No   
MDEL   DOUBLE     Yes  0        Yes     Yes     No         No   
LALM   DOUBLE     No   0        Yes     No      No         No   
ALST   DOUBLE     No   0        Yes     No      No         No   
MLST   DOUBLE     No   0        Yes     No      No         No   
--------------------------------------------------------------

3. Field Descriptions

-----------------------------------------------------------------------------------------------------
Name           Summary               Description                                                       
-----------------------------------------------------------------------------------------------------
VAL            Value Field           This field is determined by the subroutine as a result of         
                                     record processing.                                                
INAM           Initialization Name   This is the name of the initialization entry. It is called once   
                                     at record initialization time.                                    
SNAM           Subroutine Name       This the the name of the processing routine. It is called by      
                                     the the record processing routine.                                
SADR           Subroutine Address    Filled in by record processing.                                   
STYP           Subroutine Symbol     Filled in by record processing.                                   
               Type                                                                                    
INPA,...,INPL  Input Link A, Input   The input links.  Each may be a constant, a database link,        
               Link B, ...           or a channel access link. Any link not defined is ignored.        
A,...,L        A, B, ...             The input values  If the corresponding INP field is a             
                                     constant, this field is initialized with the constant value       
                                     but can be changed via dbPuts.                                    
LA,...,LL      Last A, Last B, ...   Previous input values  These fields are used to decide            
                                     when to trigger monitors on A,...,L.                              
PREC           Display Precision     Precision with which to display VAL.  This field is used by       
                                     record support to supply a value when get_precision               
                                     is called.                                                        
EGU            Engineering Units     ASCII string describing Engineering units.  This field is         
                                     used by record support to supply a units description string       
                                     when get_units is called.                                         
HOPR           High Operating        These fields determine the upper and lower display limits         
               Range                 for graphics displays and the upper and lower control             
                                     limits for control displays. The fields are used by record        
                                     support to honor calls to get_graphic_double or                   
                                     get_control_double.                                               
LOPR           Low Operating                                                                           
               Range                                                                                   
HIHI           Hihi Alarm Limit      These fields specify the alarm limits and severities.             
HIGH           High Alarm Limit                                                                        
LOW            Low Alarm Limit                                                                         
LOLO           Lolo Alarm Limit                                                                        
BRSV           Severity for a                                                                          
               subroutine return                                                                       
               value less than 0.                                                                      
HHSV           Severity for a Hihi                                                                     
               Alarm                                                                                   
HSV            Severity for a High                                                                     
               Alarm                                                                                   
LSV            Severity for a Low                                                                      
               Alarm                                                                                   
LLSV           Severity for a Lolo                                                                     
               Alarm                                                                                   
HYST           Alarm Deadband        These parameters specify hysteresis factors for triggering        
                                     monitor callbacks, i.e. monitors specified by calls to            
                                     caAddEvent or dbAddEvent. A monitor will not be                   
                                     triggered until VAL changes by more than the specified            
                                     amount.                                                           
ADEL           Archive Deadband                                                                        
MDEL           Monitor, i.e. value                                                                     
               change, Deadband                                                                        
LALM           Last Alarm Monitor    These fields are used to implement the hysteresis factors         
               Trigger Value         for monitors.                                                     
ALST           Last  Archiver                                                                          
               Monitor Trigger                                                                         
               Value                                                                                   
MLST           Last Value Change                                                                       
               Monitor Trigger                                                                         
               Value                                                                                   
-----------------------------------------------------------------------------------------------------

4. 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.

get_graphic_double

Sets the upper display and lower display limits for a field. If the field is VAL, 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, 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

5. 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.
  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.
  5. Scan forward link if necessary, set PACT FALSE, and return.

6. Example Synchronous Subroutine

This is an example 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(psub)
    struct subRecord     *psub;
{
    printf("subInit was called\n");
    return(0);
}
long subProcess(psub)
    struct subRecord     *psub;
{
    psub->val++;
    return(0);
}

7. 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 occur:

  1. subProcess is called with pact FALSE. It performs the following steps.
    1. Computes, from A, the number of ticks until asynchronous completion should occur.
    2. Prints a message stating that it is requesting an asynchronous callback.
    3. Calls the vxWorks watchdog start routine.
    4. 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:
    1. VAL is incremented.
    2. A completion message is printed.
    3. 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(pcallback)
          struct callback *pcallback;
      {
          struct dbCommon *precord=pcallback->precord;
          struct rset  *prset=(struct rset *)(precord->rset);
          dbScanLock(precord);
          (*prset->process)(precord);
          dbScanUnlock(precord);
      }
      long subInit(psub)
          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(psub)
          struct subRecord  *psub;
      {
          struct callback *pcallback=(struct callback *)(psub->dpvt);
          int  wait_time;
          /* sub.inp must be a CONSTANT*/
        if(psub->pact) {
          psub->val++;
          if(psub->b)
            printf("%s subProcess Completed\n",psub->name);
            return(0);
        } else {
          wait_time = (long)(psub->a * vxTicksPerSecond);
          if(wait_time<=0){
            if (psub->b)
              printf("%s subProcess synchronous processing\n",psub->name);
              psub->pact = TRUE;
              return(0);
          }
          if (psub->b){
            callbackSetPriority(psub->prio,pcallback);
            printf("%s Starting asynchronous processing\n",psub->name);
            wdStart(pcallback->wd_id,wait_time,callbackRequest,(int)pcallback);
            return(1);
          }
        }
          return(0);
      }
      
 
Table of Contents Next Chapter