1560 lines
51 KiB
HTML
1560 lines
51 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
|
"http://www.w3.org/TR/html4/loose.dtd">
|
|
<html><head>
|
|
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
|
|
<meta http-equiv="author" content="Dirk Zimoch">
|
|
<style type="text/css">
|
|
<!--
|
|
body { font-family:Arial,sans-serif,espy;
|
|
background:white; margin:0; }
|
|
body,p,ul,ol,dl,div,table {font-size:12pt; }
|
|
p { line-height:120%; }
|
|
pre,code,tt { font-family:"Courier New",Courier,monospace; }
|
|
code,tt { font-size:13pt; }
|
|
h1 { font-size: 24pt; margin-top:1ex; margin-bottom:0; text-align:center; }
|
|
h2 { font-size: 18pt; margin-bottom:0.5ex; }
|
|
h3 { font-size: 14pt; margin-bottom:0.5ex; }
|
|
h4 { font-size: 13pt; margin-bottom:0.5ex; }
|
|
h5 { font-size: 12pt; margin-bottom:0.5ex; }
|
|
small { font-size: 9pt; }
|
|
code { color:#0000C0; }
|
|
li { margin-top: 2pt; margin-bottom: 2pt; }
|
|
pre { font-size: 13pt;
|
|
white-space:pre; }
|
|
.box { border:1px solid #000000;
|
|
background-color:#f4f4f4;
|
|
padding:1ex;
|
|
margin: 0 2ex 1ex 2ex; font-size:90%; }
|
|
th.PageTitle {
|
|
font-size : 14pt;
|
|
font-weight : bold; }
|
|
.menuf {
|
|
font-size:11pt;
|
|
color:#333333;
|
|
font-weight:600;
|
|
text-decoration:none;
|
|
}
|
|
.menuf:link {color:#333333;}
|
|
.menuf:visited {color:#666666;}
|
|
.menuf:hover {color:#FF0000;}
|
|
.menuf:active {color:#FF0000;}
|
|
.menus, .menus a {
|
|
font-size:10pt;
|
|
color:#333333;
|
|
text-decoration:none;
|
|
}
|
|
.menus:visited, .menus a:visited {color:#666666;}
|
|
.menus:hover, .menus a:hover {color:#FF0000;}
|
|
.menus:active, .menus a:active {color:#FF0000;}
|
|
a:hover {color:#FF0000;}
|
|
.red {color:#FF0000;}
|
|
.green {color:#008000;}
|
|
.blue {color:#0000C0;}
|
|
|
|
@media screen {
|
|
.printlayout {display:none;}
|
|
}
|
|
|
|
@media print {
|
|
.screenlayout {display:none;}
|
|
code { color:#000000; }
|
|
a:link {color:#000000;text-decoration:none}
|
|
a:visited {color:#000000;text-decoration:none}
|
|
a:hover {color:#000000;text-decoration:none}
|
|
a:active {color:#000000;text-decoration:none}
|
|
}
|
|
-->
|
|
</style>
|
|
<link rel="shortcut icon" href="http://epics.web.psi.ch/images/sls_icon.ico">
|
|
</head>
|
|
<body bgcolor="#FFFFFF">
|
|
<table cellspacing="0" cellpadding="0" border="0" width="100%">
|
|
|
|
<tr class="screenlayout">
|
|
<td bgcolor="#267ab8" colspan="5" valign="bottom" height="10">
|
|
<img
|
|
src="../images/black"
|
|
width="100%" height="1" alt=""></td>
|
|
</tr>
|
|
|
|
<tr class="screenlayout">
|
|
<td rowspan="2" colspan="2" align="center">
|
|
<a class="menuf" href="http://www.psi.ch"><img
|
|
src="../images/psi_logo" border="0"
|
|
alt="PAUL SCHERRER INSTITUT"></a></td>
|
|
<td rowspan="2"><img
|
|
src="../images/space"
|
|
width="1" height="65" alt=""></td>
|
|
<th class="PageTitle"><center>
|
|
<big>EPICS at PSI<big>
|
|
</center>
|
|
</th>
|
|
<td><img
|
|
src="../images/space"
|
|
width="10" height="1" alt=""></td>
|
|
</tr>
|
|
|
|
<tr class="screenlayout">
|
|
<th width="100%" valign="bottom" align="left">
|
|
<table border="0" cellspacing="0" cellpadding="0"><tr><td><a
|
|
href="https://www.psi.ch"
|
|
class="menuf">PSI</a></td><td><img
|
|
src="../images/space"
|
|
width="10" height="1" alt=""></td><td bgcolor="black"><img
|
|
src="../images/space"
|
|
width="1" height="1" alt=""></td><td><img
|
|
src="../images/space"
|
|
width="10" height="1" alt=""></td><td><a
|
|
href="https://www.aps.anl.gov/epics"
|
|
class="menuf">EPICS</a></td><td><img
|
|
src="../images/space"
|
|
width="10" height="1" alt=""></td><td bgcolor="black"><img
|
|
src="../images/space"
|
|
width="1" height="1" alt=""></td><td><img
|
|
src="../images/space"
|
|
width="10" height="1" alt=""></td><td><a
|
|
href="https://www.psi.ch/en/sls"
|
|
class="menuf">SLS</a></td><td><img
|
|
src="../images/space"
|
|
width="10" height="1" alt=""></td><td bgcolor="black"><img
|
|
src="../images/space"
|
|
width="1" height="1" alt=""></td><td><img
|
|
src="../images/space"
|
|
width="10" height="1" alt=""></td><td><a
|
|
href="https://www.psi.ch/en/swissfel"
|
|
class="menuf">SwissFEL</a></td><td><img
|
|
src="../images/space"
|
|
width="10" height="1" alt=""></td><td bgcolor="black"><img
|
|
src="../images/space"
|
|
width="1" height="1" alt=""></td><td><img
|
|
src="../images/space"
|
|
width="10" height="1" alt=""></td><td><a
|
|
href="https://www.psi.ch/en/protontherapy"
|
|
class="menuf">Proscan</a></td></tr></table>
|
|
</th>
|
|
</tr>
|
|
|
|
<tr class="screenlayout">
|
|
<td height="5" bgcolor="#267ab8" colspan="6" valign="bottom">
|
|
<img
|
|
src="../images/black"
|
|
width="100%" height="1" alt=""></td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="screenlayout" bgcolor="#e3eaf6" valign="top" align="center" width="179">
|
|
<br><a href="http://www.aps.anl.gov/epics"><img
|
|
src="../images/EPICS_small"
|
|
alt="EPICS" border=0></a><br><br>
|
|
<table cellspacing="0" cellpadding="0" border="0" width="100%"><tr><td><img
|
|
src="../images/space"
|
|
width="20" height="29" alt=""></td><th width="100%" align="left"><a
|
|
href="../index.html"
|
|
class="menuf">EPICS at PSI</a>
|
|
<img
|
|
src="../images/black"
|
|
height="1" width="100%" alt=""></th></tr></table>
|
|
<table cellspacing="0" cellpadding="0" border="0" width="100%"><tr><td><img
|
|
src="../images/space"
|
|
width="20" height="29" alt=""></td><th width="100%" align="left"><a
|
|
href="../software.html"
|
|
class="menuf">Software</a>
|
|
<ul style="margin:0 0 0 0; padding-left:1em;">
|
|
<li class="menus"><a href="s7plc.html"
|
|
>PLC Communication</a></li>
|
|
<li class="menus"><a href="streamdevice.html"
|
|
>StreamDevice</a></li>
|
|
<li class="menus"><a href="regDev.html"
|
|
>regDev</a></li>
|
|
<li class="menus"><a href="iocmon.html"
|
|
>IOC Monitoring</a></li>
|
|
<li class="menus"><a href="pcmon.html"
|
|
>PC Monitoring</a></li>
|
|
<li class="menus"><a href="firewire.html"
|
|
>Firewire Camera</a></li>
|
|
<li class="menus"><a href="http://dps.web.psi.ch/template.html?/psc/"
|
|
>Digital PS Control</a></li>
|
|
<li class="menus"><a href="tclioc.html"
|
|
>Tcl-IOC</a></li>
|
|
<li class="menus"><a href="iocLogBrowser.html"
|
|
>iocLogBrowser</a></li>
|
|
<li class="menus"><a href="ioc-octave.html"
|
|
>IOC-Octave</a></li>
|
|
<li class="menus"><a href="http://gfa-it.web.psi.ch/epicsSharp/"
|
|
>C# EPICS</a></li>
|
|
<li class="menus"><a href="generalTime.html"
|
|
>generalTime</a></li>
|
|
<li class="menus"><a href="GPMM.html"
|
|
>GPMM</a></li>
|
|
<li class="menus"><a href="sequencer.html"
|
|
>SNC/SEQ</a></li>
|
|
<li class="menus"><a href="caqtdm.html"
|
|
>caQtDM</a></li>
|
|
<li class="menus"><a href="CSDataQuick.html"
|
|
>CSDataQuick</a></li>
|
|
</ul>
|
|
<img
|
|
src="../images/black"
|
|
height="1" width="100%" alt=""></th></tr></table>
|
|
<table cellspacing="0" cellpadding="0" border="0" width="100%"><tr><td><img
|
|
src="../images/space"
|
|
width="20" height="29" alt=""></td><th width="100%" align="left"><a
|
|
href="../training.html"
|
|
class="menuf">Training</a>
|
|
<ul style="margin:0 0 0 0; padding-left:1em;">
|
|
<li class="menus"><a href="../training/PSI-training.html"
|
|
>Courses at PSI</a></li>
|
|
<li class="menus"><a href="../training/caClientLessons.html"
|
|
>CA client lessons</a></li>
|
|
<li class="menus"><a href="../training/downloads.html"
|
|
>Downloads</a></li>
|
|
</ul>
|
|
<img
|
|
src="../images/black"
|
|
height="1" width="100%" alt=""></th></tr></table>
|
|
<form method="get" action="http://www.google.com/search">
|
|
<table border="0" cellpadding="0" cellspacing="0">
|
|
<tr><td align="center" nowrap>
|
|
<input type="search" placeholder="search" name="q" size="13" maxlength="255" value=""><br>
|
|
<input type="hidden" name="domains" value="epics.web.psi.ch">
|
|
<small>
|
|
<input type="radio" name="sitesearch" value=""> web
|
|
<input type="radio" name="sitesearch" value="epics.web.psi.ch"
|
|
checked="checked"> epics.web.psi.ch<br>
|
|
</small>
|
|
</td></tr></table>
|
|
</form><p></p><small>
|
|
Author: <a href="mailto:Dirk Zimoch <dirk.zimoch@psi.ch>?subject=http://epics.web.psi.ch%2Fsoftware%2FregDev%2F">Dirk Zimoch</a><br>
|
|
Phone: +41 56 310 5182<br>
|
|
Updated: 24.08.2021<br>
|
|
<br><a
|
|
href="http://epics.web.psi.ch/software/regDev/%2Fsoftware%2FregDev%2Findex.php?forprint"><img
|
|
src="../images/printer"
|
|
border="0" alt=""></a>
|
|
<br><a
|
|
href="http://epics.web.psi.ch/software/regDev/%2Fsoftware%2FregDev%2Findex.php?forprint">Printer friendly version</a>
|
|
<br> </small><br><div><a href="http://validator.w3.org/check?uri=http://epics.web.psi.ch/software/regDev/index.php&ss=1"><img
|
|
border="0" src="../images/valid-html401.png"
|
|
alt="[Validate HTML]" height="31" width="88"></a><a
|
|
href="http://jigsaw.w3.org/css-validator/validator?uri=http://epics.web.psi.ch/software/regDev/index.php"><img
|
|
style="border:0;width:88px;height:31px"
|
|
src="../images/vcss.png"
|
|
alt="[Validate CSS]"></a></div>
|
|
<br><img
|
|
src="../images/space"
|
|
width="179" height="1" alt=""></td>
|
|
<td width="1" bgcolor="#000000"><img
|
|
src="../images/space"
|
|
width="1" height="1" alt=""></td>
|
|
<td><img
|
|
src="../images/space"
|
|
width="10" height="1" alt=""></td>
|
|
<td valign="top" width="100%" colspan="2">
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
<html>
|
|
<head>
|
|
<title>RegDev EPICS Device Support</title>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
|
<meta name="author" content="Dirk Zimoch">
|
|
<style type="text/css">
|
|
<!--
|
|
.indent {text-indent:-4ex; margin-left:4ex; text-align:left;}
|
|
@media screen {
|
|
pre,code {color:green; }
|
|
}
|
|
@media print {
|
|
a {color:black; text-decoration:none; }
|
|
}
|
|
-->
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1><em>RegDev</em> EPICS Device Support Documentation</h1>
|
|
<h2>Contents</h2>
|
|
<ol>
|
|
<li><a href="regDev.html#device">Device Support</a>
|
|
<ol>
|
|
<li><a href="regDev.html#stat">Connection Status (bi)</a></li>
|
|
<li><a href="regDev.html#ai">Analog Input (ai)</a></li>
|
|
<li><a href="regDev.html#ao">Analog Output (ao)</a></li>
|
|
<li><a href="regDev.html#calcout">Calculation Output (calcout)</a></li>
|
|
<li><a href="regDev.html#bi">Binary Input (bi)</a></li>
|
|
<li><a href="regDev.html#bo">Binary Outpu (bo)t</a></li>
|
|
<li><a href="regDev.html#mbbi">Multi Bit Binary Input (mbbi)</a></li>
|
|
<li><a href="regDev.html#mbbo">Multi Bit Binary Output (mbbo)</a></li>
|
|
<li><a href="regDev.html#mbbiDirect">Multi Bit Binary Input Direct (mbbiDirect)</a></li>
|
|
<li><a href="regDev.html#mbboDirect">Multi Bit Binary Output Direct (mbboDirect)</a></li>
|
|
<li><a href="regDev.html#longin">Long Input (longin)</a></li>
|
|
<li><a href="regDev.html#longout">Long Output (longout)</a></li>
|
|
<li><a href="regDev.html#int64in">Integer 64 bit Input (int64in)</a></li>
|
|
<li><a href="regDev.html#int64out">Integer 64 bit Output (int64out)</a></li>
|
|
<li><a href="regDev.html#stringin">String Input (stringin)</a></li>
|
|
<li><a href="regDev.html#stringout">String Output (stringout)</a></li>
|
|
<li><a href="regDev.html#waveform">Waveform Input (waveform)</a></li>
|
|
<li><a href="regDev.html#aai">Array Analog Input (aai)</a></li>
|
|
<li><a href="regDev.html#aao">Array Analog Output (aao)</a></li>
|
|
</ol></li>
|
|
<li><a href="regDev.html#driver">Driver Functions</a></li>
|
|
<li><a href="regDev.html#debugging">Debugging</a></li>
|
|
</ol>
|
|
<h2>Intro</h2>
|
|
<p>
|
|
In this document, I assume that the reader is familiar with EPICS, the
|
|
record concept and meanings of the fields of the standard records.
|
|
Recommended reading: EPICS Record Reference Manual.
|
|
</p>
|
|
<p>
|
|
This generic device support is intended to connect arbitrary synchronous
|
|
register based devices to EPICS in a simple and flexible way.
|
|
It can be used for rapid prototyping before a proper driver is available,
|
|
to access registers that are unsupported by the proper driver or as the
|
|
ultimate driver for any device which is "simple enough".
|
|
</p>
|
|
<p>
|
|
It is assumed that the device allocates a continuous block of registers.
|
|
The registers should be independent, that means one device action is
|
|
performed by reading or writing only one register.
|
|
Because each record connects to one register, it is not possible to lock
|
|
the device for several register accesses with this device support,
|
|
except if that task is performed in the low level driver and hidden from
|
|
<em>regDev</em>.
|
|
The user has to know the register offsets and data types when configuring
|
|
the records.
|
|
</p>
|
|
<p>
|
|
The actual hardware access is neither defined nor implemented in this
|
|
device support.
|
|
Instead, <em>regDev</em> defines an interface for low level drivers that
|
|
implement the hardware access.
|
|
Examples are <em>mmap</em> (a driver for memory mapped registers, VME or
|
|
mmap()) or <em>s7plc</em> (a driver for network communication to a Siemens
|
|
S7 PLC).
|
|
What is defined in <em>regDev</em> is the interface to the standard
|
|
records.
|
|
Thus it is not necessary to deal with record when writing a new low-level
|
|
driver.
|
|
Consequently, all <em>regDev</em> compatible devices look the same
|
|
on the record level.
|
|
The general idea is to have a simple and flexible device support interface
|
|
which is independent of the underlying hardware structure.
|
|
</p>
|
|
<p>
|
|
To be usable with <em>regDev</em>, a driver must implement some API
|
|
functions and register a device to <em>regDev</em> by name.
|
|
Each piece of <em>regDev</em> hardware must have a name that is unique on
|
|
the IOC.
|
|
Typically, the low level driver registers a device in a configuration
|
|
function called from the startup script.
|
|
</p>
|
|
<p>
|
|
In principle, a piece of hardware can have many blocks of registers
|
|
(e.g. on differenct VME address spaces).
|
|
The low level driver may handle this by mapping ranges of register offsets
|
|
to different blocks.
|
|
Or the low level driver registers each block with an individual name.
|
|
But then, <em>regDev</em> will handle them as different independent
|
|
devices.
|
|
</p>
|
|
<p>
|
|
A demo driver is included.
|
|
</p>
|
|
<p>
|
|
<a href="mailto:Dirk Zimoch <dirk.zimoch@psi.ch>">Dirk
|
|
Zimoch <dirk.zimoch@psi.ch></a>, 2009.
|
|
</p>
|
|
|
|
|
|
<a name="device"></a>
|
|
<h2>Device Support</h2>
|
|
<p>
|
|
<em>RegDev</em> supports the standard record types
|
|
<a href="regDev.html#ai">ai</a>,
|
|
<a href="regDev.html#ao">ao</a>,
|
|
<a href="regDev.html#bi">bi</a>,
|
|
<a href="regDev.html#bo">bo</a>,
|
|
<a href="regDev.html#mbbi">mbbi</a>,
|
|
<a href="regDev.html#mbbo">mbbo</a>,
|
|
<a href="regDev.html#mbbiDirect">mbbiDirect</a>,
|
|
<a href="regDev.html#mbboDirect">mbboDirect</a>,
|
|
<a href="regDev.html#longin">longin</a>,
|
|
<a href="regDev.html#longout">longout</a>,
|
|
<a href="regDev.html#stringin">stringin</a>,
|
|
<a href="regDev.html#stringout">stringout</a>,
|
|
and <a href="regDev.html#waveform">waveform</a>.
|
|
From EPICS R3.14.5 on <a href="regDev.html#calcout">calcout</a> is supported.
|
|
From EPICS R3.14.12 on <a href="regDev.html#aai">aai</a> and <a href="regDev.html#aao">aao</a>
|
|
records are supported.
|
|
(These records used to be commented out in earlier EPICS versions.)
|
|
From EPICS R3.16 on <a href="regDev.html#int64in">int64in</a> and
|
|
<a href="regDev.html#int64out">int64out</a> are supported.
|
|
</p>
|
|
<p>
|
|
The <code>DTYP</code> is <code>"regDev"</code> for all record types,
|
|
independent of the low level driver.
|
|
</p>
|
|
<p>
|
|
If a record processes when the device is not connected (off, down,
|
|
unreachable), the record raises an alarm with <code>SEVR="INVALID"</code>
|
|
and <code>STAT="READ"</code> or <code>"WRITE"</code>
|
|
</p>
|
|
<p>
|
|
There is also a connection status support for <a href="regDev.html#stat">bi</a>. The
|
|
<code>DTYP</code> is <code>"regDev stat"</code>. This record does not
|
|
raise an alarm when the device is disconnected. It just changes to
|
|
<code>0</code> when the device disconencts and to 1 when it connects.
|
|
</p>
|
|
<p>
|
|
It is possible to use <code>SCAN="I/O Intr"</code> if the low level driver
|
|
supports it.
|
|
Input records in <code>"I/O Intr"</code> process whenever new data has
|
|
been received from the device.
|
|
If supported by the driver, output records are processed in
|
|
<code>"I/O Intr"</code> mode whenever the driver is ready to accept new
|
|
output.
|
|
This may be useful for drivers with externally triggered or periodic
|
|
output cycles.
|
|
</p>
|
|
<p class="indent">
|
|
The general form of the <code>INP</code> or <code>OUT</code> link is:<br>
|
|
<code>
|
|
"@<i>devicename</i>:<i>offset</i>:<i>initoffset</i> T=<i>type</i>
|
|
L=<i>low</i> H=<i>high</i> B=<i>bit</i> I=<i>invertmask</i>
|
|
P=<i>packing</i> U=<i>update_ms</i>"
|
|
</code>
|
|
</p>
|
|
<ul>
|
|
<li>
|
|
<code><i>devicename</i></code> is the name that a low level driver has
|
|
used to register the device.
|
|
</li>
|
|
<li>
|
|
<code><i>offset</i></code> is the address of the register relative to the
|
|
beginning of the register block for this device.
|
|
It depends on the low level driver if offset is measured in bytes
|
|
or anything else.
|
|
The offset must be a positive integer expression within the limits of
|
|
the device register block size.
|
|
It may be calculated using the operators <code>+-*()</code>.<br>
|
|
It is possible to calculate <code><i>offset</i></code> dynamically from
|
|
another record. In this case the name of the other record must be the the
|
|
first operand in the calculation. If the record name contains any of the
|
|
characters <code>:+-*()</code>, it must be single quoted.<br>
|
|
Example: <code>'otherrecord'*8+0x100</code>;<br>
|
|
If dynamic offsets exceed the limits of the register block, the record
|
|
will rais an <code>INVALID</code> alarm.
|
|
</li>
|
|
<li>
|
|
<code><i>initoffset</i></code> is optionally used by output records to
|
|
initialize from a hardware register.
|
|
If <code><i>initoffset</i></code> is not specified but the second
|
|
<code>:</code> is there, the record initializes from the normal
|
|
<code><i>offset</i></code> address.
|
|
If <code>:<i>initoffset</i></code> is skipped (including the
|
|
<code>:</code>),
|
|
the record is not initialized by <em>regDev</em> and may be initialized
|
|
for example by auto save and restore.
|
|
Records read from <code><i>initoffset</i></code> during the
|
|
<code>init_record</code> phase in unpredictable order.
|
|
</li>
|
|
<li>
|
|
<code>T=<i>type</i></code> defines the data type of the register.
|
|
See <a href="regDev.html#type">table below</a>.
|
|
The default is <code>T=int16</code> for most record types.
|
|
</li>
|
|
<li>
|
|
<code>L=<i>low</i></code> and <code>H=<i>high</i></code> are used for
|
|
linear conversion in <a href="http://epics.web.psi.ch/software/regDev/ai">ai</a> and <a href="http://epics.web.psi.ch/software/regDev/ao">ao</a> records
|
|
if <code>LINR=LINEAR</code> and in <a href="http://epics.web.psi.ch/software/regDev/waveform">waveform</a>,
|
|
<a href="http://epics.web.psi.ch/software/regDev/aai">aai</a> and <a href="http://epics.web.psi.ch/software/regDev/aao">aao</a> if <code>FTVL=FLOAT</code>
|
|
or <code>DOUBLE</code> and <code>T</code> is an integer type.
|
|
They define the raw values which correspond to <code>EGUL</code> and
|
|
<code>EGUF</code> (or <code>LOPR</code> and <code>HOPR</code> for arrays)
|
|
respectively.
|
|
Output records will never write intger values lower than
|
|
<code>L</code> or higher than <code>H</code>.
|
|
Instead the output value saturates at the nearest limit.
|
|
The default values for
|
|
<code>L</code> and <code>H</code> depend on the data type.
|
|
</li>
|
|
<li>
|
|
<code>B=<i>bit</i></code> is only used for <a href="regDev.html#bi">bi</a> and
|
|
<a href="regDev.html#bo">bo</a> records to define the bit number within the data
|
|
byte, word, or doubleword (depending on <code>T</code>).
|
|
Bit number 0 is the least significant bit.
|
|
Note that in big endian byte order (also known as motorola format) bit 0
|
|
is in the last byte, while in little endian byte order (intel format)
|
|
bit 0 is in the first byte.
|
|
If in doubt and allowed by the hardware, use <code>T=byte</code> to avoid
|
|
all byte order problems when handling single bits.
|
|
</li>
|
|
<li>
|
|
<code>I=<i>invertmask</i></code> is used to flip bits of integer values
|
|
before writing them to or after reading them from a register.
|
|
This allows to invert the logic of bits.
|
|
The default value is 0 (i.e. do not flip bits).
|
|
</li>
|
|
<li>
|
|
<code>P=<i>packing</i></code> is used for accessing arrays through
|
|
FIFO registers.
|
|
It defines how many array elements are packed in one register access.
|
|
For example <code>T=int16 P=1</code> defines a FIFO of 16 bit values
|
|
while <code>T=int16 P=2</code> is a FIFO with 32 bits width that
|
|
contains two 16 bit values in each access.
|
|
</li>
|
|
<li>
|
|
<code>U=<i>update_ms</i></code> is used to update output records
|
|
periodically. Every <code><i>update_ms</i></code> milliseconds the output
|
|
record reads back the value from the register at <code><i>initoffset</i></code>
|
|
or <code><i>offset</i></code> if <code><i>initoffset</i></code> is not specified.
|
|
</li>
|
|
</ul>
|
|
<p>
|
|
Not all parameters <code>T</code>, <code>L</code>, <code>H</code>,
|
|
<code>B</code>, <code>I</code>, and <code>P</code> are always
|
|
required.
|
|
Unused parameters or parameters equal to the default value may be omitted.
|
|
The default values depend on the data type.
|
|
All parameters are case insensitive.
|
|
</p>
|
|
<a name="type"></a>
|
|
<center>
|
|
<table border=1 cellpadding=5>
|
|
<tr>
|
|
<th>T</th>
|
|
<th>Register Data Type</th>
|
|
<th>Default L</th>
|
|
<th>Default H</th>
|
|
</tr>
|
|
<tr>
|
|
<td><tt>int8</tt>
|
|
</td><td>8 bit (1 byte) signed integer number</td>
|
|
<td><tt>-0x7f<br>-127</tt></td>
|
|
<td><tt>0x7f<br>127</tt></td>
|
|
</tr>
|
|
<tr>
|
|
<td><tt>uint8<br>unsign8<br>unsigned8<br>byte<br>char</tt>
|
|
</td><td>8 bit (1 byte) unsigned integer number</td>
|
|
<td><tt>0x00<br>0</tt></td>
|
|
<td><tt>0xff<br>255</tt></td>
|
|
</tr>
|
|
<tr>
|
|
<td><tt>int16<br>short</tt></td>
|
|
<td>16 bit (2 bytes) signed integer number</td>
|
|
<td><tt>-0x7fff<br>-32767</tt></td>
|
|
<td><tt>0x7fff<br>32767</tt></td>
|
|
</tr>
|
|
<tr>
|
|
<td><tt>uint16<br>unsign16<br>unsigned16<br>word</tt></td>
|
|
<td>16 bit (2 bytes) unsigned integer number</td>
|
|
<td><tt>0x0000<br>0</tt></td>
|
|
<td><tt>0xffff<br>65535</tt></td>
|
|
</tr>
|
|
<tr>
|
|
<td><tt>int32<br>long</tt></td>
|
|
<td>32 bit (4 bytes) signed integer number</td>
|
|
<td><tt>-0x7fffffff<br>-2147483647</tt></td>
|
|
<td><tt>0x7fffffff<br>2147483647</tt></td>
|
|
</tr>
|
|
<tr>
|
|
<td><tt>uint32<br>unsign32<br>unsigned32<br>dword</tt></td>
|
|
<td>32 bit (4 bytes) unsigned integer number</td>
|
|
<td><tt>0x00000000<br>0</tt></td>
|
|
<td><tt>0xffffffff<br>4294967295</tt></td>
|
|
</tr>
|
|
<tr>
|
|
<td><tt>int64<br>longlong</tt></td>
|
|
<td>64 bit (8 bytes) signed integer number</td>
|
|
<td><tt>-0x7fffffffffffffff<br>-9223372036854775807</tt></td>
|
|
<td><tt>0x7fffffffffffffff<br>9223372036854775807</tt></td>
|
|
</tr>
|
|
<tr>
|
|
<td><tt>uint64<br>unsign64<br>unsigned64<br>dword</tt></td>
|
|
<td>64 bit (8 bytes) unsigned integer number</td>
|
|
<td><tt>0x0000000000000000<br>0</tt></td>
|
|
<td><tt>0xffffffffffffffff<br>18446744073709551615</tt></td>
|
|
</tr>
|
|
<tr>
|
|
<td><tt>bcd8<br>bcd</tt>
|
|
</td><td>8 bit (1 byte, 2 digits) unsigned binary coded decimal</td>
|
|
<td><tt>00</tt></td>
|
|
<td><tt>99</tt></td>
|
|
</tr>
|
|
<tr>
|
|
<td><tt>bcd16</tt>
|
|
</td><td>16 bit (2 bytes, 4 digits) unsigned binary coded decimal</td>
|
|
<td><tt>0000</tt></td>
|
|
<td><tt>9999</tt></td>
|
|
</tr>
|
|
<tr>
|
|
<td><tt>bcd32</tt>
|
|
</td><td>32 bit (4 bytes, 8 digits) unsigned binary coded decimal</td>
|
|
<td><tt>00000000</tt></td>
|
|
<td><tt>99999999</tt></td>
|
|
</tr>
|
|
<tr>
|
|
<td><tt>bcd64</tt>
|
|
</td><td>64 bit (8 bytes, 16 digits) unsigned binary coded decimal</td>
|
|
<td><tt>0000000000000000</tt></td>
|
|
<td><tt>9999999999999999</tt></td>
|
|
</tr>
|
|
<tr>
|
|
<td><tt>real32<br>float32<br>float<br>single</tt></td>
|
|
<td>32 bit (4 bytes) floating point number</td>
|
|
<td>n/a</td><td>n/a</td>
|
|
</tr>
|
|
<tr>
|
|
<td><tt>real64<br>float64<br>double</tt></td>
|
|
<td>64 bit (8 bytes) floating point number</td>
|
|
<td>n/a</td><td>n/a</td>
|
|
</tr>
|
|
<tr>
|
|
<td><tt>string</tt></td>
|
|
<td>character array</td>
|
|
<td>40</td><td>n/a</td>
|
|
</tr>
|
|
</table>
|
|
</center>
|
|
|
|
<p>
|
|
If <code>T=string</code>, <code>L</code> means <i>length</i>,
|
|
not <i>low</i>.
|
|
The length includes the terminating null byte.
|
|
The default value is the length of the <code>VAL</code> field.
|
|
In the case of the stringin and stringout records, this is 40.
|
|
In case of array records (<a href="regDev.html#aai">aai</a>, <a href="regDev.html#aao">aao</a>,
|
|
<a href="regDev.html#waveform">waveform</a>) with <code>CHAR</code>
|
|
data this is the size of the array (usually <code>NELM</code>).
|
|
</p>
|
|
<p>
|
|
Note that for signed integer types, <code>L</code> is one off the smallest
|
|
possible value. This makes linear conversion symmatric on the positive
|
|
and negative side (i.e. makes sure 0 is in the middle).
|
|
As a side effect, the most negative value will never be written to the
|
|
register but will be saturated to <code>L</code>.
|
|
If that is a problem, set <code>L</code> explicitly (and maybe adjust
|
|
<code>LOPR</code>).
|
|
</p>
|
|
|
|
<h2>Example Records</h2>
|
|
<p>
|
|
In the following examples it is assumed that the low level driver supports
|
|
<code>"I/O Intr"</code> for input registers.
|
|
If that is not the case or not applicable for all registers use any other
|
|
scanning method instead.
|
|
All output records in the examples use <code>PINI=YES</code> to make sure
|
|
an initial value is written to the register. Depending on the low level driver,
|
|
this may not be necessary if the record gets initialized from an
|
|
<code><i>initoffset</i></code>.
|
|
</p>
|
|
|
|
<a name="stat"></a>
|
|
<h3>Connection Status (bi)</h3>
|
|
<pre>
|
|
record (bi, "$(RECORDNAME)") {
|
|
field (DTYP, "regDev stat")
|
|
field (INP, "@$(DEVICE)")
|
|
field (SCAN, "I/O Intr")
|
|
}
|
|
</pre>
|
|
<p>
|
|
The record value is 1 if a connection to the device is established and 0
|
|
if not.
|
|
Disconnect does not raise an alarm.
|
|
</p>
|
|
|
|
<a name="ai"></a>
|
|
<h3>Analog Input (ai)</h3>
|
|
<h4>Integer registers with linear conversion</h4>
|
|
<pre>
|
|
record (ai, "$(RECORDNAME)") {
|
|
field (DTYP, "regDev")
|
|
field (INP, "@$(DEVICE):$(OFFSET) T=$(T) L=$(L) H=$(H)")
|
|
field (SCAN, "I/O Intr")
|
|
field (LINR, "LINEAR")
|
|
field (EGUL, "$(MINVAL)")
|
|
field (EGUF, "$(MAXVAL)")
|
|
}
|
|
</pre>
|
|
<p>
|
|
If <code>T</code> is an integer type, the register is read into
|
|
<code>RVAL</code>.
|
|
If <code>LINR=LINEAR</code>, then the record
|
|
converts <code>RVAL</code> to <code>VAL</code> so that <code>L</code>
|
|
maps to <code>MINVAL</code> and <code>H</code> maps to <code>MAXVAL</code>.
|
|
</p>
|
|
<p>
|
|
Default type is <code>T=int16</code>.
|
|
Defaults for <code>L</code> and <code>H</code> depend
|
|
on <code>T</code> (see table <a href="regDev.html#type">above</a>).
|
|
</p>
|
|
<h4>Floating point registers</h4>
|
|
<p>
|
|
</p>
|
|
<pre>
|
|
record (ai, "$(RECORDNAME)") {
|
|
field (DTYP, "regDev")
|
|
field (INP, "@$(DEVICE):$(OFFSET) T=$(T)")
|
|
field (SCAN, "I/O Intr")
|
|
}
|
|
</pre>
|
|
<p>
|
|
If <code>T=float</code> or <code>T=double</code>,
|
|
the register is read directly into <code>VAL</code> and <code>L</code>,
|
|
<code>H</code>, <code>EGUL</code> and <code>EGUF</code> are ignored.
|
|
The device support emulates adjustment scaling and smoothing according to
|
|
<code>ASLO</code>, <code>AOFF</code> and <code>SMOO</code> which is done
|
|
by the record itself only when using conversion from integer registers.
|
|
</p>
|
|
<p>
|
|
<code>VAL = (<i>register</i>*ASLO+AOFF)*(1-SMOO) +
|
|
VAL<sub>old</sub>*SMOO</code>
|
|
</p>
|
|
<p>
|
|
<code>T=string</code> is not valid for ai records.
|
|
</p>
|
|
|
|
<a name="ao"></a>
|
|
<h3>Analog Output (ao)</h3>
|
|
<h4>Integer registers with linear conversion</h4>
|
|
<pre>
|
|
record (ao, "$(RECORDNAME)") {
|
|
field (DTYP, "regDev")
|
|
field (OUT, "@$(DEVICE):$(OFFSET) T=$(T) L=$(L) H=$(H)")
|
|
field (LINR, "LINEAR")
|
|
field (PINI, "YES")
|
|
field (EGUL, "$(MINVAL)")
|
|
field (EGUF, "$(MAXVAL)")
|
|
}
|
|
</pre>
|
|
<p>
|
|
If <code>T</code> is an integer type, <code>RVAL</code> is written to the
|
|
register.
|
|
If <code>LINR=LINEAR</code>, then the record
|
|
support first scales the record value (to be exact <code>OVAL</code>) so
|
|
that <code>MINVAL</code> maps to <code>L</code> and <code>MAXVAL</code>
|
|
maps to <code>H</code>.
|
|
The record may then use adjustment scaling to modify <code>RVAL</code>.
|
|
However, the device support will never write any value lower than
|
|
<code>L</code> or higher than <code>H</code>.
|
|
If necessary the value will be saturated to the nearest limit.
|
|
</p>
|
|
<p>
|
|
Default type is <code>T=int16</code>.
|
|
Defaults for <code>L</code> and <code>H</code> depend
|
|
on <code>T</code> (see table <a href="regDev.html#type">above</a>).
|
|
</p>
|
|
<h4>Floating point registers</h4>
|
|
<pre>
|
|
record (ao, "$(RECORDNAME)") {
|
|
field (DTYP, "regDev")
|
|
field (OUT, "@$(DEVICE):$(OFFSET) T=$(T)")
|
|
field (PINI, "YES")
|
|
}
|
|
</pre>
|
|
<p>
|
|
If <code>T=float</code> or <code>T=double</code>,
|
|
<code>OVAL</code> is written to the register. <code>L</code>,
|
|
<code>H</code>, <code>EGUL</code> and <code>EGUF</code> are ignored.
|
|
The device support emulates adjustment scaling according to
|
|
<code>AOFF</code> and <code>ASLO</code> which is done by the
|
|
record itself only when converting to integer registers.
|
|
</p>
|
|
<p>
|
|
<code><i>register</i>=(OVAL-AOFF)/ASLO</code>
|
|
</p>
|
|
<p>
|
|
<code>T=string</code> is not valid for ao records.
|
|
</p>
|
|
|
|
<a name="calcout"></a>
|
|
<h3>Calculation Output (calcout)</h3>
|
|
<pre>
|
|
record(calcout, "$(NAME)") {
|
|
field (DTYP, "regDev")
|
|
field (OUT, "@$(DEVICE):$(OFFSET) T=$(T) L=$(L) H=$(H)")
|
|
field (PINI, "YES")
|
|
}
|
|
</pre>
|
|
<p>
|
|
Default type is <code>T=int16</code>.
|
|
Defaults for <code>L</code> and <code>H</code> depend
|
|
on <code>T</code> (see table <a href="regDev.html#type">above</a>).
|
|
</p>
|
|
<p>
|
|
<code>OVAL</code> (the result of <code>CALC</code> or <code>OCAL</code>,
|
|
depending on <code>DOPT</code>) is written to the register. If
|
|
<code>T</code> is an integer type, the value is truncated to an
|
|
integer and compared to <code>L</code> and <code>H</code>.
|
|
If <code>OVAL</code> is lower than <code>L</code> or higher than
|
|
<code>H</code>, it is saturated to the nearest limit.
|
|
</p>
|
|
<p>
|
|
If <code>T=float</code> or <code>T=double</code>,
|
|
<code>OVAL</code> is written to the register directly without any
|
|
conversion.
|
|
</p>
|
|
<p>
|
|
<code>T=string</code> is not valid for calcout records.
|
|
</p>
|
|
<p>
|
|
To use this device support with calcout records, you need at least EPICS R3.14.5.
|
|
</p>
|
|
|
|
<a name="bi"></a>
|
|
<h3>Binary Input (bi)</h3>
|
|
<pre>
|
|
record(bi, "$(NAME)") {
|
|
field (DTYP, "regDev")
|
|
field (INP, "@$(DEVICE):$(OFFSET) T=$(T) B=$(B) I=$(I)")
|
|
field (SCAN, "I/O Intr")
|
|
}
|
|
</pre>
|
|
<p>
|
|
Default type is <code>T=int16</code>.
|
|
Default bit is <code>B=0</code>.
|
|
Default invert mask is <code>I=0</code>.
|
|
</p>
|
|
<p>
|
|
Depending on <code>T</code>, <code>B</code> can vary from 0 to 7, 15,
|
|
or 31.
|
|
Bit 0 is the least significant bit. In little endian byte order, bit 0 is
|
|
in the first byte, in big endian byte order it is in the last byte of the
|
|
register.
|
|
If in doubt and allowed by the hardware, use <code>T=byte</code> to avoid
|
|
all byte order problems when handling single bits.
|
|
</p>
|
|
<p>
|
|
The register is read to <code>RVAL</code> and masked with
|
|
2<sup><code>B</code></sup>.
|
|
If <code>I!=0</code> the bit is inverted.
|
|
The record sets <code>VAL</code> to 1 if <code>RVAL</code> is not 0.
|
|
</p>
|
|
<p>
|
|
<code>RVAL=(I==0?<i>register</i>:~<i>register</i>)&(1<<B);
|
|
VAL=(RVAL!=0)?1:0</code>
|
|
</p>
|
|
<p>
|
|
<code>T=string</code>, <code>T=float</code> or <code>T=double</code> are
|
|
not valid for bo records. Signed and unsigned types are equivalent.
|
|
</p>
|
|
|
|
<a name="bo"></a>
|
|
<h3>Binary Output (bo)</h3>
|
|
<pre>
|
|
record(bo, "$(NAME)") {
|
|
field (DTYP, "regDev")
|
|
field (OUT, "@$(DEVICE):$(OFFSET) T=$(T) B=<i>$(B)</i>")
|
|
field (PINI, "YES")
|
|
}
|
|
</pre>
|
|
<p>
|
|
Default type is <code>T=int16</code>. Default bit is <code>B=0</code>.
|
|
</p>
|
|
<p>
|
|
Depending on <code>T</code>, <code>B</code> can vary from 0 to 7, 15, or
|
|
31.
|
|
Bit 0 is the least significant bit.
|
|
In little endian byte order, bit 0 is in the first byte, in big endian byte
|
|
order it is in the last byte of the register.
|
|
If in doubt and allowed by the hardware, use <code>T=byte</code> to avoid
|
|
all byte order problems when handling single bits.
|
|
</p>
|
|
<p>
|
|
If <code>VAL</code> is not 0, then <code>RVAL</code> is set to
|
|
2<sup><code>B</code></sup>, else <code>RVAL</code> is set to 0.
|
|
Only the referenced bit of the register is modified while all other bits
|
|
remain unchanged.
|
|
Thus, other output records can write to different bits of the same
|
|
register.
|
|
<p>
|
|
<code>RVAL=(VAL!=0)?(1<<<i>B</i>):0;
|
|
<i>register</i>=(<i>register</i><sub>old</sub>&~(1<<<i>B</i>)) |
|
|
RVAL</code>
|
|
</p>
|
|
<p>
|
|
<code>T=string</code>, <code>T=float</code> or <code>T=double</code> are
|
|
not valid for bo records. Signed and unsigned types are equivalent.
|
|
</p>
|
|
|
|
<a name="mbbi"></a>
|
|
<h3>Multi Bit Binary Input (mbbi)</h3>
|
|
<pre>
|
|
record(mbbi, "$(NAME)") {
|
|
field (DTYP, "regDev")
|
|
field (INP, "@$(DEVICE):$(OFFSET) T=$(T)")
|
|
field (SCAN, "I/O Intr")
|
|
field (NOBT, "$(NUMBER_OF_BITS)")
|
|
field (SHFT, "$(RIGHT_SHIFT)")
|
|
}
|
|
</pre>
|
|
<p>
|
|
Default type is <code>T=int16</code>.
|
|
</p>
|
|
<p>
|
|
The register is read to <code>RVAL</code>, shifted right by
|
|
<code>SHFT</code> bits and masked with <code>NOBT</code> bits.
|
|
Valid values for <code>NOBT</code> and <code>SHFT</code> depend on
|
|
<code>T</code>:
|
|
<code>NOBT+SHFT</code> must not exceed the number of bits of
|
|
the type.
|
|
</p>
|
|
<p>
|
|
Bit 0 is the least significant bit.
|
|
In little endian byte order, bit 0 is in the first byte, in big endian
|
|
byte order it is in the last byte of the register.
|
|
</p>
|
|
<p>
|
|
<b>Example:</b> Use bits 4 to 9 out of 16.
|
|
<code>T=int16</code>, <code>NOBT=6</code>, <code>SHFT=4</code>
|
|
</p>
|
|
<table border=1 cellspacing=0>
|
|
<tr>
|
|
<td>register</td>
|
|
<th bgcolor="#c0c0c0" width="5%">15</th>
|
|
<th bgcolor="#c0c0c0" width="5%">14</th>
|
|
<th bgcolor="#c0c0c0" width="5%">13</th>
|
|
<th bgcolor="#c0c0c0" width="5%">12</th>
|
|
<th bgcolor="#c0c0c0" width="5%">11</th>
|
|
<th bgcolor="#c0c0c0" width="5%">10</th>
|
|
<th width="5%">9</th>
|
|
<th width="5%">8</th>
|
|
<th width="5%">7</th>
|
|
<th width="5%">6</th>
|
|
<th width="5%">5</th>
|
|
<th width="5%">4</th>
|
|
<th bgcolor="#c0c0c0" width="5%">3</th>
|
|
<th bgcolor="#c0c0c0" width="5%">2</th>
|
|
<th bgcolor="#c0c0c0" width="5%">1</th>
|
|
<th bgcolor="#c0c0c0" width="5%">0</th>
|
|
</tr>
|
|
<tr>
|
|
<td>RVAL</td>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th>9</th>
|
|
<th>8</th>
|
|
<th>7</th>
|
|
<th>6</th>
|
|
<th>5</th>
|
|
<th>4</th>
|
|
</tr>
|
|
</table>
|
|
<p>
|
|
<code>T=string</code>, <code>T=float</code> or <code>T=double</code> are
|
|
not valid for mbbi records. Signed and unsigned types are equivalent.
|
|
</p>
|
|
|
|
<a name="mbbo"></a>
|
|
<h3>Multi Bit Binary Output (mbbo)</h3>
|
|
<pre>
|
|
record(mbbo, "$(NAME)") {
|
|
field (DTYP, "regDev")
|
|
field (OUT, "@$(DEVICE):$(OFFSET) T=$(T)")
|
|
field (PINI, "YES")
|
|
field (NOBT, "$(NUMBER_OF_BITS)")
|
|
field (SHFT, "$(LEFT_SHIFT)")
|
|
}
|
|
</pre>
|
|
<p>
|
|
Default type is <code>T=int16</code>.
|
|
</p>
|
|
<p>
|
|
RVAL is masked with <code>NOBT</code> bits, shifted left by
|
|
<code>SHFT</code> bits and written to the register. Valid values for
|
|
<code>NOBT</code> and <code>SHFT</code> depend on <code>T</code>:
|
|
<code>NOBT+SHFT</code> must not exceed the number of bits of
|
|
the type.
|
|
</p>
|
|
<p>
|
|
Bit 0 is the least significant bit.
|
|
In little endian byte order, bit 0 is in the first byte, in big endian
|
|
byte order it is in the last byte of the register.
|
|
</p>
|
|
<p>
|
|
Only the referenced <code>NOBT</code> bits of the register are modified.
|
|
All other bits remain unchanged.
|
|
Thus, other output records can write to different bits of the same
|
|
register.
|
|
</p>
|
|
<p>
|
|
<b>Example:</b> Use bits 5 to 8 out of 16.
|
|
<code>T=int16</code>, <code>NOBT=4</code>, <code>SHFT=5</code>
|
|
</p>
|
|
<table border=1 cellspacing=0>
|
|
<tr>
|
|
<td>RVAL</td>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th bgcolor="#c0c0c0"> </th>
|
|
<th>8</th>
|
|
<th>7</th>
|
|
<th>6</th>
|
|
<th>5</th>
|
|
</tr>
|
|
<tr>
|
|
<td>register</td>
|
|
<th bgcolor="#c0c0c0" width="5%">15</th>
|
|
<th bgcolor="#c0c0c0" width="5%">14</th>
|
|
<th bgcolor="#c0c0c0" width="5%">13</th>
|
|
<th bgcolor="#c0c0c0" width="5%">12</th>
|
|
<th bgcolor="#c0c0c0" width="5%">11</th>
|
|
<th bgcolor="#c0c0c0" width="5%">10</th>
|
|
<th bgcolor="#c0c0c0" width="5%">9</th>
|
|
<th width="5%">8</th>
|
|
<th width="5%">7</th>
|
|
<th width="5%">6</th>
|
|
<th width="5%">5</th>
|
|
<th bgcolor="#c0c0c0" width="5%">4</th>
|
|
<th bgcolor="#c0c0c0" width="5%">3</th>
|
|
<th bgcolor="#c0c0c0" width="5%">2</th>
|
|
<th bgcolor="#c0c0c0" width="5%">1</th>
|
|
<th bgcolor="#c0c0c0" width="5%">0</th>
|
|
</tr>
|
|
</table>
|
|
<p>
|
|
<code>T=string</code>, <code>T=float</code> or <code>T=double</code> are
|
|
not valid for mbbo records. Signed and unsigned types are equivalent.
|
|
</p>
|
|
|
|
<a name="mbbiDirect"></a>
|
|
<h3>Multi Bit Binary Input Direct (mbbiDirect)</h3>
|
|
<pre>
|
|
record(mbbiDirect, "$(NAME)") {
|
|
field (DTYP, "regDev")
|
|
field (INP, "@$(DEVICE):$(OFFSET) T=$(T)")
|
|
field (SCAN, "I/O Intr")
|
|
field (NOBT, "$(NUMBER_OF_BITS)")
|
|
field (SHFT, "$(RIGHT_SHIFT)")
|
|
}
|
|
</pre>
|
|
<p>
|
|
Default type is <code>T=int16</code>.
|
|
</p>
|
|
<p>
|
|
The register is read to <code>VAL</code>, shifted right by
|
|
<code>SHFT</code> bits and masked with <code>NOBT</code> bits (see
|
|
<a href="regDev.html#mbbi">mbbi</a>).
|
|
Valid values for <code>NOBT</code> and <code>SHFT</code> depend on
|
|
<code>T</code>:
|
|
<code>NOBT+SHFT</code> must not exceed the number of bits of
|
|
the type.
|
|
</p>
|
|
<p>
|
|
Bit 0 is the least significant bit.
|
|
In little endian byte order, bit 0 is in the first byte, in big endian
|
|
byte order it is in the last byte of the register.
|
|
</p>
|
|
<p>
|
|
<code>T=string</code>, <code>T=float</code> or <code>T=double</code> are
|
|
not valid for mbbiDirect records. Signed and unsigned types are equivalent.
|
|
</p>
|
|
|
|
<a name="mbboDirect"></a>
|
|
<h3>Multi Bit Binary Output Direct (mbboDirect)</h3>
|
|
<pre>
|
|
record(mbboDirect, "$(NAME)") {
|
|
field (DTYP, "regDev")
|
|
field (OUT, "@$(DEVICE):$(OFFSET) T=$(T)")
|
|
field (PINI, "YES")
|
|
field (NOBT, "$(NUMBER_OF_BITS)")
|
|
field (SHFT, "$(LEFT_SHIFT)")
|
|
}
|
|
</pre>
|
|
<p>
|
|
Default type is <code>T=int16</code>.
|
|
</p>
|
|
<p>
|
|
VAL is masked with <code>NOBT</code> bits, shifted left by
|
|
<code>SHFT</code> bits and written to the register (see
|
|
<a href="regDev.html#mbbo">mbbo</a>).
|
|
Valid values for <code>NOBT</code> and <code>SHFT</code> depend on
|
|
<code>T</code>:
|
|
<code>NOBT+SHFT</code> must not exceed the number of bits of
|
|
the type.
|
|
</p>
|
|
<p>
|
|
Bit 0 is the least significant bit.
|
|
In little endian byte order, bit 0 is in the first byte, in big endian
|
|
byte order it is in the last byte of the register.
|
|
</p>
|
|
<p>
|
|
Only the referenced <code>NOBT</code> bits of the register are modified.
|
|
All other bits remain unchanged. Thus, other output records can write to
|
|
different bits of the same register.
|
|
</p>
|
|
<p>
|
|
<code>T=string</code>, <code>T=float</code> or <code>T=double</code> are
|
|
not valid for mbboDirect records. Signed and unsigned types are equivalent.
|
|
</p>
|
|
|
|
<a name="longin"></a>
|
|
<h3>Long Input (longin)</h3>
|
|
<pre>
|
|
record(longin, "$(NAME)") {
|
|
field (DTYP, "regDev")
|
|
field (INP, "@$(DEVICE):$(OFFSET) T=$(T)")
|
|
field (SCAN, "I/O Intr")
|
|
}
|
|
</pre>
|
|
<p>
|
|
Default type is <code>T=int16</code>.
|
|
</p>
|
|
<p>
|
|
The register is read to <code>VAL</code>. If the type has less than 32
|
|
bits, the value is zero extended or sign extended depending on the
|
|
signedness of the type.
|
|
</p>
|
|
<p>
|
|
<code>T=string</code>, <code>T=float</code> or <code>T=double</code> are
|
|
not valid for longin records.
|
|
</p>
|
|
|
|
<a name="longout"></a>
|
|
<h3>Long Output (longout)</h3>
|
|
<pre>
|
|
record(longout, "$(NAME)") {
|
|
field (DTYP, "regDev")
|
|
field (OUT, "@$(DEVICE):$(OFFSET) T=$(T)")
|
|
field (PINI, "YES")
|
|
}
|
|
</pre>
|
|
<p>
|
|
Default type is <code>T=int16</code>.
|
|
</p>
|
|
<p>
|
|
Depending on <code>T</code>, the least significant 8, 16, or 32 bits
|
|
of <code>VAL</code> are written to the register.
|
|
</p>
|
|
<p>
|
|
<code>T=string</code>, <code>T=float</code> or <code>T=double</code> are
|
|
not valid for longout records.
|
|
</p>
|
|
|
|
<a name="int64in"></a>
|
|
<h3>Integer 64 Input (int64in)</h3>
|
|
<pre>
|
|
record(int64in, "$(NAME)") {
|
|
field (DTYP, "regDev")
|
|
field (INP, "@$(DEVICE):$(OFFSET) T=$(T)")
|
|
field (SCAN, "I/O Intr")
|
|
}
|
|
</pre>
|
|
<p>
|
|
Default type is <code>T=int64</code>.
|
|
</p>
|
|
<p>
|
|
The register is read to <code>VAL</code>. If the type has less than 64
|
|
bits, the value is zero extended or sign extended depending on the
|
|
signedness of the type.
|
|
</p>
|
|
<p>
|
|
<code>T=string</code>, <code>T=float</code> or <code>T=double</code> are
|
|
not valid for int64in records.
|
|
</p>
|
|
<p>
|
|
To use int64in records, you need at least EPICS R3.16.
|
|
</p>
|
|
|
|
<a name="int64out"></a>
|
|
<h3>Integer 64 Output (int64out)</h3>
|
|
<pre>
|
|
record(int64out, "$(NAME)") {
|
|
field (DTYP, "regDev")
|
|
field (OUT, "@$(DEVICE):$(OFFSET) T=$(T)")
|
|
field (PINI, "YES")
|
|
}
|
|
</pre>
|
|
<p>
|
|
Default type is <code>T=int64</code>.
|
|
</p>
|
|
<p>
|
|
Depending on <code>T</code>, the least significant 8, 16, 32, or 64 bits
|
|
of <code>VAL</code> are written to the register.
|
|
</p>
|
|
<p>
|
|
<code>T=string</code>, <code>T=float</code> or <code>T=double</code> are
|
|
not valid for int64out records.
|
|
</p>
|
|
<p>
|
|
To use int64out records, you need at least EPICS R3.16.
|
|
</p>
|
|
|
|
<a name="stringin"></a>
|
|
<h3>String Input (stringin)</h3>
|
|
<pre>
|
|
record(stringin, "$(NAME)") {
|
|
field (DTYP, "regDev")
|
|
field (INP, "@$(DEVICE):$(OFFSET) L=$(LENGTH)")
|
|
field (SCAN, "I/O Intr")
|
|
}
|
|
</pre>
|
|
<p>
|
|
Default and only valid type is <code>T=string</code>.
|
|
Default length is <code>L=40</code>.
|
|
</p>
|
|
<p>
|
|
<code>L</code> bytes are read from the register to <code>VAL</code> and
|
|
null terminated. Thus, the effective string length is maximal
|
|
<code>L</code>-1 bytes.
|
|
</p>
|
|
|
|
<a name="stringout"></a>
|
|
<h3>String Output (stringout)</h3>
|
|
<pre>
|
|
record(stringout, "$(NAME)") {
|
|
field (DTYP, "regDev")
|
|
field (OUT, "@$(DEVICE):$(OFFSET) L=$(LENGTH)")
|
|
field (PINI, "YES")
|
|
}
|
|
</pre>
|
|
<p>
|
|
Default and only valid type is <code>T=string</code>.
|
|
Default length is <code>L=40</code>.
|
|
</p>
|
|
<p>
|
|
<code>L</code> bytes are written from <code>VAL</code> to the register.
|
|
If the actual string length of <code>VAL</code> is shorter than
|
|
<code>L</code>, the remaining space is filled with null bytes. If
|
|
it is longer than <code>L</code>, the string is truncated and not
|
|
null terminated.
|
|
</p>
|
|
|
|
<a name="waveform"></a>
|
|
<h3>Waveform Input (waveform)</h3>
|
|
<pre>
|
|
record(waveform, "$(NAME)") {
|
|
field (DTYP, "regDev")
|
|
field (INP, "@$(DEVICE):$(OFFSET)")
|
|
field (SCAN, "I/O Intr")
|
|
field (NELM, "$(NUMBER_OF_ELEMENTS)")
|
|
field (FTVL, "$(DATATYPE)")
|
|
}
|
|
</pre>
|
|
<p>
|
|
<code>NELM</code> elements are read from registers to <code>VAL</code>.
|
|
</p>
|
|
<p>
|
|
The default type <code>T</code> depends on <code>FTVL</code>.
|
|
For example <code>FTVL=LONG</code> results in <code>T=INT32</code>.
|
|
</p>
|
|
<p>
|
|
If <code>T</code> is an integer type, e.g. <code>T=INT32</code> but
|
|
<code>FTVL</code> is either <code>FLOAT</code> or <code>DOUBLE</code>,
|
|
then values are scaled so that <code>L=<i>low</i></code> and
|
|
<code>H=<i>high</i></code> map to the fields <code>LOPR</code> and
|
|
<code>HOPR</code> respectively.
|
|
</p>
|
|
<p>
|
|
If <code>T=string</code> then <code>FTVL</code> must be <code>CHAR</code> or
|
|
<code>UCHAR</code> or <code>STRING</code>.
|
|
For <code>CHAR</code> and <code>UCHAR</code>,
|
|
<code>L=<i>length</i></code> can be specified but
|
|
defaults to <code>NELM</code> and should not exceed it.
|
|
If <code>L</code> is less than <code>NELM</code>, the
|
|
remaining elements are left unchanged.
|
|
For <code>STRING</code>, <code>NELM</code> strings, each of length <code>L</code>
|
|
(default 40), are read.
|
|
</p>
|
|
|
|
<a name="aai"></a>
|
|
<h3>Array Analog Input (aai)</h3>
|
|
<pre>
|
|
record(aai, "$(NAME)") {
|
|
field (DTYP, "regDev")
|
|
field (INP, "@$(DEVICE):$(OFFSET)")
|
|
field (SCAN, "I/O Intr")
|
|
field (NELM, "$(NUMBER_OF_ELEMENTS)")
|
|
field (FTVL, "$(DATATYPE)")
|
|
}
|
|
</pre>
|
|
<p>
|
|
<code>NELM</code> elements are read from registers to <code>VAL</code>.
|
|
</p>
|
|
<p>
|
|
The default type <code>T</code> depends on <code>FTVL</code>.
|
|
For example <code>FTVL=LONG</code> results in <code>T=INT32</code>.
|
|
</p>
|
|
<p>
|
|
If <code>T</code> is an integer type, e.g. <code>T=INT32</code> but
|
|
<code>FTVL</code> is either <code>FLOAT</code> or <code>DOUBLE</code>,
|
|
then values are scaled so that <code>L=<i>low</i></code> and
|
|
<code>H=<i>high</i></code> map to the fields <code>LOPR</code> and
|
|
<code>HOPR</code> respectively.
|
|
</p>
|
|
<p>
|
|
If <code>T=string</code> then <code>FTVL</code> must be <code>CHAR</code> or
|
|
<code>UCHAR</code> or <code>STRING</code>.
|
|
For <code>CHAR</code> and <code>UCHAR</code>,
|
|
<code>L=<i>length</i></code> can be specified but
|
|
defaults to <code>NELM</code> and should not exceed it.
|
|
If <code>L</code> is less than <code>NELM</code>, the
|
|
remaining elements are left unchanged.
|
|
For <code>STRING</code>, <code>NELM</code> strings, each of length <code>L</code>
|
|
(default 40), are read.
|
|
</p>
|
|
<p>
|
|
The aai record is similar to the waveform record, but may be more
|
|
efficient, because the low level driver may use DMA to fill the record.
|
|
Aai records must be enabled in EPICS base, which is not the case by
|
|
default before EPICS version 3.14.12.
|
|
</p>
|
|
|
|
<a name="aao"></a>
|
|
<h3>Array Analog Output (aao)</h3>
|
|
<pre>
|
|
record(aai, "$(NAME)") {
|
|
field (DTYP, "regDev")
|
|
field (OUT, "@$(DEVICE):$(OFFSET)")
|
|
field (NELM, "$(NUMBER_OF_ELEMENTS)")
|
|
field (FTVL, "$(DATATYPE)")
|
|
field (PINI, "YES")
|
|
}
|
|
</pre>
|
|
<p>
|
|
<code>NELM</code> elements of <code>VAL</code> are written to
|
|
registers.
|
|
</p>
|
|
<p>
|
|
The default type <code>T</code> depends on <code>FTVL</code>.
|
|
For example <code>FTVL=LONG</code> results in <code>T=INT32</code>.
|
|
</p>
|
|
<p>
|
|
If <code>T</code> is an integer type, e.g. <code>T=INT32</code> but
|
|
<code>FTVL</code> is either <code>FLOAT</code> or <code>DOUBLE</code>,
|
|
then values are scaled so that fields <code>LOPR</code> and
|
|
<code>HOPR</code> map to <code>L=<i>low</i></code> and
|
|
<code>H=<i>high</i></code> respectively.
|
|
However, the device support will never write any value lower than
|
|
<code>L</code> or higher than <code>H</code>.
|
|
If necessary the value will be saturated to the nearest limit.
|
|
</p>
|
|
<p>
|
|
If <code>T=string</code> then <code>FTVL</code> must be <code>CHAR</code> or
|
|
<code>UCHAR</code> or <code>STRING</code>.
|
|
For <code>CHAR</code> and <code>UCHAR</code>,
|
|
<code>L=<i>length</i></code> can be specified but
|
|
defaults to <code>NELM</code> and should not exceed it.
|
|
If <code>L</code> is less than <code>NELM</code>, the
|
|
remaining elements are ignored.
|
|
For <code>STRING</code>, <code>NELM</code> strings, each of length <code>L</code>
|
|
(default 40), are written.
|
|
</p>
|
|
<p>
|
|
The aai record is similar to the waveform record, but may be more
|
|
efficient, because the low level driver may use DMA to fill the record.
|
|
Aai records must be enabled in EPICS base, which is not the case by
|
|
default before EPICS version 3.14.12.
|
|
</p>
|
|
|
|
<a name="driver"></a>
|
|
<h2>Driver Functions</h2>
|
|
<h3>Registration</h3>
|
|
<p>
|
|
A driver must implement the API functions it wants to support and
|
|
fill the function pointers into a <code>regDevSupport</code> structure.
|
|
It contains the functions <code>report</code>, <code>getInScanPvt</code>,
|
|
<code>getOutScanPvt</code>, <code>read</code>, and <code>write</code>.
|
|
Write <code>NULL</code> for any API function that is not implemented by
|
|
the driver.
|
|
The support structure can be global and static like this:
|
|
</p>
|
|
<p class="indent">
|
|
<pre>
|
|
static regDevSupport support = {
|
|
report,
|
|
getInScanPvt,
|
|
getOutScanPvt,
|
|
read,
|
|
write
|
|
};
|
|
</pre>
|
|
</p>
|
|
<p>
|
|
Each configured device must be registered with the following function:
|
|
</p>
|
|
<p class="indent">
|
|
<code>
|
|
int regDevRegisterDevice (const char* devicename,
|
|
const regDevSupport* support,
|
|
regDevice* device);
|
|
</code>
|
|
</p>
|
|
<p>
|
|
The <code>devicename</code> must be unique on the IOC and is used in the
|
|
record links to reference the device.
|
|
The <code>support</code> parameter is a pointer to the
|
|
<code>regDevSupport</code> structure of this driver.
|
|
The last parameter <code>driver</code> is a pointer to a driver private
|
|
<code>regDevice</code> structure.
|
|
It will be passed as a device handle to any API function.
|
|
The driver can freely define <code>struct regDevice</code> and put
|
|
in any information it needs to operate one device.
|
|
</p>
|
|
<h3>API functions</h3>
|
|
<p>
|
|
The driver can assume that all API functions are called in a thread save
|
|
context.
|
|
That means it will never happen that two API functions are called for the
|
|
same device at the same time.
|
|
However, API functions for different devices may be called at the same
|
|
time.
|
|
</p>
|
|
<p class="indent">
|
|
<code>
|
|
void report (regDevice* <em>device</em>,
|
|
int <em>level</em>);
|
|
</code>
|
|
</p>
|
|
<p class="indent">
|
|
<code>
|
|
IOSCANPVT getInScanPvt (regDevice* <em>device</em>,
|
|
size_t <em>offset</em>,
|
|
unsigned int <em>vec</em>,
|
|
const char *<em>user</em>);
|
|
</code>
|
|
</p>
|
|
<p class="indent">
|
|
<code>
|
|
IOSCANPVT getOutScanPvt (regDevice* <em>device</em>,
|
|
size_t <em>offset</em>,
|
|
unsigned int <em>vec</em>,
|
|
const char *<em>user</em>);
|
|
</code>
|
|
</p>
|
|
<p class="indent">
|
|
<code>
|
|
int read (regDevice* <em>device</em>,
|
|
size_t <em>offset</em>,
|
|
unsigned int <em>datalength</em>,
|
|
size_t <em>nelem</em>,
|
|
void* <em>pdata</em>,
|
|
int <em>priority</em>,
|
|
regDevTransferComplete <em>callback</em>,
|
|
const char *<em>user</em>);
|
|
</code>
|
|
</p>
|
|
<p class="indent">
|
|
<code>
|
|
int write (regDevice* <em>device</em>,
|
|
size_t <em>offset</em>,
|
|
unsigned int <em>datalength</em>,
|
|
size_t <em>nelem</em>,
|
|
void* <em>pdata</em>,
|
|
void* <em>pmask</em>,
|
|
int <em>priority</em>,
|
|
regDevTransferComplete <em>callback</em>,
|
|
const char *<em>user</em>);
|
|
</code>
|
|
</p>
|
|
|
|
<ul>
|
|
<li>
|
|
<code><em>offset</em></code> is the address offset of the register
|
|
relative to the beginning to the register block.
|
|
</li>
|
|
<li>
|
|
<code><em>datalength</em></code> is the length of the register in bytes
|
|
(one element in case of arrays).
|
|
</li>
|
|
<li>
|
|
<code><em>nelem</em></code> is the number of elements in an array.
|
|
It is 1 for scalar values but may be larger for arrays or strings.
|
|
It may also be 0. In that case the driver shall just report the connection
|
|
state by returning <code>SUCCESS</code> or an error code.
|
|
</li>
|
|
<li>
|
|
<code><em>pdata</em></code> is a pointer to a buffer of
|
|
<code><em>nelem</em></code>*<code><em>dlen</em></code> bytes.
|
|
registers values are copied to or from this buffer.
|
|
If <code><em>nelem==0</em></code>, <code><em>pdata</em></code> may be
|
|
<code>NULL</code>.
|
|
</li>
|
|
<li>
|
|
<code><em>mask</em></code> is a pointer to a bit mask of
|
|
<code><em>datalength</em></code> bytes or <code>NULL</code>.
|
|
Only those bits shall be modified where the mask contains 1 bits.
|
|
All other bits shall remain unchanged.
|
|
</li>
|
|
<li>
|
|
<code><em>priority</em></code> is a number 0...2 and may be used
|
|
as a hint for the driver to shedule requests.
|
|
</li>
|
|
<li>
|
|
<code><em>callback</em></code> is a function to be called upon request
|
|
completion if the driver decides to handle the request asynchronously
|
|
and returns <code>ASYNC_COMPLETION</code>. The driver may ignore it
|
|
completely and handle all requests synchronously. The function may be
|
|
<code>NULL</code>. In that case the driver must handle the request
|
|
synchroously and not return <code>ASYNC_COMPLETION</code>.
|
|
in wh
|
|
</li>
|
|
<li>
|
|
<code><em>user</em></code> is a string which can be used for messages.
|
|
It is the record name (actually a pointer to the record itself). If
|
|
the driver decides to use the <em>callback</em>, this pointer must be
|
|
passed to the callback function.
|
|
</li>
|
|
</ul>
|
|
<p>
|
|
Strings are handled as arrays of characters:
|
|
<code><em>datalength</em>=1</code> and <code><em>nelem</em></code> is the
|
|
buffer size including space for the terminating null byte.
|
|
</p>
|
|
<a name="debugging"></a>
|
|
<h2>1 Debugging</h2>
|
|
<p>
|
|
The variable <code>regDevDebug</code> can be set in the startup script or
|
|
at any time on the command line to change the amount or debug output.
|
|
The following levels are supported:
|
|
</p>
|
|
<p>
|
|
-1: fatal errors only<br>
|
|
0: errors only<br>
|
|
1: startup messages<br>
|
|
2:+ output record processing<br>
|
|
3:+ input record processing<br>
|
|
4:+ driver calls<br>
|
|
5:+ io printout<br>
|
|
</p>
|
|
<p>
|
|
Be careful using level>1 because many messages can introduce
|
|
considerable delays which may result in connection losses.
|
|
Default level is 0.
|
|
</p>
|
|
<p>
|
|
On vxWorks, <code>regDevDebug</code> can be set with
|
|
<code>regDevDebug=<i>level</i></code>
|
|
</p>
|
|
<p>
|
|
In the iocsh use
|
|
<code>var regDevDebug <i>level</i></code>
|
|
</p>
|
|
|
|
<hr>
|
|
<small>Dirk Zimoch, 2009</small>
|
|
</body>
|
|
</html>
|
|
<hr noshade size=1><small>
|
|
<span class="printlayout">Author: Dirk Zimoch Phone: +41 56 310 5182 Email: dirk.zimoch@psi.ch Updated: 24.08.2021 </span>
|
|
Source: /afs/psi.ch/project/epics/webhosting/software/regDev/index.php
|
|
</small>
|
|
</td></tr></table>
|
|
</body></html>
|