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.
Python bindings are automatically generated by SWIG. So always keep in mind that for precise information the SWIG documentation can come in handy in addition to the Comedi documentation.
The name of the module is called comedi
. 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:
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
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
comedi_data_read
takes as argument a
lsampl_t *data
which will contain the data
read after the function returns. So in C it is used like this:
lsampl_t data; rc = comedi_data_read(device, subdevice, channel, range, aref, &data);
As lsampl_t
is a 32-bit
unsigned int
, in Python, the function is used like this:
rc, data = comedi.comedi_data_read(device, subdevice, channel, range, aref)
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: comedi.cr_pack
,
comedi.cr_range
, etc.
So to create and modify a command, one can do in Python:
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
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 cast
from the Python object to the
C object. So to create an instruction to call the internal trigger, you would
write in Python:
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)
When you need to convert from a raw SWIG object to a proxy
object, the .frompointer
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
.thisown
to False
.
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
File
object.
You can get a File
object via
os.fdopen
. For example, to read an array of input data
from a Comedi device into a numpy array, one could do:
fileno = comedi.comedi_fileno(device) file = os.fdopen(fileno, 'r+') buf = numpy.fromfile(file, dtype=numpy.uint32, count=(nscans * nchans))