5.5. Language bindings
Prev | 5. Comedi reference | Next

### 5.5. Language bindings

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.

#### 5.5.1. Python bindings

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))

Prev | Up | Next
comedi_trigger | Home | 5.6. Kernel drivers