
This section goes into a "Language bindings" section where description for Perl and Ruby could also go.
113 lines
5.3 KiB
XML
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>
|