diff options
author | jcorgan <jcorgan@221aa14e-8319-0410-a670-987f0aec2ac5> | 2006-08-03 04:51:51 +0000 |
---|---|---|
committer | jcorgan <jcorgan@221aa14e-8319-0410-a670-987f0aec2ac5> | 2006-08-03 04:51:51 +0000 |
commit | 5d69a524f81f234b3fbc41d49ba18d6f6886baba (patch) | |
tree | b71312bf7f1e8d10fef0f3ac6f28784065e73e72 /gr-comedi |
Houston, we have a trunk.
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@3122 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'gr-comedi')
-rw-r--r-- | gr-comedi/AUTHORS | 1 | ||||
-rw-r--r-- | gr-comedi/ChangeLog | 25 | ||||
-rw-r--r-- | gr-comedi/Makefile.am | 24 | ||||
-rw-r--r-- | gr-comedi/src/Makefile.am | 91 | ||||
-rw-r--r-- | gr-comedi/src/comedi.i | 76 | ||||
-rw-r--r-- | gr-comedi/src/comedi_sink_s.cc | 233 | ||||
-rw-r--r-- | gr-comedi/src/comedi_sink_s.h | 89 | ||||
-rw-r--r-- | gr-comedi/src/comedi_source_s.cc | 229 | ||||
-rw-r--r-- | gr-comedi/src/comedi_source_s.h | 90 | ||||
-rw-r--r-- | gr-comedi/src/gri_comedi.cc | 30 | ||||
-rw-r--r-- | gr-comedi/src/gri_comedi.h | 28 | ||||
-rwxr-xr-x | gr-comedi/src/qa_comedi.py | 40 | ||||
-rw-r--r-- | gr-comedi/src/run_tests.in | 47 |
13 files changed, 1003 insertions, 0 deletions
diff --git a/gr-comedi/AUTHORS b/gr-comedi/AUTHORS new file mode 100644 index 0000000000..624606f051 --- /dev/null +++ b/gr-comedi/AUTHORS @@ -0,0 +1 @@ +Stephane Fillod <f8cfe@free.fr> diff --git a/gr-comedi/ChangeLog b/gr-comedi/ChangeLog new file mode 100644 index 0000000000..92ee15bc48 --- /dev/null +++ b/gr-comedi/ChangeLog @@ -0,0 +1,25 @@ +2005-10-10 Stephane Fillod <f8cfe@free.fr> + + * src/comedi_source.{h,cc}: new. + * src/comedi_sink.{h,cc}: new. + +# +# Copyright 2005 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# diff --git a/gr-comedi/Makefile.am b/gr-comedi/Makefile.am new file mode 100644 index 0000000000..0b0234e364 --- /dev/null +++ b/gr-comedi/Makefile.am @@ -0,0 +1,24 @@ +# +# Copyright 2005 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# + +include $(top_srcdir)/Makefile.common + +SUBDIRS = src diff --git a/gr-comedi/src/Makefile.am b/gr-comedi/src/Makefile.am new file mode 100644 index 0000000000..3311cd569e --- /dev/null +++ b/gr-comedi/src/Makefile.am @@ -0,0 +1,91 @@ +# +# Copyright 2005 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# + +include $(top_srcdir)/Makefile.common + +# Install this stuff so that it ends up as the gnuradio.comedi module +# This usually ends up at: +# ${prefix}/lib/python${python_version}/site-packages/gnuradio + +ourpythondir = $(grpythondir) +ourlibdir = $(grpyexecdir) + +EXTRA_DIST = run_tests.in + +TESTS = run_tests + +LOCAL_IFILES = \ + comedi.i + +NON_LOCAL_IFILES = \ + $(top_srcdir)/gnuradio-core/src/lib/swig/gnuradio.i + +ALL_IFILES = \ + $(LOCAL_IFILES) \ + $(NON_LOCAL_IFILES) + +BUILT_SOURCES = \ + comedi.cc \ + comedi.py + +ourpython_PYTHON = \ + comedi.py + +INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) + +SWIGCPPPYTHONARGS = -c++ -python $(PYTHON_CPPFLAGS) $(STD_DEFINES_AND_INCLUDES) +# -I$(swigincludedir) $(S-I$(grincludedir) -I$(comediincludedir) + +ourlib_LTLIBRARIES = _comedi.la + +_comedi_la_SOURCES = \ + comedi.cc \ + comedi_sink_s.cc \ + comedi_source_s.cc \ + gri_comedi.cc + +grinclude_HEADERS = \ + comedi_sink_s.h \ + comedi_source_s.h + +noinst_HEADERS = \ + gri_comedi.h + + +swiginclude_HEADERS = \ + $(LOCAL_IFILES) + +_comedi_la_LIBADD = \ + $(PYTHON_LDFLAGS) \ + $(GNURADIO_CORE_LIBS) \ + -lstdc++ + +_comedi_la_LDFLAGS = $(NO_UNDEFINED) -module -avoid-version + +comedi.cc comedi.py: comedi.i + $(SWIG) $(SWIGCPPPYTHONARGS) -module comedi -o comedi.cc $< + + +noinst_PYTHON = \ + qa_comedi.py + +MOSTLYCLEANFILES = \ + $(BUILT_SOURCES) *~ *.pyc diff --git a/gr-comedi/src/comedi.i b/gr-comedi/src/comedi.i new file mode 100644 index 0000000000..18f4f441fe --- /dev/null +++ b/gr-comedi/src/comedi.i @@ -0,0 +1,76 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +%feature("autodoc","1"); + +%include "exception.i" +%import "gnuradio.i" // the common stuff + +%{ +#include "gnuradio_swig_bug_workaround.h" // mandatory bug fix +#include "comedi_sink_s.h" +#include "comedi_source_s.h" +#include <stdexcept> +%} + +// ---------------------------------------------------------------- + +GR_SWIG_BLOCK_MAGIC(comedi,source_s) + +comedi_source_s_sptr +comedi_make_source_s (int sampling_freq, + const std::string dev = "" + ) throw (std::runtime_error); + +class comedi_source_s : public gr_sync_block { + + protected: + comedi_source_s (int sampling_freq, + const std::string device_name + ) throw (std::runtime_error); + + public: + ~comedi_source_s (); + + bool start(); + bool stop(); +}; + +// ---------------------------------------------------------------- + +GR_SWIG_BLOCK_MAGIC(comedi,sink_s) + +comedi_sink_s_sptr +comedi_make_sink_s (int sampling_freq, + const std::string dev = "" + ) throw (std::runtime_error); + +class comedi_sink_s : public gr_sync_block { + + protected: + comedi_sink_s (int sampling_freq, + const std::string device_name + ) throw (std::runtime_error); + + public: + ~comedi_sink_s (); +}; diff --git a/gr-comedi/src/comedi_sink_s.cc b/gr-comedi/src/comedi_sink_s.cc new file mode 100644 index 0000000000..2c1ffb7de9 --- /dev/null +++ b/gr-comedi/src/comedi_sink_s.cc @@ -0,0 +1,233 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/mman.h> + +#include <comedi_sink_s.h> +#include <gr_io_signature.h> +#include <stdio.h> +#include <errno.h> +#include <iostream> +#include <stdexcept> +#include <gri_comedi.h> + + +/* + * comedi_sink_s is untested because I don't own appropriate hardware. + * Feedback is welcome! --SF + */ + +static std::string +default_device_name () +{ + return "/dev/comedi0"; +} + + +// ---------------------------------------------------------------- + +comedi_sink_s_sptr +comedi_make_sink_s (int sampling_freq, const std::string dev) +{ + return comedi_sink_s_sptr (new comedi_sink_s (sampling_freq, dev)); +} + +comedi_sink_s::comedi_sink_s (int sampling_freq, + const std::string device_name) + : gr_sync_block ("comedi_sink_s", + gr_make_io_signature (0, 0, 0), + gr_make_io_signature (0, 0, 0)), + d_sampling_freq (sampling_freq), + d_device_name (device_name.empty() ? default_device_name() : device_name), + d_dev (0), + d_subdevice (COMEDI_SUBD_AO), + d_n_chan (1), // number of input channels + d_map (0), + d_buffer_size (0), + d_buf_front (0), + d_buf_back (0) +{ + int aref=AREF_GROUND; + int range=0; + + d_dev = comedi_open(d_device_name.c_str()); + if (d_dev == 0){ + comedi_perror(d_device_name.c_str()); + throw std::runtime_error ("comedi_sink_s"); + } + + unsigned int chanlist[256]; + + for(int i=0; i<d_n_chan; i++){ + chanlist[i]=CR_PACK(i,range,aref); + } + + comedi_cmd cmd; + int ret; + + ret = comedi_get_cmd_generic_timed(d_dev,d_subdevice,&cmd,(unsigned int)(1e9/sampling_freq)); + if(ret<0) + bail ("comedi_get_cmd_generic_timed", comedi_errno()); + + // TODO: check period_ns is not to far off sampling_freq + + d_buffer_size = comedi_get_buffer_size(d_dev, d_subdevice); + if (d_buffer_size <= 0) + bail ("comedi_get_buffer_size", comedi_errno()); + + d_map = mmap(NULL,d_buffer_size,PROT_WRITE,MAP_SHARED,comedi_fileno(d_dev),0); + if (d_map == MAP_FAILED) + bail ("mmap", errno); + + cmd.chanlist = chanlist; + cmd.chanlist_len = d_n_chan; + cmd.scan_end_arg = d_n_chan; + + cmd.stop_src=TRIG_NONE; + cmd.stop_arg=0; + + /* comedi_command_test() tests a command to see if the + * trigger sources and arguments are valid for the subdevice. + * If a trigger source is invalid, it will be logically ANDed + * with valid values (trigger sources are actually bitmasks), + * which may or may not result in a valid trigger source. + * If an argument is invalid, it will be adjusted to the + * nearest valid value. In this way, for many commands, you + * can test it multiple times until it passes. Typically, + * if you can't get a valid command in two tests, the original + * command wasn't specified very well. */ + ret = comedi_command_test(d_dev,&cmd); + + if(ret<0) + bail ("comedi_command_test", comedi_errno()); + + ret = comedi_command_test(d_dev,&cmd); + + if(ret<0) + bail ("comedi_command_test", comedi_errno()); + + /* start the command */ + ret = comedi_command(d_dev,&cmd); + + if(ret<0) + bail ("comedi_command", comedi_errno()); + + set_output_multiple (d_n_chan*sizeof(sampl_t)); + + assert(sizeof(sampl_t) == sizeof(short)); + set_output_signature (gr_make_io_signature (1, 1, sizeof (sampl_t))); +} + +bool +comedi_sink_s::check_topology (int ninputs, int noutputs) +{ + if (ninputs > d_n_chan) + throw std::runtime_error ("comedi_sink_s"); + + return true; +} + +comedi_sink_s::~comedi_sink_s () +{ + if (d_map) { + munmap(d_map, d_buffer_size); + d_map = 0; + } + + comedi_close(d_dev); +} + +int +comedi_sink_s::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + int ret; + + int work_left = noutput_items * sizeof(sampl_t) * d_n_chan; + sampl_t *pbuf = (sampl_t*)d_map; + + do { + + do { + ret = comedi_get_buffer_contents(d_dev,d_subdevice); + if (ret < 0) + bail ("comedi_get_buffer_contents", comedi_errno()); + + assert(ret % sizeof(sampl_t) == 0); + assert(work_left % sizeof(sampl_t) == 0); + + ret = std::min(ret, work_left); + d_buf_front += ret; + + assert(d_buffer_size%d_n_chan == 0); + if (d_buf_front-d_buf_back > (unsigned)d_buffer_size) { + d_buf_front+=d_buffer_size; + d_buf_back +=d_buffer_size; + } + + if(d_buf_front==d_buf_back){ + usleep(1000000*std::min(work_left,d_buffer_size/2)/(d_sampling_freq*sizeof(sampl_t)*d_n_chan)); + continue; + } + } while (d_buf_front==d_buf_back); + + for(unsigned i=d_buf_back/sizeof(sampl_t);i<d_buf_front/sizeof(sampl_t);i++){ + int chan = i%d_n_chan; + int i_idx = noutput_items-work_left/d_n_chan/sizeof(sampl_t)+(i-d_buf_back/sizeof(sampl_t))/d_n_chan; + + pbuf[i%(d_buffer_size/sizeof(sampl_t))] = input_items[chan]==0 ? 0 : + (int)((short*)(input_items[chan]))[i_idx] + 32767; + } + + // FIXME: how to tell comedi the buffer is *written* ? + ret = comedi_mark_buffer_read(d_dev,d_subdevice,d_buf_front-d_buf_back); + if(ret<0) + bail ("comedi_mark_buffer_read", comedi_errno()); + + work_left -= d_buf_front-d_buf_back; + + d_buf_back = d_buf_front; + + } while(work_left>0); + + return noutput_items; +} + + +void +comedi_sink_s::output_error_msg (const char *msg, int err) +{ + fprintf (stderr, "comedi_sink_s[%s]: %s: %s\n", + d_device_name.c_str(), msg, comedi_strerror(err)); +} + +void +comedi_sink_s::bail (const char *msg, int err) throw (std::runtime_error) +{ + output_error_msg (msg, err); + throw std::runtime_error ("comedi_sink_s"); +} diff --git a/gr-comedi/src/comedi_sink_s.h b/gr-comedi/src/comedi_sink_s.h new file mode 100644 index 0000000000..08fce25158 --- /dev/null +++ b/gr-comedi/src/comedi_sink_s.h @@ -0,0 +1,89 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef INCLUDED_COMEDI_SINK_H +#define INCLUDED_COMEDI_SINK_H + +#include <gr_sync_block.h> +#include <string> +#include <comedilib.h> +#include <stdexcept> + +class comedi_sink_s; +typedef boost::shared_ptr<comedi_sink_s> comedi_sink_s_sptr; + +/*! + * \brief make an COMEDI sink. + * + * \param sampling_freq sampling rate in Hz + * \param dev COMEDI device name, e.g., "/dev/comedi0" + */ +comedi_sink_s_sptr +comedi_make_sink_s (int sampling_freq, + const std::string dev = "/dev/comedi0"); + +/*! + * \brief sink using COMEDI + * + * The sink has one input stream of signed short integers. + * + * Input samples must be in the range [-32768,32767]. + */ +class comedi_sink_s : public gr_sync_block { + friend comedi_sink_s_sptr + comedi_make_sink_s (int sampling_freq, const std::string device_name); + + // typedef for pointer to class work method + typedef int (comedi_sink_s::*work_t)(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + unsigned int d_sampling_freq; + std::string d_device_name; + + comedi_t *d_dev; + int d_subdevice; + int d_n_chan; + void *d_map; + int d_buffer_size; + unsigned d_buf_front; + unsigned d_buf_back; + + // random stats + int d_nunderuns; // count of underruns + + void output_error_msg (const char *msg, int err); + void bail (const char *msg, int err) throw (std::runtime_error); + + protected: + comedi_sink_s (int sampling_freq, const std::string device_name); + + public: + ~comedi_sink_s (); + + bool check_topology (int ninputs, int noutputs); + + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /* INCLUDED_COMEDI_SINK_H */ diff --git a/gr-comedi/src/comedi_source_s.cc b/gr-comedi/src/comedi_source_s.cc new file mode 100644 index 0000000000..5041c9c30a --- /dev/null +++ b/gr-comedi/src/comedi_source_s.cc @@ -0,0 +1,229 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/mman.h> + +#include <comedi_source_s.h> +#include <gr_io_signature.h> +#include <stdio.h> +#include <errno.h> +#include <iostream> +#include <stdexcept> +#include <gri_comedi.h> + + +// FIXME these should query some kind of user preference + + +static std::string +default_device_name () +{ + return "/dev/comedi0"; +} + +// ---------------------------------------------------------------- + +comedi_source_s_sptr +comedi_make_source_s (int sampling_freq, const std::string dev) +{ + return comedi_source_s_sptr (new comedi_source_s (sampling_freq, dev)); +} + +comedi_source_s::comedi_source_s (int sampling_freq, + const std::string device_name) + : gr_sync_block ("comedi_source_s", + gr_make_io_signature (0, 0, 0), + gr_make_io_signature (0, 0, 0)), + d_sampling_freq (sampling_freq), + d_device_name (device_name.empty() ? default_device_name() : device_name), + d_dev (0), + d_subdevice (0/*COMEDI_SUBD_AI*/), + d_n_chan (1), // number of input channels + d_map (0), + d_buffer_size (0), + d_buf_front (0), + d_buf_back (0) +{ + int aref=AREF_GROUND; + int range=0; + + d_dev = comedi_open(d_device_name.c_str()); + if (d_dev == 0){ + comedi_perror(d_device_name.c_str()); + throw std::runtime_error ("comedi_source_s"); + } + + unsigned int chanlist[256]; + + for(int i=0; i<d_n_chan; i++){ + chanlist[i]=CR_PACK(i,range,aref); + } + + comedi_cmd cmd; + int ret; + + ret = comedi_get_cmd_generic_timed(d_dev,d_subdevice,&cmd,(unsigned int)(1e9/sampling_freq)); + if(ret<0) + bail ("comedi_get_cmd_generic_timed", comedi_errno()); + + // TODO: check period_ns is not to far off sampling_freq + + d_buffer_size = comedi_get_buffer_size(d_dev, d_subdevice); + if (d_buffer_size <= 0) + bail ("comedi_get_buffer_size", comedi_errno()); + + d_map = mmap(NULL,d_buffer_size,PROT_READ,MAP_SHARED,comedi_fileno(d_dev),0); + if (d_map == MAP_FAILED) + bail ("mmap", errno); + + cmd.chanlist = chanlist; + cmd.chanlist_len = d_n_chan; + cmd.scan_end_arg = d_n_chan; + + cmd.stop_src=TRIG_NONE; + cmd.stop_arg=0; + + /* comedi_command_test() tests a command to see if the + * trigger sources and arguments are valid for the subdevice. + * If a trigger source is invalid, it will be logically ANDed + * with valid values (trigger sources are actually bitmasks), + * which may or may not result in a valid trigger source. + * If an argument is invalid, it will be adjusted to the + * nearest valid value. In this way, for many commands, you + * can test it multiple times until it passes. Typically, + * if you can't get a valid command in two tests, the original + * command wasn't specified very well. */ + ret = comedi_command_test(d_dev,&cmd); + + if(ret<0) + bail ("comedi_command_test", comedi_errno()); + + ret = comedi_command_test(d_dev,&cmd); + + if(ret<0) + bail ("comedi_command_test", comedi_errno()); + + /* start the command */ + ret = comedi_command(d_dev,&cmd); + + if(ret<0) + bail ("comedi_command", comedi_errno()); + + set_output_multiple (d_n_chan*sizeof(sampl_t)); + + assert(sizeof(sampl_t) == sizeof(short)); + set_output_signature (gr_make_io_signature (1, 1, sizeof (sampl_t))); +} + +bool +comedi_source_s::check_topology (int ninputs, int noutputs) +{ + if (noutputs > d_n_chan) + throw std::runtime_error ("comedi_source_s"); + + return true; +} + +comedi_source_s::~comedi_source_s () +{ + if (d_map) { + munmap(d_map, d_buffer_size); + d_map = 0; + } + + comedi_close(d_dev); +} + +int +comedi_source_s::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + int ret; + + int work_left = noutput_items * sizeof(sampl_t) * d_n_chan; + sampl_t *pbuf = (sampl_t*)d_map; + + do { + + do { + ret = comedi_get_buffer_contents(d_dev,d_subdevice); + if (ret < 0) + bail ("comedi_get_buffer_contents", comedi_errno()); + + assert(ret % sizeof(sampl_t) == 0); + assert(work_left % sizeof(sampl_t) == 0); + + ret = std::min(ret, work_left); + d_buf_front += ret; + + assert(d_buffer_size%d_n_chan == 0); + if (d_buf_front-d_buf_back > (unsigned)d_buffer_size) { + d_buf_front+=d_buffer_size; + d_buf_back +=d_buffer_size; + } + + if(d_buf_front==d_buf_back){ + usleep(1000000*std::min(work_left,d_buffer_size/2)/(d_sampling_freq*sizeof(sampl_t)*d_n_chan)); + continue; + } + } while (d_buf_front==d_buf_back); + + for(unsigned i=d_buf_back/sizeof(sampl_t);i<d_buf_front/sizeof(sampl_t);i++){ + int chan = i%d_n_chan; + int o_idx = noutput_items-work_left/d_n_chan/sizeof(sampl_t)+(i-d_buf_back/sizeof(sampl_t))/d_n_chan; + + if (output_items[chan]) + ((short*)(output_items[chan]))[o_idx] = + (int)pbuf[i%(d_buffer_size/sizeof(sampl_t))] - 32767; + } + + ret = comedi_mark_buffer_read(d_dev,d_subdevice,d_buf_front-d_buf_back); + if(ret<0) + bail ("comedi_mark_buffer_read", comedi_errno()); + + work_left -= d_buf_front-d_buf_back; + + d_buf_back = d_buf_front; + + } while(work_left>0); + + return noutput_items; +} + +void +comedi_source_s::output_error_msg (const char *msg, int err) +{ + fprintf (stderr, "comedi_source_s[%s]: %s: %s\n", + d_device_name.c_str(), msg, comedi_strerror(err)); +} + +void +comedi_source_s::bail (const char *msg, int err) throw (std::runtime_error) +{ + output_error_msg (msg, err); + throw std::runtime_error ("comedi_source_s"); +} diff --git a/gr-comedi/src/comedi_source_s.h b/gr-comedi/src/comedi_source_s.h new file mode 100644 index 0000000000..e759c43a35 --- /dev/null +++ b/gr-comedi/src/comedi_source_s.h @@ -0,0 +1,90 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef INCLUDED_COMEDI_SOURCE_S_H +#define INCLUDED_COMEDI_SOURCE_S_H + +#include <gr_sync_block.h> +#include <string> +#include <comedilib.h> +#include <stdexcept> + +class comedi_source_s; +typedef boost::shared_ptr<comedi_source_s> comedi_source_s_sptr; + +/*! + * \brief make a COMEDI source. + * + * \param sampling_freq sampling rate in Hz + * \param dev COMEDI device name, e.g., "/dev/comedi0" + */ +comedi_source_s_sptr +comedi_make_source_s (int sampling_freq, + const std::string dev = "/dev/comedi0"); + +/*! + * \brief source using COMEDI + * + * The source has one to many input stream of signed short integers. + * + * Output samples will be in the range [-32768,32767]. + */ +class comedi_source_s : public gr_sync_block { + friend comedi_source_s_sptr + comedi_make_source_s (int sampling_freq, const std::string device_name); + + // typedef for pointer to class work method + typedef int (comedi_source_s::*work_t)(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + unsigned int d_sampling_freq; + std::string d_device_name; + + comedi_t *d_dev; + int d_subdevice; + int d_n_chan; + void *d_map; + int d_buffer_size; + unsigned d_buf_front; + unsigned d_buf_back; + + // random stats + int d_noverruns; // count of overruns + + void output_error_msg (const char *msg, int err); + void bail (const char *msg, int err) throw (std::runtime_error); + + + protected: + comedi_source_s (int sampling_freq, const std::string device_name); + + public: + ~comedi_source_s (); + + bool check_topology (int ninputs, int noutputs); + + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /* INCLUDED_COMEDI_SOURCE_S_H */ diff --git a/gr-comedi/src/gri_comedi.cc b/gr-comedi/src/gri_comedi.cc new file mode 100644 index 0000000000..e456262938 --- /dev/null +++ b/gr-comedi/src/gri_comedi.cc @@ -0,0 +1,30 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gri_comedi.h> +#include <algorithm> + + diff --git a/gr-comedi/src/gri_comedi.h b/gr-comedi/src/gri_comedi.h new file mode 100644 index 0000000000..5e1f00e933 --- /dev/null +++ b/gr-comedi/src/gri_comedi.h @@ -0,0 +1,28 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef INCLUDED_GRI_COMEDI_H +#define INCLUDED_GRI_COMEDI_H + +#include <stdio.h> + +#endif /* INCLUDED_GRI_COMEDI_H */ diff --git a/gr-comedi/src/qa_comedi.py b/gr-comedi/src/qa_comedi.py new file mode 100755 index 0000000000..98b2f91892 --- /dev/null +++ b/gr-comedi/src/qa_comedi.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# +# Copyright 2005 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# + +from gnuradio import gr, gr_unittest +import comedi + +class qa_comedi (gr_unittest.TestCase): + + def setUp (self): + self.fg = gr.flow_graph () + + def tearDown (self): + self.fg = None + + def test_000_nop (self): + """Just see if we can import the module... + They may not have COMEDI library, etc. Don't try to run anything""" + pass + +if __name__ == '__main__': + gr_unittest.main () diff --git a/gr-comedi/src/run_tests.in b/gr-comedi/src/run_tests.in new file mode 100644 index 0000000000..6c0ba9d18c --- /dev/null +++ b/gr-comedi/src/run_tests.in @@ -0,0 +1,47 @@ +#!/bin/sh + +# All this strange PYTHONPATH manipulation is required to run our +# tests using our just built shared library and swig-generated python +# code prior to installation. + +# build tree == src tree unless you're doing a VPATH build. +# If you don't know what a VPATH build is, you're not doing one. Relax... + +prefix=@prefix@ +exec_prefix=@exec_prefix@ + +# Where to look in the build tree for our shared library +libbld=@abs_top_builddir@/gr-comedi/src +# Where to look in the src tree for swig generated python code +libsrc=@abs_top_srcdir@/gr-comedi/src +# Where to look in the src tree for hand written python code +py=@abs_top_srcdir@/gr-comedi/src + +# Where to look for GNU Radio python modules in current build tree +# FIXME this is wrong on a distcheck. We really need to ask gnuradio-core +# where it put its python files. +grpythonbld=@abs_top_builddir@/gnuradio-core/src/python/:@abs_top_builddir@/gnuradio-core/src/lib/swig/:@abs_top_builddir@/gnuradio-core/src/lib/swig/.libs + +PYTHONPATH="$grpythonbld:$libbld:$libbld/.libs:$libsrc:$py:$PYTHONPATH" +export PYTHONPATH + +# +# This is the simple part... +# Run everything that matches qa_*.py and return the final result. +# + +ok=yes +for file in @srcdir@/qa_*.py +do + if ! $file + then + ok=no + fi +done + +if [ $ok = yes ] +then + exit 0 +else + exit 1 +fi |