diff options
author | Tom Rondeau <trondeau@vt.edu> | 2013-03-10 22:48:39 -0400 |
---|---|---|
committer | Tom Rondeau <trondeau@vt.edu> | 2013-03-10 22:48:39 -0400 |
commit | 5a3f0062fa438875b68191363d4ff78ccd07d0c9 (patch) | |
tree | 9f883de47cc6ce1535d0a91219fbd0511d56acf8 | |
parent | 1bc6349e4714c5c4856b3abb95dc5f6b15c44281 (diff) | |
parent | 45f9c0a5792526279ebf5ffa6a4853c7e2de6dd6 (diff) |
Merge branch 'master' into next
-rw-r--r-- | gr-blocks/grc/blocks_block_tree.xml | 3 | ||||
-rw-r--r-- | gr-blocks/grc/blocks_file_descriptor_sink.xml | 59 | ||||
-rw-r--r-- | gr-blocks/grc/blocks_file_descriptor_source.xml | 73 | ||||
-rw-r--r-- | gr-blocks/grc/blocks_file_sink.xml | 78 | ||||
-rw-r--r-- | gr-blocks/include/blocks/CMakeLists.txt | 4 | ||||
-rw-r--r-- | gr-blocks/include/blocks/file_descriptor_sink.h | 54 | ||||
-rw-r--r-- | gr-blocks/include/blocks/file_descriptor_source.h | 61 | ||||
-rw-r--r-- | gr-blocks/include/blocks/file_sink.h | 55 | ||||
-rw-r--r-- | gr-blocks/include/blocks/file_sink_base.h | 80 | ||||
-rw-r--r-- | gr-blocks/lib/CMakeLists.txt | 4 | ||||
-rw-r--r-- | gr-blocks/lib/file_descriptor_sink_impl.cc | 94 | ||||
-rw-r--r-- | gr-blocks/lib/file_descriptor_sink_impl.h | 49 | ||||
-rw-r--r-- | gr-blocks/lib/file_descriptor_source_impl.cc | 156 | ||||
-rw-r--r-- | gr-blocks/lib/file_descriptor_source_impl.h | 58 | ||||
-rw-r--r-- | gr-blocks/lib/file_sink_base.cc | 131 | ||||
-rw-r--r-- | gr-blocks/lib/file_sink_impl.cc | 90 | ||||
-rw-r--r-- | gr-blocks/lib/file_sink_impl.h | 48 | ||||
-rw-r--r-- | gr-blocks/python/qa_file_source_sink.py | 93 | ||||
-rw-r--r-- | gr-blocks/swig/blocks_swig.i | 11 |
19 files changed, 1201 insertions, 0 deletions
diff --git a/gr-blocks/grc/blocks_block_tree.xml b/gr-blocks/grc/blocks_block_tree.xml index 573558466d..124cbe651f 100644 --- a/gr-blocks/grc/blocks_block_tree.xml +++ b/gr-blocks/grc/blocks_block_tree.xml @@ -31,6 +31,7 @@ <cat> <name>Sources (New)</name> <block>blocks_file_source</block> + <block>blocks_file_descriptor_source</block> <block>blocks_file_meta_source</block> <block>blocks_pdu_to_tagged_stream</block> <block>blocks_random_pdu</block> @@ -40,6 +41,8 @@ </cat> <cat> <name>Sinks (New)</name> + <block>blocks_file_sink</block> + <block>blocks_file_descriptor_sink</block> <block>blocks_file_meta_sink</block> <block>blocks_tagged_stream_to_pdu</block> <block>blocks_tag_debug</block> diff --git a/gr-blocks/grc/blocks_file_descriptor_sink.xml b/gr-blocks/grc/blocks_file_descriptor_sink.xml new file mode 100644 index 0000000000..211d86dfd3 --- /dev/null +++ b/gr-blocks/grc/blocks_file_descriptor_sink.xml @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<!-- +################################################### +##File Sink +################################################### + --> +<block> + <name>File Descriptor Sink</name> + <key>blocks_file_descriptor_sink</key> + <import>from gnuradio import blocks</import> + <make>blocks.file_descriptor_sink($type.size*$vlen, $fd)</make> + <param> + <name>File Descriptor</name> + <key>fd</key> + <type>int</type> + </param> + <param> + <name>Input Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> +</block> diff --git a/gr-blocks/grc/blocks_file_descriptor_source.xml b/gr-blocks/grc/blocks_file_descriptor_source.xml new file mode 100644 index 0000000000..b29335c3af --- /dev/null +++ b/gr-blocks/grc/blocks_file_descriptor_source.xml @@ -0,0 +1,73 @@ +<?xml version="1.0"?> +<!-- +################################################### +##File Source +################################################### + --> +<block> + <name>File Descriptor Source</name> + <key>blocks_file_descriptor_source</key> + <import>from gnuradio import blocks</import> + <make>blocks.file_descriptor_source($type.size*$vlen, $fd, $repeat)</make> + <param> + <name>File Descriptor</name> + <key>fd</key> + <type>int</type> + </param> + <param> + <name>Output Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Repeat</name> + <key>repeat</key> + <value>True</value> + <type>enum</type> + <option> + <name>Yes</name> + <key>True</key> + </option> + <option> + <name>No</name> + <key>False</key> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <check>$vlen > 0</check> + <source> + <name>out</name> + <type>$type</type> + <vlen>$vlen</vlen> + </source> +</block> diff --git a/gr-blocks/grc/blocks_file_sink.xml b/gr-blocks/grc/blocks_file_sink.xml new file mode 100644 index 0000000000..75ef86a6b8 --- /dev/null +++ b/gr-blocks/grc/blocks_file_sink.xml @@ -0,0 +1,78 @@ +<?xml version="1.0"?> +<!-- +################################################### +##File Sink +################################################### + --> +<block> + <name>File Sink</name> + <key>blocks_file_sink</key> + <import>from gnuradio import blocks</import> + <make>blocks.file_sink($type.size*$vlen, $file) +self.$(id).set_unbuffered($unbuffered)</make> + <callback>set_unbuffered($unbuffered)</callback> + <callback>open($file)</callback> + <param> + <name>File</name> + <key>file</key> + <value></value> + <type>file_save</type> + </param> + <param> + <name>Input Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>size:gr.sizeof_gr_complex</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>size:gr.sizeof_float</opt> + </option> + <option> + <name>Int</name> + <key>int</key> + <opt>size:gr.sizeof_int</opt> + </option> + <option> + <name>Short</name> + <key>short</key> + <opt>size:gr.sizeof_short</opt> + </option> + <option> + <name>Byte</name> + <key>byte</key> + <opt>size:gr.sizeof_char</opt> + </option> + </param> + <param> + <name>Vec Length</name> + <key>vlen</key> + <value>1</value> + <type>int</type> + </param> + <param> + <name>Unbuffered</name> + <key>unbuffered</key> + <value>False</value> + <type>bool</type> + <option> + <name>Off</name> + <key>False</key> + </option> + <option> + <name>On</name> + <key>True</key> + </option> + </param> + + <check>$vlen > 0</check> + <sink> + <name>in</name> + <type>$type</type> + <vlen>$vlen</vlen> + </sink> +</block> diff --git a/gr-blocks/include/blocks/CMakeLists.txt b/gr-blocks/include/blocks/CMakeLists.txt index 3315430a5f..5cc2731cb1 100644 --- a/gr-blocks/include/blocks/CMakeLists.txt +++ b/gr-blocks/include/blocks/CMakeLists.txt @@ -101,6 +101,7 @@ install(FILES api.h control_loop.h count_bits.h + file_sink_base.h fxpt.h fxpt_nco.h fxpt_vco.h @@ -123,6 +124,9 @@ install(FILES conjugate_cc.h deinterleave.h delay.h + file_descriptor_sink.h + file_descriptor_source.h + file_sink.h file_source.h file_meta_sink.h file_meta_source.h diff --git a/gr-blocks/include/blocks/file_descriptor_sink.h b/gr-blocks/include/blocks/file_descriptor_sink.h new file mode 100644 index 0000000000..df59e24c0a --- /dev/null +++ b/gr-blocks/include/blocks/file_descriptor_sink.h @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2013 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_GR_FILE_DESCRIPTOR_SINK_H +#define INCLUDED_GR_FILE_DESCRIPTOR_SINK_H + +#include <blocks/api.h> +#include <gr_sync_block.h> + +namespace gr { + namespace blocks { + + /*! + * \brief Write stream to file descriptor. + * \ingroup sink_blk + */ + class BLOCKS_API file_descriptor_sink : virtual public gr_sync_block + { + public: + // gr::blocks::file_descriptor_sink::sptr + typedef boost::shared_ptr<file_descriptor_sink> sptr; + + /*! + * Build a file descriptor sink block. + * + * \param itemsize item size of the incoming data stream. + * \param fd file descriptor (as an integer). + */ + static sptr make(size_t itemsize, int fd); + }; + + } /* namespace blocks */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_FILE_DESCRIPTOR_SINK_H */ diff --git a/gr-blocks/include/blocks/file_descriptor_source.h b/gr-blocks/include/blocks/file_descriptor_source.h new file mode 100644 index 0000000000..ff4f14792b --- /dev/null +++ b/gr-blocks/include/blocks/file_descriptor_source.h @@ -0,0 +1,61 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2013 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_GR_FILE_DESCRIPTOR_SOURCE_H +#define INCLUDED_GR_FILE_DESCRIPTOR_SOURCE_H + +#include <blocks/api.h> +#include <gr_sync_block.h> + + +namespace gr { + namespace blocks { + + /*! + * \brief Read stream from file descriptor. + * \ingroup source_blk + */ + class BLOCKS_API file_descriptor_source : virtual public gr_sync_block + { + protected: + virtual int read_items(char *buf, int nitems) = 0; + virtual int handle_residue(char *buf, int nbytes_read) = 0; + virtual void flush_residue() = 0; + + public: + // gr::blocks::file_descriptor_source::sptr + typedef boost::shared_ptr<file_descriptor_source> sptr; + + /*! + * Build a file descriptor source block. + * + * \param itemsize item size of the incoming data stream. + * \param fd file descriptor (as an integer). + * \param repeat repeat the data stream continuously. + */ + static sptr make(size_t itemsize, int fd, bool repeat); + }; + + } /* namespace blocks */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_FILE_DESCRIPTOR_SOURCE_H */ diff --git a/gr-blocks/include/blocks/file_sink.h b/gr-blocks/include/blocks/file_sink.h new file mode 100644 index 0000000000..08c2adf1f7 --- /dev/null +++ b/gr-blocks/include/blocks/file_sink.h @@ -0,0 +1,55 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2007,2013 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_GR_FILE_SINK_H +#define INCLUDED_GR_FILE_SINK_H + +#include <blocks/api.h> +#include <blocks/file_sink_base.h> +#include <gr_sync_block.h> + +namespace gr { + namespace blocks { + + /*! + * \brief Write stream to file. + * \ingroup sink_blk + */ + class BLOCKS_API file_sink : virtual public gr_sync_block, + virtual public file_sink_base + { + public: + // gr::blocks::file_sink::sptr + typedef boost::shared_ptr<file_sink> sptr; + + /*! + * \brief Make a file sink. + * \param itemsize size of the input data items. + * \param filename name of the file to open and write output to. + */ + static sptr make(size_t itemsize, const char *filename); + }; + + } /* namespace blocks */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_FILE_SINK_H */ diff --git a/gr-blocks/include/blocks/file_sink_base.h b/gr-blocks/include/blocks/file_sink_base.h new file mode 100644 index 0000000000..3eeb0e63da --- /dev/null +++ b/gr-blocks/include/blocks/file_sink_base.h @@ -0,0 +1,80 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2007,2008,2013 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_GR_FILE_SINK_BASE_H +#define INCLUDED_GR_FILE_SINK_BASE_H + +#include <blocks/api.h> +#include <boost/thread.hpp> +#include <cstdio> + +namespace gr { + namespace blocks { + + /*! + * \brief Common base class for file sinks + */ + class BLOCKS_API file_sink_base + { + protected: + FILE *d_fp; // current FILE pointer + FILE *d_new_fp; // new FILE pointer + bool d_updated; // is there a new FILE pointer? + bool d_is_binary; + boost::mutex d_mutex; + bool d_unbuffered; + + protected: + file_sink_base(const char *filename, bool is_binary); + + public: + file_sink_base() {} + ~file_sink_base(); + + /*! + * \brief Open filename and begin output to it. + */ + bool open(const char *filename); + + /*! + * \brief Close current output file. + * + * Closes current output file and ignores any output until + * open is called to connect to another file. + */ + void close(); + + /*! + * \brief if we've had an update, do it now. + */ + void do_update(); + + /*! + * \brief turn on unbuffered writes for slower outputs + */ + void set_unbuffered(bool unbuffered); + }; + + } /* namespace blocks */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_FILE_SINK_BASE_H */ diff --git a/gr-blocks/lib/CMakeLists.txt b/gr-blocks/lib/CMakeLists.txt index c1a6e55738..7e429a8d1b 100644 --- a/gr-blocks/lib/CMakeLists.txt +++ b/gr-blocks/lib/CMakeLists.txt @@ -143,6 +143,7 @@ list(APPEND gr_blocks_sources ${generated_sources} control_loop.cc count_bits.cc + file_sink_base.cc fxpt.cc wavfile.cc add_ff_impl.cc @@ -160,6 +161,9 @@ list(APPEND gr_blocks_sources conjugate_cc_impl.cc deinterleave_impl.cc delay_impl.cc + file_descriptor_sink_impl.cc + file_descriptor_source_impl.cc + file_sink_impl.cc file_source_impl.cc file_meta_sink_impl.cc file_meta_source_impl.cc diff --git a/gr-blocks/lib/file_descriptor_sink_impl.cc b/gr-blocks/lib/file_descriptor_sink_impl.cc new file mode 100644 index 0000000000..a1f26220d2 --- /dev/null +++ b/gr-blocks/lib/file_descriptor_sink_impl.cc @@ -0,0 +1,94 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010,2013 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 "file_descriptor_sink_impl.h" +#include <gr_io_signature.h> +#include <cstdio> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdexcept> +#include <stdio.h> + +#ifdef HAVE_IO_H +#include <io.h> +#endif + +namespace gr { + namespace blocks { + + file_descriptor_sink::sptr + file_descriptor_sink::make(size_t itemsize, int fd) + { + return gnuradio::get_initial_sptr + (new file_descriptor_sink_impl(itemsize, fd)); + } + + file_descriptor_sink_impl::file_descriptor_sink_impl(size_t itemsize, int fd) + : gr_sync_block("file_descriptor_sink", + gr_make_io_signature(1, 1, itemsize), + gr_make_io_signature(0, 0, 0)), + d_itemsize(itemsize), d_fd(fd) + { + } + + file_descriptor_sink_impl::~file_descriptor_sink_impl() + { + close(d_fd); + } + + int + file_descriptor_sink_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + char *inbuf = (char*)input_items[0]; + unsigned long byte_size = noutput_items * d_itemsize; + + while(byte_size > 0) { + ssize_t r; + + r = write(d_fd, inbuf, byte_size); + if(r == -1) { + if(errno == EINTR) + continue; + else { + perror("file_descriptor_sink"); + return -1; // indicate we're done + } + } + else { + byte_size -= r; + inbuf += r; + } + } + + return noutput_items; + } + + } /* namespace blocks */ +} /* namespace gr */ diff --git a/gr-blocks/lib/file_descriptor_sink_impl.h b/gr-blocks/lib/file_descriptor_sink_impl.h new file mode 100644 index 0000000000..90b02f4163 --- /dev/null +++ b/gr-blocks/lib/file_descriptor_sink_impl.h @@ -0,0 +1,49 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2013 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_GR_FILE_DESCRIPTOR_SINK_IMPL_H +#define INCLUDED_GR_FILE_DESCRIPTOR_SINK_IMPL_H + +#include <blocks/file_descriptor_sink.h> + +namespace gr { + namespace blocks { + + class file_descriptor_sink_impl : public file_descriptor_sink + { + private: + size_t d_itemsize; + int d_fd; + + public: + file_descriptor_sink_impl(size_t itemsize, int fd); + ~file_descriptor_sink_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace blocks */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_FILE_DESCRIPTOR_SINK_IMPL_H */ diff --git a/gr-blocks/lib/file_descriptor_source_impl.cc b/gr-blocks/lib/file_descriptor_source_impl.cc new file mode 100644 index 0000000000..667e96b7fa --- /dev/null +++ b/gr-blocks/lib/file_descriptor_source_impl.cc @@ -0,0 +1,156 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2005,2013 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 "file_descriptor_source_impl.h" +#include <gr_io_signature.h> +#include <cstdio> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdexcept> +#include <stdio.h> +#include <string.h> + +#ifdef HAVE_IO_H +#include <io.h> +#endif + +namespace gr { + namespace blocks { + + file_descriptor_source::sptr + file_descriptor_source::make(size_t itemsize, int fd, bool repeat) + { + return gnuradio::get_initial_sptr + (new file_descriptor_source_impl(itemsize, fd, repeat)); + } + + file_descriptor_source_impl::file_descriptor_source_impl(size_t itemsize, + int fd, + bool repeat) + : gr_sync_block("file_descriptor_source", + gr_make_io_signature(0, 0, 0), + gr_make_io_signature(1, 1, itemsize)), + d_itemsize(itemsize), d_fd(fd), d_repeat(repeat), + d_residue(new unsigned char[itemsize]), d_residue_len (0) + { + } + + file_descriptor_source_impl::~file_descriptor_source_impl() + { + close(d_fd); + delete [] d_residue; + } + + int + file_descriptor_source_impl::read_items(char *buf, int nitems) + { + assert(nitems > 0); + assert(d_residue_len < d_itemsize); + + int nbytes_read = 0; + + if(d_residue_len > 0) { + memcpy(buf, d_residue, d_residue_len); + nbytes_read = d_residue_len; + d_residue_len = 0; + } + + int r = read(d_fd, buf + nbytes_read, + nitems * d_itemsize - nbytes_read); + if(r <= 0) { + handle_residue(buf, nbytes_read); + return r; + } + + r = handle_residue(buf, r + nbytes_read); + + if(r == 0) // block until we get something + return read_items(buf, nitems); + + return r; + } + + int + file_descriptor_source_impl::handle_residue(char *buf, int nbytes_read) + { + assert(nbytes_read >= 0); + int nitems_read = nbytes_read / d_itemsize; + d_residue_len = nbytes_read % d_itemsize; + if(d_residue_len > 0) { + // fprintf (stderr, "handle_residue: %d\n", d_residue_len); + memcpy(d_residue, buf + nbytes_read - d_residue_len, d_residue_len); + } + return nitems_read; + } + + int + file_descriptor_source_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + assert(noutput_items > 0); + + char *o = (char*)output_items[0]; + int nread = 0; + + while(1) { + int r = read_items(o, noutput_items - nread); + if(r == -1) { + if(errno == EINTR) + continue; + else { + perror("file_descriptor_source[read]"); + return -1; + } + } + else if(r == 0) { // end of file + if(!d_repeat) + break; + else { + flush_residue(); + if(lseek(d_fd, 0, SEEK_SET) == -1) { + perror("file_descriptor_source[lseek]"); + return -1; + } + } + } + else { + o += r * d_itemsize; + nread += r; + break; + } + } + + if(nread == 0) // EOF + return -1; + + return nread; + } + + } /* namespace blocks */ +} /* namespace gr */ diff --git a/gr-blocks/lib/file_descriptor_source_impl.h b/gr-blocks/lib/file_descriptor_source_impl.h new file mode 100644 index 0000000000..dd86e18af1 --- /dev/null +++ b/gr-blocks/lib/file_descriptor_source_impl.h @@ -0,0 +1,58 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2013 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_GR_FILE_DESCRIPTOR_SOURCE_IMPL_H +#define INCLUDED_GR_FILE_DESCRIPTOR_SOURCE_IMPL_H + +#include <blocks/file_descriptor_source.h> + +namespace gr { + namespace blocks { + + class file_descriptor_source_impl : public file_descriptor_source + { + private: + size_t d_itemsize; + int d_fd; + bool d_repeat; + + unsigned char *d_residue; + unsigned long d_residue_len; + + protected: + int read_items(char *buf, int nitems); + int handle_residue(char *buf, int nbytes_read); + void flush_residue() { d_residue_len = 0; } + + public: + file_descriptor_source_impl(size_t itemsize, int fd, bool repeat); + ~file_descriptor_source_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace blocks */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_FILE_DESCRIPTOR_SOURCE_IMPL_H */ diff --git a/gr-blocks/lib/file_sink_base.cc b/gr-blocks/lib/file_sink_base.cc new file mode 100644 index 0000000000..47c8f9882b --- /dev/null +++ b/gr-blocks/lib/file_sink_base.cc @@ -0,0 +1,131 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2006,2007,2009,2013 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 <blocks/file_sink_base.h> +#include <cstdio> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdexcept> +#include <stdio.h> +#include <gruel/thread.h> + +// win32 (mingw/msvc) specific +#ifdef HAVE_IO_H +#include <io.h> +#endif +#ifdef O_BINARY +#define OUR_O_BINARY O_BINARY +#else +#define OUR_O_BINARY 0 +#endif + +// should be handled via configure +#ifdef O_LARGEFILE +#define OUR_O_LARGEFILE O_LARGEFILE +#else +#define OUR_O_LARGEFILE 0 +#endif + +namespace gr { + namespace blocks { + + file_sink_base::file_sink_base(const char *filename, bool is_binary) + : d_fp(0), d_new_fp(0), d_updated(false), d_is_binary(is_binary) + { + if (!open(filename)) + throw std::runtime_error ("can't open file"); + } + + file_sink_base::~file_sink_base() + { + close(); + if(d_fp) { + fclose(d_fp); + d_fp = 0; + } + } + + bool + file_sink_base::open(const char *filename) + { + gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function + + // we use the open system call to get access to the O_LARGEFILE flag. + int fd; + if((fd = ::open(filename, + O_WRONLY|O_CREAT|O_TRUNC|OUR_O_LARGEFILE|OUR_O_BINARY, + 0664)) < 0){ + perror(filename); + return false; + } + if(d_new_fp) { // if we've already got a new one open, close it + fclose(d_new_fp); + d_new_fp = 0; + } + + if((d_new_fp = fdopen (fd, d_is_binary ? "wb" : "w")) == NULL) { + perror (filename); + ::close(fd); // don't leak file descriptor if fdopen fails. + } + + d_updated = true; + return d_new_fp != 0; + } + + void + file_sink_base::close() + { + gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function + + if(d_new_fp) { + fclose(d_new_fp); + d_new_fp = 0; + } + d_updated = true; + } + + void + file_sink_base::do_update() + { + if(d_updated) { + gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this block + if(d_fp) + fclose(d_fp); + d_fp = d_new_fp; // install new file pointer + d_new_fp = 0; + d_updated = false; + } + } + + void + file_sink_base::set_unbuffered(bool unbuffered) + { + d_unbuffered = unbuffered; + } + + } /* namespace blocks */ +} /* namespace gr */ diff --git a/gr-blocks/lib/file_sink_impl.cc b/gr-blocks/lib/file_sink_impl.cc new file mode 100644 index 0000000000..88dcb5a021 --- /dev/null +++ b/gr-blocks/lib/file_sink_impl.cc @@ -0,0 +1,90 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2006,2007,2010,2013 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 "file_sink_impl.h" +#include <gr_io_signature.h> +#include <stdexcept> + +namespace gr { + namespace blocks { + + file_sink::sptr + file_sink::make(size_t itemsize, const char *filename) + { + return gnuradio::get_initial_sptr + (new file_sink_impl(itemsize, filename)); + } + + file_sink_impl::file_sink_impl(size_t itemsize, const char *filename) + : gr_sync_block("file_sink", + gr_make_io_signature(1, 1, itemsize), + gr_make_io_signature(0, 0, 0)), + file_sink_base(filename, true), + d_itemsize(itemsize) + { + } + + file_sink_impl::~file_sink_impl() + { + } + + int + file_sink_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + char *inbuf = (char*)input_items[0]; + int nwritten = 0; + + do_update(); // update d_fp is reqd + + if(!d_fp) + return noutput_items; // drop output on the floor + + while(nwritten < noutput_items) { + int count = fwrite(inbuf, d_itemsize, noutput_items - nwritten, d_fp); + if(count == 0) { + if(ferror(d_fp)) { + std::stringstream s; + s << "file_sink write failed with error " << fileno(d_fp) << std::endl; + throw std::runtime_error(s.str()); + } + else { // is EOF + break; + } + } + nwritten += count; + inbuf += count * d_itemsize; + } + + if(d_unbuffered) + fflush (d_fp); + + return nwritten; + } + + } /* namespace blocks */ +} /* namespace gr */ diff --git a/gr-blocks/lib/file_sink_impl.h b/gr-blocks/lib/file_sink_impl.h new file mode 100644 index 0000000000..8e802ad88a --- /dev/null +++ b/gr-blocks/lib/file_sink_impl.h @@ -0,0 +1,48 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2007,2013 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_GR_FILE_SINK_IMPL_H +#define INCLUDED_GR_FILE_SINK_IMPL_H + +#include <blocks/file_sink.h> + +namespace gr { + namespace blocks { + + class file_sink_impl : public file_sink + { + private: + size_t d_itemsize; + + public: + file_sink_impl(size_t itemsize, const char *filename); + ~file_sink_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace blocks */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_FILE_SINK_IMPL_H */ diff --git a/gr-blocks/python/qa_file_source_sink.py b/gr-blocks/python/qa_file_source_sink.py new file mode 100644 index 0000000000..d1d67074d5 --- /dev/null +++ b/gr-blocks/python/qa_file_source_sink.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python +# +# Copyright 2013 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 blocks_swig as blocks +import os + +class test_file_source_sink(gr_unittest.TestCase): + + def setUp (self): + self.tb = gr.top_block () + + def tearDown (self): + self.tb = None + + def test_001(self): + src_data = range(1000) + expected_result = range(1000) + + filename = "tmp.32f" + src = gr.vector_source_f(src_data) + snk = blocks.file_sink(gr.sizeof_float, filename) + snk.set_unbuffered(True) + + src2 = blocks.file_source(gr.sizeof_float, filename) + snk2 = gr.vector_sink_f() + + self.tb.connect(src, snk) + self.tb.run() + + self.tb.disconnect(src, snk) + self.tb.connect(src2, snk2) + self.tb.run() + + os.remove(filename) + + result_data = snk2.data() + self.assertFloatTuplesAlmostEqual(expected_result, result_data) + + def test_descriptor_001(self): + src_data = range(1000) + expected_result = range(1000) + + filename = "tmp.32f" + fhandle0 = open(filename, "wb") + fd0 = fhandle0.fileno() + + src = gr.vector_source_f(src_data) + snk = blocks.file_descriptor_sink(gr.sizeof_float, fd0) + + self.tb.connect(src, snk) + self.tb.run() + os.fsync(fd0) + fhandle0.close() + + fhandle1 = open(filename, "rb") + fd1 = fhandle1.fileno() + src2 = blocks.file_descriptor_source(gr.sizeof_float, fd1, False) + snk2 = gr.vector_sink_f() + + self.tb.disconnect(src, snk) + self.tb.connect(src2, snk2) + self.tb.run() + os.fsync(fd1) + fhandle1.close() + + os.remove(filename) + + result_data = snk2.data() + self.assertFloatTuplesAlmostEqual(expected_result, result_data) + +if __name__ == '__main__': + gr_unittest.run(test_file_source_sink, "test_file_source_sink.xml") + diff --git a/gr-blocks/swig/blocks_swig.i b/gr-blocks/swig/blocks_swig.i index 974ee1e4bf..91938f3f2b 100644 --- a/gr-blocks/swig/blocks_swig.i +++ b/gr-blocks/swig/blocks_swig.i @@ -71,6 +71,10 @@ #include "blocks/divide_ss.h" #include "blocks/divide_ii.h" #include "blocks/divide_cc.h" +#include "blocks/file_descriptor_sink.h" +#include "blocks/file_descriptor_source.h" +#include "blocks/file_sink_base.h" +#include "blocks/file_sink.h" #include "blocks/file_source.h" #include "blocks/file_meta_sink.h" #include "blocks/file_meta_source.h" @@ -224,6 +228,10 @@ %include "blocks/control_loop.h" %include "blocks/deinterleave.h" %include "blocks/delay.h" +%include "blocks/file_descriptor_sink.h" +%include "blocks/file_descriptor_source.h" +%include "blocks/file_sink_base.h" +%include "blocks/file_sink.h" %include "blocks/file_source.h" %include "blocks/file_meta_sink.h" %include "blocks/file_meta_source.h" @@ -383,6 +391,9 @@ GR_SWIG_BLOCK_MAGIC2(blocks, divide_ff); GR_SWIG_BLOCK_MAGIC2(blocks, divide_ss); GR_SWIG_BLOCK_MAGIC2(blocks, divide_ii); GR_SWIG_BLOCK_MAGIC2(blocks, divide_cc); +GR_SWIG_BLOCK_MAGIC2(blocks, file_descriptor_sink); +GR_SWIG_BLOCK_MAGIC2(blocks, file_descriptor_source); +GR_SWIG_BLOCK_MAGIC2(blocks, file_sink); GR_SWIG_BLOCK_MAGIC2(blocks, file_source); GR_SWIG_BLOCK_MAGIC2(blocks, file_meta_sink); GR_SWIG_BLOCK_MAGIC2(blocks, file_meta_source); |