comedilib/doc/bindings.xml
Éric Piel 7d4ad9ad15 doc: add a section about Python bindings
This section goes into a "Language bindings" section where description
for Perl and Ruby could also go.
2012-10-29 17:08:09 +00:00

113 lines
5.3 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="languagebindings">
<title>Language bindings</title>
<para>
Comedilib is a C library but comes also with bindings for Python, Perl, and Ruby.
This enables usage of a DAQ device directly from these higher level languages.
</para>
<section id="pythonbindings">
<title>Python bindings</title>
<para>
Python bindings are automatically generated by SWIG. So always keep in mind that
for precise information the <ulink url="http://www.swig.org/Doc2.0/index.html">SWIG documentation</ulink>
can come in handy in addition to the &comedi; documentation.
</para>
<para>
The name of the module is called <filename>comedi</filename>. All the C functions, structs, and
constants are directly available as is. So you can refer directly to the C
documentation for most of the usage. Note that, as in C, the functions either return the
successful result or an error code. Unlike typical Python functions,
no exceptions are generated on errors (excepted type-checking
performed by SWIG). For example, to open a &comedi; device you can write in
Python:
<programlisting>
import comedi
device = comedi.comedi_open("/dev/comedi0")
if device is None:
errno = comedi.comedi_errno()
print "Error (%d) %s" % (errno, comedi.comedi_strerror(errno))
return
</programlisting>
</para>
<para>
There are a few things to be aware of. The SWIG bindings automatically take care
of converting functions with output parameters to function returning multiple
values, if the type of the output parameter is simple. For example
<function>comedi_data_read</function> takes as argument a
<parameter class="function">lsampl_t *data</parameter> which will contain the data
read after the function returns. So in C it is used like this:
<programlisting><![CDATA[
lsampl_t data;
rc = comedi_data_read(device, subdevice, channel, range, aref, &data);
]]></programlisting>
As <parameter class="function">lsampl_t</parameter> is a 32-bit
<parameter class="function">unsigned int</parameter>, in Python, the function is used like this:
<programlisting>
rc, data = comedi.comedi_data_read(device, subdevice, channel, range, aref)
</programlisting>
</para>
<para>
SWIG takes care of converting simple types between Python and C, but does not
convert more complex types such as arrays or structs. Special Python classes are
created for these. Moreover, &comedi; also provides a few macros. These macros
are available in Python as functions with similar names, but lowercase: <function>comedi.cr_pack</function>,
<function>comedi.cr_range</function>, etc.
So to create and modify a command, one can do in Python:
<programlisting>
cmd = comedi.comedi_cmd_struct()
comedi.comedi_get_cmd_generic_timed(device, subdevice, cmd, nchans, period_ns)
cmd.stop_src = comedi.TRIG_COUNT
cmd.stop_arg = nscans
# create and add the channel list
clist = comedi.chanlist(nchans)
for i, channel in range(nchans):
clist[i] = comedi.cr_pack(channel, range, comedi.AREF_GROUND)
cmd.chanlist = clist
</programlisting>
</para>
<para>
One unfortunate consequence is that the objects to represent arrays are as low-level
as C arrays (i.e., a pointer with an addition). They have no range checking and
no iterator. In addition, they have to be <function>cast</function> from the Python object to the
C object. So to create an instruction to call the internal trigger, you would
write in Python:
<programlisting>
insn = comedi.comedi_insn_struct()
insn.subdev = subdevice
insn.insn = comedi.INSN_INTTRIG
insn.n = 1
data = comedi.lsampl_array(insn.n)
data[0] = num
insn.data = data.cast()
rc = comedi.comedi_do_insn(device, insn)
</programlisting>
</para>
<para>
When you need to convert from a raw SWIG object to a proxy
object, the <function>.frompointer</function> of the Python object can be used. Also note that by default
when the proxy object is deleted, SWIG frees the memory associated to it. To
still be able to use the memory, you need to set
<parameter class="function">.thisown</parameter> to <parameter class="function">False</parameter>.
</para>
<para>
Reading (or writing) a large set of data from a &comedi; device is done via a file.
In C, this is done by using a file number, but in Python you need a
<parameter class="function">File</parameter> object.
You can get a <parameter class="function">File</parameter> object via
<function>os.fdopen</function>. For example, to read an array of input data
from a &comedi; device into a numpy array, one could do:
<programlisting>
fileno = comedi.comedi_fileno(device)
file = os.fdopen(fileno, 'r+')
buf = numpy.fromfile(file, dtype=numpy.uint32, count=(nscans * nchans))
</programlisting>
</para>
</section>
</section>