Comedi::Lib - Perl API for Comedilib (NEW version)
NEW version
Version 0.24
Comedi::Lib provides a Perl wrapper around the Comedilib library. This supports Perl code controlling and accessing control and measurement devices.
Comedi::Lib
Comedilib
use Comedi::Lib; # Create a Comedi::Lib object and open the Comedi device my $cref = Comedi::Lib->new(device => '/dev/comedi0', open_flag => 1); # Get the driver and board name of the device my $dname = $cref->get_driver_name(); my $bname = $cref->get_board_name(); ... ... ... # Close the Comedi device (optional) $cref->close();
This module provides a Perl API for Comedilib. Comedilib is a separately distributed package containing a user-space library that provides a developer-friendly interface to the Comedi devices. This module consists of the functions that the Comedilib library provides.
I don't use XS, C::Scan or something like that, to export constants and macros to the callers name-space, as long as it's not clarified which constants and macros used for Comedilib and which for 'pure' Comedi (driver development). Both the documentation and the source code couldn't help me at all to resolve that problem.
XS
C::Scan
This module does _not_ support any ALPHA constants, macros or functions. This will be done by a separately module, anytime soon.
ALPHA
Comedi::Lib is dependent on the Comedilib library. Please download and install the latest version at http://www.comedi.org/. The Comedilib library _must_ be found in your library path when using this module. The library is defaultly installed in /usr/local/lib - in this case, be sure that the /usr/local/lib path is in your /etc/ld.so.conf.
library path
/usr/local/lib
/etc/ld.so.conf
Comedi::Lib also depends on the InlineX::C2XS, define and enum modules, as well as the Test::More, POSIX and Carp core modules, and the strict and warnings pragmas.
None, this is an object-oriented Perl module.
This class provides a set of constants . The constants defined at this time are:
# Comedi's major device number COMEDI_MAJOR # Maximum number of minor devices (this can be increased) COMEDI_NDEVICES # Number of config options in the config structure COMEDI_NDEVCONFOPTS # Length of nth chunk of firmware data COMEDI_DEVCONF_AUX_DATA3_LENGTH COMEDI_DEVCONF_AUX_DATA2_LENGTH COMEDI_DEVCONF_AUX_DATA1_LENGTH COMEDI_DEVCONF_AUX_DATA0_LENGTH COMEDI_DEVCONF_AUX_DATA_HI COMEDI_DEVCONF_AUX_DATA_LO COMEDI_DEVCONF_AUX_DATA_LENGTH # Max length of device and driver names COMEDI_NAMELEN # Packs and unpacks a channel/range number (see also macro section) CR_FLAGS_MASK CR_ALT_FILTER CR_DITHER CR_DEGLITCH CR_ALT_SOURCE CR_EDGE CR_INVERT # Analog ref AREF_GROUND AREF_COMMON AREF_DIFF AREF_OTHER # Counters GPCT_RESET GPCT_SET_SOURCE GPCT_SET_GATE GPCT_SET_DIRECTION GPCT_SET_OPERATION GPCT_ARM GPCT_DISARM GPCT_GET_INT_CLK_FRQ GPCT_INT_CLOCK GPCT_EXT_PIN GPCT_NO_GATE GPCT_UP GPCT_DOWN GPCT_HWUD GPCT_SIMPLE_EVENT GPCT_SINGLE_PERIOD GPCT_SINGLE_PW GPCT_CONT_PULSE_OUT GPCT_SINGLE_PULSE_OUT # Instructions INSN_MASK_WRITE INSN_MASK_READ INSN_MASK_SPECIAL INSN_READ INSN_WRITE INSN_BITS INSN_CONFIG INSN_GTOD INSN_WAIT INSN_INTTRIG # Trigger flags, used in comedi_trig structures TRIG_BOGUS TRIG_DITHER TRIG_DEGLITCH TRIG_CONFIG TRIG_WAKE_EOS # Command flags, used in comedi_cmd structures CMDF_PRIORITY TRIG_RT CMDF_WRITE TRIG_WRITE CMDF_RAWDATA COMEDI_EV_START COMEDI_EV_SCAN_BEGIN COMEDI_EV_CONVERT COMEDI_EV_SCAN_END COMEDI_EV_STOP TRIG_ROUND_MASK TRIG_ROUND_NEAREST TRIG_ROUND_DOWN TRIG_ROUND_UP TRIG_ROUND_UP_NEXT # Trigger sources TRIG_ANY TRIG_INVALID TRIG_NONE TRIG_NOW TRIG_FOLLOW TRIG_TIME TRIG_TIMER TRIG_COUNT TRIG_EXT TRIG_INT TRIG_OTHER # Subdevice flags SDF_BUSY SDF_BUSY_OWNER SDF_LOCKED SDF_LOCK_OWNER SDF_MAXDATA SDF_FLAGS SDF_RANGETYPE SDF_MODE0 SDF_MODE1 SDF_MODE2 SDF_MODE3 SDF_MODE4 SDF_CMD SDF_SOFT_CALIBRATED SDF_CMD_WRITE SDF_CMD_READ SDF_READABLE SDF_WRITABLE SDF_WRITEABLE SDF_INTERNAL SDF_RT SDF_GROUND SDF_COMMON SDF_DIFF SDF_OTHER SDF_DITHER SDF_DEGLITCH SDF_MMAP SDF_RUNNING SDF_LSAMPL SDF_PACKED SDF_PWM_COUNTER SDF_PWM_HBRIDGE # Subdevice types COMEDI_SUBD_UNUSED COMEDI_SUBD_AI COMEDI_SUBD_AO COMEDI_SUBD_DI COMEDI_SUBD_DO COMEDI_SUBD_DIO COMEDI_SUBD_COUNTER COMEDI_SUBD_TIMER COMEDI_SUBD_MEMORY COMEDI_SUBD_CALIB COMEDI_SUBD_PROC COMEDI_SUBD_SERIAL COMEDI_SUBD_PWM # Configuration instructions INSN_CONFIG_DIO_INPUT INSN_CONFIG_DIO_OUTPUT INSN_CONFIG_DIO_OPENDRAIN INSN_CONFIG_ANALOG_TRIG INSN_CONFIG_ALT_SOURCE INSN_CONFIG_DIGITAL_TRIG INSN_CONFIG_BLOCK_SIZE INSN_CONFIG_TIMER_1 INSN_CONFIG_FILTER INSN_CONFIG_CHANGE_NOTIFY COMEDI_INPUT COMEDI_OUTPUT COMEDI_OPENDRAIN COMEDI_UNKNOWN_SUPPORT COMEDI_SUPPORTED COMEDI_UNSUPPORTED # Range stuff (see also macro section) RF_EXTERNAL # Units UNIT_volt UNIT_mA UNIT_none COMEDI_MIN_SPEED
This class provides also a set of (pseudo-)macros (implemented as a method). The macros defined at this time are:
pseudo
# Packs and unpacks a channel/range number CR_PACK($chan, $rng, $aref) CR_PACK_FLAGS($chan, $rng, $aref, $flags) # Intended only for driver development work? CR_CHAN($a) CR_RANGE($a) CR_AREF($a) # Range stuff # Intended only for driver development work? RANGE_OFFSET($a) RANGE_LENGTH($a) # Intended only for driver development work? RF_UNIT($flags)
Example code,
my $chanspec = $cref->CR_PACK($chan, $rng, $aref);
Close the Comedi device connected to the object.
Create a new Comedi::Lib object for accessing the library.
my $cref = Comedi::Lib->new(device => '/dev/comedi0', open_flag => 1);
Close a Comedi device.
my $retval = $cref->close(); if ($retval != 0) { croak "Couldn't close the Comedi device"; }
If successful, close() returns 0. On failure, -1 is returned.
close()
Trigger an explicit open() call to open the Comedi device. If the device is already open, close and reopen it.
open()
You _need_ to be root to open a Comedi device. Comedi::Lib checks that.
# Create a new object (don't open the device yet). my $cref = Comedi::Lib->new(device => "/dev/comedi1", open_flag => 0); ... ... ... # Now open the Comedi device $cref->open();
If successful, open() returns defined. On failure, undef is returned.
Change Comedilib logging properties.
The default loglevel can be set by using the environment variable COMEDILIB_LOGLEVEL. The default loglevel is 1.
COMEDILIB_LOGLEVEL
The meaning of the loglevels is as follows:
-- Comedilib prints nothing.
-- Comedilib prints error messages when there is a self-consistency error. (i.e., an internal bug)
-- Comedilib prints an error message when an invalid parameter is passed.
-- Comedilib prints an error message whenever an error is generated in the Comedilib library or in the C library, when called by Comedilib.
C
-- Comedilib prints a lot of junk.
my $previous_loglevel = $cref->loglevel($new_loglevel); print "Changed loglevel from $previous_loglevel to $new_loglevel\n";
This class method returns the previous loglevel.
Note: Comedilib evaluates the COMEDILIB_LOGLEVEL environment variable during open() is called. The Comedi::Lib implementation of this function allows you to set the above variable once the Comedi device is already opened.
Print a Comedilib error message.
unless ($cref->open()) { $cref->perror($device); croak "Terminating..."; }
The class method perror() prints an error message to stderr. The error message consists of the argument string, a colon, a space, a description of the error condition, and a new line.
perror()
stderr
Return string describing Comedilib error code.
unless ($cref->open()) { my $errnum = $cref->errno(); my $errmsg = $cref->strerror($errnum); croak "An error has occurred - $errmsg"; }
The class method strerror() returns a character string describing the Comedilib error errnum. An unrecognized error number will return a string "undefined error", or similar.
strerror()
Number of the last Comedilib error. This error number can be converted to a human-readable form by the methods perror() and strerror().
# See strerror()
The errno() class method returns an integer describing the most recent Comedilib error. This integer my be used as the errnum argument for strerror().
errno()
Integer descriptor of the Comedi device.
my $fileno = $cref->fileno(); print "File # of Comedi device - $fileno\n";
If successful, fileno() returns a file descriptor, or -1 on error.
fileno()
Number of subdevices
my $n_subdevices = $cref->get_n_subdevices(); print "# of subdevices - $n_subdevices\n";
The class method get_n_subdevices() returns the number of subdevices belonging to the Comedi device previously opened during the Object creation or explicitly by an open() call.
get_n_subdevices()
Comedi version code.
my @version_code = $cref->get_version_code(); printf("Comedi version code - %d.%d.%d\n", @version_code);
Returns the Comedi kernel module version code, or -1 on error.
Comedi driver name.
my $driver_name = $cref->get_driver_name(); print "Comedi driver name - $driver_name\n";
Returns a character string containing the name of the driver. This class method returns undef if there is an error.
Comedi device name.
my $board_name = $cref->get_board_name(); print "Comedi board/device name - $board_name\n";
Returns a character string containing the name of the device. This class method returns undef if there is an error.
Type of subdevice.
my $subdev_type = $cref->get_subdevice_type($subdev); if ($subdev_type == Comedi::Lib::COMEDI_SUBD_AI) { print "We've an analog input subdevice\n"; }
This class method returns the subdevice type, or -1 if there is an error.
Search for subdevice type.
my $idx = $cref->find_sundevice_by_type(Comedi::Lib::COMEDI_SUBD_DO, 0); croak "No digital output subdevice found\n" if $idx == -1; print "Found digital output subdevice at index - $idx\n";
If it finds a subdevice with the requested type, find_subdevice_by_type() returns its index. If there is an error, the method returns -1 and sets the appropriate error.
find_subdevice_by_type()
Find streaming input subdevice.
my $streaming_input_support = $cref->get_read_subdevice(); if ($streaming_input_support == -1) { print "No streaming input support available\n"; } else { print "Comedi subdevice no. $streaming_input_support ", "allows streaming input\n"; }
This class method returns the subdevice whose streaming input buffer is accessible through the previous opened device. If there is no such subdevice, -1 is returned.
Find streaming output subdevice.
my $streaming_output_support = $cref->get_write_subdevice(); if ($streaming_output_support == -1) { print "No streaming output support available\n"; } else { print "Comedi subdevice no. $streaming_output_support ", "allows streaming output\n"; }
This class method returns the subdevice whose streaming output buffer is accessible through the previous opened device. If there is no such subdevice, -1 is returned.
Properties of subdevice.
my $subdev_flags = $cref->get_subdevice_flags($subdev); if ($subdev_flags & Comedi::Lib::SDF_READABLE) { print "The subdevice can be read\n"; } else { print "The subdevice can't be read\n"; } if ($subdev_flags & Comedi::Lib::SDF_WRITEABLE) { print "The subdevice can be written\n"; } else { print "The subdevice can't be written\n"; }
This method returns a bitfield describing the capabilities of the specified subdevice. If there is an error, -1 is returned, and the Comedilib error value is set.
Number of subdevice channels.
my $n_channels = $cref->get_n_channels($subdev); print "Analog input no. of channels - $n_channels\n";
Returns the number of channels of the subdevice with the index subdev. This method returns -1 on error.
Range information depends on channel.
my $retval = $cref->range_is_chan_specific($subdev); croak "An error has occurred" if $retval == -1; unless($retval) { print "The channels of the subdevice hasn't different ", "range information\n"; } else { print "Each channel of the subdevice has different ", "range information\n"; }
If each channel of the specified subdevice has different range information, this method returns 1. Otherwise, this method returns 0. If there is an error, -1 is returned.
Maximum sample depends on channnel.
my $retval = $cref->maxdata_is_chan_specific($subdev); croak "An error has occurred" if $retval == -1; unless($retval) { print "The channels of the subdevice hasn't different ", "maximum sample values\n"; } else { print "Each channel of the subdevice has different ", "maximum sample values\n"; }
If each channel of the specified subdevice has different maximum sample values, this method returns 1. Otherwise, this method returns 0. If there is an error, -1 is returned.
Maximum sample of channel.
# Read maxdata of analog input channel $chan my $maxdata = $cref->get_maxdata($subdev, $chan); croak "An error has occurred" unless $maxdata; print "Maximum data value for analog input channel $chan - $maxdata\n";
Returns the maximum valid sample value, or 0 on error.
Number of ranges of channel.
# Read number of ranges for analog input channel $chan my $n_ranges = $cref->get_n_ranges($subdev, $chan); if ($n_ranges == -1) { croak "An error has occurred"; } print "Number of ranges for analog input channel $chan - $n_ranges\n";
Returns the number of ranges of the subdevice with the index subdev and the chan channel. This method returns -1 on error.
Range information of channel.
# Read the range specification of the analog input channel $chan my $range = $cref->get_range($subdev, $chan, $rng); croak "Cannot read range specification" unless defined $range->{min}; # Print the minimal sample value of the given analog input channel print "Analog input channel $chan min sample value - $range->{min}\n";
The class method get_range() returns a hash reference that contains information that can be used to convert sample values to or from physical units. If there is an error, undef is returned.
get_range()
Search for range.
my $rng_idx = $cref->find_range($subdev, $chan, $unit, $min, $max); if ($rng_idx == -1) { print "No matching range available\n" } else { print "Found a matching range for channel $chan at index $rng_idx\n"; }
If a matching range is found, the index of the matching range is returned. If no matching range is available, the class method returns -1.
Streaming buffer size of subdevice.
my $buf_size = $cref->get_buffer_size($subdev); croak "An error has occurred" if $buf_size == -1; print "Streaming buffer size for the subdevice - $buf_size Bytes\n";
This class method returns the size -in Bytes- of the streaming buffer for the specified subdevice. On error, -1 is returned.
Maximum streaming buffer size.
my $max_size = $cref->get_max_buffer_size($subdev); croak "An error has occurred" if $max_size == -1; print "Max. streaming buffer size for the subdevice - $max_size Bytes\n";
This class method returns the maximum allowable size -in Bytes- of the streaming buffer for the specified subdevice. On error, -1 is returned.
# First, determine the virtual memory page size (look at the Comedi docu) require POSIX; my $vmps = POSIX::sysconf(&POSIX::_SC_PAGESIZE); $vmps *= 2; print "Trying to set the streaming buffer size to $vmps\n"; if ($cref->set_buffer_size($subdev, $vmps) == -1) { print "Warning: Couldn't set new streaming buffer size\n"; }
The set_buffer_size() class method returns the new buffer size in Bytes. On error, -1 is returned.
set_buffer_size()
Perform multible instructions.
my @insn_arr = ({ insn => Comedi::Lib::INSN_READ, n => 2, data => [0, 0], subdev => 0, chanspec => $cref->CR_PACK($chan, $rng, $aref) }, { insn => Comedi::Lib::INSN_WRITE, n => 1, data => [255], subdev => 1, chanspec => $cref->CR_PACK($chan, $rng, $aref) }); # Now, create a comedi_insnlist like hash reference my $comedi_insnlist = { n_insns => 2, insns => [@insn_arr] }; my $retval = $cref->do_insnlist($comedi_insnlist); croak "An error has occurred" if $retval == -1; print "[<1>] data (AI) - ", $insn_arr[0]->{data}[0], "\n"; print "[<2>] data (AI) - ", $insn_arr[0]->{data}[1], "\n";
This class method returns the number of successfully completed instructions. If there is an error before the first instruction can be executed, -1 is returned.
Perform an instruction.
# First, create a comedi_insn like hash reference my $comedi_insn = { insn => Comedi::Lib::INSN_READ, n => 2, data => [0, 0], subdev => 0, chanspec => $cref->CR_PACK($chan, $rng, $aref) }; my $retval = $cref->do_insn($comedi_insn); croak "An error has occured" if $retval == -1; print "[<1>] data (AI) - ", $comedi_insn->{data}[0], "\n"; print "[<2>] data (AI) - ", $comedi_insn->{data}[1], "\n";
This class method returns the number of samples measured, which may be less than the number of requested samples. If there is an error before the first instruction can be executed, -1 is returned.
Subdevice reservation.
my $retval = $cref->lock($subdev); croak "An error has occurred" if $retval == -1;
If successful, lock() returns 0. If there is an error, -1 is returned.
lock()
my $retval = $cref->unlock($subdev); croak "An error has occurred" if $retval == -1;
If successful, unlock() returns 0. If there is an error, -1 is returned.
unlock()
Read single sample from channel.
my $retval = $cref->data_read($subdev, $chan, $rng, $aref, \$data); croak "An error hash occurred" if $retval == -1; print "Have read a single sample value of $data\n";
On success, data_read() returns 1 (the number of samples read). If there is an error, -1 is returned.
data_read()
Read single sample from channel after delaying for specified time.
my $ret = $cref->data_read_delayed($subd, $chan, $rng, $aref, \$data, $ns); croak "An error hash occurred" if $retval == -1; print "Have read a single sample value of $data\n";
The return value of this class method is identical to the data_read() function.
Tell driver which channel/range/aref you're going to read from next.
Example code
my $retval = $cref->data_read_hint($subdev, $chan, $rng, $aref); croak "An error hash occurred" if $retval == -1;
Write single sample to channel.
my $retval = $cref->data_write($subdev, $chan, $rng, $aref, $data); croak "An error hash occurred" if $retval == -1;
On success, data_write() returns 1 (the number of samples read). If there is an error, -1 is returned.
data_write()
Change input/output properties of channel.
# For input my $retval = $cref->dio_config($subdev, $chan, Comedi::Lib::COMEDI_INPUT); croak "An error hash occurred" if $retval == -1; # For output my $retval = $cref->dio_config($subdev, $chan, Comedi::Lib::COMEDI_INPUT); croak "An error hash occurred" if $retval == -1;
If successful, 1 is returned, otherwise -1.
Query input/output properties of channel.
my $retval = $cref->dio_get_config($subdev, $chan, \$dir); croak "An error hash occurred" if $retval == -1; if ($dir == Comedi::Lib::COMEDI_INPUT) { print "Input direction\n"; } else { # Comedi::Lib::COMEDI_OUTPUT print "Output direction\n"; }
If successful, 0 is returned, otherwise -1.
Read single bit from digital channel.
my $retval = $cref->data_read($subdev, $chan, \$bit); croak "An error has occurred" if $retval == -1; print "Have read a data value of $bit\n";
Return values and errors are the same as data_read().
Write single bit to digital channel.
my $retval = $cref->data_write($subdev, $chan, $bit); croak "An error has occurred" if $retval == -1;
Return values and errors are the same as data_write().
Read/Write multible digital channels.
my $retval = $cref->dio_bitfield2($subdev, $write_mask, \$bits, $base_ch); croak "An error has occurred" if $retval == -1; # Evaluate the $bits variable...
If successful, dio_bitfield2() returns 0. If there is an error, -1 is returned.
dio_bitfield2()
Streaming input/output capabilities.
Note that this subroutine has no functionality as long as I have no testing device with the associated driver.
Patches or suggestions are welcome, send me an email (Subject: Comedi::Lib).
Stop streaming input/output in progress.
# This class method is useful in combination with command() # and this class method is not completely implemented yet.
If successful, cancel() returns 0, otherwise -1.
cancel()
Start streaming input/output.
Test streaming input/output configuration.
Force updating of streaming buffer.
my $retval = $cref->poll($subdev); croak "An error has occurred" if $retval == -1;
If successful, this class method returns the number of additional bytes available. If there is an error, -1 is returned.
my $old_buf_size = $cref->set_max_buffer_size($subdev, $max_size); if ($old_buf_size == -1) { croak "An error has occurred"; } else { print "Buffer size changed from $old_buf_size to $max_size.\n"; }
If successful, the old buffer size is returned. On error, -1 is returned.
Streaming buffer status.
This class method returns the number of bytes that are available in the streaming buffer. If there is an error, -1 is returned.
Streaming buffer control.
The mark_buffer_read() class method returns the number of bytes successfully marked as read, or -1 on error.
mark_buffer_read()
The mark_buffer_written() class method returns the number of bytes successfully marked as written, or -1 on error.
mark_buffer_written()
This class method returns the offset in bytes of the read pointer in the streaming buffer. If there is an error, -1 is returned.
Manuel Gebele <forensixs[at]gmx.de>
The linux control and measurement device interface project at http://www.comedi.org.
After installing, you can find documentation for this module with the perldoc command
perldoc Comedi::Lib
or use the man command
man Comedi::Lib
You can also look for information at:
Search CPAN http://search.cpan.org/dist/Comedi-Lib CPAN Request Tracker http://rt.cpan.org/NoAuth/Bugs.html?Dist=Comedi-Lib AnnoCPAN, annotated CPAN documentation http://annocpan.org/dist/Comedi-Lib CPAN Ratings http://cpanratings.perl.org/d/Comedi-Lib Comedi http://www.comedi.org
Please report any bugs or feature request to my email address, or through the web interface at http://rt.cpan.org/Public/Bug/Report.html?Queue=Comedi::Lib. I'll be notified, and then you'll automatically be notified of progess on your bug as I make changes.
Copyright (c) 2009 Manuel Gebele
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
To install Comedi::Lib, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Comedi::Lib
CPAN shell
perl -MCPAN -e shell install Comedi::Lib
For more information on module installation, please visit the detailed CPAN module installation guide.