Sophie

Sophie

distrib > Fedora > 14 > x86_64 > by-pkgid > 02e7bc50735df2e365110343fbf39739 > files > 110

comedilib-devel-0.8.1-7.fc14.x86_64.rpm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Acquisition and configuration functions</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="    Comedi
  "
HREF="index.html"><LINK
REL="PREVIOUS"
TITLE="Writing Comedi programs"
HREF="x403.html"><LINK
REL="NEXT"
TITLE="Writing a Comedi driver"
HREF="x1394.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Comedi: The <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>Control and Measurement Device Interface</I
></SPAN
>
handbook
  </TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x403.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x1394.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="ACQUISITIONFUNCTIONS"
>4. Acquisition and configuration functions</A
></H1
><P
>This Section gives an overview of all <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> functions with which
application programmers can implement their data acquisition. (With
<SPAN
CLASS="QUOTE"
>"acquisition"</SPAN
> we mean all possible kinds of interfacing
with the cards: input, output, configuration, streaming, etc.)
<A
HREF="x4629.html"
>Section 7</A
> explains the function calls in full
detail.</P
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="SINGLEACQUISITION"
>4.1. Functions for single acquisition</A
></H2
><P
>The simplest form of using <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> is to get one single sample to or
from an interface card. This sections explains how to do such simple
<A
HREF="x621.html#DIO"
>digital</A
> and
<A
HREF="x621.html#SINGLEANALOG"
>analog</A
> acquisitions.</P
><DIV
CLASS="SECTION"
><H3
CLASS="SECTION"
><A
NAME="DIO"
>4.1.1. Single digital acquisition</A
></H3
><P
>Many boards supported by <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> have digital input and output
channels; i.e., channels that can only produce a <TT
CLASS="LITERAL"
>0</TT
>
or a <TT
CLASS="LITERAL"
>1</TT
>.
Some boards allow the <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>direction</I
></SPAN
> (input or output)
of each channel to be specified independently in software.</P
><P
><ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> groups digital channels into a
<SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>subdevice</I
></SPAN
>, which is a group of digital channels
that have the same characteristics.  For example, digital output lines
will be grouped into a digital
output subdevice, bidirectional digital lines will be grouped
into a digital I/O subdevice.  Thus, there can be multiple
digital subdevices on a particular board.</P
><P
>Individual bits on a digital I/O device can be read and written using
the functions
<PRE
CLASS="PROGRAMLISTING"
>  int <A
HREF="r5903.html"
>comedi_dio_read</A
>(device,subdevice,channel,unsigned int *bit);
  int <A
HREF="r5929.html"
>comedi_dio_write</A
>(device,subdevice,channel,unsigned int bit);</PRE
>
The <CODE
CLASS="PARAMETER"
>device</CODE
> parameter is a
<A
HREF="x4629.html#REF-TYPE-COMEDI-T"
>pointer</A
>
to a successfully opened <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> device.
The <CODE
CLASS="PARAMETER"
>subdevice</CODE
> and
<CODE
CLASS="PARAMETER"
>channel</CODE
> parameters are positive
integers that indicate which subdevice and channel is used in the
acquisition. The integer <CODE
CLASS="PARAMETER"
>bit</CODE
>
contains the value of the acquired bit.</P
><P
>The direction of bidirectional lines can be configured using
the function
<PRE
CLASS="PROGRAMLISTING"
>  <A
HREF="r5849.html"
>comedi_dio_config</A
>(device,subdevice,channel,unsigned int dir);</PRE
>
The parameter <CODE
CLASS="PARAMETER"
>dir</CODE
> should be
either <TT
CLASS="LITERAL"
>COMEDI_INPUT</TT
> or
<TT
CLASS="LITERAL"
>COMEDI_OUTPUT</TT
>.
Many digital I/O subdevices group channels into blocks for
configuring direction.  Changing one channel in a block changes
the entire block.</P
><P
>Multiple channels can be read and written simultaneously using the
function
<PRE
CLASS="PROGRAMLISTING"
>  <A
HREF="r5955.html"
>comedi_dio_bitfield</A
>(device,subdevice,unsigned int write_mask,unsigned int *bits);</PRE
>
Each channel is assigned to a bit in the
<CODE
CLASS="PARAMETER"
>write_mask</CODE
> and
<CODE
CLASS="PARAMETER"
>bits</CODE
>
bitfield.  If a bit in
<CODE
CLASS="PARAMETER"
>write_mask</CODE
> is set, the
corresponding bit in <CODE
CLASS="PARAMETER"
>*bits</CODE
> will
be written to the corresponding digital output line.
Each digital line is then read and placed into
<CODE
CLASS="PARAMETER"
>*bits</CODE
>.  The value
of bits in <CODE
CLASS="PARAMETER"
>*bits</CODE
> corresponding
to digital output lines is undefined and device-specific.  Channel
<TT
CLASS="LITERAL"
>0</TT
> is the least significant bit in the bitfield;
channel <TT
CLASS="LITERAL"
>31</TT
> is the most significant bit.  Channels
higher than <TT
CLASS="LITERAL"
>31</TT
> cannot be accessed using this method.</P
><P
>The digital acquisition functions seem to be very simple, but, behind
the implementation screens of the <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> kernel module, they are
executed as special cases of the general
<A
HREF="x621.html#INSTRUCTIONS"
>instruction</A
> command.</P
></DIV
><DIV
CLASS="SECTION"
><H3
CLASS="SECTION"
><A
NAME="SINGLEANALOG"
>4.1.2. Single analog acquisition</A
></H3
><P
>Analog <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> channels can produce data values that are
<SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>samples</I
></SPAN
> from continuous analog signals.
These samples are integers with a significant content in
the range of, typically, <TT
CLASS="LITERAL"
>8</TT
>, <TT
CLASS="LITERAL"
>10</TT
>,
<TT
CLASS="LITERAL"
>12</TT
>, or <TT
CLASS="LITERAL"
>16</TT
> bits.</P
><P
>The
<PRE
CLASS="PROGRAMLISTING"
> int <A
HREF="r5725.html"
>comedi_data_read</A
>(<A
HREF="x4629.html#REF-TYPE-COMEDI-T"
>comedi_t</A
> * device, unsigned int subdevice, unsigned int channel,
                    unsigned int range, unsigned int aref, <A
HREF="x4629.html#REF-TYPE-LSAMPL-T"
>lsampl_t</A
> * data);</PRE
>
function reads one such data value from a <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> channel, and puts it in
the user-specified <CODE
CLASS="PARAMETER"
>data</CODE
> buffer. The
<PRE
CLASS="PROGRAMLISTING"
> int <A
HREF="r5818.html"
>comedi_data_write</A
>(<A
HREF="x4629.html#REF-TYPE-COMEDI-T"
>comedi_t</A
> * device, unsigned int subdevice, unsigned int channel,
                       unsigned int range, unsigned int aref, <A
HREF="x4629.html#REF-TYPE-LSAMPL-T"
>lsampl_t</A
> data);</PRE
>
works in the opposite direction. Data values returned by this function
are unsigned integers less than, or equal to, the maximum sample value
of the channel, which can be determined using the function
<PRE
CLASS="PROGRAMLISTING"
> <A
HREF="x4629.html#REF-TYPE-LSAMPL-T"
>lsampl_t</A
> <A
HREF="r5331.html"
>comedi_get_maxdata</A
>(<A
HREF="x4629.html#REF-TYPE-COMEDI-T"
>comedi_t</A
> * device, unsigned int subdevice, unsigned int channel);</PRE
>
Conversion of data values to physical units can be performed by the
function
<PRE
CLASS="PROGRAMLISTING"
> double <A
HREF="r5619.html"
>comedi_to_phys</A
>(<A
HREF="x4629.html#REF-TYPE-LSAMPL-T"
>lsampl_t</A
> data, comedi_range * range,  <A
HREF="x4629.html#REF-TYPE-LSAMPL-T"
>lsampl_t</A
> maxdata);</PRE
>
There are two data structures in these commands that are not fully
self-explanatory:
<P
></P
><UL
><LI
><P
><A
HREF="x4629.html#REF-TYPE-COMEDI-T"
>comedi_t</A
>: this data structure
contains all information that a user program has to know about an
<SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>open</I
></SPAN
> <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> device. The programmer doesn't have
to fill in this data structure manually: it gets filled in by opening
the device.</P
></LI
><LI
><P
><A
HREF="x4629.html#REF-TYPE-LSAMPL-T"
>lsampl_t</A
>: this
<SPAN
CLASS="QUOTE"
>"data structure"</SPAN
> represents one single sample. On most
architectures, it's nothing more than a 32 bits value. Internally,
<ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> does some conversion from raw sample data to
<SPAN
CLASS="QUOTE"
>"correct"</SPAN
> integers. This is called <SPAN
CLASS="QUOTE"
>"data
munging"</SPAN
>.</P
></LI
></UL
></P
><P
>Each single acquisition by, for example,
<CODE
CLASS="FUNCTION"
> <A
HREF="r5725.html"
>comedi_data_read()</A
></CODE
>
requires quite some overhead, because all the arguments of the
function call are checked. If multiple acquisitions must be done on
the same channel, this overhead can be avoided by using a function
that can read more than one sample:
<PRE
CLASS="PROGRAMLISTING"
>  int <A
HREF="r5903.html"
>comedi_data_read_n</A
>(<A
HREF="x4629.html#REF-TYPE-COMEDI-T"
>comedi_t</A
> *it, unsigned int subdev, unsigned int chan, unsigned int range,
      unsigned int aref, <A
HREF="x4629.html#REF-TYPE-LSAMPL-T"
>lsampl_t</A
> *data, unsigned int n)</PRE
>
The number of samples, <CODE
CLASS="PARAMETER"
>n</CODE
>, is
limited by the <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> implementation (to a maximum of 100 samples),
because the call is blocking.</P
><P
>The start of the data acquisition can also be delayed by a specified
number of nano-seconds:
<PRE
CLASS="PROGRAMLISTING"
>int <A
HREF="r5758.html"
>comedi_data_read_delayed</A
>(<A
HREF="x4629.html#REF-TYPE-COMEDI-T"
>comedi_t</A
> *it, unsigned int subdev, unsigned int chan, unsigned int range,
    unsigned int aref, <A
HREF="x4629.html#REF-TYPE-LSAMPL-T"
>lsampl_t</A
> *data, unsigned int nano_sec)</PRE
>
All these read and write acquisition functions are implemented on top
of the generic <A
HREF="x621.html#INSTRUCTIONS"
>instruction</A
>
command.</P
></DIV
></DIV
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="INSTRUCTIONS"
>4.2. Instructions for multiple acquisitions</A
></H2
><P
>The <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>instruction</I
></SPAN
> is one of the most generic,
overloaden and flexible functions in the <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> API. It is used to
execute a multiple of identical acquisitions on the same channel, but
also to perform a
<A
HREF="x621.html#INSTRUCTIONSCONFIGURATION"
>configuration</A
> of a
channel.
<A
NAME="ANCHOR.INSTRUCTION.LIST"
></A
>
An <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>instruction list</I
></SPAN
> is a list of instructions,
possibly on different channels. Both instructions and instructions
lists are executed <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>synchronously</I
></SPAN
>, i.e., while
<SPAN
CLASS="strong"
><B
CLASS="EMPHASIS"
>blocking</B
></SPAN
> the calling process.
This is one of the limitations of instructions; the other one is that
they cannot code an acquisition involving timers or external events.
These limits are eliminated by the
<A
HREF="x621.html#COMMANDSSTREAMING"
>command</A
> acquisition
primitive.</P
><DIV
CLASS="SECTION"
><H3
CLASS="SECTION"
><A
NAME="COMEDIINSNSTRUCTURE"
>4.2.1. The instruction data structure</A
></H3
><P
>All the information needed to execute an instruction is stored in the
<A
HREF="x4629.html#REF-TYPE-COMEDI-INSN"
>comedi_insn</A
>
data structure:
<PRE
CLASS="PROGRAMLISTING"
>struct <A
NAME="INSN-DATA-STRUCTURE"
></A
>comedi_insn_struct{
  <A
NAME="INSN-DATA-STRUCTURE-INSN"
></A
>unsigned int insn;      // integer encoding the type of acquisition
                          // (or configuration)
  unsigned int n;         // number of elements in data array
  <A
HREF="x4629.html#REF-TYPE-LSAMPL-T"
>lsampl_t</A
> <A
NAME="INSN-DATA-STRUCTURE-DATA"
></A
>*data;         // pointer to data buffer
  unsigned int subdev;    // subdevice
  unsigned int <A
NAME="INSN-DATA-STRUCTURE-CHANSPEC"
></A
><A
HREF="x4629.html#REF-MACRO-CR-PACK"
>chanspec</A
>; // encoded channel specification
  unsigned int unused[3];
} comedi_insn;</PRE
>
Because of the large flexibility of the instruction function, many
types of instruction do not need to fill in all fields, or attach
different meanings to the same field. But the current implementation
of <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> requires the
<A
HREF="x621.html#INSN-DATA-STRUCTURE-DATA"
>data</A
> field to be at
least one byte long.</P
><P
>The <A
HREF="x621.html#INSN-DATA-STRUCTURE-INSN"
>insn</A
> flag of the
<A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data structure</A
>
determines the type of acquisition executed in the corresponding
instruction:
<P
></P
><UL
><LI
><P
>INSN_READ: the instruction executes a read on an analog channel.</P
></LI
><LI
><P
>INSN_WRITE: the instruction executes a write on an analog channel.</P
></LI
><LI
><P
>INSN_BITS: indicates that the instruction must
read or write values on multiple digital I/O channels.</P
></LI
><LI
><P
>INSN_GTOD: the instruction performs a <SPAN
CLASS="QUOTE"
>"Get Time Of Day"</SPAN
>
acquisition.</P
></LI
><LI
><P
>INSN_WAIT: the instruction blocks for a specified number of
nanoseconds.</P
></LI
></UL
></P
></DIV
><DIV
CLASS="SECTION"
><H3
CLASS="SECTION"
><A
NAME="INSTRUCTIONEXECUTION"
>4.2.2. Instruction execution</A
></H3
><P
>Once an instruction data structure has been filled in, the
corresponding instruction is executed as follows:
<PRE
CLASS="PROGRAMLISTING"
> int <A
HREF="r5553.html"
>comedi_do_insn</A
>(<A
HREF="x4629.html#REF-TYPE-COMEDI-T"
>comedi_t</A
> *it, <A
HREF="x4629.html#REF-TYPE-COMEDI-INSN"
>comedi_insn</A
> * instruction);</PRE
>
Many <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> instructions are shortcuts that relieve the programmer
from explicitly filling in the data structure and calling the
<A
HREF="r5553.html"
>comedi_do_insn</A
>
function.</P
><P
>The
<PRE
CLASS="PROGRAMLISTING"
> int <A
HREF="r5527.html"
>comedi_do_insnlist</A
><A
HREF="x4629.html#REF-TYPE-COMEDI-T"
>comedi_t</A
> *it, <A
HREF="x4629.html#REF-TYPE-COMEDI-INSNLIST"
>comedi_insnlist</A
> * list)</PRE
>
instruction allows to perform a list of instructions in one function
call. The number of instructions in the list is limited in the
implementation, because instructions are executed
<SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>synchronously</I
></SPAN
>, i.e., the call blocks until the
whole instruction (list) has finished.</P
></DIV
></DIV
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="INSTRUCTIONSCONFIGURATION"
>4.3. Instructions for configuration</A
></H2
><P
><A
HREF="x621.html#INSTRUCTIONS"
>Section 4.2</A
> explains how instructions are used to do
<SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>acquisition</I
></SPAN
> on channels. This section explains
how they are used to <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>configure</I
></SPAN
> a subdevice.
There are various sorts of configurations, and the
specific information for each different configuration possibility is
to be specified via the
<A
HREF="x621.html#INSN-DATA-STRUCTURE-DATA"
>data</A
> buffer of the
<A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data structure</A
>.
(So, the pointer to a
<A
HREF="x4629.html#REF-TYPE-LSAMPL-T"
>lsampl_t</A
>
is misused as a pointer to an array with board-specific information.)</P
><P
>Using INSN_CONFIG as the
<A
HREF="x621.html#INSN-DATA-STRUCTURE-INSN"
>insn</A
> flag in an
<A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data structure</A
>
indicates that the instruction will
<SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>not perform acquisition</I
></SPAN
> on a
channel, but will <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>configure</I
></SPAN
> that channel.
The
<A
HREF="x4629.html#REF-MACRO-CR-PACK"
>chanspec</A
> field in the
<A
HREF="x621.html#INSN-DATA-STRUCTURE-CHANSPEC"
>comedi_insn</A
>
data structure, contains the channel to be configured.
The zeroth element of the data array
is always an id that specifies
what type of configuration instruction is being performed.  The
meaning of rest of the elements in the data array
depend on the configuration instruction id.
Some of the
possible ids are summarised in the table below, along with the
meanings of the data array elements for
each type of configuration instruction.</P
><DIV
CLASS="INFORMALTABLE"
><P
></P
><A
NAME="AEN800"
></A
><TABLE
BORDER="1"
CLASS="CALSTABLE"
><COL><COL><COL><COL><THEAD
><TR
><TH
>data[0]</TH
><TH
>Description</TH
><TH
>n (number of elements in data array)</TH
><TH
>Meanings of data[1], ..., data[n-1]</TH
></TR
></THEAD
><TBODY
><TR
><TD
>INSN_CONFIG_DIO_INPUT</TD
><TD
>Configure a dio line as input.  It is easier to use comedi_dio_config() than
to use this configuration instruction directly.</TD
><TD
>1</TD
><TD
>n/a</TD
></TR
><TR
><TD
>INSN_CONFIG_DIO_OUTPUT</TD
><TD
>Configure a dio line as output.  It is easier to use comedi_dio_config() than
to use this configuration instruction directly.</TD
><TD
>1</TD
><TD
>n/a</TD
></TR
><TR
><TD
>INSN_CONFIG_ALT_SOURCE</TD
><TD
>Select an alternate input source.  This instruction is
used by comedi_calibrate to configure analog input channels
which can be redirected to read internal calibration
references.  You need to set the CR_ALT_SOURCE flag in the chanspec
when reading to actually read from the configured alternate input source.
If you are using comedi_data_read(), then the channel parameter can be
bitwise or'd with the CR_ALT_SOURCE flag.</TD
><TD
>2</TD
><TD
><P
></P
><TABLE
BORDER="0"
><TBODY
><TR
><TD
>data[1]: alternate input source.</TD
></TR
></TBODY
></TABLE
><P
></P
></TD
></TR
><TR
><TD
>INSN_CONFIG_BLOCK_SIZE</TD
><TD
>Specify block size for asynchonous command data.
When performing streaming input, many boards accumulate
samples in internal fifos and transfer them to the host
computer in chunks.  Some drivers let you suggest a size in bytes for how big a
the chunks should be.  This lets you tune how often the host computer is
interrupted with a new chunk of data.</TD
><TD
>2</TD
><TD
><P
></P
><TABLE
BORDER="0"
><TBODY
><TR
><TD
>data[1]: The desired block size in bytes.  The actual configured block size is
writen back to data[1] after the instruction completes.  This instruction
acts purely as a query if the block size is set to zero.</TD
></TR
></TBODY
></TABLE
><P
></P
></TD
></TR
><TR
><TD
>INSN_CONFIG_DIO_QUERY</TD
><TD
>Queries the configuration of a dio line to see if it is an input or output.
It is probably easier to use the comedilib function comedi_dio_get_config()
than to use this instruction directly.</TD
><TD
>2</TD
><TD
><P
></P
><TABLE
BORDER="0"
><TBODY
><TR
><TD
>data[1]: The instruction sets this element to either COMEDI_INPUT or COMEDI_OUTPUT.</TD
></TR
></TBODY
></TABLE
><P
></P
></TD
></TR
></TBODY
></TABLE
><P
></P
></DIV
><P
>See the comedilib demo program demo/choose_clock.c for an example
of using a configuration instruction.</P
></DIV
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="INTTRIGCONFIGURATION"
>4.4. Instruction for internal triggering</A
></H2
><P
>This special instruction has
<A
NAME="INSN-INTTRIG"
></A
>INSN_INTTRIG as the
<A
HREF="x621.html#INSN-DATA-STRUCTURE-INSN"
>insn</A
> flag in its
<A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data structure</A
>.
Its execution causes an
<A
HREF="x621.html#TRIG-INT-START-SRC"
>internal triggering event</A
>. This
event can, for example, cause the device driver to start a conversion,
or to stop an ongoing acquisition. The exact meaning of the triggering
depends on the card and its particular driver.</P
><P
>The
<A
HREF="x621.html#INSN-DATA-STRUCTURE-DATA"
>data</A
>[0] field of the
INSN_INTTRIG instruction is reserved for future use, and should be set
to <SPAN
CLASS="QUOTE"
>"0"</SPAN
>.</P
></DIV
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="COMMANDSSTREAMING"
>4.5. Commands for streaming acquisition</A
></H2
><P
>The most powerful <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> acquisition primitive is the
<SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>command</I
></SPAN
>. It's powerful because, with one single
command, the programmer launches:
<P
></P
><UL
><LI
><P
>a possibly infinite <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>sequence of acquisitions</I
></SPAN
>,</P
></LI
><LI
><P
>accompanied with various <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>callback</I
></SPAN
> functionalities
(DMA, interrupts, driver-specific callback functions),</P
></LI
><LI
><P
>for <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>any number of channels</I
></SPAN
>,</P
></LI
><LI
><P
>with an <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>arbitrary order</I
></SPAN
> of channels in each scan
(possibly even with repeated channels per scan),</P
></LI
><LI
><P
>and with various scan <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>triggering sources</I
></SPAN
>,
external (i.e., hardware pulses) as well as internal (i.e., pulses
generated on the DAQ card itself, or generated by a
<A
HREF="x621.html#INTTRIGCONFIGURATION"
>software trigger instruction</A
>).</P
></LI
></UL
>
This command functionality exists in the <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> API, because various
data acquisition devices have the capability to perform this kind of
complex acquisition, driven by either on-board or
off-board timers and triggers.</P
><P
>A command specifies a particular data
<A
HREF="index.html#FIG-ACQ-SEQ"
>acquisition sequence</A
>, which
consists of a number of <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>scans</I
></SPAN
>, and each scan is
comprised of a number of <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>conversions</I
></SPAN
>, which
usually corresponds to a single A/D or D/A conversion. So, for
example, a scan could consist of sampling channels 1, 2 and 3 of a
particular device, and this scan should be repeated 1000 times, at
intervals of 1 millisecond apart.</P
><P
>The command function is complementary to the
<A
HREF="x621.html#INSTRUCTIONSCONFIGURATION"
>configuration instruction</A
>
function: each channel in the command's
<A
HREF="x621.html#COMMAND-DATA-STRUCT-CHANLIST"
>chanlist</A
>
should first be configured by an appropriate instruction.</P
><DIV
CLASS="SECTION"
><H3
CLASS="SECTION"
><A
NAME="EXECUTINGCOMMAND"
>4.5.1. Executing a command</A
></H3
><P
>A commands is executed by the following <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> function:
<PRE
CLASS="PROGRAMLISTING"
> int <A
HREF="r6164.html"
>comedi_command</A
>(<A
HREF="x4629.html#REF-TYPE-COMEDI-T"
>comedi_t</A
> * device,  <A
HREF="x4629.html#REF-TYPE-COMEDI-CMD"
>comedi_cmd</A
> * command);</PRE
>
The following sections explain the meaning of the
<A
HREF="x4629.html#REF-TYPE-COMEDI-CMD"
>comedi_cmd</A
> data structure.
Filling in this structure can be quite complicated, and
requires good knowledge about the exact functionalities of the DAQ
card.  So, before launching a command, the application programmer is
adviced to check whether this complex command data structure can be
successfully parsed. So, the typical sequence for executing a command is
to first send the command through
<A
HREF="r6186.html"
>comedi_command_test()</A
>
once or twice.  The test will check that the command is valid for the
particular device, and often makes some adjustments to the command
arguments, which can then be read back by the user to see the actual
values used.</P
><P
>A <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> program can find out on-line what the command capabilities
of a specific device are, by means of the
<A
HREF="r6092.html"
>comedi_get_cmd_src_mask()</A
>
function.</P
></DIV
><DIV
CLASS="SECTION"
><H3
CLASS="SECTION"
><A
NAME="COMEDICMDSTRUCTURE"
>4.5.2. The command data structure</A
></H3
><P
>The command executes according to the information about the requested
acquisition, which is stored in the
<A
HREF="x4629.html#REF-TYPE-COMEDI-CMD"
>comedi_cmd</A
>
<A
NAME="COMMAND-DATA-STRUCT"
></A
>data structure:
<PRE
CLASS="PROGRAMLISTING"
>typedef struct comedi_cmd_struct comedi_cmd;

struct comedi_cmd_struct{
  unsigned int subdev;         // which subdevice to sample
  unsigned int <A
NAME="COMMAND-DATA-STRUCT-FLAGS"
></A
>flags;          // encode some configuration possibilities
                               // of the command execution; e.g.,
                               // whether a callback routine is to be
                               // called at the end of the command

  unsigned int <A
NAME="COMMAND-DATA-STRUCT-START-SRC"
></A
>start_src;      // event to make the acquisition start
  unsigned int <A
NAME="COMMAND-DATA-STRUCT-START-ARG"
></A
>start_arg;      // parameters that influence this start

  unsigned int <A
NAME="COMMAND-DATA-STRUCT-SCAN-BEGIN-SRC"
></A
>scan_begin_src; // event to make a particular scan start
  unsigned int <A
NAME="COMMAND-DATA-STRUCT-SCAN-BEGIN-ARG"
></A
>scan_begin_arg; // parameters that influence this start`

  unsigned int <A
NAME="COMMAND-DATA-STRUCT-CONVERT-SRC"
></A
>convert_src;    // event to make a particular conversion start
  unsigned int <A
NAME="COMMAND-DATA-STRUCT-CONVERT-ARG"
></A
>convert_arg;    // parameters that influence this start

  unsigned int <A
NAME="COMMAND-DATA-STRUCT-SCAN-END-SRC"
></A
>scan_end_src;   // event to make a particular scan terminate
  unsigned int <A
NAME="COMMAND-DATA-STRUCT-SCAN-END-ARG"
></A
>scan_end_arg;   // parameters that influence this termination

  unsigned int <A
NAME="COMMAND-DATA-STRUCT-STOP-SRC"
></A
>stop_src;       // what make the acquisition terminate
  unsigned int <A
NAME="COMMAND-DATA-STRUCT-STOP-ARG"
></A
>stop_arg;       // parameters that influence this termination

  unsigned int <A
NAME="COMMAND-DATA-STRUCT-CHANLIST"
></A
>*chanlist;      // pointer to list of channels to be sampled
  unsigned int <A
NAME="COMMAND-DATA-STRUCT-CHANLIST-LEN"
></A
>chanlist_len;   // number of channels to be sampled

  sampl_t *<A
NAME="COMMAND-DATA-STRUCT-DATA"
></A
>data;               // address of buffer
  unsigned int <A
NAME="COMMAND-DATA-STRUCT-DATA-LEN"
></A
>data_len;       // number of samples to acquire
};</PRE
>
The start and end of the whole command acquisition sequence, and the
start and end of each scan and of each conversion, is triggered by a
so-called <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>event</I
></SPAN
>. More on these in
<A
HREF="x621.html#COMEDICMDSOURCES"
>Section 4.5.3</A
>.</P
><P
>The <CODE
CLASS="PARAMETER"
>subdev</CODE
> member of the
<A
HREF="x4629.html#REF-TYPE-COMEDI-CMD"
>comedi_cmd</A
> structure is
the index of the subdevice the command is intended for.  The
<A
HREF="r5092.html"
>comedi_find_subdevice_by_type()</A
>
function can be useful in discovering the index of your desired subdevice.</P
><P
>The <A
HREF="x621.html#COMMAND-DATA-STRUCT-CHANLIST"
>chanlist</A
>
member of the
<A
HREF="x4629.html#REF-TYPE-COMEDI-CMD"
>comedi_cmd</A
> data
structure should point to an array whose number of elements is
specificed by
<A
HREF="x621.html#COMMAND-DATA-STRUCT-CHANLIST-LEN"
>chanlist_len</A
>
(this will generally be the same as the
<A
HREF="x621.html#COMMAND-DATA-STRUCT-SCAN-END-ARG"
>scan_end_arg</A
>).
The
<A
HREF="x621.html#COMMAND-DATA-STRUCT-CHANLIST"
>chanlist</A
>
specifies the sequence of channels and gains (and analog references)
that should be stepped through for each scan.  The elements of the
<A
HREF="x621.html#COMMAND-DATA-STRUCT-CHANLIST"
>chanlist</A
> array should be
initialized by <SPAN
CLASS="QUOTE"
>"packing"</SPAN
> the channel, range and reference
information together with the
<CODE
CLASS="PARAMETER"
> <A
HREF="x4629.html#REF-MACRO-CR-PACK"
>CR_PACK()</A
></CODE
>
macro.</P
><P
>The <A
HREF="x621.html#COMMAND-DATA-STRUCT-DATA"
>data</A
> and
<A
HREF="x621.html#COMMAND-DATA-STRUCT-DATA-LEN"
>data_len</A
>
members can be safely ignored when issueing commands from a user-space
program.  They only have meaning when a command is sent from a
<SPAN
CLASS="strong"
><B
CLASS="EMPHASIS"
>kernel</B
></SPAN
> module using the
<CODE
CLASS="FUNCTION"
>kcomedilib</CODE
> interface, in which case they specify
the buffer where the driver should write/read its data to/from.</P
><P
>The final member of the
<A
HREF="x621.html#COMMAND-DATA-STRUCT"
>comedi_cmd</A
> structure is the
<A
HREF="x621.html#COMMAND-DATA-STRUCT-FLAGS"
>flags</A
> field,
i.e., bits in a word that can be bitwise-or'd together. The meaning of
these bits are explained in a
<A
HREF="x621.html#SOURCE.FLAGS.ANCHOR"
>later section</A
>.</P
></DIV
><DIV
CLASS="SECTION"
><H3
CLASS="SECTION"
><A
NAME="COMEDICMDSOURCES"
>4.5.3. The command trigger events
<A
NAME="SOURCE.TRIGGER.ANCHOR"
></A
></A
></H3
><P
>A command is a very versatile acquisition instruction, in the sense
that it offers lots of possibilities to let different hardware and
software sources determine when acquisitions are started, performed,
and stopped. More specifically, the command
<A
HREF="x621.html#COMMAND-DATA-STRUCT"
>data structure</A
>
has <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>five</I
></SPAN
> types of events: start the
<A
HREF="index.html#ACQUISITIONTERMINOLOGY"
>acquisition</A
>,
start a <A
HREF="index.html#SCAN"
>scan</A
>, start a
<A
HREF="index.html#CONVERSION"
>conversion</A
>, stop a scan, and stop
the acquisition.  Each event can be given its own
<SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
><A
HREF="x621.html#SOURCE.TRIGGER.ANCHOR"
>source</A
></I
></SPAN
>
(the <CODE
CLASS="PARAMETER"
>*_src</CODE
> members in the
<A
HREF="x4629.html#REF-TYPE-COMEDI-CMD"
>comedi_cmd</A
> data
structure). And each event source can have a corresponding
argument (the <CODE
CLASS="PARAMETER"
>*_arg</CODE
> members of
the <A
HREF="x4629.html#REF-TYPE-COMEDI-CMD"
>comedi_cmd</A
> data
structure) whose meaning depends on the type of source trigger.
For example, to specify an external digital line <SPAN
CLASS="QUOTE"
>"3"</SPAN
> as a
source (in general, <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>any</I
></SPAN
> of the five event
sources), you would use
<CODE
CLASS="PARAMETER"
>src</CODE
>=<A
HREF="x621.html#TRIG-EXT"
>TRIG_EXT</A
> and
<CODE
CLASS="PARAMETER"
>arg</CODE
>=3.</P
><P
>The following paragraphs discuss in somewhat more detail the trigger
event sources(<CODE
CLASS="PARAMETER"
>*_src</CODE
>), and the
corresponding arguments (<CODE
CLASS="PARAMETER"
>*_arg</CODE
>).</P
><P
>The start of an acquisition is controlled by the
<A
HREF="x621.html#COMMAND-DATA-STRUCT-START-SRC"
>start_src</A
> events.
The available options are:
<P
></P
><UL
><LI
><P
><A
NAME="TRIG-NOW-START-SRC"
></A
>
TRIG_NOW: the
<A
HREF="x621.html#COMMAND-DATA-STRUCT-START-SRC"
>start_src</A
>
event occurs
<A
HREF="x621.html#COMMAND-DATA-STRUCT-START-ARG"
>start_arg</A
>
nanoseconds after the
<A
HREF="x4629.html#REF-TYPE-COMEDI-CMD"
>comedi_cmd</A
>
is called. Currently, only
<A
HREF="x621.html#COMMAND-DATA-STRUCT-START-ARG"
>start_arg</A
>=0 is
supported.</P
></LI
><LI
><P
><A
NAME="TRIG-FOLLOW-START-SRC"
></A
>
TRIG_FOLLOW:  (For an output device.) The
<A
HREF="x621.html#COMMAND-DATA-STRUCT-START-SRC"
>start_src</A
>
event occurs when data is written to the buffer.</P
></LI
><LI
><P
><A
NAME="TRIG-EXT-START-SRC"
></A
>
TRIG_EXT: the start event occurs when an external trigger signal
occurs; e.g., a rising edge of a digital line.
<A
HREF="x621.html#COMMAND-DATA-STRUCT-START-ARG"
>start_arg</A
>
chooses the particular digital line.</P
></LI
><LI
><P
><A
NAME="TRIG-INT-START-SRC"
></A
>
TRIG_INT: the start event occurs on a <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> internal signal, which
is typically caused by an
<A
HREF="x621.html#INSN-INTTRIG"
>INSN_INTTRIG instruction</A
>.</P
></LI
></UL
>
The start of the beginning of each
<A
HREF="index.html#SCAN"
>scan</A
> is controlled by the
<A
HREF="x621.html#COMMAND-DATA-STRUCT-SCAN-BEGIN-SRC"
>scan_begin</A
> events.
The available options are:
<P
></P
><UL
><LI
><P
><A
NAME="TRIG-TIMER-START-SCAN"
></A
>
TRIG_TIMER:
<A
HREF="x621.html#COMMAND-DATA-STRUCT-SCAN-BEGIN-SRC"
>scan_begin</A
>
events occur periodically.  The time between
<A
HREF="x621.html#COMMAND-DATA-STRUCT-SCAN-BEGIN-SRC"
>scan_begin</A
>
events is
<A
HREF="x621.html#COMMAND-DATA-STRUCT-CONVERT-ARG"
>convert_arg</A
>
nanoseconds.</P
></LI
><LI
><P
><A
NAME="TRIG-FOLLOW-START-SCAN"
></A
>
TRIG_FOLLOW:  The
<A
HREF="x621.html#COMMAND-DATA-STRUCT-SCAN-BEGIN-SRC"
>scan_begin</A
>
event occurs immediately after a
<A
HREF="x621.html#COMMAND-DATA-STRUCT-SCAN-END-SRC"
>scan_end</A
>
event occurs.</P
></LI
><LI
><P
><A
NAME="TRIG-EXT-START-SCAN"
></A
>
TRIG_EXT: the
<A
HREF="x621.html#COMMAND-DATA-STRUCT-SCAN-BEGIN-SRC"
>scan_begin</A
>
event occurs when an external trigger signal
occurs; e.g., a rising edge of a digital line.
<A
HREF="x621.html#COMMAND-DATA-STRUCT-SCAN-BEGIN-ARG"
>scan_begin_arg</A
>
chooses the particular digital line.</P
></LI
></UL
>
The
<A
HREF="x621.html#COMMAND-DATA-STRUCT-SCAN-BEGIN-ARG"
>scan_begin_arg</A
>
used here may not be supported exactly by the device, but it
will be adjusted to the nearest supported value by
<A
HREF="r6186.html"
>comedi_command_test()</A
>.</P
><P
>The timing between each sample in a
<A
HREF="index.html#SCAN"
>scan</A
> is controlled by the
<A
HREF="x621.html#COMMAND-DATA-STRUCT-CONVERT-SRC"
>convert_*</A
>
fields:
<P
></P
><UL
><LI
><P
><A
NAME="CONVERT-TRIG-TIMER"
></A
>
<A
NAME="TRIG-TIMER"
></A
>
TRIG_TIMER: the conversion events occur periodically.  The time
between convert events is
<A
HREF="x621.html#COMMAND-DATA-STRUCT-CONVERT-ARG"
>convert_arg</A
>
nanoseconds.</P
></LI
><LI
><P
><A
NAME="CONVERT-TRIG-EXT"
></A
>
<A
NAME="TRIG-EXT"
></A
>
TRIG_EXT: the conversion events occur when an external trigger signal
occurs, e.g., a rising edge of a digital line.
<A
HREF="x621.html#COMMAND-DATA-STRUCT-CONVERT-ARG"
>convert_arg</A
>
chooses the particular digital line.</P
></LI
><LI
><P
><A
NAME="CONVERT-TRIG-NOW"
></A
>
<A
NAME="TRIG-NOW"
></A
>
TRIG_NOW: All conversion events in a
<A
HREF="index.html#SCAN"
>scan</A
> occur simultaneously.</P
></LI
></UL
>
The <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>end</I
></SPAN
> of each scan is almost always specified
using
<A
HREF="x621.html#TRIG-COUNT"
>TRIG_COUNT</A
>, with the argument being
the same as the number of channels in the
<A
HREF="x621.html#COMMAND-DATA-STRUCT-CHANLIST"
>chanlist</A
>.  You
could probably find a device that allows something else, but it would
be strange.</P
><P
>The end of an
<A
HREF="index.html#ACQUISITIONTERMINOLOGY"
>acquisition</A
> is
controlled by
<A
HREF="x621.html#COMMAND-DATA-STRUCT-STOP-SRC"
>stop_src</A
>
and <A
HREF="x621.html#COMMAND-DATA-STRUCT-STOP-ARG"
>stop_arg</A
>:
<P
></P
><UL
><LI
><P
><A
NAME="ACQUISITION-END-TRIG-COUNT"
></A
>
<A
NAME="TRIG-COUNT"
></A
>
TRIG_COUNT:  stop the acquisition after
<A
HREF="x621.html#COMMAND-DATA-STRUCT-STOP-ARG"
>stop_arg</A
>
scans.</P
></LI
><LI
><P
><A
NAME="ACQUISITION-END-TRIG-NONE"
></A
>
<A
NAME="TRIG-NONE"
></A
>
TRIG_NONE: perform continuous acquisition, until stopped using
<A
HREF="r6142.html"
>comedi_cancel()</A
>.</P
><P
>Its argument is reserved and should be set to 0.
(<SPAN
CLASS="QUOTE"
>"Reserved"</SPAN
>
means that unspecified things could happen if it is set to something
else but 0.)</P
></LI
></UL
>
There are a couple of less usual or not yet implemented events:
<P
></P
><UL
><LI
><P
><A
NAME="TRIG-TIME"
></A
>
TRIG_TIME:
cause an event to occur at a particular time.</P
><P
>(This event source is reserved for future use.)</P
></LI
><LI
><P
><A
NAME="TRIGOTHER-EVENT"
></A
>
TRIG_OTHER: driver specific event trigger.</P
><P
>This event can be useful as any of the trigger sources.  Its exact
meaning is driver specific, because it implements a feature that
otherwise does not fit into the generic <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> command interface.
Configuration of TRIG_OTHER features are done by
<A
HREF="x621.html#INSTRUCTIONSCONFIGURATION"
>INSN_CONFIG</A
>
instructions.</P
><P
>The argument is reserved and should be set to 0.</P
></LI
></UL
>
Not all event sources are applicable to all events.  Supported
trigger sources for specific events depend significantly on your
particular device, and even more on the current state of its device
driver. The
<A
HREF="r6092.html"
>comedi_get_cmd_src_mask()</A
>
function is useful for determining what trigger sources a subdevice
supports.</P
></DIV
><DIV
CLASS="SECTION"
><H3
CLASS="SECTION"
><A
NAME="COMEDICMDFLAGS"
>4.5.4. The command flags
<A
NAME="SOURCE.FLAGS.ANCHOR"
></A
></A
></H3
><P
>The
<A
HREF="x621.html#COMMAND-DATA-STRUCT-FLAGS"
>flags</A
> field in the
<A
HREF="x4629.html#REF-TYPE-COMEDI-CMD"
>command data structure</A
>
is used to specify some <SPAN
CLASS="QUOTE"
>"behaviour"</SPAN
> of the acquisitions in
a command.
The meaning of the field is as follows:
<P
></P
><UL
><LI
><P
><A
NAME="TRIG-RT"
></A
>
TRIG_RT: ask the driver to use a
<SPAN
CLASS="strong"
><B
CLASS="EMPHASIS"
>hard real-time</B
></SPAN
> interrupt handler.
This will reduce latency in handling interrupts from your data
aquisition
hardware.  It can be useful if you are sampling at high frequency, or
if your hardware has a small onboard data buffer.  You must have a
real-time kernel (<A
HREF="http://www.rtai.org"
TARGET="_top"
>RTAI</A
> or
<A
HREF="http://www.rtlinux-gpl.org/"
TARGET="_top"
>RTLinux/GPL</A
>)
and must compile <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> with real-time support, or this flag will do
nothing.</P
></LI
><LI
><P
><A
NAME="TRIG-WAKE-EOS"
></A
>
TRIG_WAKE_EOS:
where <SPAN
CLASS="QUOTE"
>"EOS"</SPAN
> stands for <SPAN
CLASS="QUOTE"
>"End of Scan"</SPAN
>. Some
drivers will change their behaviour when this flag is set, trying to
transfer data at the end of every scan (instead of, for example,
passing data in chunks whenever the board's hardware data buffer is
half full).  This flag may degrade a driver's performance at high
frequencies, because the end of a scan is, in general, a much more
frequent event than the filling up of the data buffer.</P
></LI
><LI
><P
><A
NAME="TRIG-ROUND-NEAREST"
></A
>
TRIG_ROUND_NEAREST:
round to nearest supported timing period, the default.
This flag (as well as the following three), indicates how timing
arguments should be rounded if the hardware cannot achieve the exact
timing requested.</P
></LI
><LI
><P
><A
NAME="TRIG-ROUND-DOWN"
></A
>
TRIG_ROUND_DOWN: round period down.</P
></LI
><LI
><P
><A
NAME="TRIG-ROUND-UP"
></A
>
TRIG_ROUND_UP: round period up.</P
></LI
><LI
><P
><A
NAME="TRIG-ROUND-UP-NEXT"
></A
>
TRIG_ROUND_UP_NEXT:
this one doesn't do anything, and I don't know what it was intended
to do...?</P
></LI
><LI
><P
><A
NAME="TRIG-DITHER"
></A
>
TRIG_DITHER: enable dithering? Dithering is a software technique to
smooth the influence of discretization <SPAN
CLASS="QUOTE"
>"noise"</SPAN
>.</P
></LI
><LI
><P
><A
NAME="TRIG-DEGLITCH"
></A
>
TRIG_DEGLITCH: enable deglitching? Another <SPAN
CLASS="QUOTE"
>"noise"</SPAN
>
smoothing technique.</P
></LI
><LI
><P
><A
NAME="TRIG-WRITE"
></A
>
TRIG_WRITE:
write to bidirectional devices.  Could be useful, in principle, if
someone wrote a driver that supported commands for a digital I/O
device that could do either input or output.</P
></LI
><LI
><P
><A
NAME="TRIG-BOGUS"
></A
>
TRIG_BOGUS: do the motions?</P
></LI
><LI
><P
><A
NAME="TRIG-OTHER"
></A
>
TRIG_CONFIG: perform configuration, not triggering.  This is a legacy
of the deprecated
<A
HREF="x4629.html#REF-TYPE-COMEDI-CMD"
>comedi_trig_struct</A
>
data structure, and has no function at present.</P
></LI
></UL
></P
></DIV
><DIV
CLASS="SECTION"
><H3
CLASS="SECTION"
><A
NAME="AEN1109"
>4.5.5. Anti-aliasing</A
></H3
><P
>If you wish to aquire accurate waveforms, it is vital that you use an
anti-alias filter.  An anti-alias filter is a low-pass filter used to
remove all    frequencies higher than the Nyquist frequency (half your sampling rate)
from your analog input signal
before you convert it to digital.  If you fail to filter your input signal,
any high frequency components in the original analog signal will create
artifacts in your recorded    digital waveform that cannot be corrected.</P
><P
>For example, suppose you are sampling an analog input channel at a rate of
1000 Hz.  If you were to apply a 900 Hz sine wave to the input, you
would find that your
sampling rate is not high enough to faithfully record the 900 Hz input,
since it is above your Nyquist frequency of 500 Hz.  Instead, what you
will see in your recorded digital waveform is a 100 Hz sine wave!  If you
don't use an anti-alias filter, it is impossible to tell whether the 100
Hz sine wave you see in your digital signal was really produced by a
100 Hz input signal, or a 900 Hz signal aliased to 100 Hz, or a 1100 Hz
signal, etc.</P
><P
>In practice, the cutoff frequency for the anti-alias filter is usually
set 10% to 20% below the Nyquist frequency due to fact that real filters
do not have infinitely sharp cutoffs.</P
></DIV
></DIV
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="SLOWLYVARYING"
>4.6. Slowly-varying inputs</A
></H2
><P
>Sometimes, your input channels change slowly enough that
you are able to average many successive input values to get a
more accurate measurement of the actual value.  In general,
the more samples you average, the better your estimate
gets, roughly by a factor of sqrt(number_of_samples).
Obviously, there are limitations to this:</P
><P
></P
><UL
><LI
><P
>you are ultimately limited by <SPAN
CLASS="QUOTE"
>"Spurious Free Dynamic
Range"</SPAN
>. This SFDR is one of the popular measures to quantify how
much noise a signal carries. If you take a Fourier transform of your
signal, you will see several <SPAN
CLASS="QUOTE"
>"peaks"</SPAN
> in the transform: one
or more of the fundamental harmonics of the measured signal, and lots
of little <SPAN
CLASS="QUOTE"
>"peaks"</SPAN
> (called <SPAN
CLASS="QUOTE"
>"spurs"</SPAN
>) caused by
noise. The SFDR is then the difference between the amplitude of the
fundamental harmonic and of the largest spur (at frequencies below
half of the Nyquist frequency of the DAQ sampler!).</P
></LI
><LI
><P
>you need to have <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>some</I
></SPAN
> noise on the input channel,
otherwise you will be averaging the same number <TT
CLASS="LITERAL"
>N</TT
>
times. (Of course, this only holds if the noise is large enough to
cause at least a one-bit discretization.)</P
></LI
><LI
><P
>the more noise you have, the greater your SFDR, but it
takes many more samples to compensate for the increased
noise.</P
></LI
><LI
><P
>if you feel the need to average samples for, for example, two seconds,
your signal will need to be <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>very</I
></SPAN
> slowly-varying,
i.e., not varying more than your target uncertainty for the entire two
seconds.</P
></LI
></UL
><P
>As you might have guessed, the <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> library has functions
to help you in your quest to accurately measure slowly varying
inputs:
<PRE
CLASS="PROGRAMLISTING"
>  int <A
HREF="r6018.html"
>comedi_sv_init</A
>(<A
HREF="x4629.html#REF-TYPE-COMEDI-SV-T"
>comedi_sv_t</A
> * sv, <A
HREF="x4629.html#REF-TYPE-COMEDI-T"
>comedi_t</A
> * device, unsigned int subdevice, unsigned int channel);</PRE
>
This function initializes the
<A
HREF="x4629.html#REF-TYPE-COMEDI-SV-T"
>comedi_sv_t</A
> data structure, used
to do the averaging acquisition:
<PRE
CLASS="PROGRAMLISTING"
>struct comedi_sv_struct{
  <A
HREF="x4629.html#REF-TYPE-COMEDI-T"
>comedi_t</A
> *dev;
  unsigned int subdevice;
  unsigned int chan;

  /* range policy */
  int range;
  int aref;

  /* number of measurements to average (for analog inputs) */
  int n;

  lsampl_t maxdata;
};</PRE
>
The actual acquisition is done with:
<PRE
CLASS="PROGRAMLISTING"
>  int <A
HREF="r6068.html"
>comedi_sv_measure</A
>(<A
HREF="x4629.html#REF-TYPE-COMEDI-SV-T"
>comedi_sv_t</A
> * sv, double * data);</PRE
>
The number of samples over which the
<CODE
CLASS="FUNCTION"
>comedi_sv_measure()</CODE
> averages is limited by the
implementation (currently the limit is 100 samples).</P
><P
>One typical use for this function is the measurement of thermocouple
voltages.
And the <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> self-calibration utility also uses these functions.
On some hardware, it is possible to tell it to measure an
internal stable voltage reference, which is typically going
to be very slowly varying; on the kilosecond time scale
or more.  So, it is reasonable to measure millions of samples,
to get a very accurate measurement of the A/D converter output
value that corresponds to the voltage reference.  Sometimes,
however, this is overkill, since there is no need to
perform a part-per-million calibration to a standard that
is only accurate to a part-per-thousand.</P
></DIV
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="EXPERIMENTALFUNCTIONALITY"
>4.7. Experimental functionality</A
></H2
><P
>The following subsections document functionality that has not yet
matured. Most of this functionality has even not been implemented yet
in any single device driver. This information is included here, in
order to stimulate discussion about their API, and to encourage
pioneering implementations.</P
><DIV
CLASS="SECTION"
><H3
CLASS="SECTION"
><A
NAME="DIGITALINPUTCOMBINING"
>4.7.1. Digital input combining machines</A
></H3
><P
>(<SPAN
CLASS="strong"
><B
CLASS="EMPHASIS"
>Status: experimental (i.e., no driver implements
this yet)</B
></SPAN
>)</P
><P
>When one or several digital inputs are used to modify an output
value, either an accumulator or a single digital line or bit,
a bitfield structure is typically used in the <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> interface.
The digital inputs have two properties, <SPAN
CLASS="QUOTE"
>"sensitive"</SPAN
> inputs
and <SPAN
CLASS="QUOTE"
>"modifier"</SPAN
> inputs.  Edge transitions on sensitive
inputs cause changes in the output signal, whereas modifier inputs
change the effect of edge transitions on sensitive inputs.  Note that
inputs can be both modifier inputs and sensitive inputs.</P
><P
>For simplification purposes, it is assumed that multiple digital
inputs do not change simultaneously.</P
><P
>The combined state of the modifier inputs determine a modifier
state.  For each combination of modifier state and sensitive
input, there is a set of bits that determine the effect on the
output value due to positive or negative transitions of the
sensitive input.  For each transition direction, there are two
bits defined as follows:
<P
></P
><TABLE
BORDER="0"
><TBODY
><TR
><TD
>00: transition is ignored.</TD
></TR
><TR
><TD
>01: accumulator is incremented, or output is set.</TD
></TR
><TR
><TD
>10: accumulator is decremented, or output is cleared.</TD
></TR
><TR
><TD
>11: reserved.</TD
></TR
></TBODY
></TABLE
><P
></P
>
For example, a simple digital follower is specified by the bit
pattern 01 10, because it sets the output on positive transitions
of the input, and clears the output on negative transitions.  A
digital inverter is similarily 10 01.  These systems have only
one sensitive input.</P
><P
>As another example, a simple up counter, which increments on
positive transitions of one input, is specified by 01 00.  This
system has only one sensitive input.</P
><P
>When multiple digital inputs are used, the inputs are divided
into two types, inputs which cause changes in the accumulator, and
those that only modify the meaning of transitions on other inputs.
Modifier inputs do not require bitfields, but there needs to be
a bitfield of length 4*(2^(N-1)) for each edge sensitive input,
where N is the total number of inputs.  Since N is usually 2 or
3, with only one edge sensitive input, the scaling issues are
not significant.</P
></DIV
><DIV
CLASS="SECTION"
><H3
CLASS="SECTION"
><A
NAME="ANALOGCONVERSION"
>4.7.2. Analog filtering configuration</A
></H3
><P
><SPAN
CLASS="strong"
><B
CLASS="EMPHASIS"
>(Status: design (i.e., no driver implements
this yet).)</B
></SPAN
></P
><P
>The <A
HREF="x621.html#INSN-DATA-STRUCTURE-INSN"
>insn</A
> field of the
<A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data structure</A
>
has not been assigned yet.</P
><P
>The <A
HREF="x621.html#INSN-DATA-STRUCTURE-CHANSPEC"
>chanspec</A
> field
of the <A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data
structure</A
> is ignored.</P
><P
>Some devices have the capability to add white noise (dithering) to
analog input measurement.  This additional noise can then be averaged
out, to get a more accurate measurement of the input signal.  It
should not be assumed that channels can be separately configured.
A simple design can use 1 bit to turn this feature on/off.</P
><P
>Some devices have the capability of changing the glitch characteristics
of analog output subsytems.  The default (off) case should be where
the average settling time is lowest.  A simple design can use 1 bit
to turn this feature on/off.</P
><P
>Some devices have a configurable analog filters as part of the analog
input stage.  A simple design can use 1 bit to enable/disable the
filter.  Default is disabled, i.e., the filter being bypassed, or if
the choice is between two filters, the filter with the largest
bandwidth.</P
></DIV
><DIV
CLASS="SECTION"
><H3
CLASS="SECTION"
><A
NAME="WAVEFORMGENERATION"
>4.7.3. Analog Output Waveform Generation</A
></H3
><P
><SPAN
CLASS="strong"
><B
CLASS="EMPHASIS"
>(Status: design (i.e., no driver implements
this yet).)</B
></SPAN
></P
><P
>The <A
HREF="x621.html#INSN-DATA-STRUCTURE-INSN"
>insn</A
> field of the
<A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data structure</A
>
has not been assigned yet.</P
><P
>The <A
HREF="x621.html#INSN-DATA-STRUCTURE-CHANSPEC"
>chanspec</A
> field
of the <A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data
structure</A
> is ignored.</P
><P
>Some devices have the ability to cyclicly loop through samples kept in
an on-board analog output FIFO.  This config should allow the user to
enable/disable this mode.</P
><P
>This config should allow the user to configure the number of samples
to loop through.  It may be necessary to configure the channels used.</P
></DIV
><DIV
CLASS="SECTION"
><H3
CLASS="SECTION"
><A
NAME="EXTENDEDTRIGGERING"
>4.7.4. Extended Triggering</A
></H3
><P
><SPAN
CLASS="strong"
><B
CLASS="EMPHASIS"
>(Status: alpha.)</B
></SPAN
></P
><P
>The <A
HREF="x621.html#INSN-DATA-STRUCTURE-INSN"
>insn</A
> field of the
<A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data structure</A
>
has not been assigned yet.</P
><P
>The <A
HREF="x621.html#INSN-DATA-STRUCTURE-CHANSPEC"
>chanspec</A
> field
of the <A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data
structure</A
> is ignored.</P
><P
>This section covers common information for all extended
triggering configuration, and doesn't describe a particular
type of extended trigger.</P
><P
>Extended triggering is used to configure triggering engines that
do not fit into commands.  In a typical programming sequence, the
application will use
<A
HREF="x621.html#INSTRUCTIONSCONFIGURATION"
>configuration instructions</A
>
to configure an extended trigger, and a
<A
HREF="x621.html#COMMANDSSTREAMING"
>command</A
>,
specifying
<A
HREF="x621.html#TRIG-OTHER"
>TRIG_OTHER</A
> as one of the trigger
sources.</P
><P
>Extended trigger configuration should be designed in such a way
that the user can probe for valid parameters, similar to how
command testing works.  An extended trigger configuration instruction
should not configure the hardware directly, rather, the configuration
should be saved until the subsequent command is issued.  This
allows more flexibility for future interface changes.</P
><P
>It has not been decided whether the configuration stage should return a
token that is then used as the trigger argument in the command.
Using tokens is one method to satisfy the problem that extended
trigger configurations may have subtle compatiblity issues with
other trigger sources/arguments that can only be determined at
command test time.  Passing all stages of a command test should
only be allowed with a properly configured extended trigger.</P
><P
>Extended triggers must use
<A
HREF="x621.html#INSN-DATA-STRUCTURE-DATA"
>data[1]</A
> as flags.  The
upper 16 bits are reserved and used only for flags that are common to
all extended triggers.  The lower 16 bits may be defined by the
particular type of extended trigger.</P
><P
>Various types of extended triggers must use
<A
HREF="x621.html#INSN-DATA-STRUCTURE-DATA"
>data[1]</A
> to know which
event the extended trigger will be assigned to in the command
structure.  The possible values are an OR'd mask of the following:</P
><P
></P
><UL
><LI
><P
>COMEDI_EV_START
    </P
></LI
><LI
><P
>COMEDI_EV_SCAN_BEGIN
    </P
></LI
><LI
><P
>COMEDI_EV_CONVERT
    </P
></LI
><LI
><P
>COMEDI_EV_SCAN_END
    </P
></LI
><LI
><P
>COMEDI_EV_STOP
    </P
></LI
></UL
></DIV
><DIV
CLASS="SECTION"
><H3
CLASS="SECTION"
><A
NAME="ANALOGTRIGGERING"
>4.7.5. Analog Triggering</A
></H3
><P
><SPAN
CLASS="strong"
><B
CLASS="EMPHASIS"
>(Status: alpha. The <CODE
CLASS="FUNCTION"
>ni_mio_common.c</CODE
> driver
implements this feature.)</B
></SPAN
></P
><P
>The <A
HREF="x621.html#INSN-DATA-STRUCTURE-INSN"
>insn</A
> field of the
<A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data structure</A
>
has not been assigned yet.</P
><P
>The <A
HREF="x621.html#INSN-DATA-STRUCTURE-CHANSPEC"
>chanspec</A
> field
of the <A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data
structure</A
> is ignored.</P
><P
>The <A
HREF="x621.html#INSN-DATA-STRUCTURE-DATA"
>data</A
> field
of the <A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data
structure</A
> is used as follows:
<P
></P
><TABLE
BORDER="0"
><TBODY
><TR
><TD
>data[1]:  trigger and combining machine configuration.
  </TD
></TR
><TR
><TD
>data[2]: analog triggering signal chanspec.
  </TD
></TR
><TR
><TD
>data[3]: primary analog level.
  </TD
></TR
><TR
><TD
>data[4]: secondary analog level.
  </TD
></TR
></TBODY
></TABLE
><P
></P
></P
><P
>Analog triggering is described by a digital combining machine that
has two sensitive digital inputs.  The sensitive digital inputs are
generated by configurable analog comparators.  The analog comparators
generate a digital 1 when the analog triggering signal is greater
than the comparator level.  The digital inputs are not modifier
inputs.  Note, however, there is an effective modifier due to the
restriction that the primary analog comparator level must be less
than the secondary analog comparator level.</P
><P
>If only one analog comparator signal is used, the combining machine
for the secondary input should be set to ignored, and the secondary
analog level should be set to 0.</P
><P
>The interpretation of the chanspec and voltage levels is device
dependent, but should correspond to similar values of the analog
input subdevice, if possible.</P
><P
>Notes:  Reading range information is not addressed.  This makes it
difficult to convert comparator voltages to data values.</P
><P
>Possible extensions: A parameter that specifies the necessary time
that the set condition has to be true before the trigger is generated.
A parameter that specifies the necessary time that the reset condition
has to be true before the state machine is reset.</P
></DIV
><DIV
CLASS="SECTION"
><H3
CLASS="SECTION"
><A
NAME="BITFIELDMATCHING"
>4.7.6. Bitfield Pattern Matching Extended Trigger</A
></H3
><P
><SPAN
CLASS="strong"
><B
CLASS="EMPHASIS"
>(Status: design. No driver implements this feature yet.)</B
></SPAN
></P
><P
>The <A
HREF="x621.html#INSN-DATA-STRUCTURE-INSN"
>insn</A
> field of the
<A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data structure</A
>
has not been assigned yet.</P
><P
>The <A
HREF="x621.html#INSN-DATA-STRUCTURE-CHANSPEC"
>chanspec</A
> field
of the <A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data
structure</A
> is ignored.</P
><P
>The <A
HREF="x621.html#INSN-DATA-STRUCTURE-DATA"
>data</A
> field
of the <A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data
structure</A
> is used as follows:</P
><P
></P
><TABLE
BORDER="0"
><TBODY
><TR
><TD
>data[1]: trigger flags.
  </TD
></TR
><TR
><TD
>data[2]: mask.
  </TD
></TR
><TR
><TD
>data[3]: pattern.
  </TD
></TR
></TBODY
></TABLE
><P
></P
><P
>The pattern matching trigger issues a trigger when all of a specifed
set of input lines match a specified pattern.  If the device allows,
the input lines should correspond to the input lines of a digital input
subdevice, however, this will necessarily be device dependent.  Each
possible digital line that can be matched is assigned a bit in the
mask and pattern.  A bit set in the mask indicates that the
input line must match the corresponding bit in the pattern.
A bit cleared in the mask indicates that the input line is ignored.</P
><P
>Notes: This only allows 32 bits in the pattern/mask, which may be
too few.  Devices may support selecting different sets of lines from
which to match a pattern.</P
><P
>Discovery: The number of bits can be discovered by setting the mask
to all 1's.  The driver must modify this value and return -EAGAIN.</P
></DIV
><DIV
CLASS="SECTION"
><H3
CLASS="SECTION"
><A
NAME="COUNTERTIMER"
>4.7.7. Counter configuration</A
></H3
><P
><SPAN
CLASS="strong"
><B
CLASS="EMPHASIS"
>(Status: design. No driver implements this feature yet.)</B
></SPAN
></P
><P
>The <A
HREF="x621.html#INSN-DATA-STRUCTURE-INSN"
>insn</A
> field of the
<A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data structure</A
>
has not been assigned yet.</P
><P
>The <A
HREF="x621.html#INSN-DATA-STRUCTURE-CHANSPEC"
>chanspec</A
> field
of the <A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data
structure</A
> is used to specify which counter to use. (I.e., the
counter is a <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> channel.)</P
><P
>The <A
HREF="x621.html#INSN-DATA-STRUCTURE-DATA"
>data</A
> field
of the <A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data
structure</A
> is used as follows:</P
><P
></P
><TABLE
BORDER="0"
><TBODY
><TR
><TD
>data[1]: trigger configuration.
  </TD
></TR
><TR
><TD
>data[2]: primary input chanspec.
  </TD
></TR
><TR
><TD
>data[3]: primary combining machine configuration.
  </TD
></TR
><TR
><TD
>data[4]: secondary input chanspec.
  </TD
></TR
><TR
><TD
>data[5]: secondary combining machine configuration.
  </TD
></TR
><TR
><TD
>data[6]: latch configuration.
  </TD
></TR
></TBODY
></TABLE
><P
></P
><P
>Note that this configuration is only useful if the counting has to be
done in <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>software</I
></SPAN
>. Many cards offer configurable
counters in hardware; e.g., general purpose timer cards can be
configured to act as pulse generators, frequency counters, timers,
encoders, etc.</P
><P
>Counters can be operated either in synchronous mode (using
<A
HREF="x621.html#COMEDIINSNSTRUCTURE"
>INSN_READ</A
>)
or asynchronous mode (using
<A
HREF="x621.html#COMMANDSSTREAMING"
>commands</A
>), similar to analog
input subdevices.
The input signal for both modes is the accumulator.
Commands on counter subdevices are almost always specified using
<A
HREF="x621.html#COMMAND-DATA-STRUCT-SCAN-BEGIN-SRC"
>scan_begin_src</A
>
= <A
HREF="x621.html#TRIGOTHER-EVENT"
>TRIG_OTHER</A
>, with the
counter configuration also serving as the extended configuration for
the scan begin source.</P
><P
>Counters are made up of an accumulator and a combining machine that
determines when the accumulator should be incremented or decremented
based on the values of the input signals.  The combining machine
optionally determines when the accumulator should be latched and
put into a buffer.  This feature is used in asynchronous mode.</P
><P
>Note: How to access multiple pieces of data acquired at each event?</P
></DIV
><DIV
CLASS="SECTION"
><H3
CLASS="SECTION"
><A
NAME="AUXCOUNTER"
>4.7.8. One source plus auxiliary counter configuration</A
></H3
><P
><SPAN
CLASS="strong"
><B
CLASS="EMPHASIS"
>(Status: design. No driver implements this feature yet.)</B
></SPAN
></P
><P
>The <A
HREF="x621.html#INSN-DATA-STRUCTURE-INSN"
>insn</A
> field of the
<A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data structure</A
>
has not been assigned yet.</P
><P
>The <A
HREF="x621.html#INSN-DATA-STRUCTURE-CHANSPEC"
>chanspec</A
> field
of the <A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data
structure</A
> is used to ...</P
><P
>The <A
HREF="x621.html#INSN-DATA-STRUCTURE-DATA"
>data</A
> field
of the <A
HREF="x621.html#INSN-DATA-STRUCTURE"
>instruction data
structure</A
> is used as follows:</P
><P
><P
></P
><TABLE
BORDER="0"
><TBODY
><TR
><TD
>data[1]: is flags, including the flags for the command triggering
configuration.  If a command is not subsequently issued on the
subdevice, the command triggering portion of the flags are ignored.
 </TD
></TR
><TR
><TD
>data[2]: determines the mode of operation.  The mode of operation
is actually a bitfield that encodes what to do for various
transitions of the source signals.</TD
></TR
><TR
><TD
>data[3], data[4]: determine the primary source for the counter,
similar to the
<A
HREF="x621.html#COMMAND-DATA-STRUCT-SCAN-BEGIN-SRC"
>_src</A
> and the
<A
HREF="x621.html#COMMAND-DATA-STRUCT-SCAN-BEGIN-ARG"
>_arg</A
> fields
used in the
<A
HREF="x621.html#COMMAND-DATA-STRUCT"
>command data structure</A
>.</TD
></TR
></TBODY
></TABLE
><P
></P
></P
><P
>Notes: How to specify which events cause a latch and push, and what
should get latched?</P
></DIV
><DIV
CLASS="SECTION"
><H3
CLASS="SECTION"
><A
NAME="RTSI"
>4.7.9. National instruments RTSI trigger bus</A
></H3
><P
>A number of NI boards support the RTSI (Real Time System Integration) bus.
It's primary use is to synchronize multiple DAQ cards.
On PXI boards, the RTSI lines correspond to the PXI trigger lines 0 to 7.  PCI
boards use cables to connect to their RTSI ports.
The RTSI bus consists of 8 digital signal lines numbered 0 to 7 that are bi-directional.
Each of these signal lines
can be configured as an input or output, and the signal appearing on the output
of each line can be configured to one of several internal board timing signals
(although on older boards RTSI line 7 can only be used for the clock signal).
The ni_pcimio, ni_atmio, and ni_mio_cs drivers expose the RTSI bus
as a digital I/O subdevice (subdevice number 10).</P
><P
>The functions comedi_dio_config() and comedi_dio_get_config() can be used on
the RTSI subdevice to
set/query the direction (input or output) of each of the RTSI lines individually.</P
><P
>The subdevice also supports the
INSN_CONFIG_SET_CLOCK_SRC and INSN_CONFIG_GET_CLOCK_SRC configuration
instructions, which can be
used to configure/query what source the board uses to synchronize its
master clock to.  The various possibilities are defined in the comedi.h
header file:</P
><DIV
CLASS="INFORMALTABLE"
><P
></P
><A
NAME="AEN1326"
></A
><TABLE
BORDER="1"
CLASS="CALSTABLE"
><COL><COL><THEAD
><TR
><TH
>Clock Source</TH
><TH
>Description</TH
></TR
></THEAD
><TBODY
><TR
><TD
>NI_MIO_INTERNAL_CLOCK</TD
><TD
>Use the board's internal oscillator.</TD
></TR
><TR
><TD
>NI_MIO_RTSI_CLOCK</TD
><TD
>Use the RTSI line 7 as the master clock.  This source is
only supported on pre-m-series boards.  The newer m-series boards
use NI_MIO_PLL_RTSI_CLOCK() instead.</TD
></TR
><TR
><TD
>NI_MIO_PLL_PXI_STAR_TRIGGER_CLOCK</TD
><TD
>Only available for newer m-series PXI boards.  Synchronizes the board's
phased-locked loop (which runs at 80MHz) to the PXI star trigger
line.</TD
></TR
><TR
><TD
>NI_MIO_PLL_PXI10_CLOCK</TD
><TD
>Only available for newer m-series PXI boards.
Synchronizes the board's
phased-locked loop (which runs at 80MHz) to the 10 MHz PXI backplane
clock.</TD
></TR
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>unsigned NI_MIO_PLL_RTSI_CLOCK(unsigned n)</PRE
></TD
><TD
>Only available for newer m-series boards.
The function returns a clock source which will cause the board's
phased-locked loop (which runs at 80MHz) to syncronize to the RTSI
line specified in the function argument.</TD
></TR
></TBODY
></TABLE
><P
></P
></DIV
><P
>For all clock sources except NI_MIO_INTERNAL_CLOCK and NI_MIO_PLL_PXI10_CLOCK,
you should pass the period of the clock your are feeding to the board when
using INSN_CONFIG_SET_CLOCK_SRC.</P
><P
>Finally, the configuration instructions INSN_CONFIG_SET_ROUTING and
INSN_CONFIG_GET_ROUTING can be used to select/query which internal signal
will appear on a given RTSI output line.  The header file comedi.h defines
the following signal sources which can be routed to an RTSI line:</P
><DIV
CLASS="INFORMALTABLE"
><P
></P
><A
NAME="AEN1351"
></A
><TABLE
BORDER="1"
CLASS="CALSTABLE"
><COL><COL><THEAD
><TR
><TH
>Signal Source</TH
><TH
>Description</TH
></TR
></THEAD
><TBODY
><TR
><TD
>NI_RTSI_OUTPUT_ADR_START1</TD
><TD
>ADR_START1, an analog input start signal.  See the NI's
DAQ-STC Technical Reference Manual for more information.</TD
></TR
><TR
><TD
>NI_RTSI_OUTPUT_ADR_START2</TD
><TD
>ADR_START2, an analog input stop signal.  See the NI's
DAQ-STC Technical Reference Manual for more information.</TD
></TR
><TR
><TD
>NI_RTSI_OUTPUT_SCLKG</TD
><TD
>SCLKG, a sample clock signal.  See the NI's
DAQ-STC Technical Reference Manual for more information.</TD
></TR
><TR
><TD
>NI_RTSI_OUTPUT_DACUPDN</TD
><TD
>DACUPDN, a dac update signal.  See the NI's
DAQ-STC Technical Reference Manual for more information.</TD
></TR
><TR
><TD
>NI_RTSI_OUTPUT_DA_START1</TD
><TD
>DA_START1, an analog output start signal.  See the NI's
DAQ-STC Technical Reference Manual for more information.</TD
></TR
><TR
><TD
>NI_RTSI_OUTPUT_G_SRC0</TD
><TD
>G_SRC0, the source signal to general purpose counter 0.  See the NI's
DAQ-STC Technical Reference Manual for more information.</TD
></TR
><TR
><TD
>NI_RTSI_OUTPUT_G_GATE0</TD
><TD
>G_GATE0, the gate signal to general purpose counter 0.  See the NI's
DAQ-STC Technical Reference Manual for more information.</TD
></TR
><TR
><TD
>NI_RTSI_OUTPUT_RGOUT0</TD
><TD
>RGOUT0, the output signal of general purpose counter 0.  See the NI's
DAQ-STC Technical Reference Manual for more information.</TD
></TR
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>unsigned NI_RTSI_OUTPUT_RTSI_BRD(unsigned n)</PRE
></TD
><TD
>RTSI_BRD0 though RTSI_BRD3 are four internal signals which can
have various other signals routed to them in turn.  Currently, comedi
provides no way to configure the signals routed to the RTSI_BRD lines.
See the NI's DAQ-STC Technical Reference Manual for more information.</TD
></TR
><TR
><TD
>NI_RTSI_OUTPUT_RTSI_OSC</TD
><TD
>The RTSI clock signal.  On pre-m-series boards, this signal is always
routed to RTSI line 7, and cannot be routed to lines 0 through 6.  On
m-series boards, any RTSI line can be configured to output the clock
signal.</TD
></TR
></TBODY
></TABLE
><P
></P
></DIV
><P
>The RTSI bus pins may be used as trigger inputs for many of the
COMEDI trigger functions. To use the RTSI bus pins, set the source to be
TRIG_EXT and the source argument using the return values from the
NI_EXT_RTSI() function (or similarly the NI_EXT_PFI() function if you want
to trigger from a PFI line).  The CR_EDGE and CR_INVERT flags may
also be set on the trigger source argument to specify edge and
falling edge/low level triggering.&#13;</P
><P
>An example to set up a device as a master is given below.</P
><PRE
CLASS="PROGRAMLISTING"
>void comediEnableMaster(comedi_t* dev){
	comedi_insn   configCmd;
	lsampl_t      configData[2];
	int           ret;
	unsigned int  d = 0;
	static const unsigned rtsi_subdev = 10;
	static const unsigned rtsi_clock_line = 7;

	/* Route RTSI clock to line 7 (not needed on pre-m-series boards since their
		clock is always on line 7). */
	memset(&#38;configCmd, 0, sizeof(configCmd));
	memset(&#38;configData, 0, sizeof(configData));
	configCmd.insn = INSN_CONFIG;
	configCmd.subdev = rtsi_subdev;
	configCmd.chanspec = rtsi_clock_line;
	configCmd.n = 2;
	configCmd.data = configData;
	configCmd.data[0] = INSN_CONFIG_SET_ROUTING;
	configCmd.data[1] = NI_RTSI_OUTPUT_RTSI_OSC;
	ret = comedi_do_insn(dev, &#38;configCmd);
	if(ret &#60; 0){
		comedi_perror("comedi_do_insn: INSN_CONFIG");
		exit(1);
	}
	// Set clock RTSI line as output
	ret = comedi_dio_config(dev, rtsi_subdev, rtsi_clock_line, INSN_CONFIG_DIO_OUTPUT);
	if(ret &#60; 0){
		comedi_perror("comedi_dio_config");
		exit(1);
	}

	/* Set routing of the 3 main AI RTSI signals and their direction to output.
		We're reusing the already initialized configCmd instruction here since
		it's mostly the same. */
	configCmd.chanspec = 0;
	configCmd.data[1] =  NI_RTSI_OUTPUT_ADR_START1;
	ret = comedi_do_insn(dev, &#38;configCmd);
	if(ret &#60; 0){
		comedi_perror("comedi_do_insn: INSN_CONFIG");
		exit(1);
	}
	ret = comedi_dio_config(dev, rtsi_subdev, 0, INSN_CONFIG_DIO_OUTPUT);
	if(ret &#60; 0){
		comedi_perror("comedi_dio_config");
		exit(1);
	}

	configCmd.chanspec = 1;
	configCmd.data[1] =  NI_RTSI_OUTPUT_ADR_START2;
	ret = comedi_do_insn(dev, &#38;configCmd);
	if(ret &#60; 0){
		comedi_perror("comedi_do_insn: INSN_CONFIG");
		exit(1);
	}
	ret = comedi_dio_config(dev, rtsi_subdev, 1, INSN_CONFIG_DIO_OUTPUT);
	if(ret &#60; 0){
		comedi_perror("comedi_dio_config");
		exit(1);
	}

	configCmd.chanspec = 2;
	configCmd.data[1] =  NI_RTSI_OUTPUT_SCLKG;
	ret = comedi_do_insn(dev, &#38;configCmd);
	if(ret &#60; 0){
		comedi_perror("comedi_do_insn: INSN_CONFIG");
		exit(1);
	}
	ret = comedi_dio_config(dev, rtsi_subdev, 2, INSN_CONFIG_DIO_OUTPUT);
	if(ret &#60; 0){
		comedi_perror("comedi_dio_config");
		exit(1);
	}
}</PRE
><P
>An example to slave a m-series device from this master follows.  A pre-m-series
device would need to use NI_MIO_RTSI_CLOCK for the clock source instead.  In
your code, you may also wish to configure the master device to use the
external clock source instead of using its internal clock directly (for
best syncronization).</P
><PRE
CLASS="PROGRAMLISTING"
>void comediEnableSlave(comedi_t* dev){
	comedi_insn   configCmd;
	lsampl_t      configData[3];
	int           ret;
	unsigned int  d = 0;;
	static const unsigned rtsi_subdev = 10;
	static const unsigned rtsi_clock_line = 7;

	memset(&#38;configCmd, 0, sizeof(configCmd));
	memset(&#38;configData, 0, sizeof(configData));
	configCmd.insn = INSN_CONFIG;
	configCmd.subdev = rtsi_subdev;
	configCmd.chanspec = 0;
	configCmd.n = 3;
	configCmd.data = configData;
	configCmd.data[0] = INSN_CONFIG_SET_CLOCK_SRC;
	configCmd.data[1] = NI_MIO_PLL_RTSI_CLOCK(rtsi_clock_line);
	configCmd.data[2] = 100;	/* need to give it correct external clock period */
	ret = comedi_do_insn(dev, &#38;configCmd);
	if(ret &#60; 0){
		comedi_perror("comedi_do_insn: INSN_CONFIG");
		exit(1);
	}
	/* configure RTSI clock line as input */
	ret = comedi_dio_config(dev, rtsi_subdev, rtsi_clock_line, INSN_CONFIG_DIO_INPUT);
	if(ret &#60; 0){
		comedi_perror("comedi_dio_config");
		exit(1);
	}
	/* Configure RTSI lines we are using for AI signals as inputs. */
	ret = comedi_dio_config(dev, rtsi_subdev, 0, INSN_CONFIG_DIO_INPUT);
	if(ret &#60; 0){
		comedi_perror("comedi_dio_config");
		exit(1);
	}
	ret = comedi_dio_config(dev, rtsi_subdev, 1, INSN_CONFIG_DIO_INPUT);
	if(ret &#60; 0){
		comedi_perror("comedi_dio_config");
		exit(1);
	}
	ret = comedi_dio_config(dev, rtsi_subdev, 2, INSN_CONFIG_DIO_INPUT);
	if(ret &#60; 0){
		comedi_perror("comedi_dio_config");
		exit(1);
	}
}

int comediSlaveStart(comedi_t* dev){
	comedi_cmd     cmd;
	unsigned int   nChannels = 8;
	double         sampleRate = 50000;
	unsigned int   chanList[8];
	int            i;

	// Setup chan list
	for(i = 0; i &#60; nChannels; i++){
		chanList[i] = CR_PACK(i, 0, AREF_GROUND);
	}
	// Set up command
	memset(&#38;cmd, 0, sizeof(cmd));
	ret = comedi_get_cmd_generic_timed(dev, subdevice, &#38;cmd, int(1e9/(nChannels * sampleRate)));
	if(ret&#60;0){
		printf("comedi_get_cmd_generic_timed failed\n");
		return ret;
	}
	cmd.chanlist        = chanList;
	cmd.chanlist_len    = nChannels;
	cmd.scan_end_arg    = nChannels;
	cmd.start_src        = TRIG_EXT;
	cmd.start_arg        = CR_EDGE | NI_EXT_RTSI(0);
	cmd.convert_src    = TRIG_EXT;
	cmd.convert_arg    = CR_INVERT | CR_EDGE | NI_EXT_RTSI(2);
	cmd.stop_src        = TRIG_NONE;

	ret = comedi_command(dev0, &#38;cmd0);
	if(ret&#60;0){
		printf("comedi_command failed\n");
		return ret;
	}
	return 0;
}</PRE
></DIV
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x403.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="index.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x1394.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Writing <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> programs</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Writing a <ACRONYM
CLASS="ACRONYM"
>Comedi</ACRONYM
> driver</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>