
Include the full tut3.c program listing in the document as it's not much bigger than tut3_part.c and it's a pain maintaining both of them.
254 lines
10 KiB
XML
254 lines
10 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
|
|
<!ENTITY % comedilib_entities SYSTEM "comedilib.ent">
|
|
%comedilib_entities;
|
|
]>
|
|
|
|
<section id="writingprograms" xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
<title>
|
|
Writing &comedi; programs
|
|
</title>
|
|
<para>
|
|
This section describes how &comedi;
|
|
can be used in an application, to communicate data with a set
|
|
of &comedi; devices.
|
|
<xref linkend="acquisitionfunctions"/> gives more details about
|
|
the various acquisition functions with which the application
|
|
programmer can perform data acquisition in &comedi;.
|
|
</para>
|
|
<para>
|
|
Also don't forget to take a good look at the
|
|
<filename class="directory">demo</filename>
|
|
directory of the Comedilib source code. It contains lots of examples
|
|
for the basic functionalities of &comedi;.
|
|
</para>
|
|
|
|
<section id="firstprogram">
|
|
<title>
|
|
Your first &comedi; program
|
|
</title>
|
|
|
|
<para>
|
|
This example requires a card that has analog or digital input. This
|
|
progam opens the device, gets the data, and prints it out:
|
|
<programlisting>
|
|
<xi:include href="../demo/tut1.c" parse="text"/>
|
|
</programlisting>
|
|
</para>
|
|
<para>
|
|
The source code file for the above program can be found in Comedilib,
|
|
at <filename>demo/tut1.c</filename>. You can compile the program using
|
|
</para>
|
|
|
|
<screen>
|
|
cc tut1.c -lcomedi -lm -o tut1
|
|
</screen>
|
|
<para>
|
|
The
|
|
<function>
|
|
<link linkend="func-ref-comedi-open">comedi_open</link>
|
|
</function> call can only be successful if the
|
|
<filename>comedi0</filename> device file is configured with a
|
|
valid &comedi; driver. <xref linkend="cardconfiguration"/> explains
|
|
how this driver is linked to the <quote>device file</quote>.
|
|
</para>
|
|
<para>
|
|
The <parameter class="function">range</parameter> variable tells
|
|
&comedi; which gain to use when measuring an analog voltage. Since we
|
|
don't know (yet) which numbers are valid, or what each means, we'll
|
|
use <literal>0</literal>, because it won't cause errors. Likewise
|
|
with <parameter class="function">aref</parameter>, which determines the
|
|
analog reference used.
|
|
</para>
|
|
</section>
|
|
|
|
|
|
<section id="convertingsamples">
|
|
<title>
|
|
Converting between integer data and physical units
|
|
</title>
|
|
|
|
<para>
|
|
If you selected an analog input subdevice, you probably noticed
|
|
that the output of <command>tut1</command> is an unsigned
|
|
number, for example between <literal>0</literal>
|
|
and <literal>65535</literal> for a 16 bit analog input. &comedi;
|
|
samples are unsigned, with <literal>0</literal> representing the
|
|
lowest voltage of the ADC, and a hardware-dependent maximum
|
|
value representing the highest voltage. &comedi; compensates
|
|
for anything else the manual for your device says (for example,
|
|
many boards represent bipolar analog input voltages as signed
|
|
integers). However, you probably prefer to have this number
|
|
translated to a voltage. Naturally, as a good programmer, your
|
|
first question is: <quote>How do I do this in a
|
|
device-independent manner?</quote>
|
|
</para>
|
|
|
|
<para>
|
|
The functions
|
|
<function><link linkend="func-ref-comedi-to-physical">comedi_to_physical</link></function>, <function><link linkend="func-ref-comedi-to-phys">comedi_to_phys</link></function>,
|
|
<function><link linkend="func-ref-comedi-from-physical">comedi_from_physical</link></function> and <function><link linkend="func-ref-comedi-from-phys">comedi_from_phys</link></function>
|
|
are used to convert between &comedi;'s integer data and floating point numbers corresponding
|
|
to physical values (voltages, etc.).
|
|
</para>
|
|
|
|
</section>
|
|
|
|
<section id="secondprogram">
|
|
<title>
|
|
Your second &comedi; program
|
|
</title>
|
|
|
|
|
|
<para>
|
|
Actually, this is the first &comedi; program again, except
|
|
we've added code to convert the integer data value to physical units.
|
|
</para>
|
|
|
|
<programlisting>
|
|
<xi:include href="../demo/tut2.c" parse="text"/>
|
|
</programlisting>
|
|
<para>
|
|
The source code file for the above program can be found in
|
|
the Comedilib source at <filename>demo/tut2.c</filename> and if
|
|
installed as a package usually at
|
|
<filename>/usr/share/doc/libcomedi-dev/demo/</filename> with all the
|
|
other tutorial/demo files.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="asyncprogram">
|
|
<title>
|
|
Asynchronous acquisition
|
|
</title>
|
|
<para>
|
|
Of special importance is the so called
|
|
"asynchronous data acquisition" where &comedi; is sampling
|
|
in the background at a given sample rate. The
|
|
user can retrieve the data whenever it is convenient.
|
|
&comedi; stores the data in a ring-buffer so that
|
|
programs can perform other tasks in the foreground, for example
|
|
plotting data or interacting with the user.
|
|
This technique is used in programs such
|
|
as <command>ktimetrace</command> or <command>comedirecord</command>.
|
|
</para>
|
|
<para>
|
|
There are two different ways how a sequence of channels is
|
|
measured during asynchronous acquisition (see also the Figure in
|
|
the introduction):
|
|
<itemizedlist>
|
|
<listitem>
|
|
The channels are measured with the help
|
|
of a multiplexer which switches to the next channel after each measurement.
|
|
This means that the sampling rate is divided by the number
|
|
of channels.
|
|
</listitem>
|
|
<listitem>
|
|
The channels are all measured at the same time, for example
|
|
when every channel has its own converter. In this case the
|
|
sampling rate need not to be divided by the number of channels.
|
|
</listitem>
|
|
</itemizedlist>
|
|
How your &comedi; device handles the asynchronous acquisition can be found out
|
|
with the command <command>comedi_board_info -v</command>.
|
|
</para>
|
|
<para>
|
|
The program <filename>demo/tut3.c</filename> demonstrates the
|
|
asynchronous acquisition. The general strategy is always
|
|
the same: first, we tell &comedi; all sampling parameters such as
|
|
the sampling rate,
|
|
the number of channels and anything it needs to know
|
|
so that it can run independently in the background.
|
|
Then &comedi; checks our request and it might
|
|
modify it. For example we might want to have a sampling rate of
|
|
16kHz but we only get 1kHz. Finally we can start
|
|
the asynchronous acquisition. Once it has been started we
|
|
need to check periodically if data is available and
|
|
request it from &comedi; so that its internal buffer
|
|
won't overrun.
|
|
</para>
|
|
<para>
|
|
In summary the asynchonous acquisition is performed in the following
|
|
way:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
Create a command structure of type <type><link linkend="ref-type-comedi-cmd">comedi_cmd</link></type>
|
|
</listitem>
|
|
<listitem>
|
|
Call the function <function><link linkend="func-ref-comedi-get-cmd-generic-timed">comedi_get_cmd_generic_timed</link></function>
|
|
to fill the command structure with your comedi device,
|
|
subdevice, sampling rate and number of channels.
|
|
</listitem>
|
|
<listitem>
|
|
Create a channel-list and store it in the command structure. This
|
|
tells comedi which channels should be sampled in the background.
|
|
</listitem>
|
|
<listitem>
|
|
Call <function><link linkend="func-ref-comedi-command-test">comedi_command_test</link></function> with your command structure. Comedi might modify your requested sampling rate and channels.
|
|
</listitem>
|
|
<listitem>
|
|
Call <function><link linkend="func-ref-comedi-command-test">comedi_command_test</link></function> again which now should return zero for success.
|
|
</listitem>
|
|
<listitem>
|
|
Call <function><link linkend="func-ref-comedi-command">comedi_command</link></function> to start the asynchronous acquisition. From now on the kernel ringbuffer will be filled at the specified sampling rate.
|
|
</listitem>
|
|
<listitem>
|
|
Call periodically the standard
|
|
function <function>read</function> and receive the data. The
|
|
result should always be non zero as long as the acquisition
|
|
is running.
|
|
</listitem>
|
|
<listitem>
|
|
Convert the received data either into
|
|
<type><link linkend="ref-type-lsampl-t">lsampl_t</link></type> or
|
|
<type><link linkend="ref-type-sampl-t">sampl_t</link></type> depending
|
|
on the subdevice flag <constant>SDF_LSAMPL</constant>.
|
|
</listitem>
|
|
<listitem>
|
|
Poll for data with <function>read</function> as long as it returns
|
|
a positive result or until the program terminates.
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
The program below is a stripped down version of the
|
|
program <filename>cmd.c</filename> in the demo directory.
|
|
It requests data from two channels at
|
|
a sampling rate of 1kHz and a total of 10000 samples.
|
|
which are then printed to stdout. You can pipe the data
|
|
into a file and plot it with gnuplot. As mentioned above, central in this
|
|
program is the loop using the standard C <function>read</function> command
|
|
which receives the buffer contents.
|
|
</para>
|
|
<programlisting>
|
|
<xi:include href="../demo/tut3.c" parse="text"/>
|
|
</programlisting>
|
|
<para>
|
|
The source code file for the above program can be found in Comedilib,
|
|
at <filename>demo/tut3.c</filename>. You can compile the program using
|
|
</para>
|
|
<screen>
|
|
cc tut3.c -lcomedi -lm -o tut3
|
|
</screen>
|
|
<para>
|
|
For advanced programmers the
|
|
function <function><link linkend="func-ref-comedi-get-buffer-contents">comedi_get_buffer_contents</link></function>
|
|
is useful to check if there is actually data in the ringbuffer
|
|
so that a call of <function>read</function> can be avoided for example
|
|
when the data readout is called by a timer call-back function.
|
|
</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Further examples</title>
|
|
<para>
|
|
See the <filename>demo</filename> subdirectory of Comedilib
|
|
for more example programs. The directory contains a
|
|
<filename>README</filename> file with descriptions of the various
|
|
demo programs.
|
|
</para>
|
|
</section>
|
|
|
|
</section>
|