Difference between revisions of "RRM 3-14 Array Subroutine"
m (→init_record) |
(EFLG actually defaults to "ON CHANGE", not to "ALWAYS") |
||
(12 intermediate revisions by 4 users not shown) | |||
Line 1: | Line 1: | ||
[[RRM 3-14|EPICS Record Reference Manual]] | |||
= aSub - Array Subroutine = | = aSub - Array Subroutine = | ||
The aSub record is a variant of the 'sub' (subroutine) record with array | The aSub record is a variant of the 'sub' (subroutine) record with array or scalar | ||
input and output fields, whose types are user specifiable at database-configure time, and associated input and output links. | input and output fields, whose types are user specifiable at database-configure time, and associated input and output links. | ||
Line 11: | Line 14: | ||
Never, Always or just when any element of an array changes value. | Never, Always or just when any element of an array changes value. | ||
The VAL field holds the value returned from the routine called during record processing. | The VAL field holds the value returned from the routine called during record processing, which is a status value that controls whether the output links are used or not. | ||
== Field Summary == | == Field Summary == | ||
<table border> | <table border="1"> | ||
<th>Field<th>Type<th>DCT<th>Initial<th>Access<th>Modify<th>Rec Proc Monitor<th>PP | <th>Field<th>Type<th>DCT<th>Initial<th>Access<th>Modify<th>Rec Proc Monitor<th>PP | ||
<tr><td>VAL<td>LONG<td>No<td>0<td>Yes<td>Yes<td>Yes<td>No | <tr><td>VAL<td>LONG<td>No<td>0<td>Yes<td>Yes<td>Yes<td>No | ||
<tr><td>OVAL<td>LONG<td>No<td>0<td>Yes<td>Yes<td>No<td>No | <tr><td>OVAL<td>LONG<td>No<td>0<td>Yes<td>Yes<td>No<td>No | ||
<tr><td>LFLG<td>MENU(IGNORE, READ)<td>Yes<td>IGNORE<td>Yes<td>Yes<td>No<td>No | <tr><td>LFLG<td>MENU(IGNORE, READ)<td>Yes<td>IGNORE<td>Yes<td>Yes<td>No<td>No | ||
<tr><td>EFLG<td>MENU(NEVER, ON CHANGE, ALWAYS)<td>Yes<td> | <tr><td>EFLG<td>MENU(NEVER, ON CHANGE, ALWAYS)<td>Yes<td>ON CHANGE<td>Yes<td>Yes<td>No<td>No | ||
<tr><td>SUBL<td>INLINK<td>Yes<td>0<td>No<td>No<td>NA<td>No | <tr><td>SUBL<td>INLINK<td>Yes<td>0<td>No<td>No<td>NA<td>No | ||
<tr><td>INAM<td>STRING<td>Yes<td>Null<td>Yes<td>No<td>No<td>No | <tr><td>INAM<td>STRING<td>Yes<td>Null<td>Yes<td>No<td>No<td>No | ||
<tr><td>SNAM<td>STRING<td>Yes<td>Null<td>Yes<td>Yes<td>No<td>No | <tr><td>SNAM<td>STRING<td>Yes<td>Null<td>Yes<td>Yes<td>No<td>No | ||
<tr><td>ONAM<td>STRING<td>Yes<td>Null<td>Yes<td>No<td>No<td>No | <tr><td>ONAM<td>STRING<td>Yes<td>Null<td>Yes<td>No<td>No<td>No | ||
<tr><td> | <tr><td>SADR<td>LONG<td>No<td>0<td>Yes<td>No<td>Yes<td>No | ||
<tr><td>BRSV<td>MENU<td>Yes<td>0<td>Yes<td>Yes<td>No<td>Yes | <tr><td>BRSV<td>MENU<td>Yes<td>0<td>Yes<td>Yes<td>No<td>Yes | ||
<tr><td>PREC<td>SHORT<td>Yes<td>0<td>Yes<td>Yes<td>No<td>No | <tr><td>PREC<td>SHORT<td>Yes<td>0<td>Yes<td>Yes<td>No<td>No | ||
<tr><td><td><td><td><td><td><td><td> | |||
<tr><td>INPA<td>INLINK<td>Yes<td>0<td>No<td>No<td>NA<td>No | <tr><td>INPA<td>INLINK<td>Yes<td>0<td>No<td>No<td>NA<td>No | ||
<tr><td>INPB<td>INLINK<td>Yes<td>0<td>No<td>No<td>NA<td>No | <tr><td>INPB<td>INLINK<td>Yes<td>0<td>No<td>No<td>NA<td>No | ||
<tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | <tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | ||
<tr><td>INPU<td>INLINK<td>Yes<td>0<td>No<td>No<td>NA<td>No | <tr><td>INPU<td>INLINK<td>Yes<td>0<td>No<td>No<td>NA<td>No | ||
<tr><td><td><td><td><td><td><td><td> | |||
<tr><td>A<td>NOACCESS<td>No<td>0<td>No<td>Yes<td>No<td>No | <tr><td>A<td>NOACCESS<td>No<td>0<td>No<td>Yes<td>No<td>No | ||
<tr><td>B<td>NOACCESS<td>No<td>0<td>No<td>Yes<td>No<td>No | <tr><td>B<td>NOACCESS<td>No<td>0<td>No<td>Yes<td>No<td>No | ||
<tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | <tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | ||
<tr><td>U<td>NOACCESS<td>No<td>0<td>No<td>Yes<td>No<td>No | <tr><td>U<td>NOACCESS<td>No<td>0<td>No<td>Yes<td>No<td>No | ||
<tr><td><td><td><td><td><td><td><td> | |||
<tr><td>FTA<td>MENU<td>Yes<td>DOUBLE<td>Yes<td>No<td>No<td>No | <tr><td>FTA<td>MENU<td>Yes<td>DOUBLE<td>Yes<td>No<td>No<td>No | ||
<tr><td>FTB<td>MENU<td>Yes<td>DOUBLE<td>Yes<td>No<td>No<td>No | <tr><td>FTB<td>MENU<td>Yes<td>DOUBLE<td>Yes<td>No<td>No<td>No | ||
<tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | <tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | ||
<tr><td>FTU<td>MENU<td>Yes<td>DOUBLE<td>Yes<td>No<td>No<td>No | <tr><td>FTU<td>MENU<td>Yes<td>DOUBLE<td>Yes<td>No<td>No<td>No | ||
<tr><td><td><td><td><td><td><td><td> | |||
<tr><td>NOA<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | <tr><td>NOA<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | ||
<tr><td>NOB<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | <tr><td>NOB<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | ||
<tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | <tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | ||
<tr><td>NOU<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | <tr><td>NOU<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | ||
<tr><td><td><td><td><td><td><td><td> | |||
<tr><td>NEA<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | <tr><td>NEA<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | ||
<tr><td>NEB<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | <tr><td>NEB<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | ||
<tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | <tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | ||
<tr><td>NEU<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | <tr><td>NEU<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | ||
<tr><td> | <tr><td><td><td><td><td><td><td><td> | ||
<tr><td>OUTA<td>OUTLINK<td>Yes<td>0<td>No<td>No<td>NA<td>No | <tr><td>OUTA<td>OUTLINK<td>Yes<td>0<td>No<td>No<td>NA<td>No | ||
<tr><td>OUTB<td>OUTLINK<td>Yes<td>0<td>No<td>No<td>NA<td>No | <tr><td>OUTB<td>OUTLINK<td>Yes<td>0<td>No<td>No<td>NA<td>No | ||
<tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | <tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | ||
<tr><td>OUTU<td>OUTLINK<td>Yes<td>0<td>No<td>No<td>NA<td>No | <tr><td>OUTU<td>OUTLINK<td>Yes<td>0<td>No<td>No<td>NA<td>No | ||
<tr><td><td><td><td><td><td><td><td> | |||
<tr><td>VALA<td>NOACCESS<td>No<td>0<td>No<td>Yes<td>Yes<td>No | <tr><td>VALA<td>NOACCESS<td>No<td>0<td>No<td>Yes<td>Yes<td>No | ||
<tr><td>VALB<td>NOACCESS<td>No<td>0<td>No<td>Yes<td>Yes<td>No | <tr><td>VALB<td>NOACCESS<td>No<td>0<td>No<td>Yes<td>Yes<td>No | ||
<tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | <tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | ||
<tr><td>VALU<td>NOACCESS<td>No<td>0<td>No<td>Yes<td>Yes<td>No | <tr><td>VALU<td>NOACCESS<td>No<td>0<td>No<td>Yes<td>Yes<td>No | ||
<tr><td><td><td><td><td><td><td><td> | |||
<tr><td>OVLA<td>NOACCESS<td>No<td>0<td>No<td>No<td>No<td>No | <tr><td>OVLA<td>NOACCESS<td>No<td>0<td>No<td>No<td>No<td>No | ||
<tr><td>OVLB<td>NOACCESS<td>No<td>0<td>No<td>No<td>No<td>No | <tr><td>OVLB<td>NOACCESS<td>No<td>0<td>No<td>No<td>No<td>No | ||
<tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | <tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | ||
<tr><td>OVLU<td>NOACCESS<td>No<td>0<td>No<td>No<td>No<td>No | <tr><td>OVLU<td>NOACCESS<td>No<td>0<td>No<td>No<td>No<td>No | ||
<tr><td><td><td><td><td><td><td><td> | |||
<tr><td>FTVA<td>MENU<td>Yes<td>DOUBLE<td>Yes<td>No<td>No<td>No | <tr><td>FTVA<td>MENU<td>Yes<td>DOUBLE<td>Yes<td>No<td>No<td>No | ||
<tr><td>FTVB<td>MENU<td>Yes<td>DOUBLE<td>Yes<td>No<td>No<td>No | <tr><td>FTVB<td>MENU<td>Yes<td>DOUBLE<td>Yes<td>No<td>No<td>No | ||
<tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | <tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | ||
<tr><td>FTVU<td>MENU<td>Yes<td>DOUBLE<td>Yes<td>No<td>No<td>No | <tr><td>FTVU<td>MENU<td>Yes<td>DOUBLE<td>Yes<td>No<td>No<td>No | ||
<tr><td><td><td><td><td><td><td><td> | |||
<tr><td>NOVA<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | <tr><td>NOVA<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | ||
<tr><td>NOVB<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | <tr><td>NOVB<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | ||
<tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | <tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | ||
<tr><td>NOVU<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | <tr><td>NOVU<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | ||
<tr><td> | <tr><td><td><td><td><td><td><td><td> | ||
<tr><td> | <tr><td>NEVA<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | ||
<tr><td>NEVB<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | |||
<tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | <tr><td>...<td>...<td>...<td>...<td>...<td>...<td>...<td>... | ||
<tr><td> | <tr><td>NEVU<td>ULONG<td>Yes<td>1<td>Yes<td>No<td>No<td>No | ||
</table> | </table> | ||
== Field Descriptions == | == Field Descriptions == | ||
<table border> | <table border="1"> | ||
<th>Name<th>Summary<th>Description | <th>Name<th>Summary<th>Description | ||
<tr><td>VAL<td>Value returned from process routine<td>This field holds the value returned from the user defined | <tr><td>VAL<td>Value returned from process routine<td>This field holds the value returned from the user defined process routine, which must be zero for the output links OUTA...OUTU to be processed. | ||
process routine. | |||
<tr><td>OVAL<td>Old VAL<td>Previous VAL, used to decide when to post events. | <tr><td>OVAL<td>Old VAL<td>Previous VAL, used to decide when to post events. | ||
<tr><td>LFLG<td>Link Flag<td>Tells the record whether to read or ignore the SUBL link. If the value is READ, then the name of the subroutine to be called at process time is read from SUBL. If the value is IGNORE, the name of the subroutine is that currently held in SNAM. | |||
<tr><td>LFLG<td>Link Flag<td>Tells the record whether to read or ignore the SUBL link. If | |||
the value is READ, then the name of the subroutine to be | |||
called at process time is read from SUBL. If the value is | |||
IGNORE, the name of the subroutine is that currently held in | |||
SNAM. | |||
<tr><td>EFLG<td>Event Flag<td>Tells the record when to post events on the output fields | <tr><td>EFLG<td>Event Flag<td>Tells the record when to post change events on the output fields VALA,...,VALU. If the value is NEVER, events are never posted. If the value is ALWAYS, events are posted everytime the record processes. If the value is ON CHANGE, events are posted when any element of an array changes value. This flag controls value, log (archive) and alarm change events. | ||
VALA,...,VALU. If the value is NEVER, events are never | |||
posted. If the value is ALWAYS, events are posted everytime | |||
the record processes. If the value is ON CHANGE, events are | |||
posted when any element of an array changes value. | |||
<tr><td>SUBL<td>Subroutine Link<td>Where to get the subroutine name from. | <tr><td>SUBL<td>Subroutine Link<td>Where to get the subroutine name from. | ||
Line 111: | Line 105: | ||
at iocInit. | at iocInit. | ||
<tr><td>SNAM<td>Process Routine<td>This is the name of the routine to be called when the record | <tr><td>SNAM<td>Process Routine<td>This is the name of the routine to be called when the record processes. Note, this can be overwritten by the SUBL link, if | ||
processes. Note, this can be overwritten by the SUBL link, if | |||
LFLG is set to READ. | LFLG is set to READ. | ||
<tr><td>ONAM<td>Process Routine<td>Old process subroutine name. | <tr><td>ONAM<td>Process Routine<td>Old process subroutine name. | ||
<tr><td> | <tr><td>SADR<td>Subroutine Address <td>The address of the routine called at process time. | ||
<tr><td>BRSV<td>Severity for a subroutine return value less than 0. <td>Specifies the Alarm severity. | <tr><td>BRSV<td>Severity for a subroutine return value less than 0. <td>Specifies the Alarm severity. | ||
<tr><td>PREC<td>Display Precision <td>Specifies the number of decimal places with which to display | <tr><td>PREC<td>Display Precision <td>Specifies the number of decimal places with which to display the values of the fields VALA,...,VALU. | ||
the values of the fields VALA,...,VALU. | |||
<tr><td>INPA,..., INPU<td>Input Link A,..., Input Link U | <tr><td>INPA,..., INPU<td>Input Link A,..., Input Link U | ||
Line 133: | Line 125: | ||
<tr><td>FTA,..., FTU<td>Field Type of A Field Type of U | <tr><td>FTA,..., FTU<td>Field Type of A Field Type of U | ||
<td>Field types of the input values. These can be CHAR, | <td>Field types of the input values. These can be any of the following: | ||
"STRING","CHAR","UCHAR","SHORT","USHORT","LONG","ULONG","FLOAT","DOUBLE, "ENUM". | |||
<tr><td>NOA..., NOU<td>Max elements in A,.. Max elements in U | |||
<td>The number of elements of storage allocated for each input field. Default is 1 (scalar value). An array is specified by setting this field to greater than 1. | |||
<tr><td> | <tr><td>NEA..., NEU<td>Number of elements in A,.. Number of elements in U | ||
<td>The number of elements in each input field. | <td>The current number of elements stored in each input field. Field contains an array if this field is greater than 1. | ||
greater than 1. | |||
<tr><td>OUTA,..., OUTU<td>Output Link A,.. Output Link U | <tr><td>OUTA,..., OUTU<td>Output Link A,.. Output Link U | ||
<td>The output links on which the scalars or arrays located at | <td>The output links on which the scalars or arrays located at VALA,...,VALU are placed during record processing. | ||
VALA,...,VALU are placed during record processing. | |||
<tr><td>VALA,.., VALU<td>Output Fields | <tr><td>VALA,.., VALU<td>Output Fields | ||
Line 157: | Line 150: | ||
when to post events if EFLG is set to ON CHANGE. | when to post events if EFLG is set to ON CHANGE. | ||
<tr><td>NOVA,..., NOVU<td> | <tr><td>NOVA,..., NOVU<td>Max elements in VALA,.. Max elements in VALU | ||
<td>The number of elements | <td>The number of elements of storage allocated for each output field. Default is 1 (scalar value). An array is specified by setting this field to greater than 1. | ||
(scalar value). An array is specified by setting this field to | |||
greater than 1 | |||
<tr><td> | <tr><td>NEVA,..., NEVU<td>Number of elements in VALA,.. Number of elements in VALU | ||
<td>The current number of elements stored in each output field. Field contains an array if this field is greater than 1. | |||
</table> | </table> | ||
Line 177: | Line 164: | ||
following: | following: | ||
* Calloc sufficient space to hold the number of input scalars and/or arrays defined by | * Calloc sufficient space to hold the number of input scalars and/or arrays defined by the settings of the fields FTA-FTU and NOA-NOU. Initialize fields NE* to the values of the associated NO* field values. | ||
* Calloc sufficient space to hold the number of output scalars and/or arrays defined by the settings of the fields FTVA-FTVU and NOVA-NOVU. For the output fields, also calloc space to hold the previous value of a field. This is required when the decision is made on whether or not to post events. | * Calloc sufficient space to hold the number of output scalars and/or arrays defined by the settings of the fields FTVA-FTVU and NOVA-NOVU. For the output fields, also calloc space to hold the previous value of a field. This is required when the decision is made on whether or not to post events. | ||
Line 203: | Line 190: | ||
* If the SNAM routine set PACT to TRUE, then return. In this case, we presume the routine has arranged that process will be called at some later time for asynchronous completion. | * If the SNAM routine set PACT to TRUE, then return. In this case, we presume the routine has arranged that process will be called at some later time for asynchronous completion. | ||
* Set PACT to TRUE. | * Set PACT to TRUE. | ||
* | * If VAL is zero, write the output values using the output links. | ||
* Get the time of processing and put it into the timestamp field. | * Get the time of processing and put it into the timestamp field. | ||
* If VAL has changed, post a change-of value and log event for this field. If EFLG is set to ALWAYS, post change-of-value and log events for every output field. If EFLG is set to ON CHANGE, post change-of-value and log events for every output field which has changed. In the case of an array, an event will be posted if any single element of the array has changed. If EFLG is set to NEVER, no change-of-value or log events are posted for the output fields. | * If VAL has changed, post a change-of value and log event for this field. If EFLG is set to ALWAYS, post change-of-value and log events for every output field. If EFLG is set to ON CHANGE, post change-of-value and log events for every output field which has changed. In the case of an array, an event will be posted if any single element of the array has changed. If EFLG is set to NEVER, no change-of-value or log events are posted for the output fields. | ||
Line 211: | Line 198: | ||
Asynchronous-completion processing: | Asynchronous-completion processing: | ||
* Call the routine specified by SNAM. | * Call the routine specified by SNAM (again). | ||
* Set VAL equal to the return value from the routine specified by SNAM. | * Set VAL equal to the return value from the routine specified by SNAM. | ||
* Set PACT to TRUE. | * Set PACT to TRUE. | ||
* | * If VAL is zero, write the output values using the output links. | ||
* Get the time of processing and put it into the timestamp field. | * Get the time of processing and put it into the timestamp field. | ||
* If VAL has changed, post a change-of value and log event for this field. If EFLG is set to ALWAYS, post change-of-value and log events for every output field. If EFLG is set to ON CHANGE, post change-of-value and log events for every output field which has changed. In the case of an array, an event will be posted if any single element of the array has changed. If EFLG is set to NEVER, no change-of-value or log events are posted for the output fields. | * If VAL has changed, post a change-of value and log event for this field. If EFLG is set to ALWAYS, post change-of-value and log events for every output field. If EFLG is set to ON CHANGE, post change-of-value and log events for every output field which has changed. In the case of an array, an event will be posted if any single element of the array has changed. If EFLG is set to NEVER, no change-of-value or log events are posted for the output fields. | ||
* Process the record on the end of the forward link, if one exists. | * Process the record on the end of the forward link, if one exists. | ||
* Set PACT to FALSE. | * Set PACT to FALSE. | ||
=== get_precision === | === get_precision === | ||
Line 256: | Line 240: | ||
== Use of the aSub Record == | == Use of the aSub Record == | ||
The aSub record has input-value fields (A-U) and output-value fields (VALA-VALU), which are completely independent. The input-value fields have associated input links (INPA-INPU), and the output-value fields have associated output links (OUTA-OUTU). Both inputs and outputs have type fields (FTA-FTU, FTVA-FTVU, which default to 'DOUBLE') and number-of-element fields (NOA-NOU, NOVA-NOVU, which default to '1'). The output links OUTA-OUTU will only be processed if the subroutine returns a zero (OK) status value. | |||
=== Example database fragment === | |||
To use the A field to read an array from some other record, then, you would need a database fragment that might look something like this: | |||
record(aSub,"my_asub_record") { | |||
field(SNAM,"my_asub_routine") | |||
... | |||
field(FTA, "LONG") | |||
field(NOA, "100") | |||
field(INPA, "myWaveform_1 NPP NMS") | |||
... | |||
} | |||
If you wanted some other record to be able to write to the A field, then you would delete the input link above. If you wanted the A field to hold a scalar value, you would either delete the NOA specification, or specify it as "1". | |||
=== Example subroutine fragment === | |||
The associated subroutine code that uses the A field might look like this: | |||
static long my_asub_routine(aSubRecord *prec) { | |||
long i, *a; | |||
double sum=0; | |||
... | |||
a = (long *)prec->a; | |||
for (i=0; i<prec->noa; i++) { | |||
sum += a[i]; | |||
} | |||
... | |||
return 0; /* process output links */ | |||
} | |||
Note that the subroutine code must always handle the value fields (A-U, VALA-VALU) as arrays, even if they contain only a single element. | |||
=== Required export code === | |||
Aside from your own code, you must export and register your subroutines so the record can locate them. The simplest way is as follows: | |||
#include <registryFunction.h> | |||
#include <epicsExport.h> | |||
static long my_asub_routine(aSubRecord *prec) { | |||
... | |||
} | |||
epicsRegisterFunction(my_asub_routine); | |||
=== Required database-definition code === | |||
The .dbd file loaded by the ioc must then contain the following line, which tells the linker to include your object file in the IOC binary: | |||
function(my_asub_routine) | |||
=== Device support, writing to hardware === | |||
The aSub record does not call any device support routines. If you want to write to hardware, you might use your output fields and links to write to some other record that can write to hardware. | |||
=== Dynamically Changing the User Routine called during Record Processing === | |||
The aSub record allows the user to dynamically change which routine is called when the record processes. This can be done in two ways: | |||
The aSub record allows the user to dynamically change which routine is called | |||
when the record processes. This can be done in two ways: | |||
* The LFLG field can be set to READ so that the name of the routine is read from the SUBL link. Thus, whatever is feeding this link can change the name of the routine before the aSub record is processed. In this case, the record looks in the symbol | * The LFLG field can be set to READ so that the name of the routine is read from the SUBL link. Thus, whatever is feeding this link can change the name of the routine before the aSub record is processed. In this case, the record looks in the symbol table for the symbol name whenever the name of routine fetched from the link changes. | ||
* The LFLG field can be set to IGNORE. In this case, the routine called during record processing is that specified in the SNAM field. Under these conditions, the SNAM | * The LFLG field can be set to IGNORE. In this case, the routine called during record processing is that specified in the SNAM field. Under these conditions, the SNAM field can be changed by a Channel Access write to that field. During development when trying several versions of the routine, it is not necessary to reboot the IOC and reload the database. A new routine can be loaded with the vxWorks ld command, and Channel Access or the dbpf command used to put the name of the routine into the record's SNAM field. The record will look up the symbol name in the symbol table whenever the SNAM field gets modified. The same routine name can even be used as the vxWorks symbol lookup returns the latest version of the code to have been loaded. |
Latest revision as of 22:54, 12 March 2013
aSub - Array Subroutine
The aSub record is a variant of the 'sub' (subroutine) record with array or scalar input and output fields, whose types are user specifiable at database-configure time, and associated input and output links.
The routine to be called at process time can be changed dynamically after the database has been loaded. The name of the routine can either be fetched in over a link from another record or written directly into the SNAM field.
The user can configure the record to decide when events will be posted for the output fields. This can be: Never, Always or just when any element of an array changes value.
The VAL field holds the value returned from the routine called during record processing, which is a status value that controls whether the output links are used or not.
Field Summary
Field | Type | DCT | Initial | Access | Modify | Rec Proc Monitor | PP |
---|---|---|---|---|---|---|---|
VAL | LONG | No | 0 | Yes | Yes | Yes | No |
OVAL | LONG | No | 0 | Yes | Yes | No | No |
LFLG | MENU(IGNORE, READ) | Yes | IGNORE | Yes | Yes | No | No |
EFLG | MENU(NEVER, ON CHANGE, ALWAYS) | Yes | ON CHANGE | Yes | Yes | No | No |
SUBL | INLINK | Yes | 0 | No | No | NA | No |
INAM | STRING | Yes | Null | Yes | No | No | No |
SNAM | STRING | Yes | Null | Yes | Yes | No | No |
ONAM | STRING | Yes | Null | Yes | No | No | No |
SADR | LONG | No | 0 | Yes | No | Yes | No |
BRSV | MENU | Yes | 0 | Yes | Yes | No | Yes |
PREC | SHORT | Yes | 0 | Yes | Yes | No | No |
INPA | INLINK | Yes | 0 | No | No | NA | No |
INPB | INLINK | Yes | 0 | No | No | NA | No |
... | ... | ... | ... | ... | ... | ... | ... |
INPU | INLINK | Yes | 0 | No | No | NA | No |
A | NOACCESS | No | 0 | No | Yes | No | No |
B | NOACCESS | No | 0 | No | Yes | No | No |
... | ... | ... | ... | ... | ... | ... | ... |
U | NOACCESS | No | 0 | No | Yes | No | No |
FTA | MENU | Yes | DOUBLE | Yes | No | No | No |
FTB | MENU | Yes | DOUBLE | Yes | No | No | No |
... | ... | ... | ... | ... | ... | ... | ... |
FTU | MENU | Yes | DOUBLE | Yes | No | No | No |
NOA | ULONG | Yes | 1 | Yes | No | No | No |
NOB | ULONG | Yes | 1 | Yes | No | No | No |
... | ... | ... | ... | ... | ... | ... | ... |
NOU | ULONG | Yes | 1 | Yes | No | No | No |
NEA | ULONG | Yes | 1 | Yes | No | No | No |
NEB | ULONG | Yes | 1 | Yes | No | No | No |
... | ... | ... | ... | ... | ... | ... | ... |
NEU | ULONG | Yes | 1 | Yes | No | No | No |
OUTA | OUTLINK | Yes | 0 | No | No | NA | No |
OUTB | OUTLINK | Yes | 0 | No | No | NA | No |
... | ... | ... | ... | ... | ... | ... | ... |
OUTU | OUTLINK | Yes | 0 | No | No | NA | No |
VALA | NOACCESS | No | 0 | No | Yes | Yes | No |
VALB | NOACCESS | No | 0 | No | Yes | Yes | No |
... | ... | ... | ... | ... | ... | ... | ... |
VALU | NOACCESS | No | 0 | No | Yes | Yes | No |
OVLA | NOACCESS | No | 0 | No | No | No | No |
OVLB | NOACCESS | No | 0 | No | No | No | No |
... | ... | ... | ... | ... | ... | ... | ... |
OVLU | NOACCESS | No | 0 | No | No | No | No |
FTVA | MENU | Yes | DOUBLE | Yes | No | No | No |
FTVB | MENU | Yes | DOUBLE | Yes | No | No | No |
... | ... | ... | ... | ... | ... | ... | ... |
FTVU | MENU | Yes | DOUBLE | Yes | No | No | No |
NOVA | ULONG | Yes | 1 | Yes | No | No | No |
NOVB | ULONG | Yes | 1 | Yes | No | No | No |
... | ... | ... | ... | ... | ... | ... | ... |
NOVU | ULONG | Yes | 1 | Yes | No | No | No |
NEVA | ULONG | Yes | 1 | Yes | No | No | No |
NEVB | ULONG | Yes | 1 | Yes | No | No | No |
... | ... | ... | ... | ... | ... | ... | ... |
NEVU | ULONG | Yes | 1 | Yes | No | No | No |
Field Descriptions
Name | Summary | Description |
---|---|---|
VAL | Value returned from process routine | This field holds the value returned from the user defined process routine, which must be zero for the output links OUTA...OUTU to be processed. |
OVAL | Old VAL | Previous VAL, used to decide when to post events. |
LFLG | Link Flag | Tells the record whether to read or ignore the SUBL link. If the value is READ, then the name of the subroutine to be called at process time is read from SUBL. If the value is IGNORE, the name of the subroutine is that currently held in SNAM. |
EFLG | Event Flag | Tells the record when to post change events on the output fields VALA,...,VALU. If the value is NEVER, events are never posted. If the value is ALWAYS, events are posted everytime the record processes. If the value is ON CHANGE, events are posted when any element of an array changes value. This flag controls value, log (archive) and alarm change events. |
SUBL | Subroutine Link | Where to get the subroutine name from. |
INAM | Initialisation Routine | This is the name of the initialisation routine to be called once,
at iocInit. |
SNAM | Process Routine | This is the name of the routine to be called when the record processes. Note, this can be overwritten by the SUBL link, if
LFLG is set to READ. |
ONAM | Process Routine | Old process subroutine name. |
SADR | Subroutine Address | The address of the routine called at process time. |
BRSV | Severity for a subroutine return value less than 0. | Specifies the Alarm severity. |
PREC | Display Precision | Specifies the number of decimal places with which to display the values of the fields VALA,...,VALU. |
INPA,..., INPU | Input Link A,..., Input Link U | The input links from where the values of A,...,U are fetched
during record processing. |
A,...,U | Input Fields | The input fields which hold the scalar values or arrays fetched
in across the input links INPA,...,INPU. |
FTA,..., FTU | Field Type of A Field Type of U | Field types of the input values. These can be any of the following:
"STRING","CHAR","UCHAR","SHORT","USHORT","LONG","ULONG","FLOAT","DOUBLE, "ENUM".
|
NOA..., NOU | Max elements in A,.. Max elements in U | The number of elements of storage allocated for each input field. Default is 1 (scalar value). An array is specified by setting this field to greater than 1. |
NEA..., NEU | Number of elements in A,.. Number of elements in U | The current number of elements stored in each input field. Field contains an array if this field is greater than 1. |
OUTA,..., OUTU | Output Link A,.. Output Link U | The output links on which the scalars or arrays located at VALA,...,VALU are placed during record processing. |
VALA,.., VALU | Output Fields | The output fields which hold the scalar values or arrays
pushed out across the output links OUTA,...,OUTU. |
FTVA,..., FTVU | Field Type of VALA Field Type of VALU | Field types of the output values. These can be CHAR,
STRING, DOUBLE, LONG, etc. |
OVLA,.., OVLU | Previous Outputs | The previous values of the outputs. These are used to decide
when to post events if EFLG is set to ON CHANGE. |
NOVA,..., NOVU | Max elements in VALA,.. Max elements in VALU | The number of elements of storage allocated for each output field. Default is 1 (scalar value). An array is specified by setting this field to greater than 1. |
NEVA,..., NEVU | Number of elements in VALA,.. Number of elements in VALU | The current number of elements stored in each output field. Field contains an array if this field is greater than 1. |
Record Support Routines
init_record
This routine is called twice at iocInit. On the first call it does the following:
- Calloc sufficient space to hold the number of input scalars and/or arrays defined by the settings of the fields FTA-FTU and NOA-NOU. Initialize fields NE* to the values of the associated NO* field values.
- Calloc sufficient space to hold the number of output scalars and/or arrays defined by the settings of the fields FTVA-FTVU and NOVA-NOVU. For the output fields, also calloc space to hold the previous value of a field. This is required when the decision is made on whether or not to post events.
On the second call, it does the following:
- Initializes SUBL if it is a constant link.
- Initializes each constant input link.
- If the field INAM is set, look-up the address of the routine and call it.
- If the field LFLG is set to IGNORE and SNAM is defined, look-up the address of the process routine.
process
This routine implements the following algorithm:
- If PACT is FALSE, perform normal processing
- If PACT is TRUE, perform asynchronous-completion processing
Normal processing:
- Set PACT to TRUE.
- If the field LFLG is set to READ, get the subroutine name from the SUBL link. If the name is not NULL and it is not the same as the previous subroutine name, lookup the subroutine address. Set the old subroutine name, ONAM, equal to the current name, SNAM.
- Fetch the values from the input links.
- Set PACT to FALSE
- If all input-link fetches succeeded, call the routine specified by SNAM.
- Set VAL equal to the return value from the routine specified by SNAM.
- If the SNAM routine set PACT to TRUE, then return. In this case, we presume the routine has arranged that process will be called at some later time for asynchronous completion.
- Set PACT to TRUE.
- If VAL is zero, write the output values using the output links.
- Get the time of processing and put it into the timestamp field.
- If VAL has changed, post a change-of value and log event for this field. If EFLG is set to ALWAYS, post change-of-value and log events for every output field. If EFLG is set to ON CHANGE, post change-of-value and log events for every output field which has changed. In the case of an array, an event will be posted if any single element of the array has changed. If EFLG is set to NEVER, no change-of-value or log events are posted for the output fields.
- Process the record on the end of the forward link, if one exists.
- Set PACT to FALSE.
Asynchronous-completion processing:
- Call the routine specified by SNAM (again).
- Set VAL equal to the return value from the routine specified by SNAM.
- Set PACT to TRUE.
- If VAL is zero, write the output values using the output links.
- Get the time of processing and put it into the timestamp field.
- If VAL has changed, post a change-of value and log event for this field. If EFLG is set to ALWAYS, post change-of-value and log events for every output field. If EFLG is set to ON CHANGE, post change-of-value and log events for every output field which has changed. In the case of an array, an event will be posted if any single element of the array has changed. If EFLG is set to NEVER, no change-of-value or log events are posted for the output fields.
- Process the record on the end of the forward link, if one exists.
- Set PACT to FALSE.
get_precision
Sets the display precision to the value of PREC for any of the output fields VALA,..., VALU. This routine could be called for any of these fields.
cvt_dbaddr
The purpose of this routine is to fill in the struct dbAddr for the field of the record for which it has been called. Typically, the number of elements in the field, the field type and the size of the field will be set in this routine. For arrays, this record support routine is essential.
get_array_info
This routine returns the current number of elements and the offset of the first value for an array. For this record, the offset field is always 0.
put_array_info
This routine is called after new values have been placed in an array.
special
This routine is called whenever the SNAM field changes. It is called twice, once before the change and once after. On the first call, the routine simply returns. On the second call, after SNAM has changed, it implements the following algorithm:
- If LFLG is set to IGNORE and SNAM is not NULL, then look-up the address of the routine specified by SNAM. Set the SADR field equal to the subroutine address.
- Post change-of-value and log events for the SADR field, if this has changed.
Use of the aSub Record
The aSub record has input-value fields (A-U) and output-value fields (VALA-VALU), which are completely independent. The input-value fields have associated input links (INPA-INPU), and the output-value fields have associated output links (OUTA-OUTU). Both inputs and outputs have type fields (FTA-FTU, FTVA-FTVU, which default to 'DOUBLE') and number-of-element fields (NOA-NOU, NOVA-NOVU, which default to '1'). The output links OUTA-OUTU will only be processed if the subroutine returns a zero (OK) status value.
Example database fragment
To use the A field to read an array from some other record, then, you would need a database fragment that might look something like this:
record(aSub,"my_asub_record") { field(SNAM,"my_asub_routine") ... field(FTA, "LONG") field(NOA, "100") field(INPA, "myWaveform_1 NPP NMS") ... }
If you wanted some other record to be able to write to the A field, then you would delete the input link above. If you wanted the A field to hold a scalar value, you would either delete the NOA specification, or specify it as "1".
Example subroutine fragment
The associated subroutine code that uses the A field might look like this:
static long my_asub_routine(aSubRecord *prec) { long i, *a; double sum=0; ... a = (long *)prec->a; for (i=0; i<prec->noa; i++) { sum += a[i]; } ... return 0; /* process output links */ }
Note that the subroutine code must always handle the value fields (A-U, VALA-VALU) as arrays, even if they contain only a single element.
Required export code
Aside from your own code, you must export and register your subroutines so the record can locate them. The simplest way is as follows:
#include <registryFunction.h> #include <epicsExport.h> static long my_asub_routine(aSubRecord *prec) { ... } epicsRegisterFunction(my_asub_routine);
Required database-definition code
The .dbd file loaded by the ioc must then contain the following line, which tells the linker to include your object file in the IOC binary:
function(my_asub_routine)
Device support, writing to hardware
The aSub record does not call any device support routines. If you want to write to hardware, you might use your output fields and links to write to some other record that can write to hardware.
Dynamically Changing the User Routine called during Record Processing
The aSub record allows the user to dynamically change which routine is called when the record processes. This can be done in two ways:
- The LFLG field can be set to READ so that the name of the routine is read from the SUBL link. Thus, whatever is feeding this link can change the name of the routine before the aSub record is processed. In this case, the record looks in the symbol table for the symbol name whenever the name of routine fetched from the link changes.
- The LFLG field can be set to IGNORE. In this case, the routine called during record processing is that specified in the SNAM field. Under these conditions, the SNAM field can be changed by a Channel Access write to that field. During development when trying several versions of the routine, it is not necessary to reboot the IOC and reload the database. A new routine can be loaded with the vxWorks ld command, and Channel Access or the dbpf command used to put the name of the routine into the record's SNAM field. The record will look up the symbol name in the symbol table whenever the SNAM field gets modified. The same routine name can even be used as the vxWorks symbol lookup returns the latest version of the code to have been loaded.