<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki-ext.aps.anl.gov/epics/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=EricNorum</id>
	<title>EPICSWIKI - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki-ext.aps.anl.gov/epics/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=EricNorum"/>
	<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Special:Contributions/EricNorum"/>
	<updated>2026-06-03T22:48:20Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.36.1</generator>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=RRM_3-14_Common&amp;diff=3714</id>
		<title>RRM 3-14 Common</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=RRM_3-14_Common&amp;diff=3714"/>
		<updated>2013-02-28T19:33:28Z</updated>

		<summary type="html">&lt;p&gt;EricNorum: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[RRM 3-14|EPICS Record Reference Manual]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Fields Common to Many Record Types ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
This chapter describes input and output fields that are common to multiple record types. These fields have the same meaning whenever they are used.&lt;br /&gt;
&lt;br /&gt;
=== Input Records ===&lt;br /&gt;
&lt;br /&gt;
==== Common Fields ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;TH&amp;gt;Name&amp;lt;TH&amp;gt;Summary&amp;lt;TH&amp;gt;Description&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;INP&amp;lt;TD&amp;gt;Input Link&amp;lt;TD&amp;gt;This field is used by the device support routines to obtain input. For soft analog records it can be a constant, a database link, or a channel access link.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;DTYP&amp;lt;TD&amp;gt;Device Type&amp;lt;TD&amp;gt;DTYP specifies the name of the device support module that will input values.  Each record type has its own set of device support routines.  If a record type does not have any associated device support, DTYP is meaningless.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;RVAL&amp;lt;TD&amp;gt;Raw Value&amp;lt;TD&amp;gt;Whenever possible this field contains the raw data value exactly as it is obtained from the hardware or from the associated device driver and before it undergoes any conversions. The &amp;lt;CODE&amp;gt;Soft Channel&amp;lt;/CODE&amp;gt; device support module reads values directly into VAL, bypassing this field.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;VAL&amp;lt;TD&amp;gt;Value&amp;lt;TD&amp;gt;This is the record's final value, after any needed conversions have been performed.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SIMM&amp;lt;TD&amp;gt;Simulation Mode&amp;lt;TD&amp;gt;This field has either the value YES or NO.  By setting this field to YES, the record can be switched into simulation mode of operation. While in simulation mode, input will be obtained from SIOL instead of INP.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SIML&amp;lt;TD&amp;gt;Simulation Mode Location&amp;lt;TD&amp;gt;This field can be a constant, a database link, or a channel access link.  If SIML is a database or channel access link, then SIMM is read from SIML.  If SIML is a constant link then SIMM is initialized with the constant value but can be changed via dbPuts.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SVAL&amp;lt;TD&amp;gt;Simulation Value&amp;lt;TD&amp;gt;This is the record's input value, in engineering units, when the record is switched into simulation mode, i.e. when SIMM is set to YES.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SIOL&amp;lt;TD&amp;gt;Simulation Value Location&amp;lt;TD&amp;gt;This field can be a constant, a database link, or a channel access link.  If SIOL is a database or channel access link, then SVAL is read from SIOL. If SIOL is a constant link then SVAL is initialized with the constant value but can be changed via dbPuts.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SIMS&amp;lt;TD&amp;gt;Simulation Mode Alarm Severity&amp;lt;TD&amp;gt;When this record is in simulation mode, it will be put into alarm with this severity and a status of SIMM.&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Device Input ====&lt;br /&gt;
&lt;br /&gt;
A device input routine normally returns one of the following values to its associated record support routine:&lt;br /&gt;
&lt;br /&gt;
* 0: Success and convert. The input value is in RVAL. The record support module is expected to compute VAL from RVAL.&lt;br /&gt;
* 2: Success, but don't convert. The device support module can specify this value if it does not want any conversions. It might do this for two reasons:&lt;br /&gt;
** A hardware error is detected (in this case, it should also raise an alarm condition).&lt;br /&gt;
** The device support routine reads values directly into the VAL field and then sets UDF to FALSE.&lt;br /&gt;
&lt;br /&gt;
==== Soft Input ====&lt;br /&gt;
&lt;br /&gt;
In almost all cases, two special device support modules are provided: Soft Channel and Raw Soft Channel. Both allow INP to be a constant, a database link, or a channel access link. The Soft Channel device support module reads input directly into the VAL field and specifies that no conversion of any type should be performed. Thus, it allows the record to hold values corresponding to the C data type of the VAL field. Note that for soft input, RVAL is not used. The Raw Soft Channel support module reads input into RVAL and asks that any specified conversions be performed.&lt;br /&gt;
&lt;br /&gt;
The device support read routine normally calls recGblGetLinkValue() which performs the following steps:&lt;br /&gt;
&lt;br /&gt;
* If the INP link type is CONSTANT recGblGetLinkValue() does nothing and returns with a status of zero.&lt;br /&gt;
* If the INP link type is DB_LINK, then dbGetLink() is called to obtain a new input value. If dbGetLink returns an error, a LINK_ALARM with a severity of INVALID_ALARM is raised. RecGblGetLinkValue() returns the status returned by dbGetLink().&lt;br /&gt;
* If the INP link type is CA_LINK, then dbCaGetLink() is called to obtain a new input value. If dbCaGetLink() returns an error, a LINK alarm with a severity of INVALID is raised. RecGblGetLinkValue() returns the status of dbCaGetLink().&lt;br /&gt;
&lt;br /&gt;
If the return status of recGblGetLinkValue() is zero and the INP link type is not CONSTANT, then UDF is set to FALSE. The device support read routine normally returns the status of recGblGetLinkValue.&lt;br /&gt;
&lt;br /&gt;
==== Simulation Mode ====&lt;br /&gt;
&lt;br /&gt;
An input record can be switched into simulation mode of operation by setting the value of SIMM to YES or RAW. During simulation, the record will be put into alarm with a severity of SIMS and a status of SIMM_ALARM. While in simulation mode, input values will be read from SIOL instead of INP:&lt;br /&gt;
            -- (SIMM = NO?) INP (if supported and directed by device support, -&amp;gt; RVAL -- convert -&amp;gt; VAL), (else -&amp;gt; VAL)&lt;br /&gt;
          /&lt;br /&gt;
SIML -&amp;gt; SIMM&lt;br /&gt;
          \&lt;br /&gt;
           -- (SIMM = YES?) SIOL -&amp;gt; SVAL -&amp;gt; VAL&lt;br /&gt;
            \&lt;br /&gt;
              -- (SIMM = RAW?) SIOL -&amp;gt; SVAL -&amp;gt; RVAL -- convert -&amp;gt; VAL&lt;br /&gt;
&lt;br /&gt;
A record can be switched into simulation mode of operation by setting the value of SIMM to YES. During simulation, the record will be put into alarm with a severity of SIMS and a status of SIMM_ALARM. While in simulation mode, input values, in engineering units, will be obtained from SIOL instead of INP. Also, while the record is in simulation mode, there will be no raw value conversion and no calls to device support when the record is processed.&lt;br /&gt;
&lt;br /&gt;
Normally input records contain a private readValue() routine which performs the following steps:&lt;br /&gt;
&lt;br /&gt;
* If PACT is TRUE, the device support read routine is called, status is set to its return code, and readValue returns.&lt;br /&gt;
* Call recGblGetLinkValue() to get a new value for SIMM if SIML is a DB_LINK or a CA_LINK.&lt;br /&gt;
* Check value of SIMM.&lt;br /&gt;
* If SIMM is NO, then call the device support read routine, set status to its return code, and return.&lt;br /&gt;
* If SIMM is YES, then call recGblGetLinkValue to read the input value from SIOL into SVAL. If success, then set VAL to SVAL and UDF to FALSE and set status to 2 (don't convert) if input record supports conversion. If SIMS is greater than zero, set alarm status to SIMM and severity to SIMS. Set status to the return code from recGblGetLinkValue and return.&lt;br /&gt;
* If SIMM is RAW, then call recGblGetLinkValue to read the input value from SIOL into SVAL. If success, then set RVAL to SVAL and UDF to FALSE and set status to 0 (convert) if input record supports conversion. If SIMS is greater than zero, set alarm status to SIMM and severity to SIMS. Set status to the return code from recGblGetLinkValue and return.&lt;br /&gt;
* IF SIMM is not YES, NO or RAW, a SOFT alarm with a severity of INVALID is raised, and return status is set to -1.&lt;br /&gt;
&lt;br /&gt;
=== Output Records ===&lt;br /&gt;
&lt;br /&gt;
==== Common Fields ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;TH&amp;gt;Name&amp;lt;TH&amp;gt;Summary&amp;lt;TH&amp;gt;Description&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;OUT&amp;lt;TD&amp;gt;Output Link&amp;lt;TD&amp;gt;This field is used by the device support routines to decide where to send output. For soft records, it can be a constant, a database link, or a channel access link. If the link is a constant, the result is no output.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;DTYP&amp;lt;TD&amp;gt;Device Type&amp;lt;TD&amp;gt;DTYP specifies the name of the device support module that will receive values.  Each record type has its own set of device support routines.  If a record type does not have any associated device support, DTYP is meaningless.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;VAL&amp;lt;TD&amp;gt;Value&amp;lt;TD&amp;gt;This is the desired value before any conversions to raw output have been performed.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;OVAL&amp;lt;TD&amp;gt;Output Value&amp;lt;TD&amp;gt;OVAL is used to decide when to invoke monitors. Archive and value change monitors are invoked if OVAL is not equal to VAL.  If a  record type needs to make adjustments, OVAL is used to enforce the maximum rate of change limit before converting the desired value to a raw value.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;RVAL&amp;lt;TD&amp;gt;Raw Value&amp;lt;TD&amp;gt;Whenever possible this is the actual value sent to the hardware itself or to the associated device driver.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;RBV&amp;lt;TD&amp;gt;Read Back Value&amp;lt;TD&amp;gt;Whenever possible this is the actual read back value obtained from the hardware itself or from the associated device driver.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;DOL&amp;lt;TD&amp;gt;Desired Output Location (an Input Link)&amp;lt;TD&amp;gt;DOL can be a constant, a database link, or a channel access link. There is no device support associated with DOL.  If DOL is a database or channel access link and OMSL is closed_loop, then VAL is obtained from DOL.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;OMSL&amp;lt;TD&amp;gt;Output Mode Select&amp;lt;TD&amp;gt;This field has either the value &amp;quot;supervisory&amp;quot; or &amp;quot;closed_loop&amp;quot;. DOL is used to determine VAL only if OMSL has the value &amp;quot;closed_loop&amp;quot;. By setting this field the record can be switched between supervisory and closed loop mode of operation. While in closed loop mode, the VAL field cannot be set via dbPuts.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;OIF&amp;lt;TD&amp;gt;Output Full or Incremental (analog output record only)&amp;lt;TD&amp;gt;This field, which is only used when input is obtained from DOL, determines if the value obtained from DOL is an increment to add to the current VAL or is the  actual VAL desired.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SIMM&amp;lt;TD&amp;gt;Simulation Mode&amp;lt;TD&amp;gt;This field has either the value YES or NO.  By setting this field to YES, the record can be switched into simulation mode of operation. While in simulation mode, output will be written to SIOL instead of OUT.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SIML&amp;lt;TD&amp;gt;Simulation Mode Location&amp;lt;TD&amp;gt;This field can be a constant, a database link, or a channel access link. If SIML is a database or channel access link, then SIMM is read from SIML.  If SIML is a constant link then SIMM is initialized with the constant value but can be changed via dbPuts.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SIOL&amp;lt;TD&amp;gt;Simulation Value Location&amp;lt;TD&amp;gt;This field can be a constant, a database link, or a channel access link. If SIOL is a database or channel access link, then the output value is written to SIOL. If this link is a constant, the result is no output.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SIMS&amp;lt;TD&amp;gt;Simulation Mode Alarm Severity&amp;lt;TD&amp;gt;When this record is in simulation mode, it will be put into alarm with this severity and a status of SIMM_ALARM.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;IVOA&amp;lt;TD&amp;gt;Invalid Alarm Output Action&amp;lt;TD&amp;gt;Whenever the record is put into INVALID alarm severity IVOA specifies an action. IVOA can be one of the following actions: Continue normally, Don't drive outputs, Set output equal to IVOV&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;IVOV&amp;lt;TD&amp;gt;Invalid Alarm Output Value, In Engineering Units&amp;lt;TD&amp;gt;When new severity has been set to INVALID alarm and IVOA is &amp;quot;Set output equal to IVOV&amp;quot;,  then, VAL is set to IVOV and converted to RVAL before device support is called.&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Soft Output ====&lt;br /&gt;
&lt;br /&gt;
Normally two soft output device support modules are provided Soft and Raw Soft. Both allow the output link OUT to be a constant, a database link, or a channel access link. It is normally meaningless to use constant output links. The Soft support module writes output from the value associated with OVAL or VAL (if OVAL does not exist). The Raw Soft Channel support module writes the value associated with the RVAL field after conversion has been performed.&lt;br /&gt;
&lt;br /&gt;
The device support write routine normally calls recGblPutLinkValue which performs the following steps:&lt;br /&gt;
&lt;br /&gt;
* If the OUT link type is CONSTANT recGblPutLinkValue does nothing and returns with a status of zero.&lt;br /&gt;
* If the OUT link type is DB_LINK, then dbPutLink is called to write the current value. If dbPutLink returns an error, a LINK_ALARM with a severity of INVALID_ALARM is raised. RecGblPutLinkValue returns the status of dbPutLink.&lt;br /&gt;
* If the OUT link type is CA_LINK, then dbCaPutLink is called to write the current value. If dbCaPutLink returns an error, a LINK_ALARM with a severity of INVALID_ALARM is raised. RecGblPutLinkValue returns the status of dbCaPutLink.&lt;br /&gt;
&lt;br /&gt;
The device support write routine normally returns the status of recGblPutLinkValue.&lt;br /&gt;
&lt;br /&gt;
==== Output Mode Select ====&lt;br /&gt;
&lt;br /&gt;
The fields DOL and OMSL are used to allow the output record to be part of a closed loop control algorithm. OMSL is meaningful only if DOL refers to a database or channel access link. It can have the values SUPERVISORY or CLOSED_LOOP. If the mode is SUPERVISORY, then nothing is done to VAL. If the mode is CLOSED_LOOP and the record type does not contain an OIF field, then each time the record is processed, VAL is set equal to the value obtained from the location referenced by DOL. If the mode is CLOSED_LOOP in record types with an OIF field and OIF is Full, VAL is set equal to the value obtained from the location referenced by DOL; if OIF is Incremental VAL is incremented by the value obtained from DOL.&lt;br /&gt;
&lt;br /&gt;
==== Simulation Mode ====&lt;br /&gt;
&lt;br /&gt;
An output record can be switched into simulation mode of operation by setting the value of SIMM to YES. During simulation, the record will be put into alarm with a severity of SIMS and a status of SIMM_ALARM. While in simulation mode, output values, in engineering units, will be written to SIOL instead of OUT. However, the output values are never converted.&lt;br /&gt;
Also, while the record is in simulation mode, there will be no calls to device support during record processing.&lt;br /&gt;
&lt;br /&gt;
Normally output records contain a private writeValue() routine which performs the following steps:&lt;br /&gt;
&lt;br /&gt;
* If PACT is TRUE, the device support write routine is called, status is set to its return code, and readValue returns.&lt;br /&gt;
* Call recGblGetLinkValue to get a new value for SIMM if SIML is a DB_LINK or a CA_LINK.&lt;br /&gt;
* Check value of SIMM.&lt;br /&gt;
* If SIMM is NO, then call the device support write routine, set status to its return code, and return.&lt;br /&gt;
* If SIMM is YES, then call recGblPutLinkValue to write the output value from VAL or OVAL to SIOL. Set alarm status to SIMM and severity to SIMS, if SIMS is greater than zero. Set status to the return code from recGblPutLinkValue and return.&lt;br /&gt;
* If SIMM not one of the above, a SOFT alarm with a severity of INVALID is raised, and return status is set to -1.&lt;br /&gt;
&lt;br /&gt;
==== Invalid Alarm Output Action ====&lt;br /&gt;
&lt;br /&gt;
Whenever an output record is put into INVALID alarm severity, IVOA specifies an action to take. The record support process routine for each output record contains code which performs the following steps.&lt;br /&gt;
&lt;br /&gt;
* If new severity is less than INVALID, then call writeValue:&lt;br /&gt;
* Else do the following:&lt;br /&gt;
** If IVOA is CONTINUE, then call writeValue.&lt;br /&gt;
** If IVOA is NO_OUTPUT, then do not write output.&lt;br /&gt;
** If IVOA is OUTPUT_IVOV, then set VAL to IVOV, call convert if necessary, and then call writeValue.&lt;br /&gt;
** If IVOA not one of the above, an error message is generated.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
EPICS Record Reference Manual - 19 MAY 1998&lt;/div&gt;</summary>
		<author><name>EricNorum</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=RRM_3-14_Analog_Input&amp;diff=3679</id>
		<title>RRM 3-14 Analog Input</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=RRM_3-14_Analog_Input&amp;diff=3679"/>
		<updated>2012-03-15T15:44:17Z</updated>

		<summary type="html">&lt;p&gt;EricNorum: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[RRM 3-14|EPICS Record Reference Manual]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ai - Analog Input =&lt;br /&gt;
&lt;br /&gt;
The normal use for this record type is to obtain an analog value from hardware and then convert it to engineering units. Most device support modules obtain values from hardware. The record supports alarm limits, conversion to engineering units, smoothing, and graphics and control limits.&lt;br /&gt;
&lt;br /&gt;
Two soft device modules &amp;lt;CODE&amp;gt;Soft Channel&amp;lt;/CODE&amp;gt; and &amp;lt;CODE&amp;gt;Raw Soft Channel&amp;lt;/CODE&amp;gt; are provided to obtain input via database or channel access links or via dbPutField or dbPutLink requests. The first module reads values directly into VAL. The second reads values into RVAL. These values are then converted just like raw values obtained from hardware device support modules. If soft device support with a constant INP link is chosen, then the VAL field can be modified via dbPuts.&lt;br /&gt;
&lt;br /&gt;
== Parameter Fields ==&lt;br /&gt;
&lt;br /&gt;
The fields fall into the following groups of parameters:&lt;br /&gt;
&lt;br /&gt;
* scan parameters&lt;br /&gt;
* read and convert parameters&lt;br /&gt;
* operator display parameters&lt;br /&gt;
* alarm parameters&lt;br /&gt;
* monitor parameters&lt;br /&gt;
* run-time parameters&lt;br /&gt;
&lt;br /&gt;
=== Scanning Parameters ===&lt;br /&gt;
&lt;br /&gt;
The analog input record has the standard fields for specifying under what circumstances the record will be processed. These fields are listed in [[RRM 3-14 dbCommon#Scan Fields|Scan Fields]]. In addition, [[RRM 3-14 Concepts#Scanning Specification|Scanning Specification]] explains how these fields are used. Note that I/O event scanning is only supported for those card types that interrupt.&lt;br /&gt;
&lt;br /&gt;
=== Read and Convert Parameters ===&lt;br /&gt;
&lt;br /&gt;
These parameters determine where the record gets its input and how it converts the raw signal to engineering units. For records that obtain input from devices or that use the Raw Soft Channel device support, the device support routines will return the value of this device into the RVAL field. Unless the LINR conversion field specifies NO CONVERSION, the proper conversion algorithm will be performed and the resulting value will be placed in the VAL field.&lt;br /&gt;
&lt;br /&gt;
A further explanation of these fields follows.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;TH&amp;gt;Field&amp;lt;TH&amp;gt;Summary&amp;lt;TH&amp;gt;Type&amp;lt;TH&amp;gt;DCT&amp;lt;TH&amp;gt;Initial&amp;lt;TH&amp;gt;Access&amp;lt;TH&amp;gt;Modify&lt;br /&gt;
&amp;lt;TH&amp;gt;Rec Proc Monitor&amp;lt;TH&amp;gt;PP&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;VAL&amp;lt;TD&amp;gt;Value Field&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;INP&amp;lt;TD&amp;gt;Input Link&amp;lt;TD&amp;gt;INLINK&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;N/A&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;DTYP&amp;lt;TD&amp;gt;Device Type&amp;lt;TD&amp;gt;DEVCHOICE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;LINR&amp;lt;TD&amp;gt;Type of Conversion&amp;lt;TD&amp;gt;[[RRM 3-14 Menu Choices#menuConvert|menuConvert]]&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;RVAL&amp;lt;TD&amp;gt;Raw Value&amp;lt;TD&amp;gt;LONG&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ROFF&amp;lt;TD&amp;gt;Raw Value Offset&amp;lt;TD&amp;gt;LONG&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EGUF&amp;lt;TD&amp;gt;Engineering Units Full&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EGUL&amp;lt;TD&amp;gt;Engineering Units Low&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;AOFF&amp;lt;TD&amp;gt;Adjustment Offset&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ASLO&amp;lt;TD&amp;gt;Adjustment Slope&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;1&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ESLO&amp;lt;TD&amp;gt;Slope for Linear Conversions&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;1&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EOFF&amp;lt;TD&amp;gt;Offset for Linear Conversions&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SMOO&amp;lt;TD&amp;gt;Smoothing Factor&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Input Specification ====&lt;br /&gt;
&lt;br /&gt;
As stated in the introduction to this chapter, what is entered in the INP field of the analog input record determines its run-time behavior. For an analog record that obtains its value from hardware, the address of the I/O card must appear in the INP field, and the name of the device support module must appear in the device type field (DTYP). See [[RRM 3-14 Concepts#Address Specification|Address Specification]] for information on the format of hardware addresses. Be aware that the format differs between types of cards. You can see a list of the device support modules currently supported at the user's local site by using the dbst utility in R3.13.&lt;br /&gt;
&lt;br /&gt;
The INP field can also specify a constant value, a channel access link, or a database link. When configured with a constant value, the record's VAL field is initialized with the value given to the field and the VAL field can be changed using dbPuts. See [[RRM 3-14 Concepts#Address Specification|Address Specification]] for information on database and channel access links.&lt;br /&gt;
&lt;br /&gt;
When INP is a constant, a database link, or a channel access link either one of two soft device support modules, Raw Soft Channel or Soft Channel, must be specified in DTYP field. See [[#Device Support For Soft Records|Device Support For Soft Records]] in this chapter for more on how these device support modules work.&lt;br /&gt;
&lt;br /&gt;
==== Conversion Related Fields ====&lt;br /&gt;
&lt;br /&gt;
The LINR field determines if a conversion is performed and which conversion algorithm is used to convert the raw value (RVAL). No conversions are performed if the Soft Channel device support module is used. For other records that use other device support modules, the LINR field determines what adjustments or conversions are made on the raw value. The LINR field specifies either LINEAR, NO CONVERSION, or the name of a breakpoint table, such as typeKdegC. LINEAR specifies a linear conversion; NO CONVERSION, no conversion at all; and a breakpoint table, a breakpoint conversion. Note that the EGUF, EGUL, EOFF, and ESLO fields are not used when a breakpoint table or NO CONVERSION is specified.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EGUF&amp;lt;TD rowspan=2&amp;gt;The user must calculate these fields when configuring the database for records that use LINEAR conversions. They are used by device support to calculate the values for EOFF and ESLO. See [[RRM 3-14 Concepts#Conversion Specification|Conversion Specification]] for more information on how to calculate these fields.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EGUL&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;AOFF&amp;lt;TD rowspan=2&amp;gt;These fields are adjustment parameters for the raw output values. They are applied to the raw output value after conversion from engineering units.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ASLO&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ESLO&amp;lt;TD rowspan=2&amp;gt;Computed by device support from EGUF and EGUL if LINR specifies LINEAR; the user must set these directly if LINR specifies SLOPE. Used only when LINR is LINEAR or SLOPE.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EOFF&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ROFF&amp;lt;TD&amp;gt;Deprecated. New device supports should not set this to anything other than 0. It was used to offset raw value. For backwards compatibility, it is still added to the raw value (RVAL) when value is converted.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SMOO&amp;lt;TD&amp;gt;A value between 1 and 0 specified by the user, with 0 meaning no smoothing and 1 meaning ultimate smoothing (in fact, the data value will never change). See [[RRM 3-14 Concepts#Conversion Specification|Conversion Specification]] for more information on what this field does. It is used for all records but &amp;lt;CODE&amp;gt;Soft Channel&amp;lt;/CODE&amp;gt; records.&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The record processing routine performs the following algorithm for all records except those that use the Soft Channel device support routine. Be aware that step 3 is performed only when the record specifies LINEAR:&lt;br /&gt;
&lt;br /&gt;
: 1. Val= RVAL + ROFF&lt;br /&gt;
&lt;br /&gt;
: 2. Val = Val * ASLO + AOFF&lt;br /&gt;
&lt;br /&gt;
If the conversion algorithm is LINEAR, the raw value is converted via the equation:&lt;br /&gt;
&lt;br /&gt;
: 3. val = val * ESLO + EOFF&lt;br /&gt;
&lt;br /&gt;
If the conversion is via a breakpoint table, the new value is obtained.&lt;br /&gt;
&lt;br /&gt;
The next step is to apply the following smoothing algorithm:&lt;br /&gt;
&lt;br /&gt;
: 4. if SMOO is 0 or INIT is True, VAL = val&lt;br /&gt;
&lt;br /&gt;
: 5. else VAL = val * (1 - SMOO) + Previous_value * SMOO&amp;lt;blockquote&amp;gt;This implements a first-order infinite impulse response (IIR) digital filter with z-plane pole at SMOO.  The equivalent continuous-time filter time constant &amp;amp;tau;, is&amp;lt;br/&amp;gt;&amp;amp;tau; = -T / ln(SMOO)&amp;lt;br/&amp;gt;where T is the time between record processing.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
Since VAL is now defined, the last step is to set UDF to FALSE.&lt;br /&gt;
&lt;br /&gt;
For a complete explanation on conversion parameters, see [[RRM 3-14 Concepts#Conversion Specification|Conversion Specification]]. To see how Raw Soft Channel device support uses these parameters, see [[#Device Support For Soft Records|Device Support For Soft Records]] in this chapter.&lt;br /&gt;
&lt;br /&gt;
=== Operator Display Parameters ===&lt;br /&gt;
&lt;br /&gt;
These parameters are used to present meaningful data to the operator. They display the value and other parameters of the analog input either textually or graphically. EGU is a string of up to 16 characters describing the units that the analog input measures. It is retrieved by the get_units record support routine.&lt;br /&gt;
&lt;br /&gt;
The HOPR and LOPR fields set the upper and lower display limits for the VAL, HIHI, HIGH, LOW, and LOLO fields. Both the get_graphic_double and get_control_double record support routines retrieve these fields.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
See [[RRM 3-14 dbCommon#Miscellaneous Fields|Fields Common to All Record Types]] for more on the record name (NAME) and description (DESC) fields.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;TH&amp;gt;Field&amp;lt;TH&amp;gt;Summary&amp;lt;TH&amp;gt;Type&amp;lt;TH&amp;gt;DCT&amp;lt;TH&amp;gt;Initial&amp;lt;TH&amp;gt;Access&amp;lt;TH&amp;gt;Modify&lt;br /&gt;
&amp;lt;TH&amp;gt;Rec Proc Monitor&amp;lt;TH&amp;gt;PP&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EGU&amp;lt;TD&amp;gt;Engineering Units&amp;lt;TD&amp;gt;STRING [16]&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;null&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;HOPR&amp;lt;TD&amp;gt;High Operating Range&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;LOPR&amp;lt;TD&amp;gt;Low Operating Range&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;PREC&amp;lt;TD&amp;gt;Display Precision&amp;lt;TD&amp;gt;SHORT&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;NAME&amp;lt;TD&amp;gt;Record Name&amp;lt;TD&amp;gt;STRING [29]&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;DESC&amp;lt;TD&amp;gt;Description&amp;lt;TD&amp;gt;STRING [29]&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Null&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Alarm Parameters ===&lt;br /&gt;
&lt;br /&gt;
The possible alarm state for analog inputs are the SCAN, READ, and limit alarms. The SCAN and READ alarms are called by the record or device support routines.&lt;br /&gt;
&lt;br /&gt;
The limit alarms are configured by the user in the HIHI, LOLO, HIGH, and LOW fields using numerical values. For each of these fields, there is a corresponding severity field which can be either NO_ALARM, MINOR, or MAJOR. See [[RRM 3-14 Concepts#Alarm Specification|Alarm Specification]] for a complete explanation of alarms and these fields. [[RRM 3-14 dbCommon#Alarm Fields|Alarm Fields]] lists other fields related to alarms that are common to all record types.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;TH&amp;gt;Field&amp;lt;TH&amp;gt;Summary&amp;lt;TH&amp;gt;Type&amp;lt;TH&amp;gt;DCT&amp;lt;TH&amp;gt;Initial&amp;lt;TH&amp;gt;Access&amp;lt;TH&amp;gt;Modify&lt;br /&gt;
&amp;lt;TH&amp;gt;Rec Proc Monitor&amp;lt;TH&amp;gt;PP&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;HIHI&amp;lt;TD&amp;gt;Hihi Alarm Limit&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;LOLO&amp;lt;TD&amp;gt;Lolo Alarm Limit&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;HIGH&amp;lt;TD&amp;gt;High Alarm Limit&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;LOW&amp;lt;TD&amp;gt;Low Alarm Limit&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;HHSV&amp;lt;TD&amp;gt;Hihi Alarm Severity&amp;lt;TD&amp;gt;[[RRM 3-14 Menu Choices#menuAlarmSevr|menuAlarmSevr]]&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;LLSV&amp;lt;TD&amp;gt;Lolo Alarm Severity&amp;lt;TD&amp;gt;[[RRM 3-14 Menu Choices#menuAlarmSevr|menuAlarmSevr]]&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;HSV&amp;lt;TD&amp;gt;High Alarm Severity&amp;lt;TD&amp;gt;[[RRM 3-14 Menu Choices#menuAlarmSevr|menuAlarmSevr]]&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;LSV&amp;lt;TD&amp;gt;Low Alarm Severity&amp;lt;TD&amp;gt;[[RRM 3-14 Menu Choices#menuAlarmSevr|menuAlarmSevr]]&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;HYST&amp;lt;TD&amp;gt;Alarm Deadband&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Monitor Parameters===&lt;br /&gt;
&lt;br /&gt;
These parameters are used to determine when to send monitors placed on the VAL field. The monitors are sent when the value field exceeds the last monitored field by the appropriate deadband. 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 scanned, monitors are triggered. The ADEL field is used by archive monitors and the MDEL field for all other types of monitors. See [[RRM 3-14 Concepts#Monitor Specification|Monitor Specification]] for a complete explanation of monitors.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;TH&amp;gt;Field&amp;lt;TH&amp;gt;Summary&amp;lt;TH&amp;gt;Type&amp;lt;TH&amp;gt;DCT&amp;lt;TH&amp;gt;Initial&amp;lt;TH&amp;gt;Access&amp;lt;TH&amp;gt;Modify&lt;br /&gt;
&amp;lt;TH&amp;gt;Rec Proc Monitor&amp;lt;TH&amp;gt;PP&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ADEL&amp;lt;TD&amp;gt;Archive Deadband&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;MDEL&amp;lt;TD&amp;gt;Monitor, i.e. value change, Deadband&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Run-Time Parameters and Simulation Mode Parameters ===&lt;br /&gt;
&lt;br /&gt;
These parameters are used by the run-time code for processing the analog input. They are not configurable by the user, but many can be modified after initialization. They represent the current state of the analog input. Many of them are used to process the analog input more efficiently.&lt;br /&gt;
&lt;br /&gt;
The ORAW field is used to decide if monitors should be triggered for RVAL when monitors are triggered for VAL. The LALM, MLST, and ALST fields are used to implement the hysteresis factors for monitors on the VAL field.&lt;br /&gt;
&lt;br /&gt;
The PBRK field contains a pointer to the breakpoint table specified in the LINR field (if any). The LBRK field indicates the name of the last breakpoint table used (if any).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;TH&amp;gt;Field&amp;lt;TH&amp;gt;Summary&amp;lt;TH&amp;gt;Type&amp;lt;TH&amp;gt;DCT&amp;lt;TH&amp;gt;Initial&amp;lt;TH&amp;gt;Access&amp;lt;TH&amp;gt;Modify&lt;br /&gt;
&amp;lt;TH&amp;gt;Rec Proc Monitor&amp;lt;TH&amp;gt;PP&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ORAW&amp;lt;TD&amp;gt;Old Raw Value&amp;lt;TD&amp;gt;LONG&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;LALM&amp;lt;TD&amp;gt;Last Alarm Monitor Trigger Value&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ALST&amp;lt;TD&amp;gt;Last Archiver Monitor Trigger Value&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;MLST&amp;lt;TD&amp;gt;Last Value Change Monitor Trigger Value&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;INIT&amp;lt;TD&amp;gt;Initialize&amp;lt;TD&amp;gt;SHORT&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;PBRK&amp;lt;TD&amp;gt;Address of Breakpoint Table&amp;lt;TD&amp;gt;NOACCESS&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;4&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;LBRK&amp;lt;TD&amp;gt;Last Breakpoint&amp;lt;TD&amp;gt;SHORT&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following fields are used to operate the analog input in the simulation mode. See [[RRM 3-14 Common#Simulation Mode|Fields Common to Many Record Types]] for more information on these fields.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;TH&amp;gt;Field&amp;lt;TH&amp;gt;Summary&amp;lt;TH&amp;gt;Type&amp;lt;TH&amp;gt;DCT&amp;lt;TH&amp;gt;Initial&amp;lt;TH&amp;gt;Access&amp;lt;TH&amp;gt;Modify&lt;br /&gt;
&amp;lt;TH&amp;gt;Rec Proc Monitor&amp;lt;TH&amp;gt;PP&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SIOL&amp;lt;TD&amp;gt;Simulation Value Location&amp;lt;TD&amp;gt;INLINK&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;N/A&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SVAL&amp;lt;TD&amp;gt;Simulation Value&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SIML&amp;lt;TD&amp;gt;Simulation Mode Location&amp;lt;TD&amp;gt;INLINK&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;N/A&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SIMM&amp;lt;TD&amp;gt;Simulation Mode&amp;lt;TD&amp;gt;[[RRM 3-14 Menu Choices#menuSimm|menuSimm]]&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SIMS&amp;lt;TD&amp;gt;Simulation Mode Alarm Severity&amp;lt;TD&amp;gt;[[RRM 3-14 Menu Choices#menuAlarmSevr|menuAlarmSevr]]&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Record Support ==&lt;br /&gt;
&lt;br /&gt;
=== Record Support Routines ===&lt;br /&gt;
&lt;br /&gt;
The following are the record support routines that would be of interest to an application developer. Other routines are the get_units, get_precision, get_graphic_double, and get_control_double, all of which are used for the monitor parameters.&lt;br /&gt;
&lt;br /&gt;
==== init_record ====&lt;br /&gt;
&lt;br /&gt;
This routine initializes SIMM with the value of SIML if SIML type is CONSTANT link or creates a channel access link if SIML type is PV_LINK. SVAL is likewise initialized if SIOL is CONSTANT or PV_LINK.&lt;br /&gt;
&lt;br /&gt;
This routine next checks to see that device support is available and a device support read_ai() routine is defined. If either does not exist, an error message is issued and processing is terminated.&lt;br /&gt;
&lt;br /&gt;
INIT is then set to TRUE.&lt;br /&gt;
&lt;br /&gt;
If device support includes init_record, it is called.&lt;br /&gt;
&lt;br /&gt;
==== process ====&lt;br /&gt;
&lt;br /&gt;
See next section.&lt;br /&gt;
&lt;br /&gt;
==== special ====&lt;br /&gt;
&lt;br /&gt;
The only special processing for analog input records is SPC_LINCONV, which is invoked whenever any of the fields LINR, EGUF or EGUL is changed and LINR is LINEAR.&lt;br /&gt;
&lt;br /&gt;
If the device support routine special_linconv exists, it is called.&lt;br /&gt;
&lt;br /&gt;
INIT is set TRUE. This causes PBRK, LBRK, and smoothing to be re-initialized.&lt;br /&gt;
&lt;br /&gt;
==== get_value ====&lt;br /&gt;
&lt;br /&gt;
Fills in the values of the structure valueDes so that they refer to VAL.&lt;br /&gt;
&lt;br /&gt;
==== get_alarm_double ====&lt;br /&gt;
&lt;br /&gt;
Sets the following values:&lt;br /&gt;
&lt;br /&gt;
 upper_alarm_limit = HIHI&lt;br /&gt;
 upper_warning_limit = HIGH&lt;br /&gt;
 lower_warning_limit = LOW&lt;br /&gt;
 lower_alarm_limit = LOLO&lt;br /&gt;
&lt;br /&gt;
=== Record Processing ===&lt;br /&gt;
&lt;br /&gt;
Routine process implements the following algorithm:&lt;br /&gt;
&lt;br /&gt;
# Check to see that the appropriate device support module exists. If it doesn't, an error message is issued and processing is terminated with the PACT field set to TRUE. This ensures that processes will no longer be called for this record. Thus error storms will not occur.&lt;br /&gt;
# readValue is called. See [[RRM 3-14 Common#Input Records|Input Records]] for details.&lt;br /&gt;
# If PACT has been changed to TRUE, the device support read routine has started but has not completed writing the new value. In this case, the processing routine merely returns, leaving PACT TRUE.&lt;br /&gt;
# PACT is then set to TRUE, TIME is set to tslocaltime and the return status value of readValue is checked. convert is called only if status is 0. If status is 2, then convert is not called, but status is reset to 0.&lt;br /&gt;
# Perform conversion if necessary: After conversions (if any), UDF is set to FALSE.&lt;br /&gt;
# 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.&lt;br /&gt;
# Check to see if monitors should be invoked:&lt;br /&gt;
#* Alarm monitors are invoked if the alarm status or severity has changed.&lt;br /&gt;
#* Archive and value change monitors are invoked if ADEL and MDEL conditions are met.&lt;br /&gt;
#* Monitors for RVAL are checked whenever other monitors are invoked.&lt;br /&gt;
#* NSEV and NSTA are reset to 0.&lt;br /&gt;
# Scan forward link if necessary, set PACT and INIT to FALSE, and return.&lt;br /&gt;
&lt;br /&gt;
== Device Support ==&lt;br /&gt;
&lt;br /&gt;
=== Fields Of Interest To Device Support ===&lt;br /&gt;
&lt;br /&gt;
Each analog input record must have an associated set of device support routines. The primary responsibility of the device support routines is to obtain a new raw analog input value whenever read_ai is called. The device support routines are primarily interested in the following fields:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;TH&amp;gt;Name&amp;lt;TH&amp;gt;Summary&amp;lt;TH&amp;gt;Description&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;PACT&amp;lt;TD&amp;gt;Processing Active&amp;lt;TD rowspan=5&amp;gt;See [[RRM 3-14 dbCommon|Fields Common to All Record Types]] for an explanation of these fields.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;DPVT&amp;lt;TD&amp;gt;Device Private&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;UDF&amp;lt;TD&amp;gt;VAL Undefined&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;NSEV&amp;lt;TD&amp;gt;New Alarm Severity&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;NSTA&amp;lt;TD&amp;gt;New Alarm Status&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;VAL&amp;lt;TD&amp;gt;Value&amp;lt;TD&amp;gt;This field is used by device support only if it obtains a value already converted to engineering units. See RVAL below.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;INP&amp;lt;TD&amp;gt;Input Link&amp;lt;TD&amp;gt;This field is used by the device support routines to locate its input.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EGUF&amp;lt;TD&amp;gt;Engineering Units Full&amp;lt;TD rowspan=2&amp;gt;These fields are used to calculate ESLO and EOFF. Note that these fields correspond to the high and low hardware limits.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EGUL&amp;lt;TD&amp;gt;Engineering Unit Low&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ESLO&amp;lt;TD&amp;gt;Slope&amp;lt;TD rowspan=2&amp;gt;These fields are used  for linear conversions from raw to engineering units. The device support routines must calculate these fields unless they obtain values already in engineering units.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EOFF&amp;lt;TD&amp;gt;Offset&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;RVAL&amp;lt;TD&amp;gt;Raw Value&amp;lt;TD&amp;gt;It is the responsibility of the device support routine to give this field a value. If the device support routine obtains a value already in engineering units, it should place the value in VAL and return a value of 2.&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Device Support Routines ===&lt;br /&gt;
&lt;br /&gt;
Device support consists of the following routines:&lt;br /&gt;
&lt;br /&gt;
==== report ====&lt;br /&gt;
&lt;br /&gt;
 report (FILE fp, paddr)&lt;br /&gt;
&lt;br /&gt;
Not currently used.&lt;br /&gt;
&lt;br /&gt;
==== init ====&lt;br /&gt;
&lt;br /&gt;
 init()&lt;br /&gt;
&lt;br /&gt;
This routine is called once during IOC initialization.&lt;br /&gt;
&lt;br /&gt;
==== init_record ====&lt;br /&gt;
&lt;br /&gt;
 init_record (precord)&lt;br /&gt;
&lt;br /&gt;
This routine is optional. If provided, it is called by the record support init_record routine.&lt;br /&gt;
&lt;br /&gt;
==== get_ioint_info ====&lt;br /&gt;
&lt;br /&gt;
 get_ioint_info (int cmd,struct dbCommon *precord,IOSCANPVT *ppvt)&lt;br /&gt;
&lt;br /&gt;
This routine is called by the ioEventScan system each time the record is added or deleted from an I/O event scan list. cmd has the value (0,1) if the record is being (added to, deleted from) an I/O event list. It must be provided for any device type that can use the ioEvent scanner.&lt;br /&gt;
&lt;br /&gt;
==== read_ai ====&lt;br /&gt;
&lt;br /&gt;
 read_ai(precord)&lt;br /&gt;
&lt;br /&gt;
This routine must provide a new input value. Asynchronous device support routines will return with PACT set to TRUE. If PACT is TRUE, the process routine will just return and not continue processing. When the asynchronous routine completes, it can call process which will again call read_ai.&lt;br /&gt;
&lt;br /&gt;
Because PACT is still TRUE read_ai knows that this is a request to retrieve the data obtained by the previous call. When finished, read_ai should set PACT to FALSE and return one the following values:&lt;br /&gt;
&lt;br /&gt;
: 0: Success. A new raw value is placed in RVAL. convert will be called.&lt;br /&gt;
&lt;br /&gt;
: 2: Success, but don't call convert. This is useful if read_ai obtains a value already converted to engineering units or in the event a hardware failure is detected.&lt;br /&gt;
&lt;br /&gt;
: Other: Error.&lt;br /&gt;
&lt;br /&gt;
==== special_linconv ====&lt;br /&gt;
&lt;br /&gt;
 special_linconv(precord,after)&lt;br /&gt;
&lt;br /&gt;
This routine is called whenever any of the fields LINR, EGUF, EGUL or ROFF is modified. To support linear conversion, EOFF and ESLO must be set accordingly. The record support sets EOFF to EGUL before calling this routine, which is the very common case when RAWL is zero below.&lt;br /&gt;
&lt;br /&gt;
A useful formula for calculating EOFF and ESLO is this one:&lt;br /&gt;
&lt;br /&gt;
 EOFF = (RAWF * EGUL - RAWL * EGUF) / (RAWF - RAWL)&lt;br /&gt;
 ESLO = (EGUF - EGUL) / (RAWF - RAWL)&lt;br /&gt;
&lt;br /&gt;
Here, RAWL and RAWF are the lowest resp. highest possible raw value. For instance, a 16 bit bipolar ADC might have RAWL=-0x7fff, RAWF=0x7fff.&lt;br /&gt;
&lt;br /&gt;
=== Device Support For Soft Records ===&lt;br /&gt;
&lt;br /&gt;
Two soft device support modules Soft Channel and Raw Soft Channel are provided for input records not related to actual hardware devices. The INP link type must be either CONSTANT, DB_LINK or CA_LINK.&lt;br /&gt;
&lt;br /&gt;
==== Soft Channel ====&lt;br /&gt;
&lt;br /&gt;
This module places a value directly in VAL. read_ai always returns a value of 2, which means that no conversion will ever be attempted.&lt;br /&gt;
&lt;br /&gt;
If the INP link type is constant, then the constant value is stored into VAL by init_record, and UDF is set to FALSE. If the INP link type is PV_LINK, then dbCaAddInlink is called by init_record.&lt;br /&gt;
&lt;br /&gt;
read_ai calls recGblGetLinkValue to read the current value of VAL. See [[RRM 3-14 Common#Soft Input|Soft Input]] for details.&lt;br /&gt;
&lt;br /&gt;
If the return status of recGblGetLinkValue is zero, then read_ai sets UDF to FALSE. The status of recGblGetLinkValue is returned.&lt;br /&gt;
&lt;br /&gt;
If soft support is chosen, the following fields become meaningless: LINR, EGUF, EGUL, EOFF, ESLO, ROFF, AOFF, ASLO, and SMOO. The read_ai routine always returns a value of 2 which means don't convert.&lt;br /&gt;
&lt;br /&gt;
==== Raw Soft Channel ====&lt;br /&gt;
&lt;br /&gt;
This module is like the previous except that it places its value in RVAL and read_ai returns a value of 0. Thus the record processing routine will convert the raw value in the normal way.&lt;br /&gt;
&lt;br /&gt;
If raw soft support is chosen, the fields EGUF and EGUL become meaningless. ESLO and EOFF can be set manually and will be used when LINR is LINEAR.&lt;/div&gt;</summary>
		<author><name>EricNorum</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=RRM_3-14_Analog_Input&amp;diff=3678</id>
		<title>RRM 3-14 Analog Input</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=RRM_3-14_Analog_Input&amp;diff=3678"/>
		<updated>2012-03-15T15:36:00Z</updated>

		<summary type="html">&lt;p&gt;EricNorum: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[RRM 3-14|EPICS Record Reference Manual]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ai - Analog Input =&lt;br /&gt;
&lt;br /&gt;
The normal use for this record type is to obtain an analog value from hardware and then convert it to engineering units. Most device support modules obtain values from hardware. The record supports alarm limits, conversion to engineering units, smoothing, and graphics and control limits.&lt;br /&gt;
&lt;br /&gt;
Two soft device modules &amp;lt;CODE&amp;gt;Soft Channel&amp;lt;/CODE&amp;gt; and &amp;lt;CODE&amp;gt;Raw Soft Channel&amp;lt;/CODE&amp;gt; are provided to obtain input via database or channel access links or via dbPutField or dbPutLink requests. The first module reads values directly into VAL. The second reads values into RVAL. These values are then converted just like raw values obtained from hardware device support modules. If soft device support with a constant INP link is chosen, then the VAL field can be modified via dbPuts.&lt;br /&gt;
&lt;br /&gt;
== Parameter Fields ==&lt;br /&gt;
&lt;br /&gt;
The fields fall into the following groups of parameters:&lt;br /&gt;
&lt;br /&gt;
* scan parameters&lt;br /&gt;
* read and convert parameters&lt;br /&gt;
* operator display parameters&lt;br /&gt;
* alarm parameters&lt;br /&gt;
* monitor parameters&lt;br /&gt;
* run-time parameters&lt;br /&gt;
&lt;br /&gt;
=== Scanning Parameters ===&lt;br /&gt;
&lt;br /&gt;
The analog input record has the standard fields for specifying under what circumstances the record will be processed. These fields are listed in [[RRM 3-14 dbCommon#Scan Fields|Scan Fields]]. In addition, [[RRM 3-14 Concepts#Scanning Specification|Scanning Specification]] explains how these fields are used. Note that I/O event scanning is only supported for those card types that interrupt.&lt;br /&gt;
&lt;br /&gt;
=== Read and Convert Parameters ===&lt;br /&gt;
&lt;br /&gt;
These parameters determine where the record gets its input and how it converts the raw signal to engineering units. For records that obtain input from devices or that use the Raw Soft Channel device support, the device support routines will return the value of this device into the RVAL field. Unless the LINR conversion field specifies NO CONVERSION, the proper conversion algorithm will be performed and the resulting value will be placed in the VAL field.&lt;br /&gt;
&lt;br /&gt;
A further explanation of these fields follows.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;TH&amp;gt;Field&amp;lt;TH&amp;gt;Summary&amp;lt;TH&amp;gt;Type&amp;lt;TH&amp;gt;DCT&amp;lt;TH&amp;gt;Initial&amp;lt;TH&amp;gt;Access&amp;lt;TH&amp;gt;Modify&lt;br /&gt;
&amp;lt;TH&amp;gt;Rec Proc Monitor&amp;lt;TH&amp;gt;PP&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;VAL&amp;lt;TD&amp;gt;Value Field&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;INP&amp;lt;TD&amp;gt;Input Link&amp;lt;TD&amp;gt;INLINK&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;N/A&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;DTYP&amp;lt;TD&amp;gt;Device Type&amp;lt;TD&amp;gt;DEVCHOICE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;LINR&amp;lt;TD&amp;gt;Type of Conversion&amp;lt;TD&amp;gt;[[RRM 3-14 Menu Choices#menuConvert|menuConvert]]&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;RVAL&amp;lt;TD&amp;gt;Raw Value&amp;lt;TD&amp;gt;LONG&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ROFF&amp;lt;TD&amp;gt;Raw Value Offset&amp;lt;TD&amp;gt;LONG&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EGUF&amp;lt;TD&amp;gt;Engineering Units Full&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EGUL&amp;lt;TD&amp;gt;Engineering Units Low&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;AOFF&amp;lt;TD&amp;gt;Adjustment Offset&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ASLO&amp;lt;TD&amp;gt;Adjustment Slope&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;1&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ESLO&amp;lt;TD&amp;gt;Slope for Linear Conversions&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;1&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EOFF&amp;lt;TD&amp;gt;Offset for Linear Conversions&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SMOO&amp;lt;TD&amp;gt;Smoothing Factor&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Input Specification ====&lt;br /&gt;
&lt;br /&gt;
As stated in the introduction to this chapter, what is entered in the INP field of the analog input record determines its run-time behavior. For an analog record that obtains its value from hardware, the address of the I/O card must appear in the INP field, and the name of the device support module must appear in the device type field (DTYP). See [[RRM 3-14 Concepts#Address Specification|Address Specification]] for information on the format of hardware addresses. Be aware that the format differs between types of cards. You can see a list of the device support modules currently supported at the user's local site by using the dbst utility in R3.13.&lt;br /&gt;
&lt;br /&gt;
The INP field can also specify a constant value, a channel access link, or a database link. When configured with a constant value, the record's VAL field is initialized with the value given to the field and the VAL field can be changed using dbPuts. See [[RRM 3-14 Concepts#Address Specification|Address Specification]] for information on database and channel access links.&lt;br /&gt;
&lt;br /&gt;
When INP is a constant, a database link, or a channel access link either one of two soft device support modules, Raw Soft Channel or Soft Channel, must be specified in DTYP field. See [[#Device Support For Soft Records|Device Support For Soft Records]] in this chapter for more on how these device support modules work.&lt;br /&gt;
&lt;br /&gt;
==== Conversion Related Fields ====&lt;br /&gt;
&lt;br /&gt;
The LINR field determines if a conversion is performed and which conversion algorithm is used to convert the raw value (RVAL). No conversions are performed if the Soft Channel device support module is used. For other records that use other device support modules, the LINR field determines what adjustments or conversions are made on the raw value. The LINR field specifies either LINEAR, NO CONVERSION, or the name of a breakpoint table, such as typeKdegC. LINEAR specifies a linear conversion; NO CONVERSION, no conversion at all; and a breakpoint table, a breakpoint conversion. Note that the EGUF, EGUL, EOFF, and ESLO fields are not used when a breakpoint table or NO CONVERSION is specified.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EGUF&amp;lt;TD rowspan=2&amp;gt;The user must calculate these fields when configuring the database for records that use LINEAR conversions. They are used by device support to calculate the values for EOFF and ESLO. See [[RRM 3-14 Concepts#Conversion Specification|Conversion Specification]] for more information on how to calculate these fields.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EGUL&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;AOFF&amp;lt;TD rowspan=2&amp;gt;These fields are adjustment parameters for the raw output values. They are applied to the raw output value after conversion from engineering units.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ASLO&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ESLO&amp;lt;TD rowspan=2&amp;gt;Computed by device support from EGUF and EGUL if LINR specifies LINEAR; the user must set these directly if LINR specifies SLOPE. Used only when LINR is LINEAR or SLOPE.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EOFF&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ROFF&amp;lt;TD&amp;gt;Deprecated. New device supports should not set this to anything other than 0. It was used to offset raw value. For backwards compatibility, it is still added to the raw value (RVAL) when value is converted.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SMOO&amp;lt;TD&amp;gt;A value between 1 and 0 specified by the user, with 0 meaning no smoothing and 1 meaning ultimate smoothing (in fact, the data value will never change). See [[RRM 3-14 Concepts#Conversion Specification|Conversion Specification]] for more information on what this field does. It is used for all records but &amp;lt;CODE&amp;gt;Soft Channel&amp;lt;/CODE&amp;gt; records.&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The record processing routine performs the following algorithm for all records except those that use the Soft Channel device support routine. Be aware that step 3 is performed only when the record specifies LINEAR:&lt;br /&gt;
&lt;br /&gt;
: 1. Val= RVAL + ROFF&lt;br /&gt;
&lt;br /&gt;
: 2. Val = Val * ASLO + AOFF&lt;br /&gt;
&lt;br /&gt;
If the conversion algorithm is LINEAR, the raw value is converted via the equation:&lt;br /&gt;
&lt;br /&gt;
: 3. val = val * ESLO + EOFF&lt;br /&gt;
&lt;br /&gt;
If the conversion is via a breakpoint table, the new value is obtained.&lt;br /&gt;
&lt;br /&gt;
The next step is to apply the following smoothing algorithm:&lt;br /&gt;
&lt;br /&gt;
: 4. if SMOO is 0 or INIT is True, VAL = val&lt;br /&gt;
&lt;br /&gt;
: 5. else VAL = val * (1 - SMOO) + Previous_value * SMOO&amp;lt;br/&amp;gt;This implements a first-order infinite impulse response (IIR) digital filter with z-plane pole at SMOO.  The equivalent continuous-time filter time constant is&amp;lt;br/&amp;gt;&amp;amp;tau; = -T / ln(SMOO)&amp;lt;br/&amp;gt;where T is the time between record processing.&lt;br /&gt;
Since VAL is now defined, the last step is to set UDF to FALSE.&lt;br /&gt;
&lt;br /&gt;
For a complete explanation on conversion parameters, see [[RRM 3-14 Concepts#Conversion Specification|Conversion Specification]]. To see how Raw Soft Channel device support uses these parameters, see [[#Device Support For Soft Records|Device Support For Soft Records]] in this chapter.&lt;br /&gt;
&lt;br /&gt;
=== Operator Display Parameters ===&lt;br /&gt;
&lt;br /&gt;
These parameters are used to present meaningful data to the operator. They display the value and other parameters of the analog input either textually or graphically. EGU is a string of up to 16 characters describing the units that the analog input measures. It is retrieved by the get_units record support routine.&lt;br /&gt;
&lt;br /&gt;
The HOPR and LOPR fields set the upper and lower display limits for the VAL, HIHI, HIGH, LOW, and LOLO fields. Both the get_graphic_double and get_control_double record support routines retrieve these fields.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
See [[RRM 3-14 dbCommon#Miscellaneous Fields|Fields Common to All Record Types]] for more on the record name (NAME) and description (DESC) fields.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;TH&amp;gt;Field&amp;lt;TH&amp;gt;Summary&amp;lt;TH&amp;gt;Type&amp;lt;TH&amp;gt;DCT&amp;lt;TH&amp;gt;Initial&amp;lt;TH&amp;gt;Access&amp;lt;TH&amp;gt;Modify&lt;br /&gt;
&amp;lt;TH&amp;gt;Rec Proc Monitor&amp;lt;TH&amp;gt;PP&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EGU&amp;lt;TD&amp;gt;Engineering Units&amp;lt;TD&amp;gt;STRING [16]&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;null&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;HOPR&amp;lt;TD&amp;gt;High Operating Range&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;LOPR&amp;lt;TD&amp;gt;Low Operating Range&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;PREC&amp;lt;TD&amp;gt;Display Precision&amp;lt;TD&amp;gt;SHORT&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;NAME&amp;lt;TD&amp;gt;Record Name&amp;lt;TD&amp;gt;STRING [29]&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;DESC&amp;lt;TD&amp;gt;Description&amp;lt;TD&amp;gt;STRING [29]&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Null&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Alarm Parameters ===&lt;br /&gt;
&lt;br /&gt;
The possible alarm state for analog inputs are the SCAN, READ, and limit alarms. The SCAN and READ alarms are called by the record or device support routines.&lt;br /&gt;
&lt;br /&gt;
The limit alarms are configured by the user in the HIHI, LOLO, HIGH, and LOW fields using numerical values. For each of these fields, there is a corresponding severity field which can be either NO_ALARM, MINOR, or MAJOR. See [[RRM 3-14 Concepts#Alarm Specification|Alarm Specification]] for a complete explanation of alarms and these fields. [[RRM 3-14 dbCommon#Alarm Fields|Alarm Fields]] lists other fields related to alarms that are common to all record types.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;TH&amp;gt;Field&amp;lt;TH&amp;gt;Summary&amp;lt;TH&amp;gt;Type&amp;lt;TH&amp;gt;DCT&amp;lt;TH&amp;gt;Initial&amp;lt;TH&amp;gt;Access&amp;lt;TH&amp;gt;Modify&lt;br /&gt;
&amp;lt;TH&amp;gt;Rec Proc Monitor&amp;lt;TH&amp;gt;PP&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;HIHI&amp;lt;TD&amp;gt;Hihi Alarm Limit&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;LOLO&amp;lt;TD&amp;gt;Lolo Alarm Limit&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;HIGH&amp;lt;TD&amp;gt;High Alarm Limit&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;LOW&amp;lt;TD&amp;gt;Low Alarm Limit&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;HHSV&amp;lt;TD&amp;gt;Hihi Alarm Severity&amp;lt;TD&amp;gt;[[RRM 3-14 Menu Choices#menuAlarmSevr|menuAlarmSevr]]&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;LLSV&amp;lt;TD&amp;gt;Lolo Alarm Severity&amp;lt;TD&amp;gt;[[RRM 3-14 Menu Choices#menuAlarmSevr|menuAlarmSevr]]&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;HSV&amp;lt;TD&amp;gt;High Alarm Severity&amp;lt;TD&amp;gt;[[RRM 3-14 Menu Choices#menuAlarmSevr|menuAlarmSevr]]&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;LSV&amp;lt;TD&amp;gt;Low Alarm Severity&amp;lt;TD&amp;gt;[[RRM 3-14 Menu Choices#menuAlarmSevr|menuAlarmSevr]]&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;Yes&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;HYST&amp;lt;TD&amp;gt;Alarm Deadband&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Monitor Parameters===&lt;br /&gt;
&lt;br /&gt;
These parameters are used to determine when to send monitors placed on the VAL field. The monitors are sent when the value field exceeds the last monitored field by the appropriate deadband. 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 scanned, monitors are triggered. The ADEL field is used by archive monitors and the MDEL field for all other types of monitors. See [[RRM 3-14 Concepts#Monitor Specification|Monitor Specification]] for a complete explanation of monitors.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;TH&amp;gt;Field&amp;lt;TH&amp;gt;Summary&amp;lt;TH&amp;gt;Type&amp;lt;TH&amp;gt;DCT&amp;lt;TH&amp;gt;Initial&amp;lt;TH&amp;gt;Access&amp;lt;TH&amp;gt;Modify&lt;br /&gt;
&amp;lt;TH&amp;gt;Rec Proc Monitor&amp;lt;TH&amp;gt;PP&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ADEL&amp;lt;TD&amp;gt;Archive Deadband&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;MDEL&amp;lt;TD&amp;gt;Monitor, i.e. value change, Deadband&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Run-Time Parameters and Simulation Mode Parameters ===&lt;br /&gt;
&lt;br /&gt;
These parameters are used by the run-time code for processing the analog input. They are not configurable by the user, but many can be modified after initialization. They represent the current state of the analog input. Many of them are used to process the analog input more efficiently.&lt;br /&gt;
&lt;br /&gt;
The ORAW field is used to decide if monitors should be triggered for RVAL when monitors are triggered for VAL. The LALM, MLST, and ALST fields are used to implement the hysteresis factors for monitors on the VAL field.&lt;br /&gt;
&lt;br /&gt;
The PBRK field contains a pointer to the breakpoint table specified in the LINR field (if any). The LBRK field indicates the name of the last breakpoint table used (if any).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;TH&amp;gt;Field&amp;lt;TH&amp;gt;Summary&amp;lt;TH&amp;gt;Type&amp;lt;TH&amp;gt;DCT&amp;lt;TH&amp;gt;Initial&amp;lt;TH&amp;gt;Access&amp;lt;TH&amp;gt;Modify&lt;br /&gt;
&amp;lt;TH&amp;gt;Rec Proc Monitor&amp;lt;TH&amp;gt;PP&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ORAW&amp;lt;TD&amp;gt;Old Raw Value&amp;lt;TD&amp;gt;LONG&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;LALM&amp;lt;TD&amp;gt;Last Alarm Monitor Trigger Value&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ALST&amp;lt;TD&amp;gt;Last Archiver Monitor Trigger Value&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;MLST&amp;lt;TD&amp;gt;Last Value Change Monitor Trigger Value&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;INIT&amp;lt;TD&amp;gt;Initialize&amp;lt;TD&amp;gt;SHORT&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;PBRK&amp;lt;TD&amp;gt;Address of Breakpoint Table&amp;lt;TD&amp;gt;NOACCESS&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;4&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;&amp;amp;nbsp;&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;LBRK&amp;lt;TD&amp;gt;Last Breakpoint&amp;lt;TD&amp;gt;SHORT&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following fields are used to operate the analog input in the simulation mode. See [[RRM 3-14 Common#Simulation Mode|Fields Common to Many Record Types]] for more information on these fields.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;TH&amp;gt;Field&amp;lt;TH&amp;gt;Summary&amp;lt;TH&amp;gt;Type&amp;lt;TH&amp;gt;DCT&amp;lt;TH&amp;gt;Initial&amp;lt;TH&amp;gt;Access&amp;lt;TH&amp;gt;Modify&lt;br /&gt;
&amp;lt;TH&amp;gt;Rec Proc Monitor&amp;lt;TH&amp;gt;PP&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SIOL&amp;lt;TD&amp;gt;Simulation Value Location&amp;lt;TD&amp;gt;INLINK&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;N/A&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SVAL&amp;lt;TD&amp;gt;Simulation Value&amp;lt;TD&amp;gt;DOUBLE&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SIML&amp;lt;TD&amp;gt;Simulation Mode Location&amp;lt;TD&amp;gt;INLINK&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;N/A&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SIMM&amp;lt;TD&amp;gt;Simulation Mode&amp;lt;TD&amp;gt;[[RRM 3-14 Menu Choices#menuSimm|menuSimm]]&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;SIMS&amp;lt;TD&amp;gt;Simulation Mode Alarm Severity&amp;lt;TD&amp;gt;[[RRM 3-14 Menu Choices#menuAlarmSevr|menuAlarmSevr]]&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;0&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;Yes&amp;lt;TD&amp;gt;No&amp;lt;TD&amp;gt;No&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Record Support ==&lt;br /&gt;
&lt;br /&gt;
=== Record Support Routines ===&lt;br /&gt;
&lt;br /&gt;
The following are the record support routines that would be of interest to an application developer. Other routines are the get_units, get_precision, get_graphic_double, and get_control_double, all of which are used for the monitor parameters.&lt;br /&gt;
&lt;br /&gt;
==== init_record ====&lt;br /&gt;
&lt;br /&gt;
This routine initializes SIMM with the value of SIML if SIML type is CONSTANT link or creates a channel access link if SIML type is PV_LINK. SVAL is likewise initialized if SIOL is CONSTANT or PV_LINK.&lt;br /&gt;
&lt;br /&gt;
This routine next checks to see that device support is available and a device support read_ai() routine is defined. If either does not exist, an error message is issued and processing is terminated.&lt;br /&gt;
&lt;br /&gt;
INIT is then set to TRUE.&lt;br /&gt;
&lt;br /&gt;
If device support includes init_record, it is called.&lt;br /&gt;
&lt;br /&gt;
==== process ====&lt;br /&gt;
&lt;br /&gt;
See next section.&lt;br /&gt;
&lt;br /&gt;
==== special ====&lt;br /&gt;
&lt;br /&gt;
The only special processing for analog input records is SPC_LINCONV, which is invoked whenever any of the fields LINR, EGUF or EGUL is changed and LINR is LINEAR.&lt;br /&gt;
&lt;br /&gt;
If the device support routine special_linconv exists, it is called.&lt;br /&gt;
&lt;br /&gt;
INIT is set TRUE. This causes PBRK, LBRK, and smoothing to be re-initialized.&lt;br /&gt;
&lt;br /&gt;
==== get_value ====&lt;br /&gt;
&lt;br /&gt;
Fills in the values of the structure valueDes so that they refer to VAL.&lt;br /&gt;
&lt;br /&gt;
==== get_alarm_double ====&lt;br /&gt;
&lt;br /&gt;
Sets the following values:&lt;br /&gt;
&lt;br /&gt;
 upper_alarm_limit = HIHI&lt;br /&gt;
 upper_warning_limit = HIGH&lt;br /&gt;
 lower_warning_limit = LOW&lt;br /&gt;
 lower_alarm_limit = LOLO&lt;br /&gt;
&lt;br /&gt;
=== Record Processing ===&lt;br /&gt;
&lt;br /&gt;
Routine process implements the following algorithm:&lt;br /&gt;
&lt;br /&gt;
# Check to see that the appropriate device support module exists. If it doesn't, an error message is issued and processing is terminated with the PACT field set to TRUE. This ensures that processes will no longer be called for this record. Thus error storms will not occur.&lt;br /&gt;
# readValue is called. See [[RRM 3-14 Common#Input Records|Input Records]] for details.&lt;br /&gt;
# If PACT has been changed to TRUE, the device support read routine has started but has not completed writing the new value. In this case, the processing routine merely returns, leaving PACT TRUE.&lt;br /&gt;
# PACT is then set to TRUE, TIME is set to tslocaltime and the return status value of readValue is checked. convert is called only if status is 0. If status is 2, then convert is not called, but status is reset to 0.&lt;br /&gt;
# Perform conversion if necessary: After conversions (if any), UDF is set to FALSE.&lt;br /&gt;
# 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.&lt;br /&gt;
# Check to see if monitors should be invoked:&lt;br /&gt;
#* Alarm monitors are invoked if the alarm status or severity has changed.&lt;br /&gt;
#* Archive and value change monitors are invoked if ADEL and MDEL conditions are met.&lt;br /&gt;
#* Monitors for RVAL are checked whenever other monitors are invoked.&lt;br /&gt;
#* NSEV and NSTA are reset to 0.&lt;br /&gt;
# Scan forward link if necessary, set PACT and INIT to FALSE, and return.&lt;br /&gt;
&lt;br /&gt;
== Device Support ==&lt;br /&gt;
&lt;br /&gt;
=== Fields Of Interest To Device Support ===&lt;br /&gt;
&lt;br /&gt;
Each analog input record must have an associated set of device support routines. The primary responsibility of the device support routines is to obtain a new raw analog input value whenever read_ai is called. The device support routines are primarily interested in the following fields:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;TABLE BORDER=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;TH&amp;gt;Name&amp;lt;TH&amp;gt;Summary&amp;lt;TH&amp;gt;Description&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;PACT&amp;lt;TD&amp;gt;Processing Active&amp;lt;TD rowspan=5&amp;gt;See [[RRM 3-14 dbCommon|Fields Common to All Record Types]] for an explanation of these fields.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;DPVT&amp;lt;TD&amp;gt;Device Private&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;UDF&amp;lt;TD&amp;gt;VAL Undefined&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;NSEV&amp;lt;TD&amp;gt;New Alarm Severity&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;NSTA&amp;lt;TD&amp;gt;New Alarm Status&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;VAL&amp;lt;TD&amp;gt;Value&amp;lt;TD&amp;gt;This field is used by device support only if it obtains a value already converted to engineering units. See RVAL below.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;INP&amp;lt;TD&amp;gt;Input Link&amp;lt;TD&amp;gt;This field is used by the device support routines to locate its input.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EGUF&amp;lt;TD&amp;gt;Engineering Units Full&amp;lt;TD rowspan=2&amp;gt;These fields are used to calculate ESLO and EOFF. Note that these fields correspond to the high and low hardware limits.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EGUL&amp;lt;TD&amp;gt;Engineering Unit Low&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;ESLO&amp;lt;TD&amp;gt;Slope&amp;lt;TD rowspan=2&amp;gt;These fields are used  for linear conversions from raw to engineering units. The device support routines must calculate these fields unless they obtain values already in engineering units.&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;EOFF&amp;lt;TD&amp;gt;Offset&amp;lt;TR&amp;gt;&lt;br /&gt;
&amp;lt;TD&amp;gt;RVAL&amp;lt;TD&amp;gt;Raw Value&amp;lt;TD&amp;gt;It is the responsibility of the device support routine to give this field a value. If the device support routine obtains a value already in engineering units, it should place the value in VAL and return a value of 2.&lt;br /&gt;
&amp;lt;/TABLE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Device Support Routines ===&lt;br /&gt;
&lt;br /&gt;
Device support consists of the following routines:&lt;br /&gt;
&lt;br /&gt;
==== report ====&lt;br /&gt;
&lt;br /&gt;
 report (FILE fp, paddr)&lt;br /&gt;
&lt;br /&gt;
Not currently used.&lt;br /&gt;
&lt;br /&gt;
==== init ====&lt;br /&gt;
&lt;br /&gt;
 init()&lt;br /&gt;
&lt;br /&gt;
This routine is called once during IOC initialization.&lt;br /&gt;
&lt;br /&gt;
==== init_record ====&lt;br /&gt;
&lt;br /&gt;
 init_record (precord)&lt;br /&gt;
&lt;br /&gt;
This routine is optional. If provided, it is called by the record support init_record routine.&lt;br /&gt;
&lt;br /&gt;
==== get_ioint_info ====&lt;br /&gt;
&lt;br /&gt;
 get_ioint_info (int cmd,struct dbCommon *precord,IOSCANPVT *ppvt)&lt;br /&gt;
&lt;br /&gt;
This routine is called by the ioEventScan system each time the record is added or deleted from an I/O event scan list. cmd has the value (0,1) if the record is being (added to, deleted from) an I/O event list. It must be provided for any device type that can use the ioEvent scanner.&lt;br /&gt;
&lt;br /&gt;
==== read_ai ====&lt;br /&gt;
&lt;br /&gt;
 read_ai(precord)&lt;br /&gt;
&lt;br /&gt;
This routine must provide a new input value. Asynchronous device support routines will return with PACT set to TRUE. If PACT is TRUE, the process routine will just return and not continue processing. When the asynchronous routine completes, it can call process which will again call read_ai.&lt;br /&gt;
&lt;br /&gt;
Because PACT is still TRUE read_ai knows that this is a request to retrieve the data obtained by the previous call. When finished, read_ai should set PACT to FALSE and return one the following values:&lt;br /&gt;
&lt;br /&gt;
: 0: Success. A new raw value is placed in RVAL. convert will be called.&lt;br /&gt;
&lt;br /&gt;
: 2: Success, but don't call convert. This is useful if read_ai obtains a value already converted to engineering units or in the event a hardware failure is detected.&lt;br /&gt;
&lt;br /&gt;
: Other: Error.&lt;br /&gt;
&lt;br /&gt;
==== special_linconv ====&lt;br /&gt;
&lt;br /&gt;
 special_linconv(precord,after)&lt;br /&gt;
&lt;br /&gt;
This routine is called whenever any of the fields LINR, EGUF, EGUL or ROFF is modified. To support linear conversion, EOFF and ESLO must be set accordingly. The record support sets EOFF to EGUL before calling this routine, which is the very common case when RAWL is zero below.&lt;br /&gt;
&lt;br /&gt;
A useful formula for calculating EOFF and ESLO is this one:&lt;br /&gt;
&lt;br /&gt;
 EOFF = (RAWF * EGUL - RAWL * EGUF) / (RAWF - RAWL)&lt;br /&gt;
 ESLO = (EGUF - EGUL) / (RAWF - RAWL)&lt;br /&gt;
&lt;br /&gt;
Here, RAWL and RAWF are the lowest resp. highest possible raw value. For instance, a 16 bit bipolar ADC might have RAWL=-0x7fff, RAWF=0x7fff.&lt;br /&gt;
&lt;br /&gt;
=== Device Support For Soft Records ===&lt;br /&gt;
&lt;br /&gt;
Two soft device support modules Soft Channel and Raw Soft Channel are provided for input records not related to actual hardware devices. The INP link type must be either CONSTANT, DB_LINK or CA_LINK.&lt;br /&gt;
&lt;br /&gt;
==== Soft Channel ====&lt;br /&gt;
&lt;br /&gt;
This module places a value directly in VAL. read_ai always returns a value of 2, which means that no conversion will ever be attempted.&lt;br /&gt;
&lt;br /&gt;
If the INP link type is constant, then the constant value is stored into VAL by init_record, and UDF is set to FALSE. If the INP link type is PV_LINK, then dbCaAddInlink is called by init_record.&lt;br /&gt;
&lt;br /&gt;
read_ai calls recGblGetLinkValue to read the current value of VAL. See [[RRM 3-14 Common#Soft Input|Soft Input]] for details.&lt;br /&gt;
&lt;br /&gt;
If the return status of recGblGetLinkValue is zero, then read_ai sets UDF to FALSE. The status of recGblGetLinkValue is returned.&lt;br /&gt;
&lt;br /&gt;
If soft support is chosen, the following fields become meaningless: LINR, EGUF, EGUL, EOFF, ESLO, ROFF, AOFF, ASLO, and SMOO. The read_ai routine always returns a value of 2 which means don't convert.&lt;br /&gt;
&lt;br /&gt;
==== Raw Soft Channel ====&lt;br /&gt;
&lt;br /&gt;
This module is like the previous except that it places its value in RVAL and read_ai returns a value of 0. Thus the record processing routine will convert the raw value in the normal way.&lt;br /&gt;
&lt;br /&gt;
If raw soft support is chosen, the fields EGUF and EGUL become meaningless. ESLO and EOFF can be set manually and will be used when LINR is LINEAR.&lt;/div&gt;</summary>
		<author><name>EricNorum</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=How_do_I_get_EPICS_applications_to_work_with_a_Mac_OS_X_firewall&amp;diff=2941</id>
		<title>How do I get EPICS applications to work with a Mac OS X firewall</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=How_do_I_get_EPICS_applications_to_work_with_a_Mac_OS_X_firewall&amp;diff=2941"/>
		<updated>2011-10-05T16:19:28Z</updated>

		<summary type="html">&lt;p&gt;EricNorum: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;For OS X 10.6 (Snow Leopard) and up&lt;br /&gt;
*Start the System Preferences application&lt;br /&gt;
*Select the &amp;quot;Security &amp;amp; Privacy&amp;quot; pane&lt;br /&gt;
*Select the &amp;quot;Firewall&amp;quot; tab&lt;br /&gt;
*Open the lock to allow changes&lt;br /&gt;
*Ensure that the firewall is on&lt;br /&gt;
*Click the &amp;quot;Advanced…&amp;quot; button&lt;br /&gt;
*Add your EPICS applications (e.g. caRepeater, caget, camonitor, caput, StripTool, edm, soft IOCs, etc.) to the list and set the firewall to &amp;quot;Allow incoming connections&amp;quot; to them&lt;/div&gt;</summary>
		<author><name>EricNorum</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=How_do_I_get_EPICS_applications_to_work_with_a_Mac_OS_X_firewall&amp;diff=1920</id>
		<title>How do I get EPICS applications to work with a Mac OS X firewall</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=How_do_I_get_EPICS_applications_to_work_with_a_Mac_OS_X_firewall&amp;diff=1920"/>
		<updated>2011-10-05T16:18:46Z</updated>

		<summary type="html">&lt;p&gt;EricNorum: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;For OS X 10.6 (Snow Leopard) and up&lt;br /&gt;
*Start the System Preferences application&lt;br /&gt;
*Select the &amp;quot;Security &amp;amp; Privacy&amp;quot; pane&lt;br /&gt;
*Select the &amp;quot;Firewall&amp;quot; tab&lt;br /&gt;
*Open the lock to allow changes&lt;br /&gt;
*Ensure that the firewall is on&lt;br /&gt;
*Click the 'Advanced…&amp;quot; button&lt;br /&gt;
*Add your EPICS applications (e.g. caRepeater, caget, camonitor, caput, StripTool, edm, soft IOCs, etc.) to the list and set the firewall to &amp;quot;Allow incoming connections&amp;quot; to them&lt;/div&gt;</summary>
		<author><name>EricNorum</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=How_do_I_get_EPICS_applications_to_work_with_a_Mac_OS_X_firewall%3F&amp;diff=2940</id>
		<title>How do I get EPICS applications to work with a Mac OS X firewall?</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=How_do_I_get_EPICS_applications_to_work_with_a_Mac_OS_X_firewall%3F&amp;diff=2940"/>
		<updated>2011-10-05T16:17:21Z</updated>

		<summary type="html">&lt;p&gt;EricNorum: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;These instructions apply to OS X 10.6 and higher&lt;br /&gt;
&lt;br /&gt;
* Start the System Preferences application&lt;br /&gt;
* Select the &amp;quot;Security &amp;amp; Privacy&amp;quot; pane&lt;br /&gt;
* Select the &amp;quot;Firewall&amp;quot; tab&lt;br /&gt;
* Open the lock to allow changes&lt;br /&gt;
* Ensure that the firewall is on&lt;br /&gt;
* Click the 'Advanced…&amp;quot; button&lt;br /&gt;
* Add your EPICS applications (e.g. caRepeater, caget, camonitor, caput, StripTool, edm, soft IOCs, etc.) to the list and set the firewall to &amp;quot;Allow incoming connections&amp;quot; to them&lt;/div&gt;</summary>
		<author><name>EricNorum</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=HowTo_Documents&amp;diff=2677</id>
		<title>HowTo Documents</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=HowTo_Documents&amp;diff=2677"/>
		<updated>2011-10-05T16:14:24Z</updated>

		<summary type="html">&lt;p&gt;EricNorum: /* Applications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a directory of various How-To documents written by members of the EPICS collaboration.  Contributions to this page are most welcome!&lt;br /&gt;
&lt;br /&gt;
=== EPICS Base on Different Architectures and Operating Systems ===&lt;br /&gt;
&lt;br /&gt;
* [http://www.aps.anl.gov/epics/base/RTEMS/tutorial/ Getting Started with EPICS on RTEMS]&lt;br /&gt;
* [[HowToPC104|Getting Started with R3.14.7 on a PC104 running Linux]]&lt;br /&gt;
* [[How To Port EPICS to a new OS/Architecture]]&lt;br /&gt;
* [[How To Use Posix Thread Priority Scheduling under Linux]]&lt;br /&gt;
&lt;br /&gt;
=== Drivers and Device Support ===&lt;br /&gt;
&lt;br /&gt;
* [http://www.aps.anl.gov/epics/modules/soft/asyn/HowToDoSerial_StreamDevice.html How To Do Serial (using Asyn Driver and StreamDevice)]&lt;br /&gt;
* [http://www.aps.anl.gov/epics/modules/soft/asyn/R4-15/HowToDoSerial/tutorial.pdf How To Do Serial (using Asyn Driver and devGPIB)]&lt;br /&gt;
* [http://www.aps.anl.gov/epics/modules/soft/asyn/BeginnerGuideToASYN-VXI11.pdf Beginners Guide to using VXI-11 (with Asyn Driver)]&lt;br /&gt;
* [[How to make your EPICS driver operating system independent]]&lt;br /&gt;
* [[How To Write Device Support that uses Asyn Driver]] ''(Incomplete!)''&lt;br /&gt;
* [[How to use GPIB ports with linux-gpib and StreamDevice]]&lt;br /&gt;
&lt;br /&gt;
=== Applications ===&lt;br /&gt;
&lt;br /&gt;
* [[Common Database patterns]]&lt;br /&gt;
* [[How To Install Channel Archiver On Scientific Linux]]&lt;br /&gt;
* [[What PV Save and Restore Tools are available]]&lt;br /&gt;
* [[How to Add a New Breakpoint Table]]&lt;br /&gt;
* [[&amp;quot;Best Practice&amp;quot; Guidelines]]&lt;br /&gt;
* [[How do I get EPICS applications to work with a Mac OS X firewall?]]&lt;br /&gt;
&lt;br /&gt;
=== Infrastructure and Other Stuff ===&lt;br /&gt;
&lt;br /&gt;
* [[How To Set Up a Linux Box as an IOC Boot Server]]&lt;br /&gt;
* [[How To Set Up a Mirror of the EPICS Web Site]]&lt;br /&gt;
* [[How to Set Up a Soft IOC Framework on Linux]]&lt;br /&gt;
* [[How to Set Up Console Access and Logging for VME and Soft IOCs]]&lt;br /&gt;
* [[How to Set Up NAL (Nagios Alarm Handler) to monitor an EPICS network]]&lt;br /&gt;
&lt;br /&gt;
=== Collaboration Stuff ===&lt;br /&gt;
&lt;br /&gt;
* [[How to run an EPICS Collaboration Meeting]]&lt;/div&gt;</summary>
		<author><name>EricNorum</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=%22Best_Practice%22_Guidelines&amp;diff=2938</id>
		<title>&quot;Best Practice&quot; Guidelines</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=%22Best_Practice%22_Guidelines&amp;diff=2938"/>
		<updated>2011-08-24T22:59:44Z</updated>

		<summary type="html">&lt;p&gt;EricNorum: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== &amp;quot;Best Practice&amp;quot; Guidelines for Developers ==&lt;br /&gt;
This document presents some guidelines that have been found useful.  Please add your own suggestions!&lt;br /&gt;
&lt;br /&gt;
=== Support Modules ===&lt;br /&gt;
* If your IOC application source directory contains '.c' files you should '''definitely''' consider moving them to a support module (either existing or new). A big problem in the past has been the proliferation of similar or identical '.c' files among multiple IOC applications. Help stamp out this practice now! To a lesser degree you should consider doing the same for any sequence programs in your application although these tend to be much more application-specific and thus impractical to move to a support module.&lt;br /&gt;
* Use &amp;lt;tt&amp;gt;/''path_to_base_bin''/makeBaseApp.pl -t support&amp;lt;/tt&amp;gt; to create a new support module. If you're writing a new message-based instrument support module &amp;lt;tt&amp;gt;/''path_to_asyn_bin''/makeSupport.pl -t streamSCPI&amp;lt;/tt&amp;gt; is a good place to start.&lt;br /&gt;
* Nothing within the support 'modules' directory tree should be an 'App'. Nothing within the 'ioc' applications directory tree should be anything but an 'App'.&lt;br /&gt;
&lt;br /&gt;
=== Device Support ===&lt;br /&gt;
* All message-based devices (with any expected lifetime) should be converted to use ASYN. If you are starting from existing devGpib support see [http://www.aps.anl.gov/epics/modules/soft/asyn/R4-10/gpibCoreConversion/conversionNotes.html these guidelines for conversion]. If you are starting on brand-new support see [http://www.aps.anl.gov/epics/modules/soft/asyn/R4-10/HowToDoSerial/tutorial.html these notes] or have a look at the [http://epics.web.psi.ch/software/streamdevice/ stream device support].&lt;br /&gt;
* Support for a particular device should be in its own support module.&lt;br /&gt;
&lt;br /&gt;
=== Database Files ===&lt;br /&gt;
* Support modules and IOC applications should install all .db files into their &amp;lt;top&amp;gt;/db directory. When an application uses a .db file from a support module that file may be copied from the support module &amp;lt;top&amp;gt;/db directory to the IOC application &amp;lt;top&amp;gt;/db directory. This is done by adding lines like&amp;lt;br&amp;gt;&amp;lt;tt&amp;gt;DB_INSTALLS += $(ASYN)/db/asynRecord.db&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;to the application &amp;lt;top&amp;gt;/''appName''/Db/Makefile. This allows all the .db files needed by an application to be found in a single location.&lt;br /&gt;
* Template files that are part of support modules do not need to be copied to your application Db source directory. The build system knows to look in support module db directories for template files.&lt;br /&gt;
&lt;br /&gt;
=== Application Makefile ===&lt;br /&gt;
* Add support module .dbd files to your application using the Makefile&amp;lt;br&amp;gt;&amp;lt;tt&amp;gt;''xxxxxx''_DBD += ''yyyyy''.dbd&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;mechanism.&lt;br /&gt;
&lt;br /&gt;
=== st.cmd ===&lt;br /&gt;
* Expansion of substitution/template files should be performed at build-time on the host rather than at application startup on the IOC.&lt;br /&gt;
* '''vxWorks only''' --- The '''ld''' command to load the application executable code must not use vxWorks shell redirection since this may break the commands later in the script. Change lines like&amp;lt;br&amp;gt;&amp;lt;tt&amp;gt;ld &amp;lt; libpm.munch&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;into&amp;lt;br&amp;gt;&amp;lt;tt&amp;gt;ld 0,0, &amp;quot;libpm.munch&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Autosave/restore ===&lt;br /&gt;
* The autosave/restore support module provides several diagnostic PVs. One of the most important of these is a PV which indicates the success or failure of autosave operations. An infrastructure monitoring system can check this PV and provide warnings about problems. All applications which use autosave/restore should include these PVs.&amp;lt;br&amp;gt;To add the PVs to an application:&lt;br /&gt;
# Add the following line to the &amp;lt;top&amp;gt;/''appName''/Db/Makefile&amp;lt;br&amp;gt;&amp;lt;tt&amp;gt;DB_INSTALLS += $(AUTOSAVE)/asApp/Db/save_restoreStatus.db&amp;lt;/tt&amp;gt;&lt;br /&gt;
# If you're using the IOC shell, add the following lines to the st.cmd script (before iocInit)&amp;lt;br&amp;gt;&amp;lt;tt&amp;gt;save_restoreSet_status_prefix($(IOC))&amp;lt;br&amp;gt;dbLoadRecords(db/save_restoreStatus.db,P=$(IOC))&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;If you're using the vxWorks shell to read the startup script the command must either specify the IOC name explicitly&amp;lt;br&amp;gt;&amp;lt;tt&amp;gt;save_restoreSet_status_prefix(&amp;quot;iocxxxxx&amp;quot;)&amp;lt;br&amp;gt;dbLoadRecords(&amp;quot;db/save_restoreStatus.db&amp;quot;,&amp;quot;P=iocxxxxx&amp;quot;)&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;or use iocshCmd to parse the lines&amp;lt;br&amp;gt;&amp;lt;tt&amp;gt;iocshCmd(&amp;quot;save_restoreSet_status_prefix($(IOC))&amp;quot;)&amp;lt;br&amp;gt;iocshCmd(&amp;quot;dbLoadRecords(db/save_restoreStatus.db,P=$(IOC))&amp;quot;)&amp;lt;/tt&amp;gt;&lt;/div&gt;</summary>
		<author><name>EricNorum</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=%22Best_Practice%22_Guidelines&amp;diff=1904</id>
		<title>&quot;Best Practice&quot; Guidelines</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=%22Best_Practice%22_Guidelines&amp;diff=1904"/>
		<updated>2011-08-24T22:59:07Z</updated>

		<summary type="html">&lt;p&gt;EricNorum: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== &amp;quot;Best Practice&amp;quot; Guidelines for Developers ==&lt;br /&gt;
This document presents some guidelines that have been found useful.  Please add your own suggestions!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Support Modules ===&lt;br /&gt;
* If your IOC application source directory contains '.c' files you should '''definitely''' consider moving them to a support module (either existing or new). A big problem in the past has been the proliferation of similar or identical '.c' files among multiple IOC applications. Help stamp out this practice now! To a lesser degree you should consider doing the same for any sequence programs in your application although these tend to be much more application-specific and thus impractical to move to a support module.&lt;br /&gt;
* Use &amp;lt;tt&amp;gt;/''path_to_base_bin''/makeBaseApp.pl -t support&amp;lt;/tt&amp;gt; to create a new support module. If you're writing a new message-based instrument support module &amp;lt;tt&amp;gt;/''path_to_asyn_bin''/makeSupport.pl -t streamSCPI&amp;lt;/tt&amp;gt; is a good place to start.&lt;br /&gt;
* Nothing within the support 'modules' directory tree should be an 'App'. Nothing within the 'ioc' applications directory tree should be anything but an 'App'.&lt;br /&gt;
&lt;br /&gt;
=== Device Support ===&lt;br /&gt;
* All message-based devices (with any expected lifetime) should be converted to use ASYN. If you are starting from existing devGpib support see [http://www.aps.anl.gov/epics/modules/soft/asyn/R4-10/gpibCoreConversion/conversionNotes.html these guidelines for conversion]. If you are starting on brand-new support see [http://www.aps.anl.gov/epics/modules/soft/asyn/R4-10/HowToDoSerial/tutorial.html these notes] or have a look at the [http://epics.web.psi.ch/software/streamdevice/ stream device support].&lt;br /&gt;
* Support for a particular device should be in its own support module.&lt;br /&gt;
&lt;br /&gt;
=== Database Files ===&lt;br /&gt;
* Support modules and IOC applications should install all .db files into their &amp;lt;top&amp;gt;/db directory. When an application uses a .db file from a support module that file may be copied from the support module &amp;lt;top&amp;gt;/db directory to the IOC application &amp;lt;top&amp;gt;/db directory. This is done by adding lines like&amp;lt;br&amp;gt;&amp;lt;tt&amp;gt;DB_INSTALLS += $(ASYN)/db/asynRecord.db&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;to the application &amp;lt;top&amp;gt;/''appName''/Db/Makefile. This allows all the .db files needed by an application to be found in a single location.&lt;br /&gt;
* Template files that are part of support modules do not need to be copied to your application Db source directory. The build system knows to look in support module db directories for template files.&lt;br /&gt;
&lt;br /&gt;
=== Application Makefile ===&lt;br /&gt;
* Add support module .dbd files to your application using the Makefile&amp;lt;br&amp;gt;&amp;lt;tt&amp;gt;''xxxxxx''_DBD += ''yyyyy''.dbd&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;mechanism.&lt;br /&gt;
&lt;br /&gt;
=== st.cmd ===&lt;br /&gt;
* Expansion of substitution/template files should be performed at build-time on the host rather than at application startup on the IOC.&lt;br /&gt;
* '''vxWorks only''' --- The '''ld''' command to load the application executable code must not use vxWorks shell redirection since this may break the commands later in the script. Change lines like&amp;lt;br&amp;gt;&amp;lt;tt&amp;gt;ld &amp;lt; libpm.munch&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;into&amp;lt;br&amp;gt;&amp;lt;tt&amp;gt;ld 0,0, &amp;quot;libpm.munch&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Autosave/restore ===&lt;br /&gt;
* The autosave/restore support module provides several diagnostic PVs. One of the most important of these is a PV which indicates the success or failure of autosave operations. An infrastructure monitoring system can check this PV and provide warnings about problems. All applications which use autosave/restore should include these PVs.&amp;lt;br&amp;gt;To add the PVs to an application:&lt;br /&gt;
# Add the following line to the &amp;lt;top&amp;gt;/''appName''/Db/Makefile&amp;lt;br&amp;gt;&amp;lt;tt&amp;gt;DB_INSTALLS += $(AUTOSAVE)/asApp/Db/save_restoreStatus.db&amp;lt;/tt&amp;gt;&lt;br /&gt;
# If you're using the IOC shell, add the following lines to the st.cmd script (before iocInit)&amp;lt;br&amp;gt;&amp;lt;tt&amp;gt;save_restoreSet_status_prefix($(IOC))&amp;lt;br&amp;gt;dbLoadRecords(db/save_restoreStatus.db,P=$(IOC))&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;If you're using the vxWorks shell to read the startup script the command must either specify the IOC name explicitly&amp;lt;br&amp;gt;&amp;lt;tt&amp;gt;save_restoreSet_status_prefix(&amp;quot;iocxxxxx&amp;quot;)&amp;lt;br&amp;gt;dbLoadRecords(&amp;quot;db/save_restoreStatus.db&amp;quot;,&amp;quot;P=iocxxxxx&amp;quot;)&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;or use iocshCmd to parse the lines&amp;lt;br&amp;gt;&amp;lt;tt&amp;gt;iocshCmd(&amp;quot;save_restoreSet_status_prefix($(IOC))&amp;quot;)&amp;lt;br&amp;gt;iocshCmd(&amp;quot;dbLoadRecords(db/save_restoreStatus.db,P=$(IOC))&amp;quot;)&amp;lt;/tt&amp;gt;&lt;/div&gt;</summary>
		<author><name>EricNorum</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=HowTo_Documents&amp;diff=1905</id>
		<title>HowTo Documents</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=HowTo_Documents&amp;diff=1905"/>
		<updated>2011-08-24T22:31:06Z</updated>

		<summary type="html">&lt;p&gt;EricNorum: /* Applications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a directory of various How-To documents written by members of the EPICS collaboration.  Contributions to this page are most welcome!&lt;br /&gt;
&lt;br /&gt;
=== EPICS Base on Different Architectures and Operating Systems ===&lt;br /&gt;
&lt;br /&gt;
* [http://www.aps.anl.gov/epics/base/RTEMS/tutorial/ Getting Started with EPICS on RTEMS]&lt;br /&gt;
* [[HowToPC104|Getting Started with R3.14.7 on a PC104 running Linux]]&lt;br /&gt;
* [[How To Port EPICS to a new OS/Architecture]]&lt;br /&gt;
&lt;br /&gt;
=== Drivers and Device Support ===&lt;br /&gt;
&lt;br /&gt;
* [http://www.aps.anl.gov/epics/modules/soft/asyn/HowToDoSerial_StreamDevice.html How To Do Serial (using Asyn Driver and StreamDevice)]&lt;br /&gt;
* [http://www.aps.anl.gov/epics/modules/soft/asyn/R4-15/HowToDoSerial/tutorial.pdf How To Do Serial (using Asyn Driver and devGPIB)]&lt;br /&gt;
* [http://www.aps.anl.gov/epics/modules/soft/asyn/BeginnerGuideToASYN-VXI11.pdf Beginners Guide to using VXI-11 (with Asyn Driver)]&lt;br /&gt;
* [[How to make your EPICS driver operating system independent]]&lt;br /&gt;
* [[How To Write Device Support that uses Asyn Driver]] ''(Incomplete!)''&lt;br /&gt;
* [[How to use GPIB ports with linux-gpib and StreamDevice]]&lt;br /&gt;
&lt;br /&gt;
=== Applications ===&lt;br /&gt;
&lt;br /&gt;
* [[Common Database patterns]]&lt;br /&gt;
* [[How To Install Channel Archiver On Scientific Linux]]&lt;br /&gt;
* [[What PV Save and Restore Tools are available]]&lt;br /&gt;
* [[How to Add a New Breakpoint Table]]&lt;br /&gt;
* [[&amp;quot;Best Practice&amp;quot; Guidelines]]&lt;br /&gt;
&lt;br /&gt;
=== Infrastructure and Other Stuff ===&lt;br /&gt;
&lt;br /&gt;
* [[How To Set Up a Linux Box as an IOC Boot Server]]&lt;br /&gt;
* [[How To Set Up a Mirror of the EPICS Web Site]]&lt;br /&gt;
* [[How to Set Up a Soft IOC Framework on Linux]]&lt;br /&gt;
* [[How to Set Up Console Access and Logging for VME and Soft IOCs]]&lt;br /&gt;
* [[How to Set Up NAL (Nagios Alarm Handler) to monitor an EPICS network]]&lt;br /&gt;
&lt;br /&gt;
=== Collaboration Stuff ===&lt;br /&gt;
&lt;br /&gt;
* [[How to run an EPICS Collaboration Meeting]]&lt;/div&gt;</summary>
		<author><name>EricNorum</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_make_your_EPICS_driver_operating_system_independent&amp;diff=2834</id>
		<title>How to make your EPICS driver operating system independent</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_make_your_EPICS_driver_operating_system_independent&amp;diff=2834"/>
		<updated>2009-01-30T15:44:18Z</updated>

		<summary type="html">&lt;p&gt;EricNorum: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=How to make your EPICS driver operating system independent=&lt;br /&gt;
&lt;br /&gt;
'''W. Eric Norum et. al.'''&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
The following table shows the changes made to some existing drivers to allow them to be used on systems other than vxWorks. Note that it is a very preliminary start at a set of conversion instructions. There's still no `cookbook' document to guide you, but many drivers can be converted without doing much more than applying the translations shown. A technique that I've found works well is to first change all the &amp;lt;code&amp;gt;#include&amp;lt;/code&amp;gt; statements that mention vxWorks header files to their OSI equivalents, then enter a compile-edit cycle until all compile errors have been eliminated.&lt;br /&gt;
&lt;br /&gt;
==Conversions==&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;3&amp;quot;&lt;br /&gt;
! align=&amp;quot;CENTER&amp;quot; | '''vxWorks'''&lt;br /&gt;
! align=&amp;quot;CENTER&amp;quot; | '''OSI'''&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;vxWorks.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;stdlib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsStdlib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;stdio.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsStdioRedirect.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;iosLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;taskLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsThread.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;memLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;rebootLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsExit.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;intLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsInterrupt.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;wdLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsTimer.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;lstLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;ellLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;vme.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;devLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;sysLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;iv.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsExport.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;#include &amp;lt;iocsh.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ERROR&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;-1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OK&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;semLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 SEM_ID flag = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);&lt;br /&gt;
 semGive(flag);&lt;br /&gt;
 semTake(flag, WAIT_FOREVER);&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;epicsEvent.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 epicsEventId flag = epicsEventMustCreate(epicsEventEmpty);&lt;br /&gt;
 epicsEventSignal(flag);&lt;br /&gt;
 epicsEventMustWait(flag);&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;semLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 SEM_ID Lock = semMCreate(SEM_Q_PRIORITY);&lt;br /&gt;
 semTake(Lock, WAIT_FOREVER);&lt;br /&gt;
 semGive(Lock);&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;epicsMutex.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 epicsMutexId Lock = epicsMutexMustCreate();&lt;br /&gt;
 epicsMutexLock(Lock);&lt;br /&gt;
 epicsMutexUnlock(Lock);&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;taskDelay(1)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | To generate a `short' delay:&lt;br /&gt;
 epicsThreadSleep(0.001)&lt;br /&gt;
This works because the operating system specific layer ensures a delay of at least one system clock tick for epicsThreadSleep arguments greater than 0.&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;taskDelay(30)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | Much old code assumes a 60 Hz vxWorks system clock. On such systems the equivalent for the command shown would be:&lt;br /&gt;
 epicsThreadSleep(0.5)&lt;br /&gt;
Of course, other code may assumes a 50 Hz or 100 Hz system clock rate.  You can&lt;br /&gt;
find out what your system clock rate is using epicsThreadSleepQuantum(), which returns the clock period in seconds.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;taskSuspend(0)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsThreadSuspendSelf()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;pre&amp;gt;intConnect(INUM_TO_IVEC(irqVector),&lt;br /&gt;
        irqHandler, pLink)&amp;lt;/pre&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;pre&amp;gt;devConnectInterruptVME(irqVector,&lt;br /&gt;
        irqHandler, pLink)&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;sysIntEnable(IrqLevel)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;devEnableInterruptLevelVME(IrqLevel)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;pre&amp;gt;sysBusToLocalAdrs(VME_AM_SUP_SHORT_IO,&lt;br /&gt;
        (char*)CardAddress, (char**)&amp;amp;ErLink[Card].pEr)&amp;lt;/pre&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;pre&amp;gt;devRegisterAddress(&amp;quot;apsEr&amp;quot;, atVMEA16,&lt;br /&gt;
        CardAddress, 0x40, (void*)&amp;amp;ErLink[Card].pEr)&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;vxMemProbe(pReg, READ, sizeof(short), &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;devReadProbe(sizeof(short), pReg, &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;vxMemProbe(pReg,WRITE,sizeof(short), &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;devWriteProbe(sizeof(short), pReg, &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;key = intLock()&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;key = epicsInterruptLock()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;intUnlock(key)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsInterruptUnlock(key)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;pre&amp;gt;#include &amp;lt;wdLib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sysLib.h&amp;gt;&lt;br /&gt;
WDOG_ID wd = wdCreate();&lt;br /&gt;
wdStart(wd, delay * sysClkRateGet(),&lt;br /&gt;
        (FUNCPTR) wdCallback, (int) arg);&amp;lt;/pre&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;pre&amp;gt;#include &amp;lt;epicsTimer.h&amp;gt;&lt;br /&gt;
#include &amp;lt;epicsThread.h&amp;gt;&lt;br /&gt;
epicsTimerQueueId tq = epicsTimerQueueAllocate(1,&lt;br /&gt;
        epicsThreadPriorityScanLow);&lt;br /&gt;
epicsTimerId wd = epicsTimerQueueCreateTimer(tq,&lt;br /&gt;
        wdCallback, (void *) arg);&lt;br /&gt;
epicsTimerStartDelay(wd, delay);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the watchdog timer is being used only to invoke timed callbacks it may be possible to eliminate the watchdog timer completely and just use callbackRequestDelayed instead.  If the timed callbacks are being used only for invoking record processing things are even simpler – just use callbackRequestProcessCallbackDelayed.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rebootHookAdd((FUNCPTR)ErRebootFunc)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsAtExit(ErRebootFunc, NULL)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;pre&amp;gt;#include &amp;lt;fast_lock.h&amp;gt;&lt;br /&gt;
FAST_LOCK lock;&lt;br /&gt;
FASTLOCKINIT(&amp;amp;mzconf[card].lock);&lt;br /&gt;
FASTLOCKFREE(&amp;amp;mzconf[card].lock);&lt;br /&gt;
FASTLOCK(&amp;amp;mzconf[card].lock);&lt;br /&gt;
FASTUNLOCK(&amp;amp;mzconf[card].lock);&amp;lt;/pre&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | You'll have to use your judgement here. If the section of code being protected is quick (less than a few microseconds) it's reasonable to simply disable interrupts while the code is active. In this case you can remove the 'lock' variable and the init/free operations and then add a local 'key' variable and replace the lock/unlock operations with epicsInterruptLock/Unlock operations. If the section of code being protected is longer you'll have to convert the FASTLOCK to an EPICS mutex.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;taskSpawn(...)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsThreadCreate(...)&amp;lt;/code&amp;gt;&lt;br /&gt;
You should consider rewriting the driver to use the &amp;quot;worker thread&amp;quot; environment provided by the ASYN package. This is likely to result in a shorter, simpler, and more robust driver.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Some other changes==&lt;br /&gt;
&lt;br /&gt;
* Some R3.13 record support database definitions explicitly mention all fields rather than including dbCommon.dbd. This can cause problems with FAST_LOCK. The solution is to add &amp;lt;code&amp;gt;include &amp;quot;dbCommon.dbd&amp;quot;&amp;lt;/code&amp;gt; at the beginning of the file in question and to remove all entries for the fields provided by dbCommon.dbd.&lt;br /&gt;
* You should set up IOC shell command registrations for all `configure' functions and for any other commands you may need to call from the IOC shell. Here's an example of a fairly complex configuration command:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * IOC shell command registration&lt;br /&gt;
  */&lt;br /&gt;
 #include &amp;lt;iocsh.h&amp;gt;&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg0 = { &amp;quot;card&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg1 = { &amp;quot;VME A16 offset&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg2 = { &amp;quot;VME memory offset&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg3 = { &amp;quot;interrupt vector&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg4 = { &amp;quot;interrupt level&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg5 = { &amp;quot;use DMA&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg6 = { &amp;quot;nchannels&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg7 = { &amp;quot;kilosamplesPerChan&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg *vtr10012ConfigArgs[] = {&lt;br /&gt;
     &amp;amp;vtr10012ConfigArg0, &amp;amp;vtr10012ConfigArg1, &amp;amp;vtr10012ConfigArg2,&lt;br /&gt;
     &amp;amp;vtr10012ConfigArg3, &amp;amp;vtr10012ConfigArg4, &amp;amp;vtr10012ConfigArg5,&lt;br /&gt;
     &amp;amp;vtr10012ConfigArg6,&amp;amp;vtr10012ConfigArg7};&lt;br /&gt;
 static const iocshFuncDef vtr10012ConfigFuncDef =&lt;br /&gt;
                       {&amp;quot;vtr10012Config&amp;quot;,8,vtr10012ConfigArgs};&lt;br /&gt;
 static void vtr10012ConfigCallFunc(const iocshArgBuf *args)&lt;br /&gt;
 {&lt;br /&gt;
     vtr10012Config(args[0].ival, args[1].ival, args[2].ival,&lt;br /&gt;
                  args[3].ival, args[4].ival, args[5].ival,&lt;br /&gt;
                  args[6].ival, args[7].ival);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 /*&lt;br /&gt;
  * This routine is called before multitasking has started, so there's&lt;br /&gt;
  * no race condition in the test/set of firstTime.&lt;br /&gt;
  */&lt;br /&gt;
 static void&lt;br /&gt;
 drvVtr10012RegisterCommands(void)&lt;br /&gt;
 {&lt;br /&gt;
     static int firstTime = 1;&lt;br /&gt;
     if (firstTime) {&lt;br /&gt;
         iocshRegister(&amp;amp;vtr10012ConfigFuncDef,vtr10012ConfigCallFunc);&lt;br /&gt;
         firstTime = 0;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
 epicsExportRegistrar(drvVtr10012RegisterCommands);&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
You must also provide a corresponding registrar statement in a &amp;lt;code&amp;gt;.dbd&amp;lt;/code&amp;gt; file:&lt;br /&gt;
 registrar(drvVtr10012RegisterCommands)&lt;br /&gt;
* If your driver provides functions that are referred to by name from database files you must:&lt;br /&gt;
** &amp;lt;code&amp;gt;#include &amp;lt;registryFunction.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
** Add an &amp;lt;code&amp;gt;epicsExportFunction()&amp;lt;/code&amp;gt; statement for each such function.&lt;br /&gt;
** Add a corresponding &amp;lt;code&amp;gt;function&amp;lt;/code&amp;gt; statement in a &amp;lt;code&amp;gt;.dbd&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
==Additional Information==&lt;br /&gt;
&lt;br /&gt;
The procedure for converting a support module from R3.13 to R3.14 is described in the [http://www.aps.anl.gov/epics/base/R3-14/8-docs/ConvertingR3.13AppsToR3.14.html Converting R3.13 Apps to R3.14] document.&lt;/div&gt;</summary>
		<author><name>EricNorum</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_make_your_EPICS_driver_operating_system_independent&amp;diff=1639</id>
		<title>How to make your EPICS driver operating system independent</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_make_your_EPICS_driver_operating_system_independent&amp;diff=1639"/>
		<updated>2009-01-30T14:50:03Z</updated>

		<summary type="html">&lt;p&gt;EricNorum: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=How to make your EPICS driver operating system independent=&lt;br /&gt;
&lt;br /&gt;
'''W. Eric Norum et. al.'''&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
The following table shows the changes made to some existing drivers to allow them to be used on systems other than vxWorks. Note that it is a very preliminary start at a set of conversion instructions. There's still no `cookbook' document to guide you, but many drivers can be converted without doing much more than applying the translations shown. A technique that I've found works well is to first change all the &amp;lt;code&amp;gt;#include&amp;lt;/code&amp;gt; statements that mention vxWorks header files to their OSI equivalents, then enter a compile-edit cycle until all compile errors have been eliminated.&lt;br /&gt;
&lt;br /&gt;
==Conversions==&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;3&amp;quot;&lt;br /&gt;
! align=&amp;quot;CENTER&amp;quot; | '''vxWorks'''&lt;br /&gt;
! align=&amp;quot;CENTER&amp;quot; | '''OSI'''&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;vxWorks.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;stdlib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsStdlib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;stdio.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsStdioRedirect.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;iosLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;taskLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsThread.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;memLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;rebootLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsExit.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;intLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsInterrupt.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;wdLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsTimer.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;lstLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;ellLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;vme.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;devLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;sysLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;iv.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsExport.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;#include &amp;lt;iocsh.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ERROR&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;-1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OK&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;semLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 SEM_ID flag = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);&lt;br /&gt;
 semGive(flag);&lt;br /&gt;
 semTake(flag, WAIT_FOREVER);&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;epicsEvent.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 epicsEventId flag = epicsEventMustCreate(epicsEventEmpty);&lt;br /&gt;
 epicsEventSignal(flag);&lt;br /&gt;
 epicsEventMustWait(flag);&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;semLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 SEM_ID Lock = semMCreate(SEM_Q_PRIORITY);&lt;br /&gt;
 semTake(Lock, WAIT_FOREVER);&lt;br /&gt;
 semGive(Lock);&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;epicsMutex.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 epicsMutexId Lock = epicsMutexMustCreate();&lt;br /&gt;
 epicsMutexLock(Lock);&lt;br /&gt;
 epicsMutexUnlock(Lock);&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;taskDelay(1)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | To generate a `short' delay:&lt;br /&gt;
 epicsThreadSleep(0.001)&lt;br /&gt;
This works because the operating system specific layer ensures a delay of at least one system clock tick for epicsThreadSleep arguments greater than 0.&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;taskDelay(30)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | Much old code assumes a 60 Hz vxWorks system clock. On such systems the equivalent for the command shown would be:&lt;br /&gt;
 epicsThreadSleep(0.5)&lt;br /&gt;
Of course, other code may assumes a 50 Hz or 100 Hz system clock rate.  You can&lt;br /&gt;
find out what your system clock rate is using epicsThreadSleepQuantum(), which returns the clock period in seconds.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;taskSuspend(0)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsThreadSuspendSelf()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;pre&amp;gt;intConnect(INUM_TO_IVEC(irqVector),&lt;br /&gt;
        irqHandler, pLink)&amp;lt;/pre&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;pre&amp;gt;devConnectInterruptVME(irqVector,&lt;br /&gt;
        irqHandler, pLink)&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;sysIntEnable(IrqLevel)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;devEnableInterruptLevelVME(IrqLevel)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;pre&amp;gt;sysBusToLocalAdrs(VME_AM_SUP_SHORT_IO,&lt;br /&gt;
        (char*)CardAddress, (char**)&amp;amp;ErLink[Card].pEr)&amp;lt;/pre&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;pre&amp;gt;devRegisterAddress(&amp;quot;apsEr&amp;quot;, atVMEA16,&lt;br /&gt;
        CardAddress, 0x40, (void*)&amp;amp;ErLink[Card].pEr)&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;vxMemProbe(pReg, READ, sizeof(short), &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;devReadProbe(sizeof(short), pReg, &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;vxMemProbe(pReg,WRITE,sizeof(short), &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;devWriteProbe(sizeof(short), pReg, &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;key = intLock()&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;key = epicsInterruptLock()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;intUnlock(key)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsInterruptUnlock(key)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;pre&amp;gt;#include &amp;lt;wdLib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sysLib.h&amp;gt;&lt;br /&gt;
WDOG_ID wd = wdCreate();&lt;br /&gt;
wdStart(wd, delay * sysClkRateGet(),&lt;br /&gt;
        (FUNCPTR) wdCallback, (int) arg);&amp;lt;/pre&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;pre&amp;gt;#include &amp;lt;epicsTimer.h&amp;gt;&lt;br /&gt;
#include &amp;lt;epicsThread.h&amp;gt;&lt;br /&gt;
epicsTimerQueueId tq = epicsTimerQueueAllocate(1,&lt;br /&gt;
        epicsThreadPriorityScanLow);&lt;br /&gt;
epicsTimerId wd = epicsTimerQueueCreateTimer(tq,&lt;br /&gt;
        wdCallback, (void *) arg);&lt;br /&gt;
epicsTimerStartDelay(wd, delay);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the watchdog timer is being used only to invoke timed callbacks it may be possible to eliminate the watchdog timer completely and just use callbackRequestDelayed instead.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rebootHookAdd((FUNCPTR)ErRebootFunc)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsAtExit(ErRebootFunc, NULL)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;pre&amp;gt;#include &amp;lt;fast_lock.h&amp;gt;&lt;br /&gt;
FAST_LOCK lock;&lt;br /&gt;
FASTLOCKINIT(&amp;amp;mzconf[card].lock);&lt;br /&gt;
FASTLOCKFREE(&amp;amp;mzconf[card].lock);&lt;br /&gt;
FASTLOCK(&amp;amp;mzconf[card].lock);&lt;br /&gt;
FASTUNLOCK(&amp;amp;mzconf[card].lock);&amp;lt;/pre&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | You'll have to use your judgement here. If the section of code being protected is quick (less than a few microseconds) it's reasonable to simply disable interrupts while the code is active. In this case you can remove the 'lock' variable and the init/free operations and then add a local 'key' variable and replace the lock/unlock operations with epicsInterruptLock/Unlock operations. If the section of code being protected is longer you'll have to convert the FASTLOCK to an EPICS mutex.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;taskSpawn(...)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsThreadCreate(...)&amp;lt;/code&amp;gt;&lt;br /&gt;
You should consider rewriting the driver to use the &amp;quot;worker thread&amp;quot; environment provided by the ASYN package. This is likely to result in a shorter, simpler, and more robust driver.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Some other changes==&lt;br /&gt;
&lt;br /&gt;
* Some R3.13 record support database definitions explicitly mention all fields rather than including dbCommon.dbd. This can cause problems with FAST_LOCK. The solution is to add &amp;lt;code&amp;gt;include &amp;quot;dbCommon.dbd&amp;quot;&amp;lt;/code&amp;gt; at the beginning of the file in question and to remove all entries for the fields provided by dbCommon.dbd.&lt;br /&gt;
* You should set up IOC shell command registrations for all `configure' functions and for any other commands you may need to call from the IOC shell. Here's an example of a fairly complex configuration command:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * IOC shell command registration&lt;br /&gt;
  */&lt;br /&gt;
 #include &amp;lt;iocsh.h&amp;gt;&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg0 = { &amp;quot;card&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg1 = { &amp;quot;VME A16 offset&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg2 = { &amp;quot;VME memory offset&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg3 = { &amp;quot;interrupt vector&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg4 = { &amp;quot;interrupt level&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg5 = { &amp;quot;use DMA&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg6 = { &amp;quot;nchannels&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg7 = { &amp;quot;kilosamplesPerChan&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg *vtr10012ConfigArgs[] = {&lt;br /&gt;
     &amp;amp;vtr10012ConfigArg0, &amp;amp;vtr10012ConfigArg1, &amp;amp;vtr10012ConfigArg2,&lt;br /&gt;
     &amp;amp;vtr10012ConfigArg3, &amp;amp;vtr10012ConfigArg4, &amp;amp;vtr10012ConfigArg5,&lt;br /&gt;
     &amp;amp;vtr10012ConfigArg6,&amp;amp;vtr10012ConfigArg7};&lt;br /&gt;
 static const iocshFuncDef vtr10012ConfigFuncDef =&lt;br /&gt;
                       {&amp;quot;vtr10012Config&amp;quot;,8,vtr10012ConfigArgs};&lt;br /&gt;
 static void vtr10012ConfigCallFunc(const iocshArgBuf *args)&lt;br /&gt;
 {&lt;br /&gt;
     vtr10012Config(args[0].ival, args[1].ival, args[2].ival,&lt;br /&gt;
                  args[3].ival, args[4].ival, args[5].ival,&lt;br /&gt;
                  args[6].ival, args[7].ival);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 /*&lt;br /&gt;
  * This routine is called before multitasking has started, so there's&lt;br /&gt;
  * no race condition in the test/set of firstTime.&lt;br /&gt;
  */&lt;br /&gt;
 static void&lt;br /&gt;
 drvVtr10012RegisterCommands(void)&lt;br /&gt;
 {&lt;br /&gt;
     static int firstTime = 1;&lt;br /&gt;
     if (firstTime) {&lt;br /&gt;
         iocshRegister(&amp;amp;vtr10012ConfigFuncDef,vtr10012ConfigCallFunc);&lt;br /&gt;
         firstTime = 0;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
 epicsExportRegistrar(drvVtr10012RegisterCommands);&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
You must also provide a corresponding registrar statement in a &amp;lt;code&amp;gt;.dbd&amp;lt;/code&amp;gt; file:&lt;br /&gt;
 registrar(drvVtr10012RegisterCommands)&lt;br /&gt;
* If your driver provides functions that are referred to by name from database files you must:&lt;br /&gt;
** &amp;lt;code&amp;gt;#include &amp;lt;registryFunction.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
** Add an &amp;lt;code&amp;gt;epicsExportFunction()&amp;lt;/code&amp;gt; statement for each such function.&lt;br /&gt;
** Add a corresponding &amp;lt;code&amp;gt;function&amp;lt;/code&amp;gt; statement in a &amp;lt;code&amp;gt;.dbd&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
==Additional Information==&lt;br /&gt;
&lt;br /&gt;
The procedure for converting a support module from R3.13 to R3.14 is described in the [http://www.aps.anl.gov/epics/base/R3-14/8-docs/ConvertingR3.13AppsToR3.14.html Converting R3.13 Apps to R3.14] document.&lt;/div&gt;</summary>
		<author><name>EricNorum</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_make_your_EPICS_driver_operating_system_independent&amp;diff=1398</id>
		<title>How to make your EPICS driver operating system independent</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_make_your_EPICS_driver_operating_system_independent&amp;diff=1398"/>
		<updated>2006-10-19T16:37:27Z</updated>

		<summary type="html">&lt;p&gt;EricNorum: /* Some other changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=How to make your EPICS driver operating system independent=&lt;br /&gt;
&lt;br /&gt;
'''W. Eric Norum'''&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
The following table shows the changes made to some existing drivers to allow them to be used on systems other than vxWorks. Note that it is a very preliminary start at a set of conversion instructions. There's still no `cookbook' document to guide you, but many drivers can be converted without doing much more than applying the translations shown. A technique that I've found works well is to first change all the &amp;lt;code&amp;gt;#include&amp;lt;/code&amp;gt; statements that mention vxWorks header files to their OSI equivalents, then enter a compile-edit cycle until all compile errors have been eliminated.&lt;br /&gt;
&lt;br /&gt;
==Conversions==&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;3&amp;quot;&lt;br /&gt;
! align=&amp;quot;CENTER&amp;quot; | '''vxWorks'''&lt;br /&gt;
! align=&amp;quot;CENTER&amp;quot; | '''OSI'''&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;vxWorks.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;stdlib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsStdlib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;stdio.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsStdioRedirect.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;iosLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;taskLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsThread.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;memLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;rebootLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsExit.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;intLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsInterrupt.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;lstLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;vme.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;devLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;sysLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;iv.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsExport.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;#include &amp;lt;iocsh.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ERROR&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;-1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OK&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;semLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 SEM_ID flag = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);&lt;br /&gt;
 semGive(flag);&lt;br /&gt;
 semTake(flag, WAIT_FOREVER);&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;epicsEvent.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 epicsEventId flag = epicsEventMustCreate(epicsEventEmpty);&lt;br /&gt;
 epicsEventSignal(flag);&lt;br /&gt;
 epicsEventMustWait(flag);&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;semLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 SEM_ID Lock = semMCreate(SEM_Q_PRIORITY);&lt;br /&gt;
 semTake(Lock, WAIT_FOREVER);&lt;br /&gt;
 semGive(Lock);&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;epicsMutex.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 epicsMutexId Lock = epicsMutexMustCreate();&lt;br /&gt;
 epicsMutexLock(Lock);&lt;br /&gt;
 epicsMutexUnlock(Lock);&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;taskDelay(1)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | To generate a `short' delay:&lt;br /&gt;
 epicsThreadSleep(0.001)&lt;br /&gt;
This works because the operating system specific layer ensures a delay of at least one system clock tick for epicsThreadSleep arguments greater than 0.&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;taskDelay(30)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | Much old code assumes a 60 Hz vxWorks system clock. On such systems the equivalent for the command shown would be:&lt;br /&gt;
 epicsThreadSleep(0.5)&lt;br /&gt;
Of course, other code may assumes a 50 Hz or 100 Hz system clock rate.  You can&lt;br /&gt;
find out what your system clock rate is using epicsThreadSleepQuantum(), which returns the clock period in seconds.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;taskSuspend(0)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsThreadSuspendSelf()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;intConnect(INUM_TO_IVEC(IrqVector), IrqHandler, pLink)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;devConnectInterruptVME(IrqVector, IrqHandler, pLink)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;sysIntEnable(IrqLevel)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;devEnableInterruptLevelVME(IrqLevel)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;sysBusToLocalAdrs(VME_AM_SUP_SHORT_IO, (char*)CardAddress, (char**)&amp;amp;ErLink[Card].pEr)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;devRegisterAddress(&amp;quot;apsEr&amp;quot;, atVMEA16, CardAddress, 0x40, (void*)&amp;amp;ErLink[Card].pEr)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;vxMemProbe(pReg, READ, sizeof(short), &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;devReadProbe(sizeof(short), pReg, &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;vxMemProbe(pReg,WRITE,sizeof(short), &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;devWriteProbe(sizeof(short), pReg, &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;key = intLock()&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;key = epicsInterruptLock()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;intUnlock(key)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsInterrupUnlock(key)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rebootHookAdd((FUNCPTR)ErRebootFunc)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsAtExit(ErRebootFunc, NULL)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;fast_lock.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 FAST_LOCK lock;&lt;br /&gt;
 FASTLOCKINIT(&amp;amp;mzconf[card].lock);&lt;br /&gt;
 FASTLOCKFREE(&amp;amp;mzconf[card].lock);&lt;br /&gt;
 FASTLOCK(&amp;amp;mzconf[card].lock);&lt;br /&gt;
 FASTUNLOCK(&amp;amp;mzconf[card].lock);&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | You'll have to use your judgement here. If the section of code being protected is quick (less than a few microseconds) it's reasonable to simply disable interrupts while the code is active. In this case you can remove the 'lock' variable and the init/free operations and then add a local 'key' variable and replace the lock/unlock operations with epicsInterruptLock/Unlock operations. If the section of code being protected is longer you'll have to convert the FASTLOCK to an EPICS mutex.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;taskSpawn(...)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsThreadCreate(...)&amp;lt;/code&amp;gt;&lt;br /&gt;
You should consider rewriting the driver to use the &amp;quot;worker thread&amp;quot; environment provided by the ASYN package. This is likely to result in a shorter, simpler, and more robust driver.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Some other changes==&lt;br /&gt;
&lt;br /&gt;
* Some R3.13 record support database definitions explicitly mention all fields rather than including dbCommon.dbd. This can cause problems with FAST_LOCK. The solution is to add &amp;lt;code&amp;gt;include &amp;quot;dbCommon.dbd&amp;quot;&amp;lt;/code&amp;gt; at the beginning of the file in question and to remove all entries for the fields provided by dbCommon.dbd.&lt;br /&gt;
* You should set up IOC shell command registrations for all `configure' functions and for any other commands you may need to call from the IOC shell. Here's an example of a fairly complex configuration command:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * IOC shell command registration&lt;br /&gt;
  */&lt;br /&gt;
 #include &amp;lt;iocsh.h&amp;gt;&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg0 = { &amp;quot;card&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg1 = { &amp;quot;VME A16 offset&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg2 = { &amp;quot;VME memory offset&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg3 = { &amp;quot;interrupt vector&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg4 = { &amp;quot;interrupt level&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg5 = { &amp;quot;use DMA&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg6 = { &amp;quot;nchannels&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg7 = { &amp;quot;kilosamplesPerChan&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg *vtr10012ConfigArgs[] = {&lt;br /&gt;
     &amp;amp;vtr10012ConfigArg0, &amp;amp;vtr10012ConfigArg1, &amp;amp;vtr10012ConfigArg2,&lt;br /&gt;
     &amp;amp;vtr10012ConfigArg3, &amp;amp;vtr10012ConfigArg4, &amp;amp;vtr10012ConfigArg5,&lt;br /&gt;
     &amp;amp;vtr10012ConfigArg6,&amp;amp;vtr10012ConfigArg7};&lt;br /&gt;
 static const iocshFuncDef vtr10012ConfigFuncDef =&lt;br /&gt;
                       {&amp;quot;vtr10012Config&amp;quot;,8,vtr10012ConfigArgs};&lt;br /&gt;
 static void vtr10012ConfigCallFunc(const iocshArgBuf *args)&lt;br /&gt;
 {&lt;br /&gt;
     vtr10012Config(args[0].ival, args[1].ival, args[2].ival,&lt;br /&gt;
                  args[3].ival, args[4].ival, args[5].ival,&lt;br /&gt;
                  args[6].ival, args[7].ival);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 /*&lt;br /&gt;
  * This routine is called before multitasking has started, so there's&lt;br /&gt;
  * no race condition in the test/set of firstTime.&lt;br /&gt;
  */&lt;br /&gt;
 static void&lt;br /&gt;
 drvVtr10012RegisterCommands(void)&lt;br /&gt;
 {&lt;br /&gt;
     static int firstTime = 1;&lt;br /&gt;
     if (firstTime) {&lt;br /&gt;
         iocshRegister(&amp;amp;vtr10012ConfigFuncDef,vtr10012ConfigCallFunc);&lt;br /&gt;
         firstTime = 0;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
 epicsExportRegistrar(drvVtr10012RegisterCommands);&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
You must also provide a corresponding registrar statement in a &amp;lt;code&amp;gt;.dbd&amp;lt;/code&amp;gt; file:&lt;br /&gt;
 registrar(drvVtr10012RegisterCommands)&lt;br /&gt;
* If your driver provides functions that are referred to by name from database files you must:&lt;br /&gt;
** &amp;lt;code&amp;gt;#include &amp;lt;registryFunction.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
** Add an &amp;lt;code&amp;gt;epicsExportFunction()&amp;lt;/code&amp;gt; statement for each such function.&lt;br /&gt;
** Add a corresponding &amp;lt;code&amp;gt;function&amp;lt;/code&amp;gt; statement in a &amp;lt;code&amp;gt;.dbd&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
==Additional Information==&lt;br /&gt;
&lt;br /&gt;
The procedure for converting a support module from R3.13 to R3.14 is described in the [http://www.aps.anl.gov/epics/base/R3-14/8-docs/ConvertingR3.13AppsToR3.14.html Converting R3.13 Apps to R3.14] document.&lt;br /&gt;
&lt;br /&gt;
==Acknowledgments==&lt;br /&gt;
&lt;br /&gt;
* Peter Denison (Diamond) for getting me started on this document and for useful suggestions.&lt;br /&gt;
* Steve Shoaf and Nick DiMonte (ANL) for some early conversions.&lt;br /&gt;
* Andrew Johnson for 'wikifying' the contents and setting up this page.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
 Eric Norum 2006-08-17&lt;/div&gt;</summary>
		<author><name>EricNorum</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_make_your_EPICS_driver_operating_system_independent&amp;diff=1395</id>
		<title>How to make your EPICS driver operating system independent</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_make_your_EPICS_driver_operating_system_independent&amp;diff=1395"/>
		<updated>2006-08-18T18:44:42Z</updated>

		<summary type="html">&lt;p&gt;EricNorum: /* Conversions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=How to make your EPICS driver operating system independent=&lt;br /&gt;
&lt;br /&gt;
'''W. Eric Norum'''&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
The following table shows the changes made to some existing drivers to allow them to be used on systems other than vxWorks. Note that it is a very preliminary start at a set of conversion instructions. There's still no `cookbook' document to guide you, but many drivers can be converted without doing much more than applying the translations shown. A technique that I've found works well is to first change all the &amp;lt;code&amp;gt;#include&amp;lt;/code&amp;gt; statements that mention vxWorks header files to their OSI equivalents, then enter a compile-edit cycle until all compile errors have been eliminated.&lt;br /&gt;
&lt;br /&gt;
==Conversions==&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;3&amp;quot;&lt;br /&gt;
! align=&amp;quot;CENTER&amp;quot; | '''vxWorks'''&lt;br /&gt;
! align=&amp;quot;CENTER&amp;quot; | '''OSI'''&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;vxWorks.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;stdlib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsStdlib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;stdio.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsStdioRedirect.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;iosLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;taskLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsThread.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;memLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;rebootLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsExit.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;intLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsInterrupt.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;lstLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;vme.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;devLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;sysLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;iv.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsExport.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;#include &amp;lt;iocsh.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ERROR&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;-1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OK&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;semLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 SEM_ID flag = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);&lt;br /&gt;
 semGive(flag);&lt;br /&gt;
 semTake(flag, WAIT_FOREVER);&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;epicsEvent.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 epicsEventId flag = epicsEventMustCreate(epicsEventEmpty);&lt;br /&gt;
 epicsEventSignal(flag);&lt;br /&gt;
 epicsEventMustWait(flag);&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;semLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 SEM_ID Lock = semMCreate(SEM_Q_PRIORITY);&lt;br /&gt;
 semTake(Lock, WAIT_FOREVER);&lt;br /&gt;
 semGive(Lock);&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;epicsMutex.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 epicsMutexId Lock = epicsMutexMustCreate();&lt;br /&gt;
 epicsMutexLock(Lock);&lt;br /&gt;
 epicsMutexUnlock(Lock);&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;taskDelay(1)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | To generate a `short' delay:&lt;br /&gt;
 epicsThreadSleep(0.001)&lt;br /&gt;
This works because the operating system specific layer ensures a delay of at least one system clock tick for epicsThreadSleep arguments greater than 0.&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;taskDelay(30)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | Much old code assumes a 60 Hz vxWorks system clock. On such systems the equivalent for the command shown would be:&lt;br /&gt;
 epicsThreadSleep(0.5)&lt;br /&gt;
Of course, other code may assumes a 50 Hz or 100 Hz system clock rate...&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;taskSuspend(0)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsThreadSuspendSelf()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;intConnect(INUM_TO_IVEC(IrqVector), IrqHandler, pLink)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;devConnectInterruptVME(IrqVector, IrqHandler, pLink)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;sysIntEnable(IrqLevel)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;devEnableInterruptLevelVME(IrqLevel)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;sysBusToLocalAdrs(VME_AM_SUP_SHORT_IO, (char*)CardAddress, (char**)&amp;amp;ErLink[Card].pEr)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;devRegisterAddress(&amp;quot;apsEr&amp;quot;, atVMEA16, CardAddress, 0x40, (void*)&amp;amp;ErLink[Card].pEr)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;vxMemProbe(pReg, READ, sizeof(short), &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;devReadProbe(sizeof(short), pReg, &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;vxMemProbe(pReg,WRITE,sizeof(short), &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;devWriteProbe(sizeof(short), pReg, &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;key = intLock()&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;key = epicsInterruptLock()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;intUnlock(key)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsInterrupUnlock(key)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rebootHookAdd((FUNCPTR)ErRebootFunc)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsAtExit(ErRebootFunc, NULL)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;fast_lock.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 FAST_LOCK lock;&lt;br /&gt;
 FASTLOCKINIT(&amp;amp;mzconf[card].lock);&lt;br /&gt;
 FASTLOCKFREE(&amp;amp;mzconf[card].lock);&lt;br /&gt;
 FASTLOCK(&amp;amp;mzconf[card].lock);&lt;br /&gt;
 FASTUNLOCK(&amp;amp;mzconf[card].lock);&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | You'll have to use your judgement here. If the section of code being protected is quick (less than a few microseconds) it's reasonable to simply disable interrupts while the code is active. In this case you can remove the 'lock' variable and the init/free operations and then add a local 'key' variable and replace the lock/unlock operations with epicsInterruptLock/Unlock operations. If the section of code being protected is longer you'll have to convert the FASTLOCK to an EPICS mutex.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;taskSpawn(...)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsThreadCreate(...)&amp;lt;/code&amp;gt;&lt;br /&gt;
You should consider rewriting the driver to use the &amp;quot;worker thread&amp;quot; environment provided by the ASYN package. This is likely to result in a shorter, simpler, and more robust driver.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Some other changes==&lt;br /&gt;
&lt;br /&gt;
* Some R3.13 record support database definitions explicitly mention all fields rather than including dbCommon.dbd. This can cause problems with FAST_LOCK. The solution is to add &amp;lt;code&amp;gt;include &amp;quot;dbCommon.dbd&amp;quot;&amp;lt;/code&amp;gt; at the beginning of the file in question and to remove all entries for the fields provided by dbCommon.dbd.&lt;br /&gt;
* You should set up IOC shell command registrations for all `configure' functions and for any other commands you may need to call from the IOC shell. Here's an example of a fairly complex configuration command:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * IOC shell command registration&lt;br /&gt;
  */&lt;br /&gt;
 #include &amp;lt;iocsh.h&amp;gt;&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg0 = { &amp;quot;card&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg1 = { &amp;quot;VME A16 offset&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg2 = { &amp;quot;VME memory offset&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg3 = { &amp;quot;interrupt vector&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg4 = { &amp;quot;interrupt level&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg5 = { &amp;quot;use DMA&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg6 = { &amp;quot;nchannels&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg7 = { &amp;quot;kilosamplesPerChan&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg *vtr10012ConfigArgs[] = {&lt;br /&gt;
     &amp;amp;vtr10012ConfigArg0, &amp;amp;vtr10012ConfigArg1, &amp;amp;vtr10012ConfigArg2,&lt;br /&gt;
     &amp;amp;vtr10012ConfigArg3, &amp;amp;vtr10012ConfigArg4, &amp;amp;vtr10012ConfigArg5,&lt;br /&gt;
     &amp;amp;vtr10012ConfigArg6,&amp;amp;vtr10012ConfigArg7};&lt;br /&gt;
 static const iocshFuncDef vtr10012ConfigFuncDef =&lt;br /&gt;
                       {&amp;quot;vtr10012Config&amp;quot;,8,vtr10012ConfigArgs};&lt;br /&gt;
 static void vtr10012ConfigCallFunc(const iocshArgBuf *args)&lt;br /&gt;
 {&lt;br /&gt;
     vtr10012Config(args[0].ival, args[1].ival, args[2].ival,&lt;br /&gt;
                  args[3].ival, args[4].ival, args[5].ival,&lt;br /&gt;
                  args[6].ival, args[7].ival);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 /*&lt;br /&gt;
  * This routine is called before multitasking has started, so there's&lt;br /&gt;
  * no race condition in the test/set of firstTime.&lt;br /&gt;
  */&lt;br /&gt;
 static void&lt;br /&gt;
 drvVtr10012RegisterCommands(void)&lt;br /&gt;
 {&lt;br /&gt;
     static int firstTime = 1;&lt;br /&gt;
     if (firstTime) {&lt;br /&gt;
         iocshRegister(&amp;amp;vtr10012ConfigFuncDef,vtr10012ConfigCallFunc);&lt;br /&gt;
         firstTime = 0;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
 epicsExportRegistrar(drvVtr10012RegisterCommands);&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
You must also provide a corresponding registrar statement in a &amp;lt;code&amp;gt;.dbd&amp;lt;/code&amp;gt; file:&lt;br /&gt;
 registrar(drvVtr10012RegisterCommands)&lt;br /&gt;
* If your driver provides functions that are referred to by name from database files you must:&lt;br /&gt;
** &amp;lt;code&amp;gt;#include &amp;lt;registryFunction.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
** Add an &amp;lt;code&amp;gt;epicsExportFuncion()&amp;lt;/code&amp;gt; statement for each such function.&lt;br /&gt;
** Add a corresponding &amp;lt;code&amp;gt;function&amp;lt;/code&amp;gt; statement in a &amp;lt;code&amp;gt;.dbd&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
==Additional Information==&lt;br /&gt;
&lt;br /&gt;
The procedure for converting a support module from R3.13 to R3.14 is described in the [http://www.aps.anl.gov/epics/base/R3-14/8-docs/ConvertingR3.13AppsToR3.14.html Converting R3.13 Apps to R3.14] document.&lt;br /&gt;
&lt;br /&gt;
==Acknowledgments==&lt;br /&gt;
&lt;br /&gt;
* Peter Denison (Diamond) for getting me started on this document and for useful suggestions.&lt;br /&gt;
* Steve Shoaf and Nick DiMonte (ANL) for some early conversions.&lt;br /&gt;
* Andrew Johnson for 'wikifying' the contents and setting up this page.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
 Eric Norum 2006-08-17&lt;/div&gt;</summary>
		<author><name>EricNorum</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_make_your_EPICS_driver_operating_system_independent&amp;diff=1394</id>
		<title>How to make your EPICS driver operating system independent</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_make_your_EPICS_driver_operating_system_independent&amp;diff=1394"/>
		<updated>2006-08-18T18:42:48Z</updated>

		<summary type="html">&lt;p&gt;EricNorum: /* Acknowledgments */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=How to make your EPICS driver operating system independent=&lt;br /&gt;
&lt;br /&gt;
'''W. Eric Norum'''&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
The following table shows the changes made to some existing drivers to allow them to be used on systems other than vxWorks. Note that it is a very preliminary start at a set of conversion instructions. There's still no `cookbook' document to guide you, but many drivers can be converted without doing much more than applying the translations shown. A technique that I've found works well is to first change all the &amp;lt;code&amp;gt;#include&amp;lt;/code&amp;gt; statements that mention vxWorks header files to their OSI equivalents, then enter a compile-edit cycle until all compile errors have been eliminated.&lt;br /&gt;
&lt;br /&gt;
==Conversions==&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;3&amp;quot;&lt;br /&gt;
! align=&amp;quot;CENTER&amp;quot; | '''vxWorks'''&lt;br /&gt;
! align=&amp;quot;CENTER&amp;quot; | '''OSI'''&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;vxWorks.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;stdlib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsStdlib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;stdio.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsStdioRedirect.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;iosLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;taskLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsThread.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;memLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;rebootLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsExit.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;intLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsInterrupt.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;lstLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;vme.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;devLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;sysLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;iv.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsExport.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;iocsh.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ERROR&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;-1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OK&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;semLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 SEM_ID flag = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);&lt;br /&gt;
 semGive(flag);&lt;br /&gt;
 semTake(flag, WAIT_FOREVER);&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;epicsEvent.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 epicsEventId flag = epicsEventMustCreate(epicsEventEmpty);&lt;br /&gt;
 epicsEventSignal(flag);&lt;br /&gt;
 epicsEventMustWait(flag);&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;semLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 SEM_ID Lock = semMCreate(SEM_Q_PRIORITY);&lt;br /&gt;
 semTake(Lock, WAIT_FOREVER);&lt;br /&gt;
 semGive(Lock);&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;epicsMutex.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 epicsMutexId Lock = epicsMutexMustCreate();&lt;br /&gt;
 epicsMutexLock(Lock);&lt;br /&gt;
 epicsMutexUnlock(Lock);&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;taskDelay(1)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | To generate a `short' delay:&lt;br /&gt;
 epicsThreadSleep(0.001)&lt;br /&gt;
This works because the operating system specific layer ensures a delay of at least one system clock tick for epicsThreadSleep arguments greater than 0.&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;taskDelay(30)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | Much old code assumes a 60 Hz vxWorks system clock. On such systems the equivalent for the command shown would be:&lt;br /&gt;
 epicsThreadSleep(0.5)&lt;br /&gt;
Of course, other code may assumes a 50 Hz or 100 Hz system clock rate...&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;taskSuspend(0)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsThreadSuspendSelf()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;intConnect(INUM_TO_IVEC(IrqVector), IrqHandler, pLink)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;devConnectInterruptVME(IrqVector, IrqHandler, pLink)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;sysIntEnable(IrqLevel)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;devEnableInterruptLevelVME(IrqLevel)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;sysBusToLocalAdrs(VME_AM_SUP_SHORT_IO, (char*)CardAddress, (char**)&amp;amp;ErLink[Card].pEr)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;devRegisterAddress(&amp;quot;apsEr&amp;quot;, atVMEA16, CardAddress, 0x40, (void*)&amp;amp;ErLink[Card].pEr)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;vxMemProbe(pReg, READ, sizeof(short), &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;devReadProbe(sizeof(short), pReg, &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;vxMemProbe(pReg,WRITE,sizeof(short), &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;devWriteProbe(sizeof(short), pReg, &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;key = intLock()&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;key = epicsInterruptLock()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;intUnlock(key)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsInterrupUnlock(key)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rebootHookAdd((FUNCPTR)ErRebootFunc)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsAtExit(ErRebootFunc, NULL)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;fast_lock.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 FAST_LOCK lock;&lt;br /&gt;
 FASTLOCKINIT(&amp;amp;mzconf[card].lock);&lt;br /&gt;
 FASTLOCKFREE(&amp;amp;mzconf[card].lock);&lt;br /&gt;
 FASTLOCK(&amp;amp;mzconf[card].lock);&lt;br /&gt;
 FASTUNLOCK(&amp;amp;mzconf[card].lock);&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | You'll have to use your judgement here. If the section of code being protected is quick (less than a few microseconds) it's reasonable to simply disable interrupts while the code is active. In this case you can remove the 'lock' variable and the init/free operations and then add a local 'key' variable and replace the lock/unlock operations with epicsInterruptLock/Unlock operations. If the section of code being protected is longer you'll have to convert the FASTLOCK to an EPICS mutex.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;taskSpawn(...)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsThreadCreate(...)&amp;lt;/code&amp;gt;&lt;br /&gt;
You should consider rewriting the driver to use the &amp;quot;worker thread&amp;quot; environment provided by the ASYN package. This is likely to result in a shorter, simpler, and more robust driver.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Some other changes==&lt;br /&gt;
&lt;br /&gt;
* Some R3.13 record support database definitions explicitly mention all fields rather than including dbCommon.dbd. This can cause problems with FAST_LOCK. The solution is to add &amp;lt;code&amp;gt;include &amp;quot;dbCommon.dbd&amp;quot;&amp;lt;/code&amp;gt; at the beginning of the file in question and to remove all entries for the fields provided by dbCommon.dbd.&lt;br /&gt;
* You should set up IOC shell command registrations for all `configure' functions and for any other commands you may need to call from the IOC shell. Here's an example of a fairly complex configuration command:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * IOC shell command registration&lt;br /&gt;
  */&lt;br /&gt;
 #include &amp;lt;iocsh.h&amp;gt;&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg0 = { &amp;quot;card&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg1 = { &amp;quot;VME A16 offset&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg2 = { &amp;quot;VME memory offset&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg3 = { &amp;quot;interrupt vector&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg4 = { &amp;quot;interrupt level&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg5 = { &amp;quot;use DMA&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg6 = { &amp;quot;nchannels&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg7 = { &amp;quot;kilosamplesPerChan&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg *vtr10012ConfigArgs[] = {&lt;br /&gt;
     &amp;amp;vtr10012ConfigArg0, &amp;amp;vtr10012ConfigArg1, &amp;amp;vtr10012ConfigArg2,&lt;br /&gt;
     &amp;amp;vtr10012ConfigArg3, &amp;amp;vtr10012ConfigArg4, &amp;amp;vtr10012ConfigArg5,&lt;br /&gt;
     &amp;amp;vtr10012ConfigArg6,&amp;amp;vtr10012ConfigArg7};&lt;br /&gt;
 static const iocshFuncDef vtr10012ConfigFuncDef =&lt;br /&gt;
                       {&amp;quot;vtr10012Config&amp;quot;,8,vtr10012ConfigArgs};&lt;br /&gt;
 static void vtr10012ConfigCallFunc(const iocshArgBuf *args)&lt;br /&gt;
 {&lt;br /&gt;
     vtr10012Config(args[0].ival, args[1].ival, args[2].ival,&lt;br /&gt;
                  args[3].ival, args[4].ival, args[5].ival,&lt;br /&gt;
                  args[6].ival, args[7].ival);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 /*&lt;br /&gt;
  * This routine is called before multitasking has started, so there's&lt;br /&gt;
  * no race condition in the test/set of firstTime.&lt;br /&gt;
  */&lt;br /&gt;
 static void&lt;br /&gt;
 drvVtr10012RegisterCommands(void)&lt;br /&gt;
 {&lt;br /&gt;
     static int firstTime = 1;&lt;br /&gt;
     if (firstTime) {&lt;br /&gt;
         iocshRegister(&amp;amp;vtr10012ConfigFuncDef,vtr10012ConfigCallFunc);&lt;br /&gt;
         firstTime = 0;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
 epicsExportRegistrar(drvVtr10012RegisterCommands);&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
You must also provide a corresponding registrar statement in a &amp;lt;code&amp;gt;.dbd&amp;lt;/code&amp;gt; file:&lt;br /&gt;
 registrar(drvVtr10012RegisterCommands)&lt;br /&gt;
* If your driver provides functions that are referred to by name from database files you must:&lt;br /&gt;
** &amp;lt;code&amp;gt;#include &amp;lt;registryFunction.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
** Add an &amp;lt;code&amp;gt;epicsExportFuncion()&amp;lt;/code&amp;gt; statement for each such function.&lt;br /&gt;
** Add a corresponding &amp;lt;code&amp;gt;function&amp;lt;/code&amp;gt; statement in a &amp;lt;code&amp;gt;.dbd&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
==Additional Information==&lt;br /&gt;
&lt;br /&gt;
The procedure for converting a support module from R3.13 to R3.14 is described in the [http://www.aps.anl.gov/epics/base/R3-14/8-docs/ConvertingR3.13AppsToR3.14.html Converting R3.13 Apps to R3.14] document.&lt;br /&gt;
&lt;br /&gt;
==Acknowledgments==&lt;br /&gt;
&lt;br /&gt;
* Peter Denison (Diamond) for getting me started on this document and for useful suggestions.&lt;br /&gt;
* Steve Shoaf and Nick DiMonte (ANL) for some early conversions.&lt;br /&gt;
* Andrew Johnson for 'wikifying' the contents and setting up this page.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
 Eric Norum 2006-08-17&lt;/div&gt;</summary>
		<author><name>EricNorum</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_make_your_EPICS_driver_operating_system_independent&amp;diff=1393</id>
		<title>How to make your EPICS driver operating system independent</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=How_to_make_your_EPICS_driver_operating_system_independent&amp;diff=1393"/>
		<updated>2006-08-18T18:41:55Z</updated>

		<summary type="html">&lt;p&gt;EricNorum: /* Conversions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=How to make your EPICS driver operating system independent=&lt;br /&gt;
&lt;br /&gt;
'''W. Eric Norum'''&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
The following table shows the changes made to some existing drivers to allow them to be used on systems other than vxWorks. Note that it is a very preliminary start at a set of conversion instructions. There's still no `cookbook' document to guide you, but many drivers can be converted without doing much more than applying the translations shown. A technique that I've found works well is to first change all the &amp;lt;code&amp;gt;#include&amp;lt;/code&amp;gt; statements that mention vxWorks header files to their OSI equivalents, then enter a compile-edit cycle until all compile errors have been eliminated.&lt;br /&gt;
&lt;br /&gt;
==Conversions==&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;3&amp;quot;&lt;br /&gt;
! align=&amp;quot;CENTER&amp;quot; | '''vxWorks'''&lt;br /&gt;
! align=&amp;quot;CENTER&amp;quot; | '''OSI'''&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;vxWorks.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;stdlib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsStdlib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;stdio.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsStdioRedirect.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;iosLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;taskLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsThread.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;memLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;rebootLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsExit.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;intLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsInterrupt.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;lstLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;vme.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;devLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;sysLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;iv.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;epicsExport.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#include &amp;lt;iocsh.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ERROR&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;-1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OK&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;semLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 SEM_ID flag = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);&lt;br /&gt;
 semGive(flag);&lt;br /&gt;
 semTake(flag, WAIT_FOREVER);&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;epicsEvent.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 epicsEventId flag = epicsEventMustCreate(epicsEventEmpty);&lt;br /&gt;
 epicsEventSignal(flag);&lt;br /&gt;
 epicsEventMustWait(flag);&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;semLib.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 SEM_ID Lock = semMCreate(SEM_Q_PRIORITY);&lt;br /&gt;
 semTake(Lock, WAIT_FOREVER);&lt;br /&gt;
 semGive(Lock);&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;epicsMutex.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 epicsMutexId Lock = epicsMutexMustCreate();&lt;br /&gt;
 epicsMutexLock(Lock);&lt;br /&gt;
 epicsMutexUnlock(Lock);&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;taskDelay(1)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | To generate a `short' delay:&lt;br /&gt;
 epicsThreadSleep(0.001)&lt;br /&gt;
This works because the operating system specific layer ensures a delay of at least one system clock tick for epicsThreadSleep arguments greater than 0.&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;taskDelay(30)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | Much old code assumes a 60 Hz vxWorks system clock. On such systems the equivalent for the command shown would be:&lt;br /&gt;
 epicsThreadSleep(0.5)&lt;br /&gt;
Of course, other code may assumes a 50 Hz or 100 Hz system clock rate...&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;taskSuspend(0)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsThreadSuspendSelf()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;intConnect(INUM_TO_IVEC(IrqVector), IrqHandler, pLink)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;devConnectInterruptVME(IrqVector, IrqHandler, pLink)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;sysIntEnable(IrqLevel)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;devEnableInterruptLevelVME(IrqLevel)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;sysBusToLocalAdrs(VME_AM_SUP_SHORT_IO, (char*)CardAddress, (char**)&amp;amp;ErLink[Card].pEr)&amp;lt;/code&amp;gt;&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;devRegisterAddress(&amp;quot;apsEr&amp;quot;, atVMEA16, CardAddress, 0x40, (void*)&amp;amp;ErLink[Card].pEr)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;vxMemProbe(pReg, READ, sizeof(short), &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;devReadProbe(sizeof(short), pReg, &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;vxMemProbe(pReg,WRITE,sizeof(short), &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;devWriteProbe(sizeof(short), pReg, &amp;amp;value)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;key = intLock()&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;key = epicsInterruptLock()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;intUnlock(key)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsInterrupUnlock(key)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rebootHookAdd((FUNCPTR)ErRebootFunc)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsAtExit(ErRebootFunc, NULL)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | &amp;lt;code&amp;gt;#include &amp;lt;fast_lock.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 FAST_LOCK lock;&lt;br /&gt;
 FASTLOCKINIT(&amp;amp;mzconf[card].lock);&lt;br /&gt;
 FASTLOCKFREE(&amp;amp;mzconf[card].lock);&lt;br /&gt;
 FASTLOCK(&amp;amp;mzconf[card].lock);&lt;br /&gt;
 FASTUNLOCK(&amp;amp;mzconf[card].lock);&lt;br /&gt;
| valign=&amp;quot;TOP&amp;quot; | You'll have to use your judgement here. If the section of code being protected is quick (less than a few microseconds) it's reasonable to simply disable interrupts while the code is active. In this case you can remove the 'lock' variable and the init/free operations and then add a local 'key' variable and replace the lock/unlock operations with epicsInterruptLock/Unlock operations. If the section of code being protected is longer you'll have to convert the FASTLOCK to an EPICS mutex.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;taskSpawn(...)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;epicsThreadCreate(...)&amp;lt;/code&amp;gt;&lt;br /&gt;
You should consider rewriting the driver to use the &amp;quot;worker thread&amp;quot; environment provided by the ASYN package. This is likely to result in a shorter, simpler, and more robust driver.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Some other changes==&lt;br /&gt;
&lt;br /&gt;
* Some R3.13 record support database definitions explicitly mention all fields rather than including dbCommon.dbd. This can cause problems with FAST_LOCK. The solution is to add &amp;lt;code&amp;gt;include &amp;quot;dbCommon.dbd&amp;quot;&amp;lt;/code&amp;gt; at the beginning of the file in question and to remove all entries for the fields provided by dbCommon.dbd.&lt;br /&gt;
* You should set up IOC shell command registrations for all `configure' functions and for any other commands you may need to call from the IOC shell. Here's an example of a fairly complex configuration command:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * IOC shell command registration&lt;br /&gt;
  */&lt;br /&gt;
 #include &amp;lt;iocsh.h&amp;gt;&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg0 = { &amp;quot;card&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg1 = { &amp;quot;VME A16 offset&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg2 = { &amp;quot;VME memory offset&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg3 = { &amp;quot;interrupt vector&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg4 = { &amp;quot;interrupt level&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg5 = { &amp;quot;use DMA&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg6 = { &amp;quot;nchannels&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg vtr10012ConfigArg7 = { &amp;quot;kilosamplesPerChan&amp;quot;,iocshArgInt};&lt;br /&gt;
 static const iocshArg *vtr10012ConfigArgs[] = {&lt;br /&gt;
     &amp;amp;vtr10012ConfigArg0, &amp;amp;vtr10012ConfigArg1, &amp;amp;vtr10012ConfigArg2,&lt;br /&gt;
     &amp;amp;vtr10012ConfigArg3, &amp;amp;vtr10012ConfigArg4, &amp;amp;vtr10012ConfigArg5,&lt;br /&gt;
     &amp;amp;vtr10012ConfigArg6,&amp;amp;vtr10012ConfigArg7};&lt;br /&gt;
 static const iocshFuncDef vtr10012ConfigFuncDef =&lt;br /&gt;
                       {&amp;quot;vtr10012Config&amp;quot;,8,vtr10012ConfigArgs};&lt;br /&gt;
 static void vtr10012ConfigCallFunc(const iocshArgBuf *args)&lt;br /&gt;
 {&lt;br /&gt;
     vtr10012Config(args[0].ival, args[1].ival, args[2].ival,&lt;br /&gt;
                  args[3].ival, args[4].ival, args[5].ival,&lt;br /&gt;
                  args[6].ival, args[7].ival);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 /*&lt;br /&gt;
  * This routine is called before multitasking has started, so there's&lt;br /&gt;
  * no race condition in the test/set of firstTime.&lt;br /&gt;
  */&lt;br /&gt;
 static void&lt;br /&gt;
 drvVtr10012RegisterCommands(void)&lt;br /&gt;
 {&lt;br /&gt;
     static int firstTime = 1;&lt;br /&gt;
     if (firstTime) {&lt;br /&gt;
         iocshRegister(&amp;amp;vtr10012ConfigFuncDef,vtr10012ConfigCallFunc);&lt;br /&gt;
         firstTime = 0;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
 epicsExportRegistrar(drvVtr10012RegisterCommands);&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
You must also provide a corresponding registrar statement in a &amp;lt;code&amp;gt;.dbd&amp;lt;/code&amp;gt; file:&lt;br /&gt;
 registrar(drvVtr10012RegisterCommands)&lt;br /&gt;
* If your driver provides functions that are referred to by name from database files you must:&lt;br /&gt;
** &amp;lt;code&amp;gt;#include &amp;lt;registryFunction.h&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
** Add an &amp;lt;code&amp;gt;epicsExportFuncion()&amp;lt;/code&amp;gt; statement for each such function.&lt;br /&gt;
** Add a corresponding &amp;lt;code&amp;gt;function&amp;lt;/code&amp;gt; statement in a &amp;lt;code&amp;gt;.dbd&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
==Additional Information==&lt;br /&gt;
&lt;br /&gt;
The procedure for converting a support module from R3.13 to R3.14 is described in the [http://www.aps.anl.gov/epics/base/R3-14/8-docs/ConvertingR3.13AppsToR3.14.html Converting R3.13 Apps to R3.14] document.&lt;br /&gt;
&lt;br /&gt;
==Acknowledgments==&lt;br /&gt;
&lt;br /&gt;
* Peter Denison (Diamond) for getting me started on this document and for useful suggestions.&lt;br /&gt;
* Steve Shoaf and Nick DiMonte (ANL) for some early conversions.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
 Eric Norum 2006-08-17&lt;/div&gt;</summary>
		<author><name>EricNorum</name></author>
	</entry>
</feed>