diff options
Diffstat (limited to 'gr-comedi/src')
-rw-r--r-- | gr-comedi/src/CMakeLists.txt | 117 | ||||
-rw-r--r-- | gr-comedi/src/comedi.i | 74 | ||||
-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 |
9 files changed, 930 insertions, 0 deletions
diff --git a/gr-comedi/src/CMakeLists.txt b/gr-comedi/src/CMakeLists.txt new file mode 100644 index 000000000..1d9dac2c4 --- /dev/null +++ b/gr-comedi/src/CMakeLists.txt @@ -0,0 +1,117 @@ +# Copyright 2011 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 3, 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., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +######################################################################## +# Setup the include and linker paths +######################################################################## +include_directories( + ${GR_COMEDI_INCLUDE_DIRS} + ${GNURADIO_CORE_INCLUDE_DIRS} + ${GRUEL_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} + ${COMEDI_INCLUDE_DIRS} +) + +link_directories( + ${Boost_LIBRARY_DIRS} + ${COMEDI_LIBRARY_DIRS} +) + +######################################################################## +# Setup library +######################################################################## +list(APPEND gr_comedi_sources + comedi_sink_s.cc + comedi_source_s.cc + gri_comedi.cc +) + +list(APPEND comedi_libs + gnuradio-core + ${Boost_LIBRARIES} + ${COMEDI_LIBRARIES} +) + +add_library(gnuradio-comedi SHARED ${gr_comedi_sources}) +target_link_libraries(gnuradio-comedi ${comedi_libs}) +GR_LIBRARY_FOO(gnuradio-comedi RUNTIME_COMPONENT "comedi_runtime" DEVEL_COMPONENT "comedi_devel") + +######################################################################## +# Install public header files +######################################################################## +install(FILES + comedi_sink_s.h + comedi_source_s.h + DESTINATION ${GR_INCLUDE_DIR}/gnuradio + COMPONENT "comedi_devel" +) + +######################################################################## +# Setup swig generation +######################################################################## +if(ENABLE_PYTHON) +include(GrPython) +include(GrSwig) + +set(GR_SWIG_INCLUDE_DIRS + ${GR_COMEDI_INCLUDE_DIRS} + ${GNURADIO_CORE_SWIG_INCLUDE_DIRS} + ${GRUEL_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} +) + +set(GR_SWIG_DOC_FILE ${CMAKE_CURRENT_BINARY_DIR}/comedi_swig_doc.i) +set(GR_SWIG_DOC_DIRS ${CMAKE_CURRENT_SOURCE_DIR}) + +set(GR_SWIG_LIBRARIES gnuradio-comedi) + +GR_SWIG_MAKE(comedi comedi.i) + +GR_SWIG_INSTALL( + TARGETS comedi + DESTINATION ${GR_PYTHON_DIR}/gnuradio + COMPONENT "comedi_python" +) + +install( + FILES comedi.i + ${CMAKE_CURRENT_BINARY_DIR}/comedi_swig_doc.i + DESTINATION ${GR_INCLUDE_DIR}/gnuradio/swig + COMPONENT "comedi_swig" +) + +endif(ENABLE_PYTHON) + +######################################################################## +# Handle the unit tests +######################################################################## +if(ENABLE_TESTING AND ENABLE_PYTHON) + +list(APPEND GR_TEST_PYTHON_DIRS + ${CMAKE_BINARY_DIR}/gr-comedi/src +) +list(APPEND GR_TEST_TARGET_DEPS gnuradio-comedi) + +include(GrTest) +file(GLOB py_qa_test_files "qa_*.py") +foreach(py_qa_test_file ${py_qa_test_files}) + get_filename_component(py_qa_test_name ${py_qa_test_file} NAME_WE) + GR_ADD_TEST(${py_qa_test_name} ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B} ${py_qa_test_file}) +endforeach(py_qa_test_file) +endif(ENABLE_TESTING AND ENABLE_PYTHON) diff --git a/gr-comedi/src/comedi.i b/gr-comedi/src/comedi.i new file mode 100644 index 000000000..d3660580a --- /dev/null +++ b/gr-comedi/src/comedi.i @@ -0,0 +1,74 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2009 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 3, 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., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +%include "gnuradio.i" // the common stuff + +//load generated python docstrings +%include "comedi_swig_doc.i" + +%{ +#include "comedi_sink_s.h" +#include "comedi_source_s.h" +%} + +// ---------------------------------------------------------------- + +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 000000000..de1decfb6 --- /dev/null +++ b/gr-comedi/src/comedi_sink_s.cc @@ -0,0 +1,233 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2010 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 3, 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., 51 Franklin Street, + * Boston, MA 02110-1301, 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 gnuradio::get_initial_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,d_n_chan,(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 000000000..94d39710c --- /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 3, 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., 51 Franklin Street, + * Boston, MA 02110-1301, 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 a 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 dev); + + // 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 000000000..517f1440b --- /dev/null +++ b/gr-comedi/src/comedi_source_s.cc @@ -0,0 +1,229 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2010 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 3, 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., 51 Franklin Street, + * Boston, MA 02110-1301, 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 gnuradio::get_initial_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,d_n_chan,(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 000000000..b9fde4c1e --- /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 3, 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., 51 Franklin Street, + * Boston, MA 02110-1301, 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 dev); + + // 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 000000000..97b3ccd3e --- /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 3, 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., 51 Franklin Street, + * Boston, MA 02110-1301, 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 000000000..571a41180 --- /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 3, 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., 51 Franklin Street, + * Boston, MA 02110-1301, 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 000000000..a407ab62b --- /dev/null +++ b/gr-comedi/src/qa_comedi.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# +# Copyright 2005,2007 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 3, 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., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio import gr, gr_unittest +import comedi + +class qa_comedi (gr_unittest.TestCase): + + def setUp (self): + self.tb = gr.top_block () + + def tearDown (self): + self.tb = 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 () |