diff options
author | Johnathan Corgan <johnathan@corganlabs.com> | 2013-03-26 20:18:53 -0700 |
---|---|---|
committer | Johnathan Corgan <johnathan@corganlabs.com> | 2013-03-26 20:18:53 -0700 |
commit | 26dceecc80390f10cedb94bd9e4fd655827d7f17 (patch) | |
tree | f88cb2995133048b4a2191bae688fa09b33a19ae /gnuradio-runtime/lib | |
parent | 9bbbda510c265b211b5b571db79ba259c67ee049 (diff) |
runtime: migrate remaining gnuradio-core contents into gnuradio-runtime
Diffstat (limited to 'gnuradio-runtime/lib')
122 files changed, 16094 insertions, 0 deletions
diff --git a/gnuradio-runtime/lib/CMakeLists.txt b/gnuradio-runtime/lib/CMakeLists.txt new file mode 100644 index 0000000000..b8ece6e772 --- /dev/null +++ b/gnuradio-runtime/lib/CMakeLists.txt @@ -0,0 +1,256 @@ +# 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. + +include(GrMiscUtils) +GR_CHECK_HDR_N_DEF(sys/resource.h HAVE_SYS_RESOURCE_H) + +######################################################################## +# Handle the generated constants +######################################################################## +execute_process(COMMAND ${PYTHON_EXECUTABLE} -c + "import time;print time.strftime('%a, %d %b %Y %H:%M:%S', time.gmtime())" + OUTPUT_VARIABLE BUILD_DATE OUTPUT_STRIP_TRAILING_WHITESPACE +) +message(STATUS "Loading build date ${BUILD_DATE} into gr_constants...") +message(STATUS "Loading version ${VERSION} into gr_constants...") + +#double escape for windows backslash path separators +string(REPLACE "\\" "\\\\" prefix ${prefix}) +string(REPLACE "\\" "\\\\" SYSCONFDIR ${SYSCONFDIR}) +string(REPLACE "\\" "\\\\" GR_PREFSDIR ${GR_PREFSDIR}) + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/gr_constants.cc.in + ${CMAKE_CURRENT_BINARY_DIR}/gr_constants.cc +@ONLY) + +list(APPEND gnuradio_runtime_sources ${CMAKE_CURRENT_BINARY_DIR}/gr_constants.cc) + +######################################################################## +# Include subdirs rather to populate to the sources lists. +######################################################################## +#GR_INCLUDE_SUBDIRECTORY(foo) + +######################################################################## +# Setup the include and linker paths +######################################################################## +include_directories(${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/../include/ + ${Boost_INCLUDE_DIRS} + ${GRUEL_INCLUDE_DIRS} + ${VOLK_INCLUDE_DIRS} +) + +######################################################################## +# Setup library +######################################################################## +list(APPEND gnuradio_runtime_sources + complex_vec_test.cc + gr_basic_block.cc + gr_block.cc + gr_block_detail.cc + gr_block_executor.cc + gr_block_gateway.cc + gr_block_registry.cc + gr_buffer.cc + gr_circular_file.cc + gr_dispatcher.cc + gr_error_handler.cc + gr_fast_atan2f.cc + gr_feval.cc + gr_flat_flowgraph.cc + gr_flowgraph.cc + gr_fxpt.cc + gr_hier_block2.cc + gr_hier_block2_detail.cc + gri_debugger_hook.cc + gr_io_signature.cc + gr_local_sighandler.cc + gr_logger.cc + gr_message.cc + gr_misc.cc + gr_msg_accepter.cc + gr_msg_handler.cc + gr_msg_queue.cc + gr_pagesize.cc + gr_preferences.cc + gr_prefs.cc + gr_random.cc + gr_realtime.cc + gr_reverse.cc + gr_scheduler.cc + gr_scheduler_sts.cc + gr_scheduler_tpb.cc + gr_select_handler.cc + gr_sincos.c + gr_single_threaded_scheduler.cc + gr_sptr_magic.cc + gr_sync_block.cc + gr_sync_decimator.cc + gr_sync_interpolator.cc + gr_sys_paths.cc + gr_tagged_stream_block.cc + gr_test.cc + gr_top_block.cc + gr_top_block_impl.cc + gr_tpb_detail.cc + gr_tpb_thread_body.cc + gr_vmcircbuf.cc + gr_vmcircbuf_createfilemapping.cc + gr_vmcircbuf_mmap_shm_open.cc + gr_vmcircbuf_mmap_tmpfile.cc + gr_vmcircbuf_sysv_shm.cc + malloc16.c +) + +# PowerPC workaround for posix_memalign +# Might not be needed, but we'll keep it for now. +if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)") + list(APPEND gnuradio_core_sources + ${CMAKE_CURRENT_SOURCE_DIR}/posix_memalign.cc + ) +endif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)") + +list(APPEND gnuradio_runtime_libs + gruel + volk + ${Boost_LIBRARIES} +) + +#need to link with librt on ubuntu 11.10 for shm_* +if(LINUX) + list(APPEND gnuradio_runtime_libs rt) +endif() + +if(ENABLE_GR_CTRLPORT) + +# Add definition so we can compile in ControlPort to the blocks. +ADD_DEFINITIONS(-DGR_CTRLPORT) + +######################################################################## +# Run ICE To compile Slice files +######################################################################## +EXECUTE_PROCESS( + COMMAND "${ICE_SLICE2CPP}" "-I${CMAKE_CURRENT_SOURCE_DIR}" + "--output-dir=${CMAKE_CURRENT_BINARY_DIR}" + "${CMAKE_CURRENT_SOURCE_DIR}/gnuradio.ice" + ) + +list(APPEND gnuradio_runtime_sources + ice_application_base.cc + rpcmanager.cc + rpcpmtconverters_ice.cc + rpcserver_aggregator.cc + rpcserver_booter_aggregator.cc + rpcserver_booter_ice.cc + rpcserver_ice.cc + rpcserver_selector.cc + rpcpmtconverters_ice.cc +) + +# Append generated file in build directory +list(APPEND gnuradio_runtime_sources + ${CMAKE_CURRENT_BINARY_DIR}/gnuradio.cpp +) + +######################################################################## +# Add controlport stuff to gnuradio-runtime +######################################################################## + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +list(APPEND gnuradio_runtime_libs + ${ICE_LIBRARIES} +) + +endif(ENABLE_GR_CTRLPORT) + +######################################################################## +# Control availability of vmcircbuf methods. +# For now, only allows disabling of shm methods, which cause uncatchable +# segmentation faults on Cygwin with gcc 4.x (x <= 5) +# Usage: +# GR_VMCIRCBUF() +# +# Will set TRY_SHM_VMCIRCBUF to 1 by default except on Windows machines. +# Can manually set with -DTRY_SHM_VMCIRCBUF=0|1 +######################################################################## + +if(WIN32) + OPTION(TRY_SHM_VMCIRCBUF "Try SHM VMCIRCBUF" OFF) +else(WIN32) + OPTION(TRY_SHM_VMCIRCBUF "Try SHM VMCIRCBUF" ON) +endif(WIN32) + +message(STATUS "TRY_SHM_VMCIRCBUF set to ${TRY_SHM_VMCIRCBUF}.") + +if(TRY_SHM_VMCIRCBUF) + add_definitions( -DTRY_SHM_VMCIRCBUF ) +endif(TRY_SHM_VMCIRCBUF) + +add_library(gnuradio-runtime SHARED ${gnuradio_runtime_sources}) +target_link_libraries(gnuradio-runtime ${gnuradio_runtime_libs}) +GR_LIBRARY_FOO(gnuradio-runtime RUNTIME_COMPONENT "runtime" DEVEL_COMPONENT "runtime_devel") +set_target_properties(gnuradio-runtime PROPERTIES LINK_INTERFACE_LIBRARIES "gruel") + +add_dependencies(gnuradio-runtime + runtime_generated_includes +) + +######################################################################## +# Setup tests +######################################################################## +if(ENABLE_TESTING) +include(GrTest) + +######################################################################## +# Append gnuradio-runtime test sources +######################################################################## +list(APPEND test_gnuradio_runtime_sources + qa_gr_buffer.cc + qa_gr_circular_file.cc + qa_gr_fxpt.cc + qa_gr_fxpt_nco.cc + qa_gr_fxpt_vco.cc + qa_gr_io_signature.cc + qa_gr_logger.cc + qa_gr_math.cc + qa_gr_vmcircbuf.cc + qa_runtime.cc + qa_sincos.cc +) + +include_directories(${CPPUNIT_INCLUDE_DIRS}) +link_directories(${CPPUNIT_LIBRARY_DIRS}) + +add_library(test-gnuradio-runtime SHARED ${test_gnuradio_runtime_sources}) +target_link_libraries(test-gnuradio-runtime gnuradio-runtime ${CPPUNIT_LIBRARIES} ${Boost_LIBRARIES}) + +######################################################################## +# Build the test executable +# Set the test environment so the build libs will be found under MSVC. +######################################################################## +list(APPEND GR_TEST_TARGET_DEPS test-gnuradio-runtime) +add_executable(gr_runtime_test test_runtime.cc) +target_link_libraries(gr_runtime_test test-gnuradio-runtime) +GR_ADD_TEST(gr-runtime-test gr_runtime_test) + +endif(ENABLE_TESTING) + diff --git a/gnuradio-runtime/lib/ICE_LICENSE b/gnuradio-runtime/lib/ICE_LICENSE new file mode 100644 index 0000000000..43ea7572d9 --- /dev/null +++ b/gnuradio-runtime/lib/ICE_LICENSE @@ -0,0 +1,54 @@ +Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved. + +This copy of Ice is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +Ice 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 version +2 along with this program; if not, see http://www.gnu.org/licenses. + +Linking Ice statically or dynamically with other software (such as a +library, module or application) is making a combined work based on Ice. +Thus, the terms and conditions of the GNU General Public License version +2 cover this combined work. + +If such software can only be used together with Ice, then not only the +combined work but the software itself is a work derived from Ice and as +such shall be licensed under the terms of the GNU General Public License +version 2. This includes the situation where Ice is only being used +through an abstraction layer. + +As a special exception to the above, ZeroC grants to the contributors for +the following projects the permission to license their Ice-based software +under the terms of the GNU Lesser General Public License (LGPL) version +2.1 or of the BSD license: + + - Orca Robotics (http://orca-robotics.sourceforge.net) + + - Mumble (http://mumble.sourceforge.net) + +This exception does not extend to the parts of Ice used by these +projects, or to any other derived work: as a whole, any work based on Ice +shall be licensed under the terms and conditions of the GNU General +Public License version 2. + +You may also combine Ice with any software not derived from Ice, provided +the license of such software is compatible with the GNU General Public +License version 2. In addition, as a special exception, ZeroC grants you +permission to combine Ice with: + + - the OpenSSL library, or with a modified version of the OpenSSL library + that uses the same license as OpenSSL + + - any library not derived from Ice and licensed under the terms of + the Apache License, version 2.0 + (http://www.apache.org/licenses/LICENSE-2.0.html) + +If you modify this copy of Ice, you may extend any of the exceptions +provided above to your version of Ice, but you are not obligated to +do so. diff --git a/gnuradio-runtime/lib/complex_vec_test.cc b/gnuradio-runtime/lib/complex_vec_test.cc new file mode 100644 index 0000000000..99acc2f355 --- /dev/null +++ b/gnuradio-runtime/lib/complex_vec_test.cc @@ -0,0 +1,82 @@ +#include <complex_vec_test.h> +#include <stddef.h> + +std::vector<std::complex<float> > +complex_vec_test0() +{ + std::vector<std::complex<float> > r(5); + + for (size_t i = 0; i < r.size(); i++) + r[i] = std::complex<float>(i, i); + + return r; +} + +std::vector<std::complex<float> > +complex_vec_test1(const std::vector<std::complex<float> > &input) +{ + std::vector<std::complex<float> > r(input.size()); + + for (size_t i = 0; i < input.size(); i++) + r[i] = std::complex<float>(input[i].real()+0.5, input[i].imag()-0.5); + + return r; +} + +std::complex<float> +complex_scalar_test0() +{ + return std::complex<float>(5, 5); +} + +std::complex<float> +complex_scalar_test1(std::complex<float> input) +{ + return std::complex<float>(input.real()+0.5, input.imag()-0.5); +} + + +std::vector<float> +float_vec_test0() +{ + std::vector<float> r(5); + + for (size_t i = 0; i < r.size(); i++) + r[i] = (float) i; + + return r; +} + +std::vector<float> +float_vec_test1(const std::vector<float> &input) +{ + std::vector<float> r(input.size()); + + for (size_t i = 0; i < input.size(); i++) + r[i] = input[i] + 0.5; + + return r; +} + +std::vector<int> +int_vec_test0() +{ + std::vector<int> r(5); + + for (size_t i = 0; i < r.size(); i++) + r[i] = (int) i; + + return r; +} + +std::vector<int> +int_vec_test1(const std::vector<int> &input) +{ + std::vector<int> r(input.size()); + + for (size_t i = 0; i < input.size(); i++) + r[i] = input[i] + 1; + + return r; +} + diff --git a/gnuradio-runtime/lib/complex_vec_test.h b/gnuradio-runtime/lib/complex_vec_test.h new file mode 100644 index 0000000000..bcfa732f41 --- /dev/null +++ b/gnuradio-runtime/lib/complex_vec_test.h @@ -0,0 +1,28 @@ +#include <gr_runtime_api.h> +#include <vector> +#include <complex> + +GR_RUNTIME_API std::vector<std::complex<float> > +complex_vec_test0(); + +GR_RUNTIME_API std::vector<std::complex<float> > +complex_vec_test1(const std::vector<std::complex<float> > &input); + +GR_RUNTIME_API std::complex<float> +complex_scalar_test0(); + +GR_RUNTIME_API std::complex<float> +complex_scalar_test1(std::complex<float> input); + +GR_RUNTIME_API std::vector<int> +int_vec_test0(); + +GR_RUNTIME_API std::vector<int> +int_vec_test1(const std::vector<int> &input); + +GR_RUNTIME_API std::vector<float> +float_vec_test0(); + +GR_RUNTIME_API std::vector<float> +float_vec_test1(const std::vector<float> &input); + diff --git a/gnuradio-runtime/lib/frontend.ice b/gnuradio-runtime/lib/frontend.ice new file mode 100644 index 0000000000..befb5b7a97 --- /dev/null +++ b/gnuradio-runtime/lib/frontend.ice @@ -0,0 +1,102 @@ +/* + * Copyright 2012 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.ice> + +[["python:package:gnuradio.ctrlport"]] +module GNURadio { + module Frontend { + + exception NotSupported {}; + exception InvalidSetting { string msg; }; + exception ReceiverFailure { string msg; }; + exception NotExist {}; + dictionary<string, string> TunerArgs; + + struct TunerStatus { + int a2dbits; + float gain; + bool isInverted; + }; + + interface Tuner { + TunerStatus configureTuner(TunerArgs args); //ADDED + idempotent TunerStatus status(); + idempotent float setGain(float gain) throws NotSupported, InvalidSetting; + idempotent bool setInversion(bool inverted) throws NotSupported, InvalidSetting; + }; + + struct ChannelStatus { + string uid; + bool active; + float freq; + float bandwidth; + int payloadBits; + bool isComplex; + string signalName; + }; + + interface Channel extends Component { + idempotent ChannelStatus status(); + idempotent FeedInfo feed(); + idempotent bool active(); + void start(); + void stop(); + idempotent float setCenterFreq(float freq) throws NotSupported, InvalidSetting; + idempotent float setBandwidth(float bw) throws NotSupported, InvalidSetting; + idempotent int setPayloadBits(int bits) throws NotSupported, InvalidSetting; + idempotent bool setComplex(bool complex) throws NotSupported, InvalidSetting; + void removeChannel() throws NotSupported; + }; + + sequence<Tuner*> TunerSeq; + sequence<Channel*> ChannelSeq; + + struct ChannelizerStatus { + string uid; + string signalName; + }; + + interface Channelizer extends Component { + idempotent ChannelizerStatus status(); + idempotent Tuner* getTuner(); + idempotent ChannelSeq getChannels(); + idempotent ChannelSeq getActiveChannels(); + idempotent ChannelSeq getInactiveChannels(); + Channel* createChannel(float freq, float bw, int payloadBits, string address, int port) throws NotSupported; + }; + + sequence<Channelizer*> ChannelizerSeq; + + interface Receiver extends AbstractReceiver { + idempotent ChannelizerSeq getInputs(); +// idempotent ChannelizerSeq getActiveInputs(); +// idempotent ChannelizerSeq getInactiveInputs(); + idempotent Channel* getChannelByID(string id) throws NotExist; + idempotent Channelizer* getChannelizerByID(string id) throws NotExist; + }; + + + }; + + + +}; diff --git a/gnuradio-runtime/lib/gen_sine_table.py b/gnuradio-runtime/lib/gen_sine_table.py new file mode 100755 index 0000000000..d7d11eff11 --- /dev/null +++ b/gnuradio-runtime/lib/gen_sine_table.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +# +# Copyright 2004 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. +# + +import math +import sys + +def wrap (x): + if x >= 2**31: + return x - 2**32 + return x + +def gen_approx_table (f, nentries, min_x, max_x): + """return a list of nentries containing tuples of the form: + (m, c, abs_error). min_x and max_x specify the domain + of the table. + """ + r = [] + incx = float (max_x - min_x) / nentries + for i in range (nentries): + a = (i * incx) + min_x + b = ((i + 1) * incx) + min_x + m = (f(b)-f(a))/(b-a) + c = (3*a+b)*(f(a)-f(b))/(4*(b-a)) + (f((a+b)/2) + f(a))/2 + abs_error = c+m*a-f(a) + r.append ((m, c, abs_error)) + return r + +def scaled_sine (x): + return math.sin (x * math.pi / 2**31) + +def gen_sine_table (): + nbits = 10 + nentries = 2**nbits + + # min_x = -2**31 + # max_x = 2**31-1 + min_x = 0 + max_x = 2**32-1 + t = gen_approx_table (scaled_sine, nentries, min_x, max_x) + + max_error = 0 + for e in t: + max_error = max (max_error, abs (e[2])) + + # sys.stdout.write ('static const int WORDBITS = 32;\n') + # sys.stdout.write ('static const int NBITS = %d;\n' % (nbits,)) + + sys.stdout.write (' // max_error = %22.15e\n' % (max_error,)) + + # sys.stdout.write ('static const double sine_table[%d][2] = {\n'% (nentries,)) + + for e in t: + sys.stdout.write (' { %22.15e, %22.15e },\n' % (2 * e[0], e[1])) + + # sys.stdout.write ('};\n') + +if __name__ == '__main__': + gen_sine_table () diff --git a/gnuradio-runtime/lib/gnuradio.ice b/gnuradio-runtime/lib/gnuradio.ice new file mode 100644 index 0000000000..e17d91901b --- /dev/null +++ b/gnuradio-runtime/lib/gnuradio.ice @@ -0,0 +1,154 @@ +/* + * Copyright 2012 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. + */ + +[["python:package:gnuradio.ctrlport"]] + +#ifndef GNURADIO_DEBUG +#define GNURADIO_DEBUG + +module GNURadio { +class Knob {}; +class KnobB extends Knob { bool value; }; +class KnobC extends Knob { byte value; }; +class KnobI extends Knob { int value; }; +class KnobF extends Knob { float value; }; +class KnobD extends Knob { double value; }; +class KnobL extends Knob { long value; }; +class KnobS extends Knob { string value; }; + +sequence<bool> VectorB; sequence<byte> VectorC; +sequence<int> VectorI; sequence<float> VectorF; +sequence<double> VectorD; sequence<string> VectorS; +sequence<long> VectorL; + +class KnobVecB extends Knob { VectorB value; }; +class KnobVecC extends Knob { VectorC value; }; +class KnobVecI extends Knob { VectorI value; }; +class KnobVecF extends Knob { VectorF value; }; +class KnobVecD extends Knob { VectorD value; }; +class KnobVecL extends Knob { VectorL value; }; +class KnobVecS extends Knob { VectorS value; }; + +enum KnobType { KNOBBOOL, KNOBCHAR, KNOBINT, KNOBFLOAT, + KNOBDOUBLE, KNOBSTRING, KNOBLONG, KNOBVECBOOL, + KNOBVECCHAR, KNOBVECINT, KNOBVECFLOAT, KNOBVECDOUBLE, + KNOBVECSTRING, KNOBVECLONG }; + +const int DISPNULL = 0x0000; +const int DISPTIME = 0x0001; +const int DISPXY = 0x0002; +const int DISPPSD = 0x0004; +const int DISPSPEC = 0x0008; +const int DISPRAST = 0x0010; +const int DISPOPTCPLX = 0x0100; +const int DISPOPTLOG = 0x0200; +const int DISPOPTSTEM = 0x0400; +const int DISPOPTSTRIP = 0x0800; +const int DISPOPTSCATTER = 0x1000; + +struct KnobProp { + KnobType type; + string units; + string description; + int display; + Knob min; + Knob max; + Knob defaultvalue; +}; + +sequence<string> KnobIDList; +dictionary<string, Knob> KnobMap; +dictionary<string, KnobProp> KnobPropMap; +dictionary<string, string> WaveformArgMap; + +interface StreamReceiver { + void push(VectorC data); +}; + +interface ControlPort { + void set(KnobMap knobs); + idempotent KnobMap get(KnobIDList knobs); + idempotent KnobPropMap properties(KnobIDList knobs); + void shutdown(); + +// string subscribe(StreamReceiver* proxy, string streamName, int requestedPeriod, int RequestedSize); +// idempotent void unsubscribe(string streamID); +}; + +struct FeedInfo { + string protocol; + string address; + string iface; + string port; +}; + +//TODO: convert this part to a Feed Info +struct ReceiverInfo { + string uid; + string signalType; + string signalName; + string allocatableObjectID; + string signalProtocol; + string signalAddress; + string signalInterface; + string signalPort; +}; + +interface Component { + void setName(string newName); +}; + +module Frontend { + interface AbstractReceiver extends Component { + idempotent ReceiverInfo getReceiverInfo(); + }; +}; + +module Booter { + dictionary<string, string> WaveformArgs; + + exception WaveformRunningError { + string waveformClass; + float centerFrequencyHz; + }; + exception SignalSourceError {string msg; }; + + interface WaveformBooter extends Frontend::AbstractReceiver { + string launchWaveform(string waveformClass, WaveformArgs args) + throws WaveformRunningError, SignalSourceError; + +// string launchWaveformWithSession(string waveformClass, WaveformArgs args, IceGrid::Session* session) +// throws WaveformRunningError; + WaveformArgMap getDriverEnum(); + WaveformArgMap getSourceInfo(); + idempotent bool waveformRunning(); + idempotent string getWaveformClass(); + void shutdown(); + }; +}; + +//interface Pingable { +// bool ping(); +//}; + +}; + +#endif diff --git a/gnuradio-runtime/lib/gr_basic_block.cc b/gnuradio-runtime/lib/gr_basic_block.cc new file mode 100644 index 0000000000..35ea797167 --- /dev/null +++ b/gnuradio-runtime/lib/gr_basic_block.cc @@ -0,0 +1,226 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2012 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 <gr_basic_block.h> +#include <gr_block_registry.h> +#include <stdexcept> +#include <sstream> +#include <iostream> + +static long s_next_id = 0; +static long s_ncurrently_allocated = 0; + +long +gr_basic_block_ncurrently_allocated() +{ + return s_ncurrently_allocated; +} + +gr_basic_block::gr_basic_block(const std::string &name, + gr_io_signature_sptr input_signature, + gr_io_signature_sptr output_signature) + : d_name(name), + d_input_signature(input_signature), + d_output_signature(output_signature), + d_unique_id(s_next_id++), + d_symbolic_id(global_block_registry.block_register(this)), + d_symbol_name(global_block_registry.register_symbolic_name(this)), + d_color(WHITE), + d_rpc_set(false), + message_subscribers(pmt::make_dict()) +{ + s_ncurrently_allocated++; +} + +gr_basic_block::~gr_basic_block() +{ + s_ncurrently_allocated--; + global_block_registry.block_unregister(this); +} + +gr_basic_block_sptr +gr_basic_block::to_basic_block() +{ + return shared_from_this(); +} + +void +gr_basic_block::set_block_alias(std::string name) +{ + global_block_registry.register_symbolic_name(this, name); +} + +// ** Message passing interface ** + +// - register a new input message port +void +gr_basic_block::message_port_register_in(pmt::pmt_t port_id) +{ + if(!pmt::is_symbol(port_id)) { + throw std::runtime_error("message_port_register_in: bad port id"); + } + msg_queue[port_id] = msg_queue_t(); + msg_queue_ready[port_id] = boost::shared_ptr<boost::condition_variable>(new boost::condition_variable()); +} + +pmt::pmt_t +gr_basic_block::message_ports_in() +{ + pmt::pmt_t port_names = pmt::make_vector(msg_queue.size(), pmt::PMT_NIL); + msg_queue_map_itr itr = msg_queue.begin(); + for(size_t i = 0; i < msg_queue.size(); i++) { + pmt::vector_set(port_names, i, (*itr).first); + itr++; + } + return port_names; +} + +// - register a new output message port +void +gr_basic_block::message_port_register_out(pmt::pmt_t port_id) +{ + if(!pmt::is_symbol(port_id)) { + throw std::runtime_error("message_port_register_out: bad port id"); + } + if(pmt::dict_has_key(message_subscribers, port_id)) { + throw std::runtime_error("message_port_register_out: port already in use"); + } + message_subscribers = pmt::dict_add(message_subscribers, port_id, pmt::PMT_NIL); +} + +pmt::pmt_t +gr_basic_block::message_ports_out() +{ + size_t len = pmt::length(message_subscribers); + pmt::pmt_t port_names = pmt::make_vector(len, pmt::PMT_NIL); + pmt::pmt_t keys = pmt::dict_keys(message_subscribers); + for(size_t i = 0; i < len; i++) { + pmt::vector_set(port_names, i, pmt::nth(i, keys)); + } + return port_names; +} + +// - publish a message on a message port +void gr_basic_block::message_port_pub(pmt::pmt_t port_id, pmt::pmt_t msg) +{ + if(!pmt::dict_has_key(message_subscribers, port_id)) { + throw std::runtime_error("port does not exist"); + } + + pmt::pmt_t currlist = pmt::dict_ref(message_subscribers, port_id, pmt::PMT_NIL); + // iterate through subscribers on port + while(pmt::is_pair(currlist)) { + pmt::pmt_t target = pmt::car(currlist); + + pmt::pmt_t block = pmt::car(target); + pmt::pmt_t port = pmt::cdr(target); + + currlist = pmt::cdr(currlist); + gr_basic_block_sptr blk = global_block_registry.block_lookup(block); + //blk->post(msg); + blk->post(port, msg); + } +} + +// - subscribe to a message port +void +gr_basic_block::message_port_sub(pmt::pmt_t port_id, pmt::pmt_t target){ + if(!pmt::dict_has_key(message_subscribers, port_id)){ + std::stringstream ss; + ss << "Port does not exist: \"" << pmt::write_string(port_id) << "\" on block: " << pmt::write_string(target) << std::endl; + throw std::runtime_error(ss.str()); + } + pmt::pmt_t currlist = pmt::dict_ref(message_subscribers,port_id,pmt::PMT_NIL); + + // ignore re-adds of the same target + if(!pmt::list_has(currlist, target)) + message_subscribers = pmt::dict_add(message_subscribers,port_id,pmt::list_add(currlist,target)); +} + +void +gr_basic_block::message_port_unsub(pmt::pmt_t port_id, pmt::pmt_t target){ + if(!pmt::dict_has_key(message_subscribers, port_id)){ + std::stringstream ss; + ss << "Port does not exist: \"" << pmt::write_string(port_id) << "\" on block: " << pmt::write_string(target) << std::endl; + throw std::runtime_error(ss.str()); + } + + // ignore unsubs of unknown targets + pmt::pmt_t currlist = pmt::dict_ref(message_subscribers,port_id,pmt::PMT_NIL); + message_subscribers = pmt::dict_add(message_subscribers,port_id,pmt::list_rm(currlist,target)); +} + +void +gr_basic_block::_post(pmt::pmt_t which_port, pmt::pmt_t msg) +{ + insert_tail(which_port, msg); +} + +void +gr_basic_block::insert_tail(pmt::pmt_t which_port, pmt::pmt_t msg) +{ + gruel::scoped_lock guard(mutex); + + if( (msg_queue.find(which_port) == msg_queue.end()) || (msg_queue_ready.find(which_port) == msg_queue_ready.end())){ + std::cout << "target port = " << pmt::symbol_to_string(which_port) << std::endl; + throw std::runtime_error("attempted to insert_tail on invalid queue!"); + } + + msg_queue[which_port].push_back(msg); + msg_queue_ready[which_port]->notify_one(); + + // wake up thread if BLKD_IN or BLKD_OUT + global_block_registry.notify_blk(alias()); +} + +pmt::pmt_t +gr_basic_block::delete_head_nowait(pmt::pmt_t which_port) +{ + gruel::scoped_lock guard(mutex); + + if (empty_p(which_port)){ + return pmt::pmt_t(); + } + + pmt::pmt_t m(msg_queue[which_port].front()); + msg_queue[which_port].pop_front(); + + return m; +} + +pmt::pmt_t +gr_basic_block::delete_head_blocking(pmt::pmt_t which_port) +{ + gruel::scoped_lock guard(mutex); + + while (empty_p(which_port)){ + msg_queue_ready[which_port]->wait(guard); + } + + pmt::pmt_t m(msg_queue[which_port].front()); + msg_queue[which_port].pop_front(); + return m; +} diff --git a/gnuradio-runtime/lib/gr_block.cc b/gnuradio-runtime/lib/gr_block.cc new file mode 100644 index 0000000000..8c8b85dc7e --- /dev/null +++ b/gnuradio-runtime/lib/gr_block.cc @@ -0,0 +1,687 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2009,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 <gr_block.h> +#include <gr_block_detail.h> +#include <stdexcept> +#include <iostream> +#include <gr_block_registry.h> +#include <gr_prefs.h> + +gr_block::gr_block (const std::string &name, + gr_io_signature_sptr input_signature, + gr_io_signature_sptr output_signature) + : gr_basic_block(name, input_signature, output_signature), + d_output_multiple (1), + d_output_multiple_set(false), + d_unaligned(0), + d_is_unaligned(false), + d_relative_rate (1.0), + d_history(1), + d_fixed_rate(false), + d_max_noutput_items_set(false), + d_max_noutput_items(0), + d_min_noutput_items(0), + d_tag_propagation_policy(TPP_ALL_TO_ALL), + d_pc_rpc_set(false), + d_max_output_buffer(std::max(output_signature->max_streams(),1), -1), + d_min_output_buffer(std::max(output_signature->max_streams(),1), -1) +{ + global_block_registry.register_primitive(alias(), this); + +#ifdef ENABLE_GR_LOG +#ifdef HAVE_LOG4CPP + gr_prefs *p = gr_prefs::singleton(); + std::string config_file = p->get_string("LOG", "log_config", ""); + std::string log_level = p->get_string("LOG", "log_level", "off"); + std::string log_file = p->get_string("LOG", "log_file", ""); + std::string debug_level = p->get_string("LOG", "debug_level", "off"); + std::string debug_file = p->get_string("LOG", "debug_file", ""); + + GR_CONFIG_LOGGER(config_file); + + GR_LOG_GETLOGGER(LOG, "gr_log." + alias()); + GR_LOG_SET_LEVEL(LOG, log_level); + if(log_file.size() > 0) { + if(log_file == "stdout") { + GR_LOG_ADD_CONSOLE_APPENDER(LOG, "cout","gr::log :%p: %c{1} - %m%n"); + } + else if(log_file == "stderr") { + GR_LOG_ADD_CONSOLE_APPENDER(LOG, "cerr","gr::log :%p: %c{1} - %m%n"); + } + else { + GR_LOG_ADD_FILE_APPENDER(LOG, log_file , true,"%r :%p: %c{1} - %m%n"); + } + } + d_logger = LOG; + + GR_LOG_GETLOGGER(DLOG, "gr_log_debug." + alias()); + GR_LOG_SET_LEVEL(DLOG, debug_level); + if(debug_file.size() > 0) { + if(debug_file == "stdout") { + GR_LOG_ADD_CONSOLE_APPENDER(DLOG, "cout","gr::debug :%p: %c{1} - %m%n"); + } + else if(debug_file == "stderr") { + GR_LOG_ADD_CONSOLE_APPENDER(DLOG, "cerr", "gr::debug :%p: %c{1} - %m%n"); + } + else { + GR_LOG_ADD_FILE_APPENDER(DLOG, debug_file, true, "%r :%p: %c{1} - %m%n"); + } + } + d_debug_logger = DLOG; +#endif /* HAVE_LOG4CPP */ +#else /* ENABLE_GR_LOG */ + d_logger = NULL; + d_debug_logger = NULL; +#endif /* ENABLE_GR_LOG */ +} + +gr_block::~gr_block () +{ + global_block_registry.unregister_primitive(alias()); +} + +// stub implementation: 1:1 + +void +gr_block::forecast (int noutput_items, gr_vector_int &ninput_items_required) +{ + unsigned ninputs = ninput_items_required.size (); + for (unsigned i = 0; i < ninputs; i++) + ninput_items_required[i] = noutput_items + history() - 1; +} + +// default implementation + +bool +gr_block::start() +{ + return true; +} + +bool +gr_block::stop() +{ + return true; +} + +void +gr_block::set_output_multiple (int multiple) +{ + if (multiple < 1) + throw std::invalid_argument ("gr_block::set_output_multiple"); + + d_output_multiple_set = true; + d_output_multiple = multiple; +} + +void +gr_block::set_alignment (int multiple) +{ + if (multiple < 1) + throw std::invalid_argument ("gr_block::set_alignment_multiple"); + + d_output_multiple = multiple; +} + +void +gr_block::set_unaligned (int na) +{ + // unaligned value must be less than 0 and it doesn't make sense + // that it's larger than the alignment value. + if ((na < 0) || (na > d_output_multiple)) + throw std::invalid_argument ("gr_block::set_unaligned"); + + d_unaligned = na; +} + +void +gr_block::set_is_unaligned (bool u) +{ + d_is_unaligned = u; +} + +void +gr_block::set_relative_rate (double relative_rate) +{ + if (relative_rate < 0.0) + throw std::invalid_argument ("gr_block::set_relative_rate"); + + d_relative_rate = relative_rate; +} + + +void +gr_block::consume (int which_input, int how_many_items) +{ + d_detail->consume (which_input, how_many_items); +} + +void +gr_block::consume_each (int how_many_items) +{ + d_detail->consume_each (how_many_items); +} + +void +gr_block::produce (int which_output, int how_many_items) +{ + d_detail->produce (which_output, how_many_items); +} + +int +gr_block::fixed_rate_ninput_to_noutput(int ninput) +{ + throw std::runtime_error("Unimplemented"); +} + +int +gr_block::fixed_rate_noutput_to_ninput(int noutput) +{ + throw std::runtime_error("Unimplemented"); +} + +uint64_t +gr_block::nitems_read(unsigned int which_input) +{ + if(d_detail) { + return d_detail->nitems_read(which_input); + } + else { + //throw std::runtime_error("No block_detail associated with block yet"); + return 0; + } +} + +uint64_t +gr_block::nitems_written(unsigned int which_output) +{ + if(d_detail) { + return d_detail->nitems_written(which_output); + } + else { + //throw std::runtime_error("No block_detail associated with block yet"); + return 0; + } +} + +void +gr_block::add_item_tag(unsigned int which_output, + const gr_tag_t &tag) +{ + d_detail->add_item_tag(which_output, tag); +} + +void +gr_block::remove_item_tag(unsigned int which_input, + const gr_tag_t &tag) +{ + d_detail->remove_item_tag(which_input, tag); +} + +void +gr_block::get_tags_in_range(std::vector<gr_tag_t> &v, + unsigned int which_output, + uint64_t start, uint64_t end) +{ + d_detail->get_tags_in_range(v, which_output, start, end); +} + +void +gr_block::get_tags_in_range(std::vector<gr_tag_t> &v, + unsigned int which_output, + uint64_t start, uint64_t end, + const pmt::pmt_t &key) +{ + d_detail->get_tags_in_range(v, which_output, start, end, key); +} + +gr_block::tag_propagation_policy_t +gr_block::tag_propagation_policy() +{ + return d_tag_propagation_policy; +} + +void +gr_block::set_tag_propagation_policy(tag_propagation_policy_t p) +{ + d_tag_propagation_policy = p; +} + + +int +gr_block::max_noutput_items() +{ + return d_max_noutput_items; +} + +void +gr_block::set_max_noutput_items(int m) +{ + if(m <= 0) + throw std::runtime_error("gr_block::set_max_noutput_items: value for max_noutput_items must be greater than 0.\n"); + + d_max_noutput_items = m; + d_max_noutput_items_set = true; +} + +void +gr_block::unset_max_noutput_items() +{ + d_max_noutput_items_set = false; +} + +bool +gr_block::is_set_max_noutput_items() +{ + return d_max_noutput_items_set; +} + +void +gr_block::set_processor_affinity(const std::vector<unsigned int> &mask) +{ + d_affinity = mask; + if(d_detail) { + d_detail->set_processor_affinity(d_affinity); + } +} + +void +gr_block::unset_processor_affinity() +{ + d_affinity.clear(); + if(d_detail) { + d_detail->unset_processor_affinity(); + } +} + +float +gr_block::pc_noutput_items() +{ + if(d_detail) { + return d_detail->pc_noutput_items(); + } + else { + return 0; + } +} + +float +gr_block::pc_noutput_items_avg() +{ + if(d_detail) { + return d_detail->pc_noutput_items_avg(); + } + else { + return 0; + } +} + +float +gr_block::pc_noutput_items_var() +{ + if(d_detail) { + return d_detail->pc_noutput_items_var(); + } + else { + return 0; + } +} + +float +gr_block::pc_nproduced() +{ + if(d_detail) { + return d_detail->pc_nproduced(); + } + else { + return 0; + } +} + +float +gr_block::pc_nproduced_avg() +{ + if(d_detail) { + return d_detail->pc_nproduced_avg(); + } + else { + return 0; + } +} + +float +gr_block::pc_nproduced_var() +{ + if(d_detail) { + return d_detail->pc_nproduced_var(); + } + else { + return 0; + } +} + +float +gr_block::pc_input_buffers_full(int which) +{ + if(d_detail) { + return d_detail->pc_input_buffers_full(static_cast<size_t>(which)); + } + else { + return 0; + } +} + +float +gr_block::pc_input_buffers_full_avg(int which) +{ + if(d_detail) { + return d_detail->pc_input_buffers_full_avg(static_cast<size_t>(which)); + } + else { + return 0; + } +} + +float +gr_block::pc_input_buffers_full_var(int which) +{ + if(d_detail) { + return d_detail->pc_input_buffers_full_var(static_cast<size_t>(which)); + } + else { + return 0; + } +} + +std::vector<float> +gr_block::pc_input_buffers_full() +{ + if(d_detail) { + return d_detail->pc_input_buffers_full(); + } + else { + return std::vector<float>(1,0); + } +} + +std::vector<float> +gr_block::pc_input_buffers_full_avg() +{ + if(d_detail) { + return d_detail->pc_input_buffers_full_avg(); + } + else { + return std::vector<float>(1,0); + } +} + +std::vector<float> +gr_block::pc_input_buffers_full_var() +{ + if(d_detail) { + return d_detail->pc_input_buffers_full_var(); + } + else { + return std::vector<float>(1,0); + } +} + +float +gr_block::pc_output_buffers_full(int which) +{ + if(d_detail) { + return d_detail->pc_output_buffers_full(static_cast<size_t>(which)); + } + else { + return 0; + } +} + +float +gr_block::pc_output_buffers_full_avg(int which) +{ + if(d_detail) { + return d_detail->pc_output_buffers_full_avg(static_cast<size_t>(which)); + } + else { + return 0; + } +} + +float +gr_block::pc_output_buffers_full_var(int which) +{ + if(d_detail) { + return d_detail->pc_output_buffers_full_var(static_cast<size_t>(which)); + } + else { + return 0; + } +} + +std::vector<float> +gr_block::pc_output_buffers_full() +{ + if(d_detail) { + return d_detail->pc_output_buffers_full(); + } + else { + return std::vector<float>(1,0); + } +} + +std::vector<float> +gr_block::pc_output_buffers_full_avg() +{ + if(d_detail) { + return d_detail->pc_output_buffers_full_avg(); + } + else { + return std::vector<float>(1,0); + } +} + +std::vector<float> +gr_block::pc_output_buffers_full_var() +{ + if(d_detail) { + return d_detail->pc_output_buffers_full_var(); + } + else { + return std::vector<float>(1,0); + } +} + +float +gr_block::pc_work_time() +{ + if(d_detail) { + return d_detail->pc_work_time(); + } + else { + return 0; + } +} + +float +gr_block::pc_work_time_avg() +{ + if(d_detail) { + return d_detail->pc_work_time_avg(); + } + else { + return 0; + } +} + +float +gr_block::pc_work_time_var() +{ + if(d_detail) { + return d_detail->pc_work_time_var(); + } + else { + return 0; + } +} + +void +gr_block::reset_perf_counters() +{ + if(d_detail) { + d_detail->reset_perf_counters(); + } +} + +void +gr_block::setup_pc_rpc() +{ + d_pc_rpc_set = true; +#ifdef GR_CTRLPORT + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( + alias(), "noutput_items", &gr_block::pc_noutput_items, + pmt::mp(0), pmt::mp(32768), pmt::mp(0), + "", "noutput items", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( + alias(), "avg noutput_items", &gr_block::pc_noutput_items_avg, + pmt::mp(0), pmt::mp(32768), pmt::mp(0), + "", "Average noutput items", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( + alias(), "var noutput_items", &gr_block::pc_noutput_items_var, + pmt::mp(0), pmt::mp(32768), pmt::mp(0), + "", "Var. noutput items", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( + alias(), "nproduced", &gr_block::pc_nproduced, + pmt::mp(0), pmt::mp(32768), pmt::mp(0), + "", "items produced", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( + alias(), "avg nproduced", &gr_block::pc_nproduced_avg, + pmt::mp(0), pmt::mp(32768), pmt::mp(0), + "", "Average items produced", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( + alias(), "var nproduced", &gr_block::pc_nproduced_var, + pmt::mp(0), pmt::mp(32768), pmt::mp(0), + "", "Var. items produced", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( + alias(), "work time", &gr_block::pc_work_time, + pmt::mp(0), pmt::mp(1e9), pmt::mp(0), + "", "clock cycles in call to work", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( + alias(), "avg work time", &gr_block::pc_work_time_avg, + pmt::mp(0), pmt::mp(1e9), pmt::mp(0), + "", "Average clock cycles in call to work", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( + alias(), "var work time", &gr_block::pc_work_time_var, + pmt::mp(0), pmt::mp(1e9), pmt::mp(0), + "", "Var. clock cycles in call to work", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, std::vector<float> >( + alias(), "input \% full", &gr_block::pc_input_buffers_full, + pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + "", "how full input buffers are", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, std::vector<float> >( + alias(), "avg input \% full", &gr_block::pc_input_buffers_full_avg, + pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + "", "Average of how full input buffers are", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, std::vector<float> >( + alias(), "var input \% full", &gr_block::pc_input_buffers_full_var, + pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + "", "Var. of how full input buffers are", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, std::vector<float> >( + alias(), "output \% full", &gr_block::pc_output_buffers_full, + pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + "", "how full output buffers are", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, std::vector<float> >( + alias(), "avg output \% full", &gr_block::pc_output_buffers_full_avg, + pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + "", "Average of how full output buffers are", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<gr_block, std::vector<float> >( + alias(), "var output \% full", &gr_block::pc_output_buffers_full_var, + pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + "", "Var. of how full output buffers are", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); +#endif /* GR_CTRLPORT */ +} + +std::ostream& +operator << (std::ostream& os, const gr_block *m) +{ + os << "<gr_block " << m->name() << " (" << m->unique_id() << ")>"; + return os; +} + +int +gr_block::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + throw std::runtime_error("gr_block::general_work() not implemented"); + return 0; +} diff --git a/gnuradio-runtime/lib/gr_block_detail.cc b/gnuradio-runtime/lib/gr_block_detail.cc new file mode 100644 index 0000000000..c85c0e9fba --- /dev/null +++ b/gnuradio-runtime/lib/gr_block_detail.cc @@ -0,0 +1,473 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2009,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 <gr_block_detail.h> +#include <gr_buffer.h> +#include <iostream> + +static long s_ncurrently_allocated = 0; + +long +gr_block_detail_ncurrently_allocated () +{ + return s_ncurrently_allocated; +} + +gr_block_detail::gr_block_detail (unsigned int ninputs, unsigned int noutputs) + : d_produce_or(0), + d_ninputs (ninputs), d_noutputs (noutputs), + d_input (ninputs), d_output (noutputs), + d_done (false), + d_ins_noutput_items(0), + d_avg_noutput_items(0), + d_var_noutput_items(0), + d_ins_nproduced(0), + d_avg_nproduced(0), + d_var_nproduced(0), + d_ins_input_buffers_full(ninputs, 0), + d_avg_input_buffers_full(ninputs, 0), + d_var_input_buffers_full(ninputs, 0), + d_ins_output_buffers_full(noutputs, 0), + d_avg_output_buffers_full(noutputs, 0), + d_var_output_buffers_full(noutputs, 0), + d_ins_work_time(0), + d_avg_work_time(0), + d_var_work_time(0), + d_pc_counter(0) +{ + s_ncurrently_allocated++; +} + +gr_block_detail::~gr_block_detail () +{ + // should take care of itself + s_ncurrently_allocated--; +} + +void +gr_block_detail::set_input (unsigned int which, gr_buffer_reader_sptr reader) +{ + if (which >= d_ninputs) + throw std::invalid_argument ("gr_block_detail::set_input"); + + d_input[which] = reader; +} + +void +gr_block_detail::set_output (unsigned int which, gr_buffer_sptr buffer) +{ + if (which >= d_noutputs) + throw std::invalid_argument ("gr_block_detail::set_output"); + + d_output[which] = buffer; +} + +gr_block_detail_sptr +gr_make_block_detail (unsigned int ninputs, unsigned int noutputs) +{ + return gr_block_detail_sptr (new gr_block_detail (ninputs, noutputs)); +} + +void +gr_block_detail::set_done (bool done) +{ + d_done = done; + for (unsigned int i = 0; i < d_noutputs; i++) + d_output[i]->set_done (done); + + for (unsigned int i = 0; i < d_ninputs; i++) + d_input[i]->set_done (done); +} + +void +gr_block_detail::consume (int which_input, int how_many_items) +{ + if (how_many_items > 0) { + input (which_input)->update_read_pointer (how_many_items); + } +} + + +void +gr_block_detail::consume_each (int how_many_items) +{ + if (how_many_items > 0) { + for (int i = 0; i < ninputs (); i++) { + d_input[i]->update_read_pointer (how_many_items); + } + } +} + +void +gr_block_detail::produce (int which_output, int how_many_items) +{ + if (how_many_items > 0){ + d_output[which_output]->update_write_pointer (how_many_items); + d_produce_or |= how_many_items; + } +} + +void +gr_block_detail::produce_each (int how_many_items) +{ + if (how_many_items > 0) { + for (int i = 0; i < noutputs (); i++) { + d_output[i]->update_write_pointer (how_many_items); + } + d_produce_or |= how_many_items; + } +} + + +uint64_t +gr_block_detail::nitems_read(unsigned int which_input) +{ + if(which_input >= d_ninputs) + throw std::invalid_argument ("gr_block_detail::n_input_items"); + return d_input[which_input]->nitems_read(); +} + +uint64_t +gr_block_detail::nitems_written(unsigned int which_output) +{ + if(which_output >= d_noutputs) + throw std::invalid_argument ("gr_block_detail::n_output_items"); + return d_output[which_output]->nitems_written(); +} + +void +gr_block_detail::add_item_tag(unsigned int which_output, const gr_tag_t &tag) +{ + if(!pmt::is_symbol(tag.key)) { + throw pmt::wrong_type("gr_block_detail::add_item_tag key", tag.key); + } + else { + // Add tag to gr_buffer's deque tags + d_output[which_output]->add_item_tag(tag); + } +} + +void +gr_block_detail::remove_item_tag(unsigned int which_input, const gr_tag_t &tag) +{ + if(!pmt::is_symbol(tag.key)) { + throw pmt::wrong_type("gr_block_detail::add_item_tag key", tag.key); + } + else { + // Add tag to gr_buffer's deque tags + d_input[which_input]->buffer()->remove_item_tag(tag); + } +} + +void +gr_block_detail::get_tags_in_range(std::vector<gr_tag_t> &v, + unsigned int which_input, + uint64_t abs_start, + uint64_t abs_end) +{ + // get from gr_buffer_reader's deque of tags + d_input[which_input]->get_tags_in_range(v, abs_start, abs_end); +} + +void +gr_block_detail::get_tags_in_range(std::vector<gr_tag_t> &v, + unsigned int which_input, + uint64_t abs_start, + uint64_t abs_end, + const pmt::pmt_t &key) +{ + std::vector<gr_tag_t> found_items; + + v.resize(0); + + // get from gr_buffer_reader's deque of tags + d_input[which_input]->get_tags_in_range(found_items, abs_start, abs_end); + + // Filter further by key name + pmt::pmt_t itemkey; + std::vector<gr_tag_t>::iterator itr; + for(itr = found_items.begin(); itr != found_items.end(); itr++) { + itemkey = (*itr).key; + if(pmt::eqv(key, itemkey)) { + v.push_back(*itr); + } + } +} + +void +gr_block_detail::set_processor_affinity(const std::vector<unsigned int> &mask) +{ + if(threaded) { + try { + gruel::thread_bind_to_processor(thread, mask); + } + catch (std::runtime_error e) { + std::cerr << "set_processor_affinity: invalid mask." << std::endl;; + } + } +} + +void +gr_block_detail::unset_processor_affinity() +{ + if(threaded) { + gruel::thread_unbind(thread); + } +} + +void +gr_block_detail::start_perf_counters() +{ + d_start_of_work = gruel::high_res_timer_now(); +} + +void +gr_block_detail::stop_perf_counters(int noutput_items, int nproduced) +{ + d_end_of_work = gruel::high_res_timer_now(); + gruel::high_res_timer_type diff = d_end_of_work - d_start_of_work; + + if(d_pc_counter == 0) { + d_ins_work_time = diff; + d_avg_work_time = diff; + d_var_work_time = 0; + d_ins_nproduced = nproduced; + d_avg_nproduced = nproduced; + d_var_nproduced = 0; + d_ins_noutput_items = noutput_items; + d_avg_noutput_items = noutput_items; + d_var_noutput_items = 0; + for(size_t i=0; i < d_input.size(); i++) { + float pfull = static_cast<float>(d_input[i]->items_available()) / + static_cast<float>(d_input[i]->max_possible_items_available()); + d_ins_input_buffers_full[i] = pfull; + d_avg_input_buffers_full[i] = pfull; + d_var_input_buffers_full[i] = 0; + } + for(size_t i=0; i < d_output.size(); i++) { + float pfull = 1.0f - static_cast<float>(d_output[i]->space_available()) / + static_cast<float>(d_output[i]->bufsize()); + d_ins_output_buffers_full[i] = pfull; + d_avg_output_buffers_full[i] = pfull; + d_var_output_buffers_full[i] = 0; + } + } + else { + float d = diff - d_avg_work_time; + d_ins_work_time = diff; + d_avg_work_time = d_avg_work_time + d/d_pc_counter; + d_var_work_time = d_var_work_time + d*d; + + d = nproduced - d_avg_nproduced; + d_ins_nproduced = nproduced; + d_avg_nproduced = d_avg_nproduced + d/d_pc_counter; + d_var_nproduced = d_var_nproduced + d*d; + + d = noutput_items - d_avg_noutput_items; + d_ins_noutput_items = noutput_items; + d_avg_noutput_items = d_avg_noutput_items + d/d_pc_counter; + d_var_noutput_items = d_var_noutput_items + d*d; + + for(size_t i=0; i < d_input.size(); i++) { + float pfull = static_cast<float>(d_input[i]->items_available()) / + static_cast<float>(d_input[i]->max_possible_items_available()); + + d = pfull - d_avg_input_buffers_full[i]; + d_ins_input_buffers_full[i] = pfull; + d_avg_input_buffers_full[i] = d_avg_input_buffers_full[i] + d/d_pc_counter; + d_var_input_buffers_full[i] = d_var_input_buffers_full[i] + d*d; + } + + for(size_t i=0; i < d_output.size(); i++) { + float pfull = 1.0f - static_cast<float>(d_output[i]->space_available()) / + static_cast<float>(d_output[i]->bufsize()); + + d = pfull - d_avg_output_buffers_full[i]; + d_ins_output_buffers_full[i] = pfull; + d_avg_output_buffers_full[i] = d_avg_output_buffers_full[i] + d/d_pc_counter; + d_var_output_buffers_full[i] = d_var_output_buffers_full[i] + d*d; + } + } + + d_pc_counter++; +} + +void +gr_block_detail::reset_perf_counters() +{ + d_pc_counter = 0; +} + +float +gr_block_detail::pc_noutput_items() +{ + return d_ins_noutput_items; +} + +float +gr_block_detail::pc_nproduced() +{ + return d_ins_nproduced; +} + +float +gr_block_detail::pc_input_buffers_full(size_t which) +{ + if(which < d_ins_input_buffers_full.size()) + return d_ins_input_buffers_full[which]; + else + return 0; +} + +std::vector<float> +gr_block_detail::pc_input_buffers_full() +{ + return d_ins_input_buffers_full; +} + +float +gr_block_detail::pc_output_buffers_full(size_t which) +{ + if(which < d_ins_output_buffers_full.size()) + return d_ins_output_buffers_full[which]; + else + return 0; +} + +std::vector<float> +gr_block_detail::pc_output_buffers_full() +{ + return d_ins_output_buffers_full; +} + +float +gr_block_detail::pc_work_time() +{ + return d_ins_work_time; +} + +float +gr_block_detail::pc_noutput_items_avg() +{ + return d_avg_noutput_items; +} + +float +gr_block_detail::pc_nproduced_avg() +{ + return d_avg_nproduced; +} + +float +gr_block_detail::pc_input_buffers_full_avg(size_t which) +{ + if(which < d_avg_input_buffers_full.size()) + return d_avg_input_buffers_full[which]; + else + return 0; +} + +std::vector<float> +gr_block_detail::pc_input_buffers_full_avg() +{ + return d_avg_input_buffers_full; +} + +float +gr_block_detail::pc_output_buffers_full_avg(size_t which) +{ + if(which < d_avg_output_buffers_full.size()) + return d_avg_output_buffers_full[which]; + else + return 0; +} + +std::vector<float> +gr_block_detail::pc_output_buffers_full_avg() +{ + return d_avg_output_buffers_full; +} + +float +gr_block_detail::pc_work_time_avg() +{ + return d_avg_work_time; +} + + +float +gr_block_detail::pc_noutput_items_var() +{ + return d_var_noutput_items/(d_pc_counter-1); +} + +float +gr_block_detail::pc_nproduced_var() +{ + return d_var_nproduced/(d_pc_counter-1); +} + +float +gr_block_detail::pc_input_buffers_full_var(size_t which) +{ + if(which < d_avg_input_buffers_full.size()) + return d_var_input_buffers_full[which]/(d_pc_counter-1); + else + return 0; +} + +std::vector<float> +gr_block_detail::pc_input_buffers_full_var() +{ + std::vector<float> var(d_avg_input_buffers_full.size(), 0); + for(size_t i = 0; i < d_avg_input_buffers_full.size(); i++) + var[i] = d_avg_input_buffers_full[i]/(d_pc_counter-1); + return var; +} + +float +gr_block_detail::pc_output_buffers_full_var(size_t which) +{ + if(which < d_avg_output_buffers_full.size()) + return d_var_output_buffers_full[which]/(d_pc_counter-1); + else + return 0; +} + +std::vector<float> +gr_block_detail::pc_output_buffers_full_var() +{ + std::vector<float> var(d_avg_output_buffers_full.size(), 0); + for(size_t i = 0; i < d_avg_output_buffers_full.size(); i++) + var[i] = d_avg_output_buffers_full[i]/(d_pc_counter-1); + return var; +} + +float +gr_block_detail::pc_work_time_var() +{ + return d_var_work_time/(d_pc_counter-1); +} diff --git a/gnuradio-runtime/lib/gr_block_executor.cc b/gnuradio-runtime/lib/gr_block_executor.cc new file mode 100644 index 0000000000..e070f3c508 --- /dev/null +++ b/gnuradio-runtime/lib/gr_block_executor.cc @@ -0,0 +1,487 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2008,2009,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 <gr_block_executor.h> +#include <gr_block.h> +#include <gr_block_detail.h> +#include <gr_buffer.h> +#include <gr_prefs.h> +#include <boost/thread.hpp> +#include <boost/format.hpp> +#include <iostream> +#include <limits> +#include <assert.h> +#include <stdio.h> + +// must be defined to either 0 or 1 +#define ENABLE_LOGGING 0 + +#if (ENABLE_LOGGING) +#define LOG(x) do { x; } while(0) +#else +#define LOG(x) do {;} while(0) +#endif + +static int which_scheduler = 0; + +inline static unsigned int +round_up (unsigned int n, unsigned int multiple) +{ + return ((n + multiple - 1) / multiple) * multiple; +} + +inline static unsigned int +round_down (unsigned int n, unsigned int multiple) +{ + return (n / multiple) * multiple; +} + +// +// Return minimum available write space in all our downstream buffers +// or -1 if we're output blocked and the output we're blocked +// on is done. +// +static int +min_available_space (gr_block_detail *d, int output_multiple, int min_noutput_items) +{ + int min_space = std::numeric_limits<int>::max(); + if (min_noutput_items == 0) + min_noutput_items = 1; + for (int i = 0; i < d->noutputs (); i++){ + gruel::scoped_lock guard(*d->output(i)->mutex()); + int avail_n = round_down(d->output(i)->space_available(), output_multiple); + int best_n = round_down(d->output(i)->bufsize()/2, output_multiple); + if (best_n < min_noutput_items) + throw std::runtime_error("Buffer too small for min_noutput_items"); + int n = std::min(avail_n, best_n); + if (n < min_noutput_items){ // We're blocked on output. + if (d->output(i)->done()){ // Downstream is done, therefore we're done. + return -1; + } + return 0; + } + min_space = std::min (min_space, n); + } + return min_space; +} + +static bool +propagate_tags(gr_block::tag_propagation_policy_t policy, gr_block_detail *d, + const std::vector<uint64_t> &start_nitems_read, double rrate, + std::vector<gr_tag_t> &rtags) +{ + // Move tags downstream + // if a sink, we don't need to move downstream + if(d->sink_p()) { + return true; + } + + switch(policy) { + case gr_block::TPP_DONT: + return true; + break; + case gr_block::TPP_ALL_TO_ALL: + // every tag on every input propogates to everyone downstream + for(int i = 0; i < d->ninputs(); i++) { + d->get_tags_in_range(rtags, i, start_nitems_read[i], + d->nitems_read(i)); + + std::vector<gr_tag_t>::iterator t; + if(rrate == 1.0) { + for(t = rtags.begin(); t != rtags.end(); t++) { + for(int o = 0; o < d->noutputs(); o++) + d->output(o)->add_item_tag(*t); + } + } + else { + for(t = rtags.begin(); t != rtags.end(); t++) { + gr_tag_t new_tag = *t; + new_tag.offset *= rrate; + for(int o = 0; o < d->noutputs(); o++) + d->output(o)->add_item_tag(new_tag); + } + } + } + break; + case gr_block::TPP_ONE_TO_ONE: + // tags from input i only go to output i + // this requires d->ninputs() == d->noutputs; this is checked when this + // type of tag-propagation system is selected in gr_block_detail + if(d->ninputs() == d->noutputs()) { + for(int i = 0; i < d->ninputs(); i++) { + d->get_tags_in_range(rtags, i, start_nitems_read[i], + d->nitems_read(i)); + + std::vector<gr_tag_t>::iterator t; + for(t = rtags.begin(); t != rtags.end(); t++) { + gr_tag_t new_tag = *t; + new_tag.offset *= rrate; + d->output(i)->add_item_tag(new_tag); + } + } + } + else { + std::cerr << "Error: gr_block_executor: propagation_policy 'ONE-TO-ONE' requires ninputs == noutputs" << std::endl; + return false; + } + + break; + default: + return true; + } + return true; +} + +gr_block_executor::gr_block_executor (gr_block_sptr block, int max_noutput_items) + : d_block(block), d_log(0), d_max_noutput_items(max_noutput_items) +{ + if (ENABLE_LOGGING){ + std::string name = str(boost::format("sst-%03d.log") % which_scheduler++); + d_log = new std::ofstream(name.c_str()); + std::unitbuf(*d_log); // make it unbuffered... + *d_log << "gr_block_executor: " + << d_block << std::endl; + } + +#ifdef GR_PERFORMANCE_COUNTERS + gr_prefs *prefs = gr_prefs::singleton(); + d_use_pc = prefs->get_bool("PerfCounters", "on", false); +#endif /* GR_PERFORMANCE_COUNTERS */ + + d_block->start(); // enable any drivers, etc. +} + +gr_block_executor::~gr_block_executor () +{ + if (ENABLE_LOGGING) + delete d_log; + + d_block->stop(); // stop any drivers, etc. +} + +gr_block_executor::state +gr_block_executor::run_one_iteration() +{ + int noutput_items; + int max_items_avail; + int max_noutput_items = d_max_noutput_items; + int new_alignment=0; + int alignment_state=-1; + + gr_block *m = d_block.get(); + gr_block_detail *d = m->detail().get(); + + LOG(*d_log << std::endl << m); + + if (d->done()){ + assert(0); + return DONE; + } + + if (d->source_p ()){ + d_ninput_items_required.resize (0); + d_ninput_items.resize (0); + d_input_items.resize (0); + d_input_done.resize(0); + d_output_items.resize (d->noutputs ()); + d_start_nitems_read.resize(0); + + // determine the minimum available output space + noutput_items = min_available_space (d, m->output_multiple (), m->min_noutput_items ()); + noutput_items = std::min(noutput_items, max_noutput_items); + LOG(*d_log << " source\n noutput_items = " << noutput_items << std::endl); + if (noutput_items == -1) // we're done + goto were_done; + + if (noutput_items == 0){ // we're output blocked + LOG(*d_log << " BLKD_OUT\n"); + return BLKD_OUT; + } + + goto setup_call_to_work; // jump to common code + } + + else if (d->sink_p ()){ + d_ninput_items_required.resize (d->ninputs ()); + d_ninput_items.resize (d->ninputs ()); + d_input_items.resize (d->ninputs ()); + d_input_done.resize(d->ninputs()); + d_output_items.resize (0); + d_start_nitems_read.resize(d->ninputs()); + LOG(*d_log << " sink\n"); + + max_items_avail = 0; + for (int i = 0; i < d->ninputs (); i++){ + { + /* + * Acquire the mutex and grab local copies of items_available and done. + */ + gruel::scoped_lock guard(*d->input(i)->mutex()); + d_ninput_items[i] = d->input(i)->items_available(); + d_input_done[i] = d->input(i)->done(); + } + + LOG(*d_log << " d_ninput_items[" << i << "] = " << d_ninput_items[i] << std::endl); + LOG(*d_log << " d_input_done[" << i << "] = " << d_input_done[i] << std::endl); + + if (d_ninput_items[i] < m->output_multiple() && d_input_done[i]) + goto were_done; + + max_items_avail = std::max (max_items_avail, d_ninput_items[i]); + } + + // take a swag at how much output we can sink + noutput_items = (int) (max_items_avail * m->relative_rate ()); + noutput_items = round_down (noutput_items, m->output_multiple ()); + noutput_items = std::min(noutput_items, max_noutput_items); + LOG(*d_log << " max_items_avail = " << max_items_avail << std::endl); + LOG(*d_log << " noutput_items = " << noutput_items << std::endl); + + if (noutput_items == 0){ // we're blocked on input + LOG(*d_log << " BLKD_IN\n"); + return BLKD_IN; + } + + goto try_again; // Jump to code shared with regular case. + } + + else { + // do the regular thing + d_ninput_items_required.resize (d->ninputs ()); + d_ninput_items.resize (d->ninputs ()); + d_input_items.resize (d->ninputs ()); + d_input_done.resize(d->ninputs()); + d_output_items.resize (d->noutputs ()); + d_start_nitems_read.resize(d->ninputs()); + + max_items_avail = 0; + for (int i = 0; i < d->ninputs (); i++){ + { + /* + * Acquire the mutex and grab local copies of items_available and done. + */ + gruel::scoped_lock guard(*d->input(i)->mutex()); + d_ninput_items[i] = d->input(i)->items_available (); + d_input_done[i] = d->input(i)->done(); + } + max_items_avail = std::max (max_items_avail, d_ninput_items[i]); + } + + // determine the minimum available output space + noutput_items = min_available_space (d, m->output_multiple (), m->min_noutput_items ()); + if (ENABLE_LOGGING){ + *d_log << " regular "; + if (m->relative_rate() >= 1.0) + *d_log << "1:" << m->relative_rate() << std::endl; + else + *d_log << 1.0/m->relative_rate() << ":1\n"; + *d_log << " max_items_avail = " << max_items_avail << std::endl; + *d_log << " noutput_items = " << noutput_items << std::endl; + } + if (noutput_items == -1) // we're done + goto were_done; + + if (noutput_items == 0){ // we're output blocked + LOG(*d_log << " BLKD_OUT\n"); + return BLKD_OUT; + } + + try_again: + if (m->fixed_rate()){ + // try to work it forward starting with max_items_avail. + // We want to try to consume all the input we've got. + int reqd_noutput_items = m->fixed_rate_ninput_to_noutput(max_items_avail); + + // only test this if we specifically set the output_multiple + if(m->output_multiple_set()) + reqd_noutput_items = round_down(reqd_noutput_items, m->output_multiple()); + + if (reqd_noutput_items > 0 && reqd_noutput_items <= noutput_items) + noutput_items = reqd_noutput_items; + + // if we need this many outputs, overrule the max_noutput_items setting + max_noutput_items = std::max(m->output_multiple(), max_noutput_items); + } + noutput_items = std::min(noutput_items, max_noutput_items); + + // Check if we're still unaligned; use up items until we're + // aligned again. Otherwise, make sure we set the alignment + // requirement. + if(!m->output_multiple_set()) { + if(m->is_unaligned()) { + // When unaligned, don't just set noutput_items to the remaining + // samples to meet alignment; this causes too much overhead in + // requiring a premature call back here. Set the maximum amount + // of samples to handle unalignment and get us back aligned. + if(noutput_items >= m->unaligned()) { + noutput_items = round_up(noutput_items, m->alignment()) \ + - (m->alignment() - m->unaligned()); + new_alignment = 0; + } + else { + new_alignment = m->unaligned() - noutput_items; + } + alignment_state = 0; + } + else if(noutput_items < m->alignment()) { + // if we don't have enough for an aligned call, keep track of + // misalignment, set unaligned flag, and proceed. + new_alignment = m->alignment() - noutput_items; + m->set_unaligned(new_alignment); + m->set_is_unaligned(true); + alignment_state = 1; + } + else { + // enough to round down to the nearest alignment and process. + noutput_items = round_down(noutput_items, m->alignment()); + m->set_is_unaligned(false); + alignment_state = 2; + } + } + + // ask the block how much input they need to produce noutput_items + m->forecast (noutput_items, d_ninput_items_required); + + // See if we've got sufficient input available + + int i; + for (i = 0; i < d->ninputs (); i++) + if (d_ninput_items_required[i] > d_ninput_items[i]) // not enough + break; + + if (i < d->ninputs ()){ // not enough input on input[i] + // if we can, try reducing the size of our output request + if (noutput_items > m->output_multiple ()){ + noutput_items /= 2; + noutput_items = round_up (noutput_items, m->output_multiple ()); + goto try_again; + } + + // We're blocked on input + LOG(*d_log << " BLKD_IN\n"); + if (d_input_done[i]) // If the upstream block is done, we're done + goto were_done; + + // Is it possible to ever fulfill this request? + if (d_ninput_items_required[i] > d->input(i)->max_possible_items_available ()){ + // Nope, never going to happen... + std::cerr << "\nsched: <gr_block " << m->name() + << " (" << m->unique_id() << ")>" + << " is requesting more input data\n" + << " than we can provide.\n" + << " ninput_items_required = " + << d_ninput_items_required[i] << "\n" + << " max_possible_items_available = " + << d->input(i)->max_possible_items_available() << "\n" + << " If this is a filter, consider reducing the number of taps.\n"; + goto were_done; + } + + // If we were made unaligned in this round but return here without + // processing; reset the unalignment claim before next entry. + if(alignment_state == 1) { + m->set_unaligned(0); + m->set_is_unaligned(false); + } + return BLKD_IN; + } + + // We've got enough data on each input to produce noutput_items. + // Finish setting up the call to work. + + for (int i = 0; i < d->ninputs (); i++) + d_input_items[i] = d->input(i)->read_pointer(); + + setup_call_to_work: + + d->d_produce_or = 0; + for (int i = 0; i < d->noutputs (); i++) + d_output_items[i] = d->output(i)->write_pointer(); + + // determine where to start looking for new tags + for (int i = 0; i < d->ninputs(); i++) + d_start_nitems_read[i] = d->nitems_read(i); + +#ifdef GR_PERFORMANCE_COUNTERS + if(d_use_pc) + d->start_perf_counters(); +#endif /* GR_PERFORMANCE_COUNTERS */ + + // Do the actual work of the block + int n = m->general_work (noutput_items, d_ninput_items, + d_input_items, d_output_items); + +#ifdef GR_PERFORMANCE_COUNTERS + if(d_use_pc) + d->stop_perf_counters(noutput_items, n); +#endif /* GR_PERFORMANCE_COUNTERS */ + + LOG(*d_log << " general_work: noutput_items = " << noutput_items + << " result = " << n << std::endl); + + // Adjust number of unaligned items left to process + if(m->is_unaligned()) { + m->set_unaligned(new_alignment); + m->set_is_unaligned(m->unaligned() != 0); + } + + if(!propagate_tags(m->tag_propagation_policy(), d, + d_start_nitems_read, m->relative_rate(), + d_returned_tags)) + goto were_done; + + if (n == gr_block::WORK_DONE) + goto were_done; + + if (n != gr_block::WORK_CALLED_PRODUCE) + d->produce_each (n); // advance write pointers + + if (d->d_produce_or > 0) // block produced something + return READY; + + // We didn't produce any output even though we called general_work. + // We have (most likely) consumed some input. + + /* + // If this is a source, it's broken. + if (d->source_p()){ + std::cerr << "gr_block_executor: source " << m + << " produced no output. We're marking it DONE.\n"; + // FIXME maybe we ought to raise an exception... + goto were_done; + } + */ + + // Have the caller try again... + return READY_NO_OUTPUT; + } + assert (0); + + were_done: + LOG(*d_log << " were_done\n"); + d->set_done (true); + return DONE; +} diff --git a/gnuradio-runtime/lib/gr_block_executor.h b/gnuradio-runtime/lib/gr_block_executor.h new file mode 100644 index 0000000000..7d5c4949a3 --- /dev/null +++ b/gnuradio-runtime/lib/gr_block_executor.h @@ -0,0 +1,78 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2008 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_BLOCK_EXECUTOR_H +#define INCLUDED_GR_BLOCK_EXECUTOR_H + +#include <gr_runtime_api.h> +#include <gr_runtime_types.h> +#include <fstream> +#include <gr_tags.h> + +//class gr_block_executor; +//typedef boost::shared_ptr<gr_block_executor> gr_block_executor_sptr; + + +/*! + * \brief Manage the execution of a single block. + * \ingroup internal + */ + +class GR_RUNTIME_API gr_block_executor { +protected: + gr_block_sptr d_block; // The block we're trying to run + std::ofstream *d_log; + + // These are allocated here so we don't have to on each iteration + + gr_vector_int d_ninput_items_required; + gr_vector_int d_ninput_items; + gr_vector_const_void_star d_input_items; + std::vector<bool> d_input_done; + gr_vector_void_star d_output_items; + std::vector<uint64_t> d_start_nitems_read; //stores where tag counts are before work + std::vector<gr_tag_t> d_returned_tags; + int d_max_noutput_items; + +#ifdef GR_PERFORMANCE_COUNTERS + bool d_use_pc; +#endif /* GR_PERFORMANCE_COUNTERS */ + + public: + gr_block_executor(gr_block_sptr block, int max_noutput_items=100000); + ~gr_block_executor (); + + enum state { + READY, // We made progress; everything's cool. + READY_NO_OUTPUT, // We consumed some input, but produced no output. + BLKD_IN, // no progress; we're blocked waiting for input data. + BLKD_OUT, // no progress; we're blocked waiting for output buffer space. + DONE, // we're done; don't call me again. + }; + + /* + * \brief Run one iteration. + */ + state run_one_iteration(); +}; + +#endif /* INCLUDED_GR_BLOCK_EXECUTOR_H */ diff --git a/gnuradio-runtime/lib/gr_block_gateway.cc b/gnuradio-runtime/lib/gr_block_gateway.cc new file mode 100644 index 0000000000..79b42803af --- /dev/null +++ b/gnuradio-runtime/lib/gr_block_gateway.cc @@ -0,0 +1,184 @@ +/* + * Copyright 2011-2012 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 <gr_block_gateway.h> +#include <gr_io_signature.h> +#include <iostream> +#include <boost/bind.hpp> + +/*********************************************************************** + * Helper routines + **********************************************************************/ +template <typename OutType, typename InType> +void copy_pointers(OutType &out, const InType &in){ + out.resize(in.size()); + for (size_t i = 0; i < in.size(); i++){ + out[i] = (void *)(in[i]); + } +} + +/*********************************************************************** + * The gr_block gateway implementation class + **********************************************************************/ +class gr_block_gateway_impl : public gr_block_gateway{ +public: + gr_block_gateway_impl( + gr_feval_ll *handler, + const std::string &name, + gr_io_signature_sptr in_sig, + gr_io_signature_sptr out_sig, + const gr_block_gw_work_type work_type, + const unsigned factor + ): + gr_block(name, in_sig, out_sig), + _handler(handler), + _work_type(work_type) + { + switch(_work_type){ + case GR_BLOCK_GW_WORK_GENERAL: + _decim = 1; //not relevant, but set anyway + _interp = 1; //not relevant, but set anyway + break; + + case GR_BLOCK_GW_WORK_SYNC: + _decim = 1; + _interp = 1; + this->set_fixed_rate(true); + break; + + case GR_BLOCK_GW_WORK_DECIM: + _decim = factor; + _interp = 1; + break; + + case GR_BLOCK_GW_WORK_INTERP: + _decim = 1; + _interp = factor; + this->set_output_multiple(_interp); + break; + } + } + + /******************************************************************* + * Overloads for various scheduler-called functions + ******************************************************************/ + void forecast( + int noutput_items, + gr_vector_int &ninput_items_required + ){ + switch(_work_type){ + case GR_BLOCK_GW_WORK_GENERAL: + _message.action = gr_block_gw_message_type::ACTION_FORECAST; + _message.forecast_args_noutput_items = noutput_items; + _message.forecast_args_ninput_items_required = ninput_items_required; + _handler->calleval(0); + ninput_items_required = _message.forecast_args_ninput_items_required; + return; + + default: + unsigned ninputs = ninput_items_required.size(); + for (unsigned i = 0; i < ninputs; i++) + ninput_items_required[i] = fixed_rate_noutput_to_ninput(noutput_items); + return; + } + } + + int general_work( + int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items + ){ + switch(_work_type){ + case GR_BLOCK_GW_WORK_GENERAL: + _message.action = gr_block_gw_message_type::ACTION_GENERAL_WORK; + _message.general_work_args_noutput_items = noutput_items; + _message.general_work_args_ninput_items = ninput_items; + copy_pointers(_message.general_work_args_input_items, input_items); + _message.general_work_args_output_items = output_items; + _handler->calleval(0); + return _message.general_work_args_return_value; + + default: + int r = work (noutput_items, input_items, output_items); + if (r > 0) consume_each(r*_decim/_interp); + return r; + } + } + + int work( + int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items + ){ + _message.action = gr_block_gw_message_type::ACTION_WORK; + _message.work_args_ninput_items = fixed_rate_noutput_to_ninput(noutput_items); + if (_message.work_args_ninput_items == 0) return -1; + _message.work_args_noutput_items = noutput_items; + copy_pointers(_message.work_args_input_items, input_items); + _message.work_args_output_items = output_items; + _handler->calleval(0); + return _message.work_args_return_value; + } + + int fixed_rate_noutput_to_ninput(int noutput_items){ + return (noutput_items*_decim/_interp) + history() - 1; + } + + int fixed_rate_ninput_to_noutput(int ninput_items){ + return std::max(0, ninput_items - (int)history() + 1)*_interp/_decim; + } + + bool start(void){ + _message.action = gr_block_gw_message_type::ACTION_START; + _handler->calleval(0); + return _message.start_args_return_value; + } + + bool stop(void){ + _message.action = gr_block_gw_message_type::ACTION_STOP; + _handler->calleval(0); + return _message.stop_args_return_value; + } + + gr_block_gw_message_type &gr_block_message(void){ + return _message; + } + +private: + gr_feval_ll *_handler; + gr_block_gw_message_type _message; + const gr_block_gw_work_type _work_type; + unsigned _decim, _interp; +}; + +boost::shared_ptr<gr_block_gateway> gr_make_block_gateway( + gr_feval_ll *handler, + const std::string &name, + gr_io_signature_sptr in_sig, + gr_io_signature_sptr out_sig, + const gr_block_gw_work_type work_type, + const unsigned factor +){ + return boost::shared_ptr<gr_block_gateway>( + new gr_block_gateway_impl(handler, name, in_sig, out_sig, work_type, factor) + ); +} diff --git a/gnuradio-runtime/lib/gr_block_registry.cc b/gnuradio-runtime/lib/gr_block_registry.cc new file mode 100644 index 0000000000..eaa770dcaf --- /dev/null +++ b/gnuradio-runtime/lib/gr_block_registry.cc @@ -0,0 +1,76 @@ +#include <gr_basic_block.h> +#include <gr_block_registry.h> +#include <gr_tpb_detail.h> +#include <gr_block_detail.h> +#include <gr_block.h> +#include <stdio.h> + +gr_block_registry global_block_registry; + +gr_block_registry::gr_block_registry(){ + d_ref_map = pmt::make_dict(); +} + +long gr_block_registry::block_register(gr_basic_block* block){ + if(d_map.find(block->name()) == d_map.end()){ + d_map[block->name()] = blocksubmap_t(); + d_map[block->name()][0] = block; + return 0; + } else { + for(size_t i=0; i<=d_map[block->name()].size(); i++){ + if(d_map[block->name()].find(i) == d_map[block->name()].end()){ + d_map[block->name()][i] = block; + return i; + } + } + } + throw std::runtime_error("should not reach this"); +} + +void gr_block_registry::block_unregister(gr_basic_block* block){ + d_map[block->name()].erase( d_map[block->name()].find(block->symbolic_id())); + d_ref_map = pmt::dict_delete(d_ref_map, pmt::intern(block->symbol_name())); + if(block->alias_set()){ + d_ref_map = pmt::dict_delete(d_ref_map, pmt::intern(block->alias())); + } +} + +std::string gr_block_registry::register_symbolic_name(gr_basic_block* block){ + std::stringstream ss; + ss << block->name() << block->symbolic_id(); + //std::cout << "register_symbolic_name: " << ss.str() << std::endl; + register_symbolic_name(block, ss.str()); + return ss.str(); +} + +void gr_block_registry::register_symbolic_name(gr_basic_block* block, std::string name){ + if(dict_has_key(d_ref_map, pmt::intern(name))){ + throw std::runtime_error("symbol already exists, can not re-use!"); + } + d_ref_map = dict_add(d_ref_map, pmt::intern(name), pmt::make_any(block)); +} + +gr_basic_block_sptr gr_block_registry::block_lookup(pmt::pmt_t symbol){ + pmt::pmt_t ref = dict_ref(d_ref_map, symbol, pmt::PMT_NIL); + if(pmt::eq(ref, pmt::PMT_NIL)){ + throw std::runtime_error("block lookup failed! block not found!"); + } + gr_basic_block* blk = boost::any_cast<gr_basic_block*>( pmt::any_ref(ref) ); + return blk->shared_from_this(); +} + + +void gr_block_registry::register_primitive(std::string blk, gr_block* ref){ + primitive_map[blk] = ref; +} + +void gr_block_registry::unregister_primitive(std::string blk){ + primitive_map.erase(primitive_map.find(blk)); +} + +void gr_block_registry::notify_blk(std::string blk){ + if(primitive_map.find(blk) == primitive_map.end()){ return; } + if(primitive_map[blk]->detail().get()) + primitive_map[blk]->detail()->d_tpb.notify_msg(); +} + diff --git a/gnuradio-runtime/lib/gr_buffer.cc b/gnuradio-runtime/lib/gr_buffer.cc new file mode 100644 index 0000000000..369959d65f --- /dev/null +++ b/gnuradio-runtime/lib/gr_buffer.cc @@ -0,0 +1,347 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2009,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 <gr_buffer.h> +#include <gr_vmcircbuf.h> +#include <gr_math.h> +#include <stdexcept> +#include <iostream> +#include <assert.h> +#include <algorithm> +#include <boost/math/common_factor_rt.hpp> + +static long s_buffer_count = 0; // counts for debugging storage mgmt +static long s_buffer_reader_count = 0; + +// ---------------------------------------------------------------------------- +// Notes on storage management +// +// Pretty much all the fundamental classes are now using the +// shared_ptr stuff for automatic reference counting. To ensure that +// no mistakes are made, we make the constructors for classes private, +// and then provide a free factory function that returns a smart +// pointer to the desired class. +// +// gr_buffer and gr_buffer_reader are no exceptions. However, they +// both want pointers to each other, and unless we do something, we'll +// never delete any of them because of the circular structure. +// They'll always have a reference count of at least one. We could +// use boost::weak_ptr's from gr_buffer to gr_buffer_reader but that +// introduces it's own problems. (gr_buffer_reader's destructor needs +// to call gr_buffer::drop_reader, but has no easy way to get a +// shared_ptr to itself.) +// +// Instead, we solve this problem by having gr_buffer hold a raw +// pointer to gr_buffer_reader in its d_reader vector. +// gr_buffer_reader's destructor calls gr_buffer::drop_reader, so +// we're never left with an dangling pointer. gr_buffer_reader still +// has a shared_ptr to the buffer ensuring that the buffer doesn't go +// away under it. However, when the reference count of a +// gr_buffer_reader goes to zero, we can successfully reclaim it. +// ---------------------------------------------------------------------------- + + +/* + * Compute the minimum number of buffer items that work (i.e., + * address space wrap-around works). To work is to satisfy this + * contraint for integer buffer_size and k: + * + * type_size * nitems == k * page_size + */ +static long +minimum_buffer_items (long type_size, long page_size) +{ + return page_size / boost::math::gcd (type_size, page_size); +} + + +gr_buffer::gr_buffer (int nitems, size_t sizeof_item, gr_block_sptr link) + : d_base (0), d_bufsize (0), d_vmcircbuf (0), + d_sizeof_item (sizeof_item), d_link(link), + d_write_index (0), d_abs_write_offset(0), d_done (false), + d_last_min_items_read(0) +{ + if (!allocate_buffer (nitems, sizeof_item)) + throw std::bad_alloc (); + + s_buffer_count++; +} + +gr_buffer_sptr +gr_make_buffer (int nitems, size_t sizeof_item, gr_block_sptr link) +{ + return gr_buffer_sptr (new gr_buffer (nitems, sizeof_item, link)); +} + +gr_buffer::~gr_buffer () +{ + delete d_vmcircbuf; + assert (d_readers.size() == 0); + s_buffer_count--; +} + +/*! + * sets d_vmcircbuf, d_base, d_bufsize. + * returns true iff successful. + */ +bool +gr_buffer::allocate_buffer (int nitems, size_t sizeof_item) +{ + int orig_nitems = nitems; + + // Any buffersize we come up with must be a multiple of min_nitems. + + int granularity = gr_vmcircbuf_sysconfig::granularity (); + int min_nitems = minimum_buffer_items (sizeof_item, granularity); + + // Round-up nitems to a multiple of min_nitems. + + if (nitems % min_nitems != 0) + nitems = ((nitems / min_nitems) + 1) * min_nitems; + + // If we rounded-up a whole bunch, give the user a heads up. + // This only happens if sizeof_item is not a power of two. + + if (nitems > 2 * orig_nitems && nitems * (int) sizeof_item > granularity){ + std::cerr << "gr_buffer::allocate_buffer: warning: tried to allocate\n" + << " " << orig_nitems << " items of size " + << sizeof_item << ". Due to alignment requirements\n" + << " " << nitems << " were allocated. If this isn't OK, consider padding\n" + << " your structure to a power-of-two bytes.\n" + << " On this platform, our allocation granularity is " << granularity << " bytes.\n"; + } + + d_bufsize = nitems; + d_vmcircbuf = gr_vmcircbuf_sysconfig::make (d_bufsize * d_sizeof_item); + if (d_vmcircbuf == 0){ + std::cerr << "gr_buffer::allocate_buffer: failed to allocate buffer of size " + << d_bufsize * d_sizeof_item / 1024 << " KB\n"; + return false; + } + + d_base = (char *) d_vmcircbuf->pointer_to_first_copy (); + return true; +} + + +int +gr_buffer::space_available () +{ + if (d_readers.empty ()) + return d_bufsize - 1; // See comment below + + else { + + // Find out the maximum amount of data available to our readers + + int most_data = d_readers[0]->items_available (); + uint64_t min_items_read = d_readers[0]->nitems_read(); + for (size_t i = 1; i < d_readers.size (); i++) { + most_data = std::max (most_data, d_readers[i]->items_available ()); + min_items_read = std::min(min_items_read, d_readers[i]->nitems_read()); + } + + if(min_items_read != d_last_min_items_read) { + prune_tags(d_last_min_items_read); + d_last_min_items_read = min_items_read; + } + + // The -1 ensures that the case d_write_index == d_read_index is + // unambiguous. It indicates that there is no data for the reader + + return d_bufsize - most_data - 1; + } +} + +void * +gr_buffer::write_pointer () +{ + return &d_base[d_write_index * d_sizeof_item]; +} + +void +gr_buffer::update_write_pointer (int nitems) +{ + gruel::scoped_lock guard(*mutex()); + d_write_index = index_add (d_write_index, nitems); + d_abs_write_offset += nitems; +} + +void +gr_buffer::set_done (bool done) +{ + gruel::scoped_lock guard(*mutex()); + d_done = done; +} + +gr_buffer_reader_sptr +gr_buffer_add_reader (gr_buffer_sptr buf, int nzero_preload, gr_block_sptr link) +{ + if (nzero_preload < 0) + throw std::invalid_argument("gr_buffer_add_reader: nzero_preload must be >= 0"); + + gr_buffer_reader_sptr r (new gr_buffer_reader (buf, + buf->index_sub(buf->d_write_index, + nzero_preload), + link)); + buf->d_readers.push_back (r.get ()); + + return r; +} + +void +gr_buffer::drop_reader (gr_buffer_reader *reader) +{ + // isn't C++ beautiful... GAG! + + std::vector<gr_buffer_reader *>::iterator result = + std::find (d_readers.begin (), d_readers.end (), reader); + + if (result == d_readers.end ()) + throw std::invalid_argument ("gr_buffer::drop_reader"); // we didn't find it... + + d_readers.erase (result); +} + +void +gr_buffer::add_item_tag(const gr_tag_t &tag) +{ + gruel::scoped_lock guard(*mutex()); + d_item_tags.push_back(tag); +} + +void +gr_buffer::remove_item_tag(const gr_tag_t &tag) +{ + gruel::scoped_lock guard(*mutex()); + for (std::deque<gr_tag_t>::iterator it = d_item_tags.begin(); it != d_item_tags.end(); ++it) { + if (*it == tag) { + d_item_tags.erase(it); + break; + } + } +} + +void +gr_buffer::prune_tags(uint64_t max_time) +{ + /* NOTE: this function _should_ lock the mutex before editing + d_item_tags. In practice, this function is only called at + runtime by min_available_space in gr_block_executor.cc, + which locks the mutex itself. + + If this function is used elsewhere, remember to lock the + buffer's mutex al la the scoped_lock line below. + */ + //gruel::scoped_lock guard(*mutex()); + std::deque<gr_tag_t>::iterator itr = d_item_tags.begin(); + + uint64_t item_time; + + // Since tags are not guarenteed to be in any particular order, + // we need to erase here instead of pop_front. An erase in the + // middle invalidates all iterators; so this resets the iterator + // to find more. Mostly, we wil be erasing from the front and + // therefore lose little time this way. + while(itr != d_item_tags.end()) { + item_time = (*itr).offset; + if(item_time < max_time) { + d_item_tags.erase(itr); + itr = d_item_tags.begin(); + } + else + itr++; + } +} + +long +gr_buffer_ncurrently_allocated () +{ + return s_buffer_count; +} + +// ---------------------------------------------------------------------------- + +gr_buffer_reader::gr_buffer_reader(gr_buffer_sptr buffer, unsigned int read_index, + gr_block_sptr link) + : d_buffer(buffer), d_read_index(read_index), d_abs_read_offset(0), d_link(link) +{ + s_buffer_reader_count++; +} + +gr_buffer_reader::~gr_buffer_reader () +{ + d_buffer->drop_reader(this); + s_buffer_reader_count--; +} + +int +gr_buffer_reader::items_available () const +{ + return d_buffer->index_sub (d_buffer->d_write_index, d_read_index); +} + +const void * +gr_buffer_reader::read_pointer () +{ + return &d_buffer->d_base[d_read_index * d_buffer->d_sizeof_item]; +} + +void +gr_buffer_reader::update_read_pointer (int nitems) +{ + gruel::scoped_lock guard(*mutex()); + d_read_index = d_buffer->index_add (d_read_index, nitems); + d_abs_read_offset += nitems; +} + +void +gr_buffer_reader::get_tags_in_range(std::vector<gr_tag_t> &v, + uint64_t abs_start, + uint64_t abs_end) +{ + gruel::scoped_lock guard(*mutex()); + + v.resize(0); + std::deque<gr_tag_t>::iterator itr = d_buffer->get_tags_begin(); + + uint64_t item_time; + while(itr != d_buffer->get_tags_end()) { + item_time = (*itr).offset; + + if((item_time >= abs_start) && (item_time < abs_end)) { + v.push_back(*itr); + } + + itr++; + } +} + +long +gr_buffer_reader_ncurrently_allocated () +{ + return s_buffer_reader_count; +} diff --git a/gnuradio-runtime/lib/gr_circular_file.cc b/gnuradio-runtime/lib/gr_circular_file.cc new file mode 100644 index 0000000000..6f710c49b1 --- /dev/null +++ b/gnuradio-runtime/lib/gr_circular_file.cc @@ -0,0 +1,203 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,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 <gr_circular_file.h> + +#include <unistd.h> +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> + +#include <algorithm> +#include <stdio.h> +#include <string.h> + +#ifdef HAVE_IO_H +#include <io.h> +#endif + +static const int HEADER_SIZE = 4096; +static const int HEADER_MAGIC = 0xEB021026; + +static const int HD_MAGIC = 0; +static const int HD_HEADER_SIZE = 1; // integer offsets into header +static const int HD_BUFFER_SIZE = 2; +static const int HD_BUFFER_BASE = 3; +static const int HD_BUFFER_CURRENT = 4; + +gr_circular_file::gr_circular_file (const char *filename, + bool writable, int size) + : d_fd (-1), d_header (0), d_buffer (0), d_mapped_size (0), d_bytes_read (0) +{ + int mm_prot; + if (writable){ +#ifdef HAVE_MMAP + mm_prot = PROT_READ | PROT_WRITE; +#endif + d_fd = open (filename, O_CREAT | O_RDWR | O_TRUNC, 0664); + if (d_fd < 0){ + perror (filename); + exit (1); + } +#ifdef HAVE_MMAP /* FIXME */ + if(ftruncate (d_fd, size + HEADER_SIZE) != 0) { + perror (filename); + exit (1); + } +#endif + } + else { +#ifdef HAVE_MMAP + mm_prot = PROT_READ; +#endif + d_fd = open (filename, O_RDONLY); + if (d_fd < 0){ + perror (filename); + exit (1); + } + } + + struct stat statbuf; + if (fstat (d_fd, &statbuf) < 0){ + perror (filename); + exit (1); + } + + if (statbuf.st_size < HEADER_SIZE){ + fprintf (stderr, "%s: file too small to be circular buffer\n", filename); + exit (1); + } + + d_mapped_size = statbuf.st_size; +#ifdef HAVE_MMAP + void *p = mmap (0, d_mapped_size, mm_prot, MAP_SHARED, d_fd, 0); + if (p == MAP_FAILED){ + perror ("gr_circular_file: mmap failed"); + exit (1); + } + + d_header = (int *) p; +#else + perror ("gr_circular_file: mmap unsupported by this system"); + exit (1); +#endif + + if (writable){ // init header + + if (size < 0){ + fprintf (stderr, "gr_circular_buffer: size must be > 0 when writable\n"); + exit (1); + } + + d_header[HD_MAGIC] = HEADER_MAGIC; + d_header[HD_HEADER_SIZE] = HEADER_SIZE; + d_header[HD_BUFFER_SIZE] = size; + d_header[HD_BUFFER_BASE] = HEADER_SIZE; // right after header + d_header[HD_BUFFER_CURRENT] = 0; + } + + // sanity check (the asserts are a bit unforgiving...) + + assert (d_header[HD_MAGIC] == HEADER_MAGIC); + assert (d_header[HD_HEADER_SIZE] == HEADER_SIZE); + assert (d_header[HD_BUFFER_SIZE] > 0); + assert (d_header[HD_BUFFER_BASE] >= d_header[HD_HEADER_SIZE]); + assert (d_header[HD_BUFFER_BASE] + d_header[HD_BUFFER_SIZE] <= d_mapped_size); + assert (d_header[HD_BUFFER_CURRENT] >= 0 && + d_header[HD_BUFFER_CURRENT] < d_header[HD_BUFFER_SIZE]); + + d_bytes_read = 0; + d_buffer = (unsigned char *) d_header + d_header[HD_BUFFER_BASE]; +} + +gr_circular_file::~gr_circular_file () +{ +#ifdef HAVE_MMAP + if (munmap ((char *) d_header, d_mapped_size) < 0){ + perror ("gr_circular_file: munmap"); + exit (1); + } +#endif + close (d_fd); +} + +bool +gr_circular_file::write (void *vdata, int nbytes) +{ + unsigned char *data = (unsigned char *) vdata; + int buffer_size = d_header[HD_BUFFER_SIZE]; + int buffer_current = d_header[HD_BUFFER_CURRENT]; + + while (nbytes > 0){ + int n = std::min (nbytes, buffer_size - buffer_current); + memcpy (d_buffer + buffer_current, data, n); + + buffer_current += n; + if (buffer_current >= buffer_size) + buffer_current = 0; + + data += n; + nbytes -= n; + } + + d_header[HD_BUFFER_CURRENT] = buffer_current; + return true; +} + +int +gr_circular_file::read (void *vdata, int nbytes) +{ + unsigned char *data = (unsigned char *) vdata; + int buffer_current = d_header[HD_BUFFER_CURRENT]; + int buffer_size = d_header[HD_BUFFER_SIZE]; + int total = 0; + + nbytes = std::min (nbytes, buffer_size - d_bytes_read); + + while (nbytes > 0){ + int offset = (buffer_current + d_bytes_read) % buffer_size; + int n = std::min (nbytes, buffer_size - offset); + memcpy (data, d_buffer + offset, n); + data += n; + d_bytes_read += n; + total += n; + nbytes -= n; + } + return total; +} + +void +gr_circular_file::reset_read_pointer () +{ + d_bytes_read = 0; +} diff --git a/gnuradio-runtime/lib/gr_circular_file.h b/gnuradio-runtime/lib/gr_circular_file.h new file mode 100644 index 0000000000..2b61bf2711 --- /dev/null +++ b/gnuradio-runtime/lib/gr_circular_file.h @@ -0,0 +1,60 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002 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 _GR_CIRCULAR_FILE_H_ +#define _GR_CIRCULAR_FILE_H_ + +#include <gr_runtime_api.h> + +/* + * writes input data into a circular buffer on disk. + * + * the file contains a fixed header: + * 0x0000: int32 magic (0xEB021026) + * 0x0004: int32 size in bytes of header (constant 4096) + * 0x0008: int32 size in bytes of circular buffer (not including header) + * 0x000C: int32 file offset to beginning of circular buffer + * 0x0010: int32 byte offset from beginning of circular buffer to + * current start of data + * + */ +class GR_RUNTIME_API gr_circular_file { + int d_fd; + int *d_header; + unsigned char *d_buffer; + int d_mapped_size; + int d_bytes_read; + +public: + gr_circular_file (const char *filename, bool writable = false, int size = 0); + ~gr_circular_file (); + + bool write (void *data, int nbytes); + + // returns # of bytes actually read or 0 if end of buffer, or -1 on error. + int read (void *data, int nbytes); + + // reset read pointer to beginning of buffer. + void reset_read_pointer (); +}; + +#endif /* _GR_CIRCULAR_FILE_H_ */
\ No newline at end of file diff --git a/gnuradio-runtime/lib/gr_constants.cc.in b/gnuradio-runtime/lib/gr_constants.cc.in new file mode 100644 index 0000000000..b94f254d66 --- /dev/null +++ b/gnuradio-runtime/lib/gr_constants.cc.in @@ -0,0 +1,57 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,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. + */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <gr_constants.h> + +const std::string +gr_prefix() +{ + return "@prefix@"; +} + +const std::string +gr_sysconfdir() +{ + return "@SYSCONFDIR@"; +} + +const std::string +gr_prefsdir() +{ + return "@GR_PREFSDIR@"; +} + +const std::string +gr_build_date() +{ + return "@BUILD_DATE@"; +} + +const std::string +gr_version() +{ + return "@VERSION@"; +} diff --git a/gnuradio-runtime/lib/gr_dispatcher.cc b/gnuradio-runtime/lib/gr_dispatcher.cc new file mode 100644 index 0000000000..96ebe9ad8b --- /dev/null +++ b/gnuradio-runtime/lib/gr_dispatcher.cc @@ -0,0 +1,193 @@ +/* -*- 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 <gr_dispatcher.h> +#include <math.h> +#include <errno.h> +#include <stdio.h> + +#ifdef HAVE_SELECT +# ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +# else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# endif +# ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +# endif +# ifdef HAVE_UNISTD_H +# include <unistd.h> +# endif +# endif +#endif + + +static gr_dispatcher_sptr s_singleton; + +gr_dispatcher_sptr +gr_make_dispatcher() +{ + return gr_dispatcher_sptr(new gr_dispatcher()); +} + +gr_dispatcher_sptr +gr_dispatcher_singleton() +{ + if (s_singleton) + return s_singleton; + + s_singleton = gr_make_dispatcher(); + return s_singleton; +} + +#if !defined(HAVE_SELECT) // Stub it out + +gr_dispatcher::gr_dispatcher() +{ +} + +gr_dispatcher::~gr_dispatcher() +{ +} + +bool +gr_dispatcher::add_handler(gr_select_handler_sptr handler) +{ + return true; +} + +bool +gr_dispatcher::del_handler(gr_select_handler_sptr handler) +{ + return true; +} + +bool +gr_dispatcher::del_handler(gr_select_handler *handler) +{ + return true; +} + +void +gr_dispatcher::loop(double timeout) +{ +} + +#else // defined(HAVE_SELECT) + +gr_dispatcher::gr_dispatcher() + : d_handler(FD_SETSIZE), d_max_index(-1) +{ +} + +gr_dispatcher::~gr_dispatcher() +{ +} + +bool +gr_dispatcher::add_handler(gr_select_handler_sptr handler) +{ + int fd = handler->fd(); + if (fd < 0 || fd >= FD_SETSIZE) + return false; + + d_max_index = std::max(d_max_index, fd); + d_handler[fd] = handler; + return true; +} + +bool +gr_dispatcher::del_handler(gr_select_handler_sptr handler) +{ + return del_handler(handler.get()); +} + +bool +gr_dispatcher::del_handler(gr_select_handler *handler) +{ + int fd = handler->fd(); + if (fd < 0 || fd >= FD_SETSIZE) + return false; + + d_handler[fd].reset(); + + if (fd == d_max_index){ + int i; + for (i = fd - 1; i >= 0 && !d_handler[i]; i--) + ; + d_max_index = i; + } + return true; +} + + +void +gr_dispatcher::loop(double timeout) +{ + struct timeval master; + struct timeval tmp; + fd_set rd_set; + fd_set wr_set; + + double secs = floor (timeout); + master.tv_sec = (long) secs; + master.tv_usec = (long) ((timeout - secs) * 1e6); + + while (d_max_index >= 0){ + FD_ZERO(&rd_set); + FD_ZERO(&wr_set); + + for (int i = 0; i <= d_max_index; i++){ + if (d_handler[i] && d_handler[i]->readable()) + FD_SET(i, &rd_set); + if (d_handler[i] && d_handler[i]->writable()) + FD_SET(i, &wr_set); + } + + tmp = master; + int retval = select(d_max_index+1, &rd_set, &wr_set, 0, &tmp); + if (retval == 0) // timed out with nothing ready + continue; + if (retval < 0){ + if (errno == EINTR) + continue; + perror ("gr_dispatcher/select"); + return; + } + + for (int i = 0; i <= d_max_index; i++){ + if (FD_ISSET(i, &rd_set)) + if (d_handler[i]) + d_handler[i]->handle_read(); + if (FD_ISSET(i, &wr_set)) + if (d_handler[i]) + d_handler[i]->handle_write(); + } + } +} + +#endif diff --git a/gnuradio-runtime/lib/gr_error_handler.cc b/gnuradio-runtime/lib/gr_error_handler.cc new file mode 100644 index 0000000000..448682966e --- /dev/null +++ b/gnuradio-runtime/lib/gr_error_handler.cc @@ -0,0 +1,244 @@ +/* -*- 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. + */ +/* + * This code is based on error.cc from the "Click Modular Router". + * Original copyright follows: + */ +/* + * error.{cc,hh} -- flexible classes for error reporting + * Eddie Kohler + * + * Copyright (c) 1999-2000 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, subject to the conditions + * listed in the Click LICENSE file. These conditions include: you must + * preserve this copyright notice, and you cannot mention the copyright + * holders in advertising related to the Software without their permission. + * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This + * notice is a summary of the Click LICENSE file; the license in that file is + * legally binding. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_error_handler.h> +#include <assert.h> +#include <stdexcept> +#include <unistd.h> + +#ifdef HAVE_IO_H +#include <io.h> +#endif + +static gr_error_handler *s_default_handler = 0; +static gr_error_handler *s_silent_handler = 0; + +bool +gr_error_handler::has_default_handler() +{ + return s_default_handler != 0; +} + +void +gr_error_handler::set_default_handler(gr_error_handler *errh) +{ + s_default_handler = errh; +} + +gr_error_handler * +gr_error_handler::default_handler() +{ + assert (s_default_handler != 0); + return s_default_handler; +} + +gr_error_handler * +gr_error_handler::silent_handler() +{ + assert (s_silent_handler != 0); + return s_silent_handler; +} + +// ---------------------------------------------------------------- + +gr_error_handler::~gr_error_handler() +{ + // nop +} + +void +gr_error_handler::debug(const char *format, ...) +{ + va_list val; + va_start(val, format); + verror(ERR_DEBUG, format, val); + va_end(val); +} + +void +gr_error_handler::message(const char *format, ...) +{ + va_list val; + va_start(val, format); + verror(ERR_MESSAGE, format, val); + va_end(val); +} + +void +gr_error_handler::warning(const char *format, ...) +{ + va_list val; + va_start(val, format); + verror(ERR_WARNING, format, val); + va_end(val); +} + +void +gr_error_handler::error(const char *format, ...) +{ + va_list val; + va_start(val, format); + verror(ERR_ERROR, format, val); + va_end(val); +} + +void +gr_error_handler::fatal(const char *format, ...) +{ + va_list val; + va_start(val, format); + verror(ERR_FATAL, format, val); + va_end(val); +} + +void +gr_error_handler::verror(seriousness s, const char *format, va_list val) +{ + std::string text = make_text(s, format, val); + handle_text(s, text); + count_error(s); +} + +void +gr_error_handler::verror_text(seriousness s, const std::string &text) +{ + // text is already made + handle_text(s, text); + count_error(s); +} + +std::string +gr_error_handler::make_text(seriousness s, const char *format, va_list val) +{ + char text_buf[4096]; + vsnprintf(text_buf, sizeof(text_buf), format, val); + text_buf[sizeof(text_buf)-1] = 0; + return text_buf; +} + +// ---------------------------------------------------------------- + +void +gr_base_error_handler::count_error(seriousness s) +{ + if (s < ERR_WARNING) + /* do nothing */; + else if (s < ERR_ERROR) + d_nwarnings++; + else + d_nerrors++; +} + +// ---------------------------------------------------------------- + +gr_file_error_handler::gr_file_error_handler(FILE *file) + : d_file(file), d_fd(-1) +{ +} + +gr_file_error_handler::gr_file_error_handler(int file_descriptor) +{ + d_fd = dup(file_descriptor); // so we can fclose it + if (d_fd == -1){ + perror("gr_file_error_handler:dup"); + throw std::invalid_argument("gr_file_error_handler:dup"); + } + d_file = fdopen(d_fd, "w"); + if (d_file == 0){ + perror("gr_file_error_handler:fdopen"); + throw std::invalid_argument("gr_file_error_handler:fdopen"); + } +} + +gr_file_error_handler::~gr_file_error_handler() +{ + if (d_fd != -1){ + fclose(d_file); + } +} + +void +gr_file_error_handler::handle_text(seriousness s, const std::string &text) +{ + if (text.length() <= 0) + return; + + fwrite(text.data(), 1, text.length(), d_file); + if (text[text.length()-1] != '\n') + fwrite("\n", 1, 1, d_file); + + if (d_fd != -1) + fflush(d_file); // keep synced with any other users of fd +} + + +// ---------------------------------------------------------------- +// static error handlers +// + +class gr_silent_error_handler : public gr_base_error_handler +{ +public: + gr_silent_error_handler() {} + void handle_text(seriousness s, const std::string &str); +}; + +void +gr_silent_error_handler::handle_text(seriousness s, const std::string &str) +{ + // nop +} + +class force_init { +public: + force_init() + { + s_default_handler = new gr_file_error_handler(stdout); + s_silent_handler = new gr_silent_error_handler(); + } +}; + +static force_init kludge; diff --git a/gnuradio-runtime/lib/gr_fast_atan2f.cc b/gnuradio-runtime/lib/gr_fast_atan2f.cc new file mode 100644 index 0000000000..8b7bfea12e --- /dev/null +++ b/gnuradio-runtime/lib/gr_fast_atan2f.cc @@ -0,0 +1,199 @@ +/* -*- 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. + */ + +#include <gr_math.h> // declaration is in here +#include <cmath> + +#define REAL float + +/***************************************************************************/ +/* Constant definitions */ +/***************************************************************************/ + +#define TAN_MAP_RES 0.003921569 /* (smallest non-zero value in table) */ +#define RAD_PER_DEG 0.017453293 +#define TAN_MAP_SIZE 256 + +/* arctangents from 0 to pi/4 radians */ +static REAL +fast_atan_table[257] = { + 0.000000e+00, 3.921549e-03, 7.842976e-03, 1.176416e-02, + 1.568499e-02, 1.960533e-02, 2.352507e-02, 2.744409e-02, + 3.136226e-02, 3.527947e-02, 3.919560e-02, 4.311053e-02, + 4.702413e-02, 5.093629e-02, 5.484690e-02, 5.875582e-02, + 6.266295e-02, 6.656816e-02, 7.047134e-02, 7.437238e-02, + 7.827114e-02, 8.216752e-02, 8.606141e-02, 8.995267e-02, + 9.384121e-02, 9.772691e-02, 1.016096e-01, 1.054893e-01, + 1.093658e-01, 1.132390e-01, 1.171087e-01, 1.209750e-01, + 1.248376e-01, 1.286965e-01, 1.325515e-01, 1.364026e-01, + 1.402496e-01, 1.440924e-01, 1.479310e-01, 1.517652e-01, + 1.555948e-01, 1.594199e-01, 1.632403e-01, 1.670559e-01, + 1.708665e-01, 1.746722e-01, 1.784728e-01, 1.822681e-01, + 1.860582e-01, 1.898428e-01, 1.936220e-01, 1.973956e-01, + 2.011634e-01, 2.049255e-01, 2.086818e-01, 2.124320e-01, + 2.161762e-01, 2.199143e-01, 2.236461e-01, 2.273716e-01, + 2.310907e-01, 2.348033e-01, 2.385093e-01, 2.422086e-01, + 2.459012e-01, 2.495869e-01, 2.532658e-01, 2.569376e-01, + 2.606024e-01, 2.642600e-01, 2.679104e-01, 2.715535e-01, + 2.751892e-01, 2.788175e-01, 2.824383e-01, 2.860514e-01, + 2.896569e-01, 2.932547e-01, 2.968447e-01, 3.004268e-01, + 3.040009e-01, 3.075671e-01, 3.111252e-01, 3.146752e-01, + 3.182170e-01, 3.217506e-01, 3.252758e-01, 3.287927e-01, + 3.323012e-01, 3.358012e-01, 3.392926e-01, 3.427755e-01, + 3.462497e-01, 3.497153e-01, 3.531721e-01, 3.566201e-01, + 3.600593e-01, 3.634896e-01, 3.669110e-01, 3.703234e-01, + 3.737268e-01, 3.771211e-01, 3.805064e-01, 3.838825e-01, + 3.872494e-01, 3.906070e-01, 3.939555e-01, 3.972946e-01, + 4.006244e-01, 4.039448e-01, 4.072558e-01, 4.105574e-01, + 4.138496e-01, 4.171322e-01, 4.204054e-01, 4.236689e-01, + 4.269229e-01, 4.301673e-01, 4.334021e-01, 4.366272e-01, + 4.398426e-01, 4.430483e-01, 4.462443e-01, 4.494306e-01, + 4.526070e-01, 4.557738e-01, 4.589307e-01, 4.620778e-01, + 4.652150e-01, 4.683424e-01, 4.714600e-01, 4.745676e-01, + 4.776654e-01, 4.807532e-01, 4.838312e-01, 4.868992e-01, + 4.899573e-01, 4.930055e-01, 4.960437e-01, 4.990719e-01, + 5.020902e-01, 5.050985e-01, 5.080968e-01, 5.110852e-01, + 5.140636e-01, 5.170320e-01, 5.199904e-01, 5.229388e-01, + 5.258772e-01, 5.288056e-01, 5.317241e-01, 5.346325e-01, + 5.375310e-01, 5.404195e-01, 5.432980e-01, 5.461666e-01, + 5.490251e-01, 5.518738e-01, 5.547124e-01, 5.575411e-01, + 5.603599e-01, 5.631687e-01, 5.659676e-01, 5.687566e-01, + 5.715357e-01, 5.743048e-01, 5.770641e-01, 5.798135e-01, + 5.825531e-01, 5.852828e-01, 5.880026e-01, 5.907126e-01, + 5.934128e-01, 5.961032e-01, 5.987839e-01, 6.014547e-01, + 6.041158e-01, 6.067672e-01, 6.094088e-01, 6.120407e-01, + 6.146630e-01, 6.172755e-01, 6.198784e-01, 6.224717e-01, + 6.250554e-01, 6.276294e-01, 6.301939e-01, 6.327488e-01, + 6.352942e-01, 6.378301e-01, 6.403565e-01, 6.428734e-01, + 6.453808e-01, 6.478788e-01, 6.503674e-01, 6.528466e-01, + 6.553165e-01, 6.577770e-01, 6.602282e-01, 6.626701e-01, + 6.651027e-01, 6.675261e-01, 6.699402e-01, 6.723452e-01, + 6.747409e-01, 6.771276e-01, 6.795051e-01, 6.818735e-01, + 6.842328e-01, 6.865831e-01, 6.889244e-01, 6.912567e-01, + 6.935800e-01, 6.958943e-01, 6.981998e-01, 7.004964e-01, + 7.027841e-01, 7.050630e-01, 7.073330e-01, 7.095943e-01, + 7.118469e-01, 7.140907e-01, 7.163258e-01, 7.185523e-01, + 7.207701e-01, 7.229794e-01, 7.251800e-01, 7.273721e-01, + 7.295557e-01, 7.317307e-01, 7.338974e-01, 7.360555e-01, + 7.382053e-01, 7.403467e-01, 7.424797e-01, 7.446045e-01, + 7.467209e-01, 7.488291e-01, 7.509291e-01, 7.530208e-01, + 7.551044e-01, 7.571798e-01, 7.592472e-01, 7.613064e-01, + 7.633576e-01, 7.654008e-01, 7.674360e-01, 7.694633e-01, + 7.714826e-01, 7.734940e-01, 7.754975e-01, 7.774932e-01, + 7.794811e-01, 7.814612e-01, 7.834335e-01, 7.853983e-01, + 7.853983e-01 + }; + + +/***************************************************************************** +Function: Arc tangent + +Syntax: angle = fast_atan2(y, x); +REAL y y component of input vector +REAL x x component of input vector +REAL angle angle of vector (x, y) in radians + +Description: This function calculates the angle of the vector (x,y) based +on a table lookup and linear interpolation. The table uses +a 256 point table covering -45 to +45 degrees and uses +symetry to determine the final angle value in the range of +-180 to 180 degrees. Note that this function uses the small +angle approximation for values close to zero. This routine +calculates the arc tangent with an average error of ++/- 0.045 degrees. +*****************************************************************************/ + +REAL +gr_fast_atan2f(REAL y, REAL x) +{ + REAL x_abs, y_abs, z; + REAL alpha, angle, base_angle; + int index; + + /* don't divide by zero! */ // FIXME could get hosed with -0.0 + if ((y == 0.0) && (x == 0.0)) + return 0.0; + + /* normalize to +/- 45 degree range */ + y_abs = fabs(y); + x_abs = fabs(x); + //z = (y_abs < x_abs ? y_abs / x_abs : x_abs / y_abs); + if (y_abs < x_abs) + z = y_abs / x_abs; + else + z = x_abs / y_abs; + + /* when ratio approaches the table resolution, the angle is */ + /* best approximated with the argument itself... */ + if (z < TAN_MAP_RES) + base_angle = z; + else { + /* find index and interpolation value */ + alpha = z * (REAL) TAN_MAP_SIZE - .5; + index = (int) alpha; + alpha -= (REAL) index; + /* determine base angle based on quadrant and */ + /* add or subtract table value from base angle based on quadrant */ + base_angle = fast_atan_table[index]; + base_angle += + (fast_atan_table[index + 1] - fast_atan_table[index]) * alpha; + } + + if (x_abs > y_abs) { /* -45 -> 45 or 135 -> 225 */ + if (x >= 0.0) { /* -45 -> 45 */ + if (y >= 0.0) + angle = base_angle; /* 0 -> 45, angle OK */ + else + angle = -base_angle; /* -45 -> 0, angle = -angle */ + } else { /* 135 -> 180 or 180 -> -135 */ + angle = 3.14159265358979323846; + if (y >= 0.0) + angle -= base_angle; /* 135 -> 180, angle = 180 - angle */ + else + angle = base_angle - angle; /* 180 -> -135, angle = angle - 180 */ + } + } else { /* 45 -> 135 or -135 -> -45 */ + if (y >= 0.0) { /* 45 -> 135 */ + angle = 1.57079632679489661923; + if (x >= 0.0) + angle -= base_angle; /* 45 -> 90, angle = 90 - angle */ + else + angle += base_angle; /* 90 -> 135, angle = 90 + angle */ + } else { /* -135 -> -45 */ + angle = -1.57079632679489661923; + if (x >= 0.0) + angle += base_angle; /* -90 -> -45, angle = -90 + angle */ + else + angle -= base_angle; /* -135 -> -90, angle = -90 - angle */ + } + } + +#ifdef ZERO_TO_TWOPI + if (angle < 0) + return (angle + TWOPI); + else + return (angle); +#else + return (angle); +#endif +} + diff --git a/gnuradio-runtime/lib/gr_feval.cc b/gnuradio-runtime/lib/gr_feval.cc new file mode 100644 index 0000000000..89f09984cf --- /dev/null +++ b/gnuradio-runtime/lib/gr_feval.cc @@ -0,0 +1,132 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 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 <gr_feval.h> + +gr_feval_dd::~gr_feval_dd(){} + +double +gr_feval_dd::eval(double x) +{ + return 0; +} + +double +gr_feval_dd::calleval(double x) +{ + return eval(x); +} + +// ---------------------------------------------------------------- + +gr_feval_cc::~gr_feval_cc(){} + +gr_complex +gr_feval_cc::eval(gr_complex x) +{ + return 0; +} + +gr_complex +gr_feval_cc::calleval(gr_complex x) +{ + return eval(x); +} + +// ---------------------------------------------------------------- + +gr_feval_ll::~gr_feval_ll(){} + +long +gr_feval_ll::eval(long x) +{ + return 0; +} + +long +gr_feval_ll::calleval(long x) +{ + return eval(x); +} + +// ---------------------------------------------------------------- + +gr_feval::~gr_feval(){} + +void +gr_feval::eval(void) +{ + // nop +} + +void +gr_feval::calleval(void) +{ + eval(); +} + +// ---------------------------------------------------------------- + +gr_feval_p::~gr_feval_p(){} + +void +gr_feval_p::eval(pmt::pmt_t x) +{ + // nop +} + +void +gr_feval_p::calleval(pmt::pmt_t x) +{ + eval(x); +} + +/* + * Trivial examples showing C++ (transparently) calling Python + */ +double +gr_feval_dd_example(gr_feval_dd *f, double x) +{ + return f->calleval(x); +} + +gr_complex +gr_feval_cc_example(gr_feval_cc *f, gr_complex x) +{ + return f->calleval(x); +} + +long +gr_feval_ll_example(gr_feval_ll *f, long x) +{ + return f->calleval(x); +} + +void +gr_feval_example(gr_feval *f) +{ + f->calleval(); +} diff --git a/gnuradio-runtime/lib/gr_flat_flowgraph.cc b/gnuradio-runtime/lib/gr_flat_flowgraph.cc new file mode 100644 index 0000000000..de1e227ef0 --- /dev/null +++ b/gnuradio-runtime/lib/gr_flat_flowgraph.cc @@ -0,0 +1,427 @@ +/* -*- c++ -*- */ +/* + * Copyright 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_flat_flowgraph.h> +#include <gr_block_detail.h> +#include <gr_io_signature.h> +#include <gr_buffer.h> +#include <gr_prefs.h> +#include <volk/volk.h> +#include <iostream> +#include <map> +#include <boost/format.hpp> + +#define GR_FLAT_FLOWGRAPH_DEBUG 0 + +// 32Kbyte buffer size between blocks +#define GR_FIXED_BUFFER_SIZE (32*(1L<<10)) + +static const unsigned int s_fixed_buffer_size = GR_FIXED_BUFFER_SIZE; + +gr_flat_flowgraph_sptr +gr_make_flat_flowgraph() +{ + return gr_flat_flowgraph_sptr(new gr_flat_flowgraph()); +} + +gr_flat_flowgraph::gr_flat_flowgraph() +{ +} + +gr_flat_flowgraph::~gr_flat_flowgraph() +{ +} + +void +gr_flat_flowgraph::setup_connections() +{ + gr_basic_block_vector_t blocks = calc_used_blocks(); + + // Assign block details to blocks + for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) + cast_to_block_sptr(*p)->set_detail(allocate_block_detail(*p)); + + // Connect inputs to outputs for each block + for(gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { + connect_block_inputs(*p); + + gr_block_sptr block = cast_to_block_sptr(*p); + block->set_unaligned(0); + block->set_is_unaligned(false); + } + + // Connect message ports connetions + for(gr_msg_edge_viter_t i = d_msg_edges.begin(); i != d_msg_edges.end(); i++){ + if(GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << boost::format("flat_fg connecting msg primitives: (%s, %s)->(%s, %s)\n") % + i->src().block() % i->src().port() % + i->dst().block() % i->dst().port(); + i->src().block()->message_port_sub( i->src().port(), pmt::cons(i->dst().block()->alias_pmt(), i->dst().port()) ); + } + +} + +gr_block_detail_sptr +gr_flat_flowgraph::allocate_block_detail(gr_basic_block_sptr block) +{ + int ninputs = calc_used_ports(block, true).size(); + int noutputs = calc_used_ports(block, false).size(); + gr_block_detail_sptr detail = gr_make_block_detail(ninputs, noutputs); + + gr_block_sptr grblock = cast_to_block_sptr(block); + if(!grblock) + throw std::runtime_error("allocate_block_detail found non-gr_block"); + + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "Creating block detail for " << block << std::endl; + + for (int i = 0; i < noutputs; i++) { + grblock->expand_minmax_buffer(i); + + gr_buffer_sptr buffer = allocate_buffer(block, i); + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "Allocated buffer for output " << block << ":" << i << std::endl; + detail->set_output(i, buffer); + + // Update the block's max_output_buffer based on what was actually allocated. + grblock->set_max_output_buffer(i, buffer->bufsize()); + } + + return detail; +} + +gr_buffer_sptr +gr_flat_flowgraph::allocate_buffer(gr_basic_block_sptr block, int port) +{ + gr_block_sptr grblock = cast_to_block_sptr(block); + if (!grblock) + throw std::runtime_error("allocate_buffer found non-gr_block"); + int item_size = block->output_signature()->sizeof_stream_item(port); + + // *2 because we're now only filling them 1/2 way in order to + // increase the available parallelism when using the TPB scheduler. + // (We're double buffering, where we used to single buffer) + int nitems = s_fixed_buffer_size * 2 / item_size; + + // Make sure there are at least twice the output_multiple no. of items + if (nitems < 2*grblock->output_multiple()) // Note: this means output_multiple() + nitems = 2*grblock->output_multiple(); // can't be changed by block dynamically + + // If any downstream blocks are decimators and/or have a large output_multiple, + // ensure we have a buffer at least twice their decimation factor*output_multiple + gr_basic_block_vector_t blocks = calc_downstream_blocks(block, port); + + // limit buffer size if indicated + if(grblock->max_output_buffer(port) > 0) { +// std::cout << "constraining output items to " << block->max_output_buffer(port) << "\n"; + nitems = std::min((long)nitems, (long)grblock->max_output_buffer(port)); + nitems -= nitems%grblock->output_multiple(); + if( nitems < 1 ) + throw std::runtime_error("problems allocating a buffer with the given max output buffer constraint!"); + } + else if(grblock->min_output_buffer(port) > 0) { + nitems = std::max((long)nitems, (long)grblock->min_output_buffer(port)); + nitems -= nitems%grblock->output_multiple(); + if( nitems < 1 ) + throw std::runtime_error("problems allocating a buffer with the given min output buffer constraint!"); + } + + for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { + gr_block_sptr dgrblock = cast_to_block_sptr(*p); + if (!dgrblock) + throw std::runtime_error("allocate_buffer found non-gr_block"); + + double decimation = (1.0/dgrblock->relative_rate()); + int multiple = dgrblock->output_multiple(); + int history = dgrblock->history(); + nitems = std::max(nitems, static_cast<int>(2*(decimation*multiple+history))); + } + +// std::cout << "gr_make_buffer(" << nitems << ", " << item_size << ", " << grblock << "\n"; + return gr_make_buffer(nitems, item_size, grblock); +} + +void +gr_flat_flowgraph::connect_block_inputs(gr_basic_block_sptr block) +{ + gr_block_sptr grblock = cast_to_block_sptr(block); + if (!grblock) + throw std::runtime_error("connect_block_inputs found non-gr_block"); + + // Get its detail and edges that feed into it + gr_block_detail_sptr detail = grblock->detail(); + gr_edge_vector_t in_edges = calc_upstream_edges(block); + + // For each edge that feeds into it + for (gr_edge_viter_t e = in_edges.begin(); e != in_edges.end(); e++) { + // Set the buffer reader on the destination port to the output + // buffer on the source port + int dst_port = e->dst().port(); + int src_port = e->src().port(); + gr_basic_block_sptr src_block = e->src().block(); + gr_block_sptr src_grblock = cast_to_block_sptr(src_block); + if (!src_grblock) + throw std::runtime_error("connect_block_inputs found non-gr_block"); + gr_buffer_sptr src_buffer = src_grblock->detail()->output(src_port); + + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "Setting input " << dst_port << " from edge " << (*e) << std::endl; + + detail->set_input(dst_port, gr_buffer_add_reader(src_buffer, grblock->history()-1, grblock)); + } +} + +void +gr_flat_flowgraph::merge_connections(gr_flat_flowgraph_sptr old_ffg) +{ + // Allocate block details if needed. Only new blocks that aren't pruned out + // by flattening will need one; existing blocks still in the new flowgraph will + // already have one. + for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { + gr_block_sptr block = cast_to_block_sptr(*p); + + if (!block->detail()) { + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "merge: allocating new detail for block " << (*p) << std::endl; + block->set_detail(allocate_block_detail(block)); + } + else + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "merge: reusing original detail for block " << (*p) << std::endl; + } + + // Calculate the old edges that will be going away, and clear the buffer readers + // on the RHS. + for (gr_edge_viter_t old_edge = old_ffg->d_edges.begin(); old_edge != old_ffg->d_edges.end(); old_edge++) { + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "merge: testing old edge " << (*old_edge) << "..."; + + gr_edge_viter_t new_edge; + for (new_edge = d_edges.begin(); new_edge != d_edges.end(); new_edge++) + if (new_edge->src() == old_edge->src() && + new_edge->dst() == old_edge->dst()) + break; + + if (new_edge == d_edges.end()) { // not found in new edge list + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "not in new edge list" << std::endl; + // zero the buffer reader on RHS of old edge + gr_block_sptr block(cast_to_block_sptr(old_edge->dst().block())); + int port = old_edge->dst().port(); + block->detail()->set_input(port, gr_buffer_reader_sptr()); + } + else { + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "found in new edge list" << std::endl; + } + } + + // Now connect inputs to outputs, reusing old buffer readers if they exist + for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { + gr_block_sptr block = cast_to_block_sptr(*p); + + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "merge: merging " << (*p) << "..."; + + if (old_ffg->has_block_p(*p)) { + // Block exists in old flow graph + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "used in old flow graph" << std::endl; + gr_block_detail_sptr detail = block->detail(); + + // Iterate through the inputs and see what needs to be done + int ninputs = calc_used_ports(block, true).size(); // Might be different now + for (int i = 0; i < ninputs; i++) { + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "Checking input " << block << ":" << i << "..."; + gr_edge edge = calc_upstream_edge(*p, i); + + // Fish out old buffer reader and see if it matches correct buffer from edge list + gr_block_sptr src_block = cast_to_block_sptr(edge.src().block()); + gr_block_detail_sptr src_detail = src_block->detail(); + gr_buffer_sptr src_buffer = src_detail->output(edge.src().port()); + gr_buffer_reader_sptr old_reader; + if (i < detail->ninputs()) // Don't exceed what the original detail has + old_reader = detail->input(i); + + // If there's a match, use it + if (old_reader && (src_buffer == old_reader->buffer())) { + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "matched, reusing" << std::endl; + } + else { + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "needs a new reader" << std::endl; + + // Create new buffer reader and assign + detail->set_input(i, gr_buffer_add_reader(src_buffer, block->history()-1, block)); + } + } + } + else { + // Block is new, it just needs buffer readers at this point + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "new block" << std::endl; + connect_block_inputs(block); + + // Make sure all buffers are aligned + setup_buffer_alignment(block); + } + + // Now deal with the fact that the block details might have changed numbers of + // inputs and outputs vs. in the old flowgraph. + } +} + +void +gr_flat_flowgraph::setup_buffer_alignment(gr_block_sptr block) +{ + const int alignment = volk_get_alignment(); + for(int i = 0; i < block->detail()->ninputs(); i++) { + void *r = (void*)block->detail()->input(i)->read_pointer(); + unsigned long int ri = (unsigned long int)r % alignment; + //std::cerr << "reader: " << r << " alignment: " << ri << std::endl; + if(ri != 0) { + size_t itemsize = block->detail()->input(i)->get_sizeof_item(); + block->detail()->input(i)->update_read_pointer(alignment-ri/itemsize); + } + block->set_unaligned(0); + block->set_is_unaligned(false); + } + + for(int i = 0; i < block->detail()->noutputs(); i++) { + void *w = (void*)block->detail()->output(i)->write_pointer(); + unsigned long int wi = (unsigned long int)w % alignment; + //std::cerr << "writer: " << w << " alignment: " << wi << std::endl; + if(wi != 0) { + size_t itemsize = block->detail()->output(i)->get_sizeof_item(); + block->detail()->output(i)->update_write_pointer(alignment-wi/itemsize); + } + block->set_unaligned(0); + block->set_is_unaligned(false); + } +} + +std::string +gr_flat_flowgraph::edge_list() +{ + std::stringstream s; + for(gr_edge_viter_t e = d_edges.begin(); e != d_edges.end(); e++) + s << (*e) << std::endl; + return s.str(); +} + +void gr_flat_flowgraph::dump() +{ + for (gr_edge_viter_t e = d_edges.begin(); e != d_edges.end(); e++) + std::cout << " edge: " << (*e) << std::endl; + + for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { + std::cout << " block: " << (*p) << std::endl; + gr_block_detail_sptr detail = cast_to_block_sptr(*p)->detail(); + std::cout << " detail @" << detail << ":" << std::endl; + + int ni = detail->ninputs(); + int no = detail->noutputs(); + for (int i = 0; i < no; i++) { + gr_buffer_sptr buffer = detail->output(i); + std::cout << " output " << i << ": " << buffer << std::endl; + } + + for (int i = 0; i < ni; i++) { + gr_buffer_reader_sptr reader = detail->input(i); + std::cout << " reader " << i << ": " << reader + << " reading from buffer=" << reader->buffer() << std::endl; + } + } + +} + +gr_block_vector_t +gr_flat_flowgraph::make_block_vector(gr_basic_block_vector_t &blocks) +{ + gr_block_vector_t result; + for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { + result.push_back(cast_to_block_sptr(*p)); + } + + return result; +} + + +void gr_flat_flowgraph::clear_endpoint(const gr_msg_endpoint &e, bool is_src){ + for(size_t i=0; i<d_msg_edges.size(); i++){ + if(is_src){ + if(d_msg_edges[i].src() == e){ + d_msg_edges.erase(d_msg_edges.begin() + i); + i--; + } + } else { + if(d_msg_edges[i].dst() == e){ + d_msg_edges.erase(d_msg_edges.begin() + i); + i--; + } + } + } +} + +void gr_flat_flowgraph::replace_endpoint(const gr_msg_endpoint &e, const gr_msg_endpoint &r, bool is_src){ + size_t n_replr(0); + if(GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << boost::format("gr_flat_flowgraph::replace_endpoint( %s, %s, %d )\n") % e.block()% r.block()% is_src; + for(size_t i=0; i<d_msg_edges.size(); i++){ + if(is_src){ + if(d_msg_edges[i].src() == e){ + if(GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << boost::format("gr_flat_flowgraph::replace_endpoint() flattening to ( %s, %s )\n") % r.block()% d_msg_edges[i].dst().block(); + d_msg_edges.push_back( gr_msg_edge(r, d_msg_edges[i].dst() ) ); + n_replr++; + } + } else { + if(d_msg_edges[i].dst() == e){ + if(GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << boost::format("gr_flat_flowgraph::replace_endpoint() flattening to ( %s, %s )\n") % r.block()% d_msg_edges[i].dst().block(); + d_msg_edges.push_back( gr_msg_edge(d_msg_edges[i].src(), r ) ); + n_replr++; + } + } + } +} + +void +gr_flat_flowgraph::enable_pc_rpc() +{ +#ifdef GR_PERFORMANCE_COUNTERS + if(gr_prefs::singleton()->get_bool("PerfCounters", "on", false)) { + gr_basic_block_viter_t p; + for(p = d_blocks.begin(); p != d_blocks.end(); p++) { + gr_block_sptr block = cast_to_block_sptr(*p); + if(!block->is_pc_rpc_set()) + block->setup_pc_rpc(); + } + } +#endif /* GR_PERFORMANCE_COUNTERS */ +} diff --git a/gnuradio-runtime/lib/gr_flat_flowgraph.h b/gnuradio-runtime/lib/gr_flat_flowgraph.h new file mode 100644 index 0000000000..9c47a77e23 --- /dev/null +++ b/gnuradio-runtime/lib/gr_flat_flowgraph.h @@ -0,0 +1,89 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,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. + */ + +#ifndef INCLUDED_GR_FLAT_FLOWGRAPH_H +#define INCLUDED_GR_FLAT_FLOWGRAPH_H + +#include <gr_runtime_api.h> +#include <gr_flowgraph.h> +#include <gr_block.h> + +// Create a shared pointer to a heap allocated gr_flat_flowgraph +// (types defined in gr_runtime_types.h) +GR_RUNTIME_API gr_flat_flowgraph_sptr gr_make_flat_flowgraph(); + +/*! + *\brief Class specializing gr_flat_flowgraph that has all nodes + * as gr_blocks, with no hierarchy + * \ingroup internal + */ +class GR_RUNTIME_API gr_flat_flowgraph : public gr_flowgraph +{ +public: + friend GR_RUNTIME_API gr_flat_flowgraph_sptr gr_make_flat_flowgraph(); + + // Destruct an arbitrary gr_flat_flowgraph + ~gr_flat_flowgraph(); + + // Wire gr_blocks together in new flat_flowgraph + void setup_connections(); + + // Merge applicable connections from existing flat flowgraph + void merge_connections(gr_flat_flowgraph_sptr sfg); + + // Return a string list of edges + std::string edge_list(); + + void dump(); + + /*! + * Make a vector of gr_block from a vector of gr_basic_block + */ + static gr_block_vector_t make_block_vector(gr_basic_block_vector_t &blocks); + + void replace_endpoint(const gr_msg_endpoint &e, const gr_msg_endpoint &r, bool is_src); + void clear_endpoint(const gr_msg_endpoint &e, bool is_src); + + /*! + * Enables export of perf. counters to ControlPort on all blocks in + * the flowgraph. + */ + void enable_pc_rpc(); + +private: + gr_flat_flowgraph(); + + gr_block_detail_sptr allocate_block_detail(gr_basic_block_sptr block); + gr_buffer_sptr allocate_buffer(gr_basic_block_sptr block, int port); + void connect_block_inputs(gr_basic_block_sptr block); + + /* When reusing a flowgraph's blocks, this call makes sure all of the + * buffer's are aligned at the machine's alignment boundary and tells + * the blocks that they are aligned. + * + * Called from both setup_connections and merge_connections for + * start and restarts. + */ + void setup_buffer_alignment(gr_block_sptr block); +}; + +#endif /* INCLUDED_GR_FLAT_FLOWGRAPH_H */ diff --git a/gnuradio-runtime/lib/gr_flowgraph.cc b/gnuradio-runtime/lib/gr_flowgraph.cc new file mode 100644 index 0000000000..63a2084802 --- /dev/null +++ b/gnuradio-runtime/lib/gr_flowgraph.cc @@ -0,0 +1,515 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_flowgraph.h> +#include <gr_io_signature.h> +#include <stdexcept> +#include <sstream> +#include <iterator> + +#define GR_FLOWGRAPH_DEBUG 0 + +gr_edge::~gr_edge() +{ +} + +gr_flowgraph_sptr gr_make_flowgraph() +{ + return gr_flowgraph_sptr(new gr_flowgraph()); +} + +gr_flowgraph::gr_flowgraph() +{ +} + +gr_flowgraph::~gr_flowgraph() +{ +} + +// FIXME: move to libgruel as a utility function +template<class T> +static +std::vector<T> +unique_vector(std::vector<T> v) +{ + std::vector<T> result; + std::insert_iterator<std::vector<T> > inserter(result, result.begin()); + + sort(v.begin(), v.end()); + unique_copy(v.begin(), v.end(), inserter); + return result; +} + +void +gr_flowgraph::connect(const gr_endpoint &src, const gr_endpoint &dst) +{ + check_valid_port(src.block()->output_signature(), src.port()); + check_valid_port(dst.block()->input_signature(), dst.port()); + check_dst_not_used(dst); + check_type_match(src, dst); + + // All ist klar, Herr Kommisar + d_edges.push_back(gr_edge(src,dst)); +} + +void +gr_flowgraph::disconnect(const gr_endpoint &src, const gr_endpoint &dst) +{ + for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { + if (src == p->src() && dst == p->dst()) { + d_edges.erase(p); + return; + } + } + + std::stringstream msg; + msg << "cannot disconnect edge " << gr_edge(src, dst) << ", not found"; + throw std::invalid_argument(msg.str()); +} + +void +gr_flowgraph::validate() +{ + d_blocks = calc_used_blocks(); + + for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { + std::vector<int> used_ports; + int ninputs, noutputs; + + if (GR_FLOWGRAPH_DEBUG) + std::cout << "Validating block: " << (*p) << std::endl; + + used_ports = calc_used_ports(*p, true); // inputs + ninputs = used_ports.size(); + check_contiguity(*p, used_ports, true); // inputs + + used_ports = calc_used_ports(*p, false); // outputs + noutputs = used_ports.size(); + check_contiguity(*p, used_ports, false); // outputs + + if (!((*p)->check_topology(ninputs, noutputs))) { + std::stringstream msg; + msg << "check topology failed on " << (*p) + << " using ninputs=" << ninputs + << ", noutputs=" << noutputs; + throw std::runtime_error(msg.str()); + } + } +} + +void +gr_flowgraph::clear() +{ + // Boost shared pointers will deallocate as needed + d_blocks.clear(); + d_edges.clear(); +} + +void +gr_flowgraph::check_valid_port(gr_io_signature_sptr sig, int port) +{ + std::stringstream msg; + + if (port < 0) { + msg << "negative port number " << port << " is invalid"; + throw std::invalid_argument(msg.str()); + } + + int max = sig->max_streams(); + if (max != gr_io_signature::IO_INFINITE && port >= max) { + msg << "port number " << port << " exceeds max of "; + if (max == 0) + msg << "(none)"; + else + msg << max-1; + throw std::invalid_argument(msg.str()); + } +} + +void +gr_flowgraph::check_valid_port(const gr_msg_endpoint &e) +{ + if (GR_FLOWGRAPH_DEBUG) + std::cout << "check_valid_port( " << e.block() << ", " << e.port() << ")\n"; + + if(!e.block()->has_msg_port(e.port())) + throw std::invalid_argument("invalid msg port in connect() or disconnect()"); +} + +void +gr_flowgraph::check_dst_not_used(const gr_endpoint &dst) +{ + // A destination is in use if it is already on the edge list + for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) + if (p->dst() == dst) { + std::stringstream msg; + msg << "destination already in use by edge " << (*p); + throw std::invalid_argument(msg.str()); + } +} + +void +gr_flowgraph::check_type_match(const gr_endpoint &src, const gr_endpoint &dst) +{ + int src_size = src.block()->output_signature()->sizeof_stream_item(src.port()); + int dst_size = dst.block()->input_signature()->sizeof_stream_item(dst.port()); + + if (src_size != dst_size) { + std::stringstream msg; + msg << "itemsize mismatch: " << src << " using " << src_size + << ", " << dst << " using " << dst_size; + throw std::invalid_argument(msg.str()); + } +} + +gr_basic_block_vector_t +gr_flowgraph::calc_used_blocks() +{ + gr_basic_block_vector_t tmp; + + // make sure free standing message blocks are included + for (gr_msg_edge_viter_t p = d_msg_edges.begin(); p != d_msg_edges.end(); p++) { +// for now only blocks receiving messages get a thread context - uncomment to allow senders to also obtain one +// tmp.push_back(p->src().block()); + tmp.push_back(p->dst().block()); + } + + // Collect all blocks in the edge list + for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { + tmp.push_back(p->src().block()); + tmp.push_back(p->dst().block()); + } + + return unique_vector<gr_basic_block_sptr>(tmp); +} + +std::vector<int> +gr_flowgraph::calc_used_ports(gr_basic_block_sptr block, bool check_inputs) +{ + std::vector<int> tmp; + + // Collect all seen ports + gr_edge_vector_t edges = calc_connections(block, check_inputs); + for (gr_edge_viter_t p = edges.begin(); p != edges.end(); p++) { + if (check_inputs == true) + tmp.push_back(p->dst().port()); + else + tmp.push_back(p->src().port()); + } + + return unique_vector<int>(tmp); +} + +gr_edge_vector_t +gr_flowgraph::calc_connections(gr_basic_block_sptr block, bool check_inputs) +{ + gr_edge_vector_t result; + + for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { + if (check_inputs) { + if (p->dst().block() == block) + result.push_back(*p); + } + else { + if (p->src().block() == block) + result.push_back(*p); + } + } + + return result; // assumes no duplicates +} + +void +gr_flowgraph::check_contiguity(gr_basic_block_sptr block, + const std::vector<int> &used_ports, + bool check_inputs) +{ + std::stringstream msg; + + gr_io_signature_sptr sig = + check_inputs ? block->input_signature() : block->output_signature(); + + int nports = used_ports.size(); + int min_ports = sig->min_streams(); + int max_ports = sig->max_streams(); + + if (nports == 0 && min_ports == 0) + return; + + if (nports < min_ports) { + msg << block << ": insufficient connected " + << (check_inputs ? "input ports " : "output ports ") + << "(" << min_ports << " needed, " << nports << " connected)"; + throw std::runtime_error(msg.str()); + } + + if (nports > max_ports && max_ports != gr_io_signature::IO_INFINITE) { + msg << block << ": too many connected " + << (check_inputs ? "input ports " : "output ports ") + << "(" << max_ports << " allowed, " << nports << " connected)"; + throw std::runtime_error(msg.str()); + } + + if (used_ports[nports-1]+1 != nports) { + for (int i = 0; i < nports; i++) { + if (used_ports[i] != i) { + msg << block << ": missing connection " + << (check_inputs ? "to input port " : "from output port ") + << i; + throw std::runtime_error(msg.str()); + } + } + } +} + +gr_basic_block_vector_t +gr_flowgraph::calc_downstream_blocks(gr_basic_block_sptr block, int port) +{ + gr_basic_block_vector_t tmp; + + for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) + if (p->src() == gr_endpoint(block, port)) + tmp.push_back(p->dst().block()); + + return unique_vector<gr_basic_block_sptr>(tmp); +} + +gr_basic_block_vector_t +gr_flowgraph::calc_downstream_blocks(gr_basic_block_sptr block) +{ + gr_basic_block_vector_t tmp; + + for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) + if (p->src().block() == block) + tmp.push_back(p->dst().block()); + + return unique_vector<gr_basic_block_sptr>(tmp); +} + +gr_edge_vector_t +gr_flowgraph::calc_upstream_edges(gr_basic_block_sptr block) +{ + gr_edge_vector_t result; + + for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) + if (p->dst().block() == block) + result.push_back(*p); + + return result; // Assume no duplicates +} + +bool +gr_flowgraph::has_block_p(gr_basic_block_sptr block) +{ + gr_basic_block_viter_t result; + result = std::find(d_blocks.begin(), d_blocks.end(), block); + return (result != d_blocks.end()); +} + +gr_edge +gr_flowgraph::calc_upstream_edge(gr_basic_block_sptr block, int port) +{ + gr_edge result; + + for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { + if (p->dst() == gr_endpoint(block, port)) { + result = (*p); + break; + } + } + + return result; +} + +std::vector<gr_basic_block_vector_t> +gr_flowgraph::partition() +{ + std::vector<gr_basic_block_vector_t> result; + gr_basic_block_vector_t blocks = calc_used_blocks(); + gr_basic_block_vector_t graph; + + while (blocks.size() > 0) { + graph = calc_reachable_blocks(blocks[0], blocks); + assert(graph.size()); + result.push_back(topological_sort(graph)); + + for (gr_basic_block_viter_t p = graph.begin(); p != graph.end(); p++) + blocks.erase(find(blocks.begin(), blocks.end(), *p)); + } + + return result; +} + +gr_basic_block_vector_t +gr_flowgraph::calc_reachable_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks) +{ + gr_basic_block_vector_t result; + + // Mark all blocks as unvisited + for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) + (*p)->set_color(gr_basic_block::WHITE); + + // Recursively mark all reachable blocks + reachable_dfs_visit(block, blocks); + + // Collect all the blocks that have been visited + for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) + if ((*p)->color() == gr_basic_block::BLACK) + result.push_back(*p); + + return result; +} + +// Recursively mark all reachable blocks from given block and block list +void +gr_flowgraph::reachable_dfs_visit(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks) +{ + // Mark the current one as visited + block->set_color(gr_basic_block::BLACK); + + // Recurse into adjacent vertices + gr_basic_block_vector_t adjacent = calc_adjacent_blocks(block, blocks); + + for (gr_basic_block_viter_t p = adjacent.begin(); p != adjacent.end(); p++) + if ((*p)->color() == gr_basic_block::WHITE) + reachable_dfs_visit(*p, blocks); +} + +// Return a list of block adjacent to a given block along any edge +gr_basic_block_vector_t +gr_flowgraph::calc_adjacent_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks) +{ + gr_basic_block_vector_t tmp; + + // Find any blocks that are inputs or outputs + for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { + if (p->src().block() == block) + tmp.push_back(p->dst().block()); + if (p->dst().block() == block) + tmp.push_back(p->src().block()); + } + + return unique_vector<gr_basic_block_sptr>(tmp); +} + +gr_basic_block_vector_t +gr_flowgraph::topological_sort(gr_basic_block_vector_t &blocks) +{ + gr_basic_block_vector_t tmp; + gr_basic_block_vector_t result; + tmp = sort_sources_first(blocks); + + // Start 'em all white + for (gr_basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++) + (*p)->set_color(gr_basic_block::WHITE); + + for (gr_basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++) { + if ((*p)->color() == gr_basic_block::WHITE) + topological_dfs_visit(*p, result); + } + + reverse(result.begin(), result.end()); + return result; +} + +gr_basic_block_vector_t +gr_flowgraph::sort_sources_first(gr_basic_block_vector_t &blocks) +{ + gr_basic_block_vector_t sources, nonsources, result; + + for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { + if (source_p(*p)) + sources.push_back(*p); + else + nonsources.push_back(*p); + } + + for (gr_basic_block_viter_t p = sources.begin(); p != sources.end(); p++) + result.push_back(*p); + + for (gr_basic_block_viter_t p = nonsources.begin(); p != nonsources.end(); p++) + result.push_back(*p); + + return result; +} + +bool +gr_flowgraph::source_p(gr_basic_block_sptr block) +{ + return (calc_upstream_edges(block).size() == 0); +} + +void +gr_flowgraph::topological_dfs_visit(gr_basic_block_sptr block, gr_basic_block_vector_t &output) +{ + block->set_color(gr_basic_block::GREY); + gr_basic_block_vector_t blocks(calc_downstream_blocks(block)); + + for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { + switch ((*p)->color()) { + case gr_basic_block::WHITE: + topological_dfs_visit(*p, output); + break; + + case gr_basic_block::GREY: + throw std::runtime_error("flow graph has loops!"); + + case gr_basic_block::BLACK: + continue; + + default: + throw std::runtime_error("invalid color on block!"); + } + } + + block->set_color(gr_basic_block::BLACK); + output.push_back(block); +} + +void gr_flowgraph::connect(const gr_msg_endpoint &src, const gr_msg_endpoint &dst){ + check_valid_port(src); + check_valid_port(dst); + for (gr_msg_edge_viter_t p = d_msg_edges.begin(); p != d_msg_edges.end(); p++) { + if(p->src() == src && p->dst() == dst){ + throw std::runtime_error("connect called on already connected edge!"); + } + } + d_msg_edges.push_back(gr_msg_edge(src,dst)); +} + +void gr_flowgraph::disconnect(const gr_msg_endpoint &src, const gr_msg_endpoint &dst){ + check_valid_port(src); + check_valid_port(dst); + for (gr_msg_edge_viter_t p = d_msg_edges.begin(); p != d_msg_edges.end(); p++) { + if(p->src() == src && p->dst() == dst){ + d_msg_edges.erase(p); + return; + } + } + throw std::runtime_error("disconnect called on non-connected edge!"); +} + + diff --git a/gnuradio-runtime/lib/gr_fxpt.cc b/gnuradio-runtime/lib/gr_fxpt.cc new file mode 100644 index 0000000000..2ea8520e6b --- /dev/null +++ b/gnuradio-runtime/lib/gr_fxpt.cc @@ -0,0 +1,35 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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 <gr_fxpt.h> + +const float gr_fxpt::s_sine_table[1 << NBITS][2] = { +#include "sine_table.h" +}; + +const float gr_fxpt::PI = 3.14159265358979323846; +const float gr_fxpt::TWO_TO_THE_31 = 2147483648.0; + diff --git a/gnuradio-runtime/lib/gr_hier_block2.cc b/gnuradio-runtime/lib/gr_hier_block2.cc new file mode 100644 index 0000000000..9e924fdaf5 --- /dev/null +++ b/gnuradio-runtime/lib/gr_hier_block2.cc @@ -0,0 +1,153 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2007,2008 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 <gr_hier_block2.h> +#include <gr_io_signature.h> +#include <gr_hier_block2_detail.h> +#include <iostream> + +#define GR_HIER_BLOCK2_DEBUG 0 + + +gr_hier_block2_sptr +gr_make_hier_block2(const std::string &name, + gr_io_signature_sptr input_signature, + gr_io_signature_sptr output_signature) +{ + return gnuradio::get_initial_sptr(new gr_hier_block2(name, input_signature, output_signature)); +} + +gr_hier_block2::gr_hier_block2(const std::string &name, + gr_io_signature_sptr input_signature, + gr_io_signature_sptr output_signature) + : gr_basic_block(name, input_signature, output_signature), + d_detail(new gr_hier_block2_detail(this)), + hier_message_ports_in(pmt::PMT_NIL), + hier_message_ports_out(pmt::PMT_NIL) +{ + // This bit of magic ensures that self() works in the constructors of derived classes. + gnuradio::detail::sptr_magic::create_and_stash_initial_sptr(this); +} + +gr_hier_block2::~gr_hier_block2() +{ + delete d_detail; +} + +gr_hier_block2::opaque_self +gr_hier_block2::self() +{ + return shared_from_this(); +} + +gr_hier_block2_sptr +gr_hier_block2::to_hier_block2() +{ + return cast_to_hier_block2_sptr(shared_from_this()); +} + +void +gr_hier_block2::connect(gr_basic_block_sptr block) +{ + d_detail->connect(block); +} + +void +gr_hier_block2::connect(gr_basic_block_sptr src, int src_port, + gr_basic_block_sptr dst, int dst_port) +{ + d_detail->connect(src, src_port, dst, dst_port); +} + +void +gr_hier_block2::msg_connect(gr_basic_block_sptr src, pmt::pmt_t srcport, + gr_basic_block_sptr dst, pmt::pmt_t dstport) +{ + if(!pmt::is_symbol(srcport)){throw std::runtime_error("bad port id"); } + d_detail->msg_connect(src, srcport, dst, dstport); +} + +void +gr_hier_block2::msg_connect(gr_basic_block_sptr src, std::string srcport, + gr_basic_block_sptr dst, std::string dstport) +{ + d_detail->msg_connect(src, pmt::mp(srcport), dst, pmt::mp(dstport)); +} + +void +gr_hier_block2::msg_disconnect(gr_basic_block_sptr src, pmt::pmt_t srcport, + gr_basic_block_sptr dst, pmt::pmt_t dstport) +{ + if(!pmt::is_symbol(srcport)){throw std::runtime_error("bad port id"); } + d_detail->msg_disconnect(src, srcport, dst, dstport); +} + +void +gr_hier_block2::msg_disconnect(gr_basic_block_sptr src, std::string srcport, + gr_basic_block_sptr dst, std::string dstport) +{ + d_detail->msg_disconnect(src, pmt::mp(srcport), dst, pmt::mp(dstport)); +} + +void +gr_hier_block2::disconnect(gr_basic_block_sptr block) +{ + d_detail->disconnect(block); +} + +void +gr_hier_block2::disconnect(gr_basic_block_sptr src, int src_port, + gr_basic_block_sptr dst, int dst_port) +{ + d_detail->disconnect(src, src_port, dst, dst_port); +} + +void +gr_hier_block2::disconnect_all() +{ + d_detail->disconnect_all(); +} + +void +gr_hier_block2::lock() +{ + d_detail->lock(); +} + +void +gr_hier_block2::unlock() +{ + d_detail->unlock(); +} + + +gr_flat_flowgraph_sptr +gr_hier_block2::flatten() const +{ + gr_flat_flowgraph_sptr new_ffg = gr_make_flat_flowgraph(); + d_detail->flatten_aux(new_ffg); + return new_ffg; +} diff --git a/gnuradio-runtime/lib/gr_hier_block2_detail.cc b/gnuradio-runtime/lib/gr_hier_block2_detail.cc new file mode 100644 index 0000000000..c8564f6698 --- /dev/null +++ b/gnuradio-runtime/lib/gr_hier_block2_detail.cc @@ -0,0 +1,641 @@ +/* + * Copyright 2006,2007,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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_hier_block2_detail.h> +#include <gr_io_signature.h> +#include <gr_prefs.h> +#include <stdexcept> +#include <sstream> +#include <boost/format.hpp> + +#define GR_HIER_BLOCK2_DETAIL_DEBUG 0 + +gr_hier_block2_detail::gr_hier_block2_detail(gr_hier_block2 *owner) : + d_owner(owner), + d_parent_detail(0), + d_fg(gr_make_flowgraph()) +{ + int min_inputs = owner->input_signature()->min_streams(); + int max_inputs = owner->input_signature()->max_streams(); + int min_outputs = owner->output_signature()->min_streams(); + int max_outputs = owner->output_signature()->max_streams(); + + if (max_inputs == gr_io_signature::IO_INFINITE || + max_outputs == gr_io_signature::IO_INFINITE || + (min_inputs != max_inputs) ||(min_outputs != max_outputs) ) { + std::stringstream msg; + msg << "Hierarchical blocks do not yet support arbitrary or" + << " variable numbers of inputs or outputs (" << d_owner->name() << ")"; + throw std::runtime_error(msg.str()); + } + + d_inputs = std::vector<gr_endpoint_vector_t>(max_inputs); + d_outputs = gr_endpoint_vector_t(max_outputs); +} + + +gr_hier_block2_detail::~gr_hier_block2_detail() +{ + d_owner = 0; // Don't use delete, we didn't allocate +} + +void +gr_hier_block2_detail::connect(gr_basic_block_sptr block) +{ + std::stringstream msg; + + // Check if duplicate + if (std::find(d_blocks.begin(), d_blocks.end(), block) != d_blocks.end()) { + msg << "Block " << block << " already connected."; + throw std::invalid_argument(msg.str()); + } + + // Check if has inputs or outputs + if (block->input_signature()->max_streams() != 0 || + block->output_signature()->max_streams() != 0) { + msg << "Block " << block << " must not have any input or output ports"; + throw std::invalid_argument(msg.str()); + } + + gr_hier_block2_sptr hblock(cast_to_hier_block2_sptr(block)); + + if (hblock && hblock.get() != d_owner) { + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "connect: block is hierarchical, setting parent to " << this << std::endl; + hblock->d_detail->d_parent_detail = this; + } + + d_blocks.push_back(block); +} + +void +gr_hier_block2_detail::connect(gr_basic_block_sptr src, int src_port, + gr_basic_block_sptr dst, int dst_port) +{ + std::stringstream msg; + + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "connecting: " << gr_endpoint(src, src_port) + << " -> " << gr_endpoint(dst, dst_port) << std::endl; + + if (src.get() == dst.get()) + throw std::invalid_argument("connect: src and destination blocks cannot be the same"); + + gr_hier_block2_sptr src_block(cast_to_hier_block2_sptr(src)); + gr_hier_block2_sptr dst_block(cast_to_hier_block2_sptr(dst)); + + if (src_block && src.get() != d_owner) { + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "connect: src is hierarchical, setting parent to " << this << std::endl; + src_block->d_detail->d_parent_detail = this; + } + + if (dst_block && dst.get() != d_owner) { + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "connect: dst is hierarchical, setting parent to " << this << std::endl; + dst_block->d_detail->d_parent_detail = this; + } + + // Connections to block inputs or outputs + int max_port; + if (src.get() == d_owner) { + max_port = src->input_signature()->max_streams(); + if ((max_port != -1 && (src_port >= max_port)) || src_port < 0) { + msg << "source port " << src_port << " out of range for " << src; + throw std::invalid_argument(msg.str()); + } + + return connect_input(src_port, dst_port, dst); + } + + if (dst.get() == d_owner) { + max_port = dst->output_signature()->max_streams(); + if ((max_port != -1 && (dst_port >= max_port)) || dst_port < 0) { + msg << "destination port " << dst_port << " out of range for " << dst; + throw std::invalid_argument(msg.str()); + } + + return connect_output(dst_port, src_port, src); + } + + // Internal connections + d_fg->connect(src, src_port, dst, dst_port); + + // TODO: connects to NC +} + +void +gr_hier_block2_detail::msg_connect(gr_basic_block_sptr src, pmt::pmt_t srcport, + gr_basic_block_sptr dst, pmt::pmt_t dstport) +{ + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "connecting message port..." << std::endl; + + // register the subscription +// this is done later... +// src->message_port_sub(srcport, pmt::cons(dst->alias_pmt(), dstport)); + + // add block uniquely to list to internal blocks + if (std::find(d_blocks.begin(), d_blocks.end(), dst) == d_blocks.end()){ + d_blocks.push_back(src); + d_blocks.push_back(dst); + } + + bool hier_out = (d_owner == src.get()) && src->message_port_is_hier_out(srcport);; + bool hier_in = (d_owner == dst.get()) && dst->message_port_is_hier_in(dstport); + + gr_hier_block2_sptr src_block(cast_to_hier_block2_sptr(src)); + gr_hier_block2_sptr dst_block(cast_to_hier_block2_sptr(dst)); + + if (src_block && src.get() != d_owner) { + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "connect: src is hierarchical, setting parent to " << this << std::endl; + src_block->d_detail->d_parent_detail = this; + } + + if (dst_block && dst.get() != d_owner) { + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "connect: dst is hierarchical, setting parent to " << this << std::endl; + dst_block->d_detail->d_parent_detail = this; + } + + // add edge for this message connection + if(GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << boost::format("connect( (%s, %s, %d), (%s, %s, %d) )\n") % + src % srcport % hier_out % + dst % dstport % hier_in; + d_fg->connect( gr_msg_endpoint(src, srcport, hier_out), gr_msg_endpoint(dst, dstport, hier_in)); +} + +void +gr_hier_block2_detail::msg_disconnect(gr_basic_block_sptr src, pmt::pmt_t srcport, + gr_basic_block_sptr dst, pmt::pmt_t dstport) +{ + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "disconnecting message port..." << std::endl; + + // unregister the subscription - if already subscribed + src->message_port_unsub(srcport, pmt::cons(dst->alias_pmt(), dstport)); + + // remove edge for this message connection + bool hier_out = (d_owner == src.get()) && src->message_port_is_hier_out(srcport);; + bool hier_in = (d_owner == dst.get()) && dst->message_port_is_hier_in(dstport); + d_fg->disconnect( gr_msg_endpoint(src, srcport, hier_out), gr_msg_endpoint(dst, dstport, hier_in)); +} + +void +gr_hier_block2_detail::disconnect(gr_basic_block_sptr block) +{ + // Check on singleton list + for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { + if (*p == block) { + d_blocks.erase(p); + + gr_hier_block2_sptr hblock(cast_to_hier_block2_sptr(block)); + if (block && block.get() != d_owner) { + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "disconnect: block is hierarchical, clearing parent" << std::endl; + hblock->d_detail->d_parent_detail = 0; + } + + return; + } + } + + // Otherwise find all edges containing block + gr_edge_vector_t edges, tmp = d_fg->edges(); + gr_edge_vector_t::iterator p; + for (p = tmp.begin(); p != tmp.end(); p++) { + if ((*p).src().block() == block || (*p).dst().block() == block) { + edges.push_back(*p); + + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "disconnect: block found in edge " << (*p) << std::endl; + } + } + + if (edges.size() == 0) { + std::stringstream msg; + msg << "cannot disconnect block " << block << ", not found"; + throw std::invalid_argument(msg.str()); + } + + for (p = edges.begin(); p != edges.end(); p++) { + disconnect((*p).src().block(), (*p).src().port(), + (*p).dst().block(), (*p).dst().port()); + } +} + +void +gr_hier_block2_detail::disconnect(gr_basic_block_sptr src, int src_port, + gr_basic_block_sptr dst, int dst_port) +{ + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "disconnecting: " << gr_endpoint(src, src_port) + << " -> " << gr_endpoint(dst, dst_port) << std::endl; + + if (src.get() == dst.get()) + throw std::invalid_argument("disconnect: source and destination blocks cannot be the same"); + + gr_hier_block2_sptr src_block(cast_to_hier_block2_sptr(src)); + gr_hier_block2_sptr dst_block(cast_to_hier_block2_sptr(dst)); + + if (src_block && src.get() != d_owner) { + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "disconnect: src is hierarchical, clearing parent" << std::endl; + src_block->d_detail->d_parent_detail = 0; + } + + if (dst_block && dst.get() != d_owner) { + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "disconnect: dst is hierarchical, clearing parent" << std::endl; + dst_block->d_detail->d_parent_detail = 0; + } + + if (src.get() == d_owner) + return disconnect_input(src_port, dst_port, dst); + + if (dst.get() == d_owner) + return disconnect_output(dst_port, src_port, src); + + // Internal connections + d_fg->disconnect(src, src_port, dst, dst_port); +} + +void +gr_hier_block2_detail::connect_input(int my_port, int port, gr_basic_block_sptr block) +{ + std::stringstream msg; + + if (my_port < 0 || my_port >= (signed)d_inputs.size()) { + msg << "input port " << my_port << " out of range for " << block; + throw std::invalid_argument(msg.str()); + } + + gr_endpoint_vector_t &endps = d_inputs[my_port]; + gr_endpoint endp(block, port); + + gr_endpoint_viter_t p = std::find(endps.begin(), endps.end(), endp); + if (p != endps.end()) { + msg << "external input port " << my_port << " already wired to " << endp; + throw std::invalid_argument(msg.str()); + } + + endps.push_back(endp); +} + +void +gr_hier_block2_detail::connect_output(int my_port, int port, gr_basic_block_sptr block) +{ + std::stringstream msg; + + if (my_port < 0 || my_port >= (signed)d_outputs.size()) { + msg << "output port " << my_port << " out of range for " << block; + throw std::invalid_argument(msg.str()); + } + + if (d_outputs[my_port].block()) { + msg << "external output port " << my_port << " already connected from " + << d_outputs[my_port]; + throw std::invalid_argument(msg.str()); + } + + d_outputs[my_port] = gr_endpoint(block, port); +} + +void +gr_hier_block2_detail::disconnect_input(int my_port, int port, gr_basic_block_sptr block) +{ + std::stringstream msg; + + if (my_port < 0 || my_port >= (signed)d_inputs.size()) { + msg << "input port number " << my_port << " out of range for " << block; + throw std::invalid_argument(msg.str()); + } + + gr_endpoint_vector_t &endps = d_inputs[my_port]; + gr_endpoint endp(block, port); + + gr_endpoint_viter_t p = std::find(endps.begin(), endps.end(), endp); + if (p == endps.end()) { + msg << "external input port " << my_port << " not connected to " << endp; + throw std::invalid_argument(msg.str()); + } + + endps.erase(p); +} + +void +gr_hier_block2_detail::disconnect_output(int my_port, int port, gr_basic_block_sptr block) +{ + std::stringstream msg; + + if (my_port < 0 || my_port >= (signed)d_outputs.size()) { + msg << "output port number " << my_port << " out of range for " << block; + throw std::invalid_argument(msg.str()); + } + + if (d_outputs[my_port].block() != block) { + msg << "block " << block << " not assigned to output " + << my_port << ", can't disconnect"; + throw std::invalid_argument(msg.str()); + } + + d_outputs[my_port] = gr_endpoint(); +} + +gr_endpoint_vector_t +gr_hier_block2_detail::resolve_port(int port, bool is_input) +{ + std::stringstream msg; + + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Resolving port " << port << " as an " + << (is_input ? "input" : "output") + << " of " << d_owner->name() << std::endl; + + gr_endpoint_vector_t result; + + if (is_input) { + if (port < 0 || port >= (signed)d_inputs.size()) { + msg << "resolve_port: hierarchical block '" << d_owner->name() + << "': input " << port << " is out of range"; + throw std::runtime_error(msg.str()); + } + + if (d_inputs[port].empty()) { + msg << "resolve_port: hierarchical block '" << d_owner->name() + << "': input " << port << " is not connected internally"; + throw std::runtime_error(msg.str()); + } + + gr_endpoint_vector_t &endps = d_inputs[port]; + gr_endpoint_viter_t p; + for (p = endps.begin(); p != endps.end(); p++) { + gr_endpoint_vector_t tmp = resolve_endpoint(*p, true); + std::copy(tmp.begin(), tmp.end(), back_inserter(result)); + } + } + else { + if (port < 0 || port >= (signed)d_outputs.size()) { + msg << "resolve_port: hierarchical block '" << d_owner->name() + << "': output " << port << " is out of range"; + throw std::runtime_error(msg.str()); + } + + if (d_outputs[port] == gr_endpoint()) { + msg << "resolve_port: hierarchical block '" << d_owner->name() + << "': output " << port << " is not connected internally"; + throw std::runtime_error(msg.str()); + } + + result = resolve_endpoint(d_outputs[port], false); + } + + if (result.empty()) { + msg << "resolve_port: hierarchical block '" << d_owner->name() + << "': unable to resolve " + << (is_input ? "input port " : "output port ") + << port; + throw std::runtime_error(msg.str()); + } + + return result; +} + +void +gr_hier_block2_detail::disconnect_all() +{ + d_fg->clear(); + d_blocks.clear(); + d_inputs.clear(); + d_outputs.clear(); +} + +gr_endpoint_vector_t +gr_hier_block2_detail::resolve_endpoint(const gr_endpoint &endp, bool is_input) const +{ + std::stringstream msg; + gr_endpoint_vector_t result; + + // Check if endpoint is a leaf node + if (cast_to_block_sptr(endp.block())) { + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Block " << endp.block() << " is a leaf node, returning." << std::endl; + result.push_back(endp); + return result; + } + + // Check if endpoint is a hierarchical block + gr_hier_block2_sptr hier_block2(cast_to_hier_block2_sptr(endp.block())); + if (hier_block2) { + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Resolving endpoint " << endp << " as an " + << (is_input ? "input" : "output") + << ", recursing" << std::endl; + return hier_block2->d_detail->resolve_port(endp.port(), is_input); + } + + msg << "unable to resolve" << (is_input ? " input " : " output ") + << "endpoint " << endp; + throw std::runtime_error(msg.str()); +} + +void +gr_hier_block2_detail::flatten_aux(gr_flat_flowgraph_sptr sfg) const +{ + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << " ** Flattening " << d_owner->name() << std::endl; + + // Add my edges to the flow graph, resolving references to actual endpoints + gr_edge_vector_t edges = d_fg->edges(); + gr_msg_edge_vector_t msg_edges = d_fg->msg_edges(); + gr_edge_viter_t p; + gr_msg_edge_viter_t q,u; + + // Only run setup_rpc if ControlPort config param is enabled. + bool ctrlport_on = gr_prefs::singleton()->get_bool("ControlPort", "on", false); + + // For every block (gr_block and gr_hier_block2), set up the RPC + // interface. + for(p = edges.begin(); p != edges.end(); p++) { + gr_basic_block_sptr b; + b = p->src().block(); + + if(ctrlport_on) { + if(!b->is_rpc_set()) { + b->setup_rpc(); + b->rpc_set(); + } + } + + b = p->dst().block(); + if(ctrlport_on) { + if(!b->is_rpc_set()) { + b->setup_rpc(); + b->rpc_set(); + } + } + } + + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Flattening stream connections: " << std::endl; + + for (p = edges.begin(); p != edges.end(); p++) { + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Flattening edge " << (*p) << std::endl; + + gr_endpoint_vector_t src_endps = resolve_endpoint(p->src(), false); + gr_endpoint_vector_t dst_endps = resolve_endpoint(p->dst(), true); + + gr_endpoint_viter_t s, d; + for (s = src_endps.begin(); s != src_endps.end(); s++) { + for (d = dst_endps.begin(); d != dst_endps.end(); d++) { + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << (*s) << "->" << (*d) << std::endl; + sfg->connect(*s, *d); + } + } + } + + // loop through flattening hierarchical connections + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Flattening msg connections: " << std::endl; + + + std::vector<std::pair<gr_msg_endpoint, bool> > resolved_endpoints; + for(q = msg_edges.begin(); q != msg_edges.end(); q++) { + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << boost::format(" flattening edge ( %s, %s, %d) -> ( %s, %s, %d)\n") % q->src().block() % q->src().port() % q->src().is_hier() % q->dst().block() % q->dst().port() % q->dst().is_hier(); + + bool normal_connection = true; + + // resolve existing connections to hier ports + if(q->dst().is_hier()){ + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << boost::format(" resolve hier output (%s, %s)") % q->dst().block() % q->dst().port() << std::endl; + sfg->replace_endpoint( q->dst(), q->src(), true ); + resolved_endpoints.push_back(std::pair<gr_msg_endpoint, bool>(q->dst(),true)); + normal_connection = false; + } + + if(q->src().is_hier()){ + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << boost::format(" resolve hier input (%s, %s)") % q->src().block() % q->src().port() << std::endl; + sfg->replace_endpoint( q->src(), q->dst(), false ); + resolved_endpoints.push_back(std::pair<gr_msg_endpoint, bool>(q->src(),false)); + normal_connection = false; + } + + // propogate non hier connections through + if(normal_connection){ + sfg->connect( q->src(), q->dst() ); + } + } + for(std::vector<std::pair<gr_msg_endpoint, bool> >::iterator it = resolved_endpoints.begin(); it != resolved_endpoints.end(); it++){ + sfg->clear_endpoint( (*it).first, (*it).second ); + } + +/* // connect primitive edges in the new fg + for(q = msg_edges.begin(); q != msg_edges.end(); q++) { + if( (!q->src().is_hier()) && (!q->dst().is_hier()) ){ + sfg->connect( q->src(), q->dst() ); + } else { + std::cout << "not connecting hier connection!" << std::endl; + } + }*/ + + // Construct unique list of blocks used either in edges, inputs, + // outputs, or by themselves. I still hate STL. + gr_basic_block_vector_t blocks; // unique list of used blocks + gr_basic_block_vector_t tmp = d_fg->calc_used_blocks(); + + // First add the list of singleton blocks + std::vector<gr_basic_block_sptr>::const_iterator b; // Because flatten_aux is const + for (b = d_blocks.begin(); b != d_blocks.end(); b++) + tmp.push_back(*b); + + // Now add the list of connected input blocks + std::stringstream msg; + for (unsigned int i = 0; i < d_inputs.size(); i++) { + if (d_inputs[i].size() == 0) { + msg << "In hierarchical block " << d_owner->name() << ", input " << i + << " is not connected internally"; + throw std::runtime_error(msg.str()); + } + + for (unsigned int j = 0; j < d_inputs[i].size(); j++) + tmp.push_back(d_inputs[i][j].block()); + } + + for (unsigned int i = 0; i < d_outputs.size(); i++) { + gr_basic_block_sptr blk = d_outputs[i].block(); + if (!blk) { + msg << "In hierarchical block " << d_owner->name() << ", output " << i + << " is not connected internally"; + throw std::runtime_error(msg.str()); + } + tmp.push_back(blk); + } + sort(tmp.begin(), tmp.end()); + + std::insert_iterator<gr_basic_block_vector_t> inserter(blocks, blocks.begin()); + unique_copy(tmp.begin(), tmp.end(), inserter); + + // Recurse hierarchical children + for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { + gr_hier_block2_sptr hier_block2(cast_to_hier_block2_sptr(*p)); + if (hier_block2 && (hier_block2.get() != d_owner)) { + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "flatten_aux: recursing into hierarchical block " << hier_block2 << std::endl; + hier_block2->d_detail->flatten_aux(sfg); + } + } +} + +void +gr_hier_block2_detail::lock() +{ + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "lock: entered in " << this << std::endl; + + if (d_parent_detail) + d_parent_detail->lock(); + else + d_owner->lock(); +} + +void +gr_hier_block2_detail::unlock() +{ + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "unlock: entered in " << this << std::endl; + + if (d_parent_detail) + d_parent_detail->unlock(); + else + d_owner->unlock(); +} + diff --git a/gnuradio-runtime/lib/gr_hier_block2_detail.h b/gnuradio-runtime/lib/gr_hier_block2_detail.h new file mode 100644 index 0000000000..d08fe20ac0 --- /dev/null +++ b/gnuradio-runtime/lib/gr_hier_block2_detail.h @@ -0,0 +1,74 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2007,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. + */ +#ifndef INCLUDED_GR_HIER_BLOCK2_DETAIL_H +#define INCLUDED_GR_HIER_BLOCK2_DETAIL_H + +#include <gr_runtime_api.h> +#include <gr_hier_block2.h> +#include <gr_flat_flowgraph.h> +#include <boost/utility.hpp> + +/*! + * \ingroup internal + */ +class GR_RUNTIME_API gr_hier_block2_detail : boost::noncopyable +{ +public: + gr_hier_block2_detail(gr_hier_block2 *owner); + ~gr_hier_block2_detail(); + + void connect(gr_basic_block_sptr block); + void connect(gr_basic_block_sptr src, int src_port, + gr_basic_block_sptr dst, int dst_port); + void msg_connect(gr_basic_block_sptr src, pmt::pmt_t srcport, + gr_basic_block_sptr dst, pmt::pmt_t dstport); + void msg_disconnect(gr_basic_block_sptr src, pmt::pmt_t srcport, + gr_basic_block_sptr dst, pmt::pmt_t dstport); + void disconnect(gr_basic_block_sptr block); + void disconnect(gr_basic_block_sptr, int src_port, + gr_basic_block_sptr, int dst_port); + void disconnect_all(); + void lock(); + void unlock(); + void flatten_aux(gr_flat_flowgraph_sptr sfg) const; + +private: + + // Private implementation data + gr_hier_block2 *d_owner; + gr_hier_block2_detail *d_parent_detail; + gr_flowgraph_sptr d_fg; + std::vector<gr_endpoint_vector_t> d_inputs; // Multiple internal endpoints per external input + gr_endpoint_vector_t d_outputs; // Single internal endpoint per external output + gr_basic_block_vector_t d_blocks; + + + void connect_input(int my_port, int port, gr_basic_block_sptr block); + void connect_output(int my_port, int port, gr_basic_block_sptr block); + void disconnect_input(int my_port, int port, gr_basic_block_sptr block); + void disconnect_output(int my_port, int port, gr_basic_block_sptr block); + + gr_endpoint_vector_t resolve_port(int port, bool is_input); + gr_endpoint_vector_t resolve_endpoint(const gr_endpoint &endp, bool is_input) const; +}; + +#endif /* INCLUDED_GR_HIER_BLOCK2_DETAIL_H */ diff --git a/gnuradio-runtime/lib/gr_io_signature.cc b/gnuradio-runtime/lib/gr_io_signature.cc new file mode 100644 index 0000000000..6ac9acd17d --- /dev/null +++ b/gnuradio-runtime/lib/gr_io_signature.cc @@ -0,0 +1,112 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <gr_io_signature.h> +#include <stdexcept> +#include <iostream> + +gr_io_signature_sptr +gr_make_io_signaturev(int min_streams, int max_streams, + const std::vector<int> &sizeof_stream_items) +{ + return gr_io_signature_sptr (new gr_io_signature (min_streams, max_streams, + sizeof_stream_items)); +} + +gr_io_signature_sptr +gr_make_io_signature(int min_streams, int max_streams, + int sizeof_stream_item) +{ + std::vector<int> sizeof_items(1); + sizeof_items[0] = sizeof_stream_item; + return gr_make_io_signaturev(min_streams, max_streams, sizeof_items); +} + +gr_io_signature_sptr +gr_make_io_signature2(int min_streams, int max_streams, + int sizeof_stream_item1, + int sizeof_stream_item2) +{ + std::vector<int> sizeof_items(2); + sizeof_items[0] = sizeof_stream_item1; + sizeof_items[1] = sizeof_stream_item2; + return gr_make_io_signaturev(min_streams, max_streams, sizeof_items); +} + +gr_io_signature_sptr +gr_make_io_signature3(int min_streams, int max_streams, + int sizeof_stream_item1, + int sizeof_stream_item2, + int sizeof_stream_item3) +{ + std::vector<int> sizeof_items(3); + sizeof_items[0] = sizeof_stream_item1; + sizeof_items[1] = sizeof_stream_item2; + sizeof_items[2] = sizeof_stream_item3; + return gr_make_io_signaturev(min_streams, max_streams, sizeof_items); +} + +// ------------------------------------------------------------------------ + + +gr_io_signature::gr_io_signature (int min_streams, int max_streams, + const std::vector<int> &sizeof_stream_items) +{ + if (min_streams < 0 + || (max_streams != IO_INFINITE && max_streams < min_streams)) + throw std::invalid_argument ("gr_io_signature(1)"); + + if (sizeof_stream_items.size() < 1) + throw std::invalid_argument("gr_io_signature(2)"); + + for (size_t i = 0; i < sizeof_stream_items.size(); i++){ + if (max_streams != 0 && sizeof_stream_items[i] < 1) + throw std::invalid_argument("gr_io_signature(3)"); + } + + d_min_streams = min_streams; + d_max_streams = max_streams; + d_sizeof_stream_item = sizeof_stream_items; +} + +gr_io_signature::~gr_io_signature () +{ +} + +int +gr_io_signature::sizeof_stream_item (int _index) const +{ + if (_index < 0) + throw std::invalid_argument ("gr_io_signature::sizeof_stream_item"); + + size_t index = _index; + return d_sizeof_stream_item[std::min(index, d_sizeof_stream_item.size() - 1)]; +} + +std::vector<int> +gr_io_signature::sizeof_stream_items() const +{ + return d_sizeof_stream_item; +} diff --git a/gnuradio-runtime/lib/gr_local_sighandler.cc b/gnuradio-runtime/lib/gr_local_sighandler.cc new file mode 100644 index 0000000000..fb31742e13 --- /dev/null +++ b/gnuradio-runtime/lib/gr_local_sighandler.cc @@ -0,0 +1,187 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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 <gr_local_sighandler.h> +#include <stdexcept> +#include <stdio.h> +#include <string.h> + + +gr_local_sighandler::gr_local_sighandler (int signum, + void (*new_handler)(int)) + : d_signum (signum) +{ +#ifdef HAVE_SIGACTION + struct sigaction new_action; + memset (&new_action, 0, sizeof (new_action)); + + new_action.sa_handler = new_handler; + sigemptyset (&new_action.sa_mask); + new_action.sa_flags = 0; + + if (sigaction (d_signum, &new_action, &d_old_action) < 0){ + perror ("sigaction (install new)"); + throw std::runtime_error ("sigaction"); + } +#endif +} + +gr_local_sighandler::~gr_local_sighandler () +{ +#ifdef HAVE_SIGACTION + if (sigaction (d_signum, &d_old_action, 0) < 0){ + perror ("sigaction (restore old)"); + throw std::runtime_error ("sigaction"); + } +#endif +} + +void +gr_local_sighandler::throw_signal (int signum) +{ + throw gr_signal (signum); +} + +/* + * Semi-hideous way to may a signal number into a signal name + */ + +#define SIGNAME(x) case x: return #x + +std::string +gr_signal::name () const +{ + char tmp[128]; + + switch (signal ()){ +#ifdef SIGHUP + SIGNAME (SIGHUP); +#endif +#ifdef SIGINT + SIGNAME (SIGINT); +#endif +#ifdef SIGQUIT + SIGNAME (SIGQUIT); +#endif +#ifdef SIGILL + SIGNAME (SIGILL); +#endif +#ifdef SIGTRAP + SIGNAME (SIGTRAP); +#endif +#ifdef SIGABRT + SIGNAME (SIGABRT); +#endif +#ifdef SIGBUS + SIGNAME (SIGBUS); +#endif +#ifdef SIGFPE + SIGNAME (SIGFPE); +#endif +#ifdef SIGKILL + SIGNAME (SIGKILL); +#endif +#ifdef SIGUSR1 + SIGNAME (SIGUSR1); +#endif +#ifdef SIGSEGV + SIGNAME (SIGSEGV); +#endif +#ifdef SIGUSR2 + SIGNAME (SIGUSR2); +#endif +#ifdef SIGPIPE + SIGNAME (SIGPIPE); +#endif +#ifdef SIGALRM + SIGNAME (SIGALRM); +#endif +#ifdef SIGTERM + SIGNAME (SIGTERM); +#endif +#ifdef SIGSTKFLT + SIGNAME (SIGSTKFLT); +#endif +#ifdef SIGCHLD + SIGNAME (SIGCHLD); +#endif +#ifdef SIGCONT + SIGNAME (SIGCONT); +#endif +#ifdef SIGSTOP + SIGNAME (SIGSTOP); +#endif +#ifdef SIGTSTP + SIGNAME (SIGTSTP); +#endif +#ifdef SIGTTIN + SIGNAME (SIGTTIN); +#endif +#ifdef SIGTTOU + SIGNAME (SIGTTOU); +#endif +#ifdef SIGURG + SIGNAME (SIGURG); +#endif +#ifdef SIGXCPU + SIGNAME (SIGXCPU); +#endif +#ifdef SIGXFSZ + SIGNAME (SIGXFSZ); +#endif +#ifdef SIGVTALRM + SIGNAME (SIGVTALRM); +#endif +#ifdef SIGPROF + SIGNAME (SIGPROF); +#endif +#ifdef SIGWINCH + SIGNAME (SIGWINCH); +#endif +#ifdef SIGIO + SIGNAME (SIGIO); +#endif +#ifdef SIGPWR + SIGNAME (SIGPWR); +#endif +#ifdef SIGSYS + SIGNAME (SIGSYS); +#endif + default: +#if defined (HAVE_SNPRINTF) +#if defined (SIGRTMIN) && defined (SIGRTMAX) + if (signal () >= SIGRTMIN && signal () <= SIGRTMAX){ + snprintf (tmp, sizeof (tmp), "SIGRTMIN + %d", signal ()); + return tmp; + } +#endif + snprintf (tmp, sizeof (tmp), "SIGNAL %d", signal ()); + return tmp; +#else + return "Unknown signal"; +#endif + } +} diff --git a/gnuradio-runtime/lib/gr_local_sighandler.h b/gnuradio-runtime/lib/gr_local_sighandler.h new file mode 100644 index 0000000000..a49ee031ca --- /dev/null +++ b/gnuradio-runtime/lib/gr_local_sighandler.h @@ -0,0 +1,65 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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_LOCAL_SIGHANDLER_H +#define INCLUDED_GR_LOCAL_SIGHANDLER_H + +#ifdef HAVE_SIGNAL_H +#include <signal.h> +#endif + +#include <gr_runtime_api.h> +#include <string> + +/*! + * \brief Get and set signal handler. + * + * \ingroup internal + * Constructor installs new handler, destructor reinstalls + * original value. + */ +class GR_RUNTIME_API gr_local_sighandler { + int d_signum; +#ifdef HAVE_SIGACTION + struct sigaction d_old_action; +#endif +public: + gr_local_sighandler (int signum, void (*new_handler)(int)); + ~gr_local_sighandler (); + + /* throw gr_signal (signum) */ + static void throw_signal (int signum); +}; + +/*! + * \brief Representation of signal. + */ +class GR_RUNTIME_API gr_signal +{ + int d_signum; +public: + gr_signal (int signum) : d_signum (signum) {} + int signal () const { return d_signum; } + std::string name () const; +}; + +#endif /* INCLUDED_GR_LOCAL_SIGHANDLER_H */ diff --git a/gnuradio-runtime/lib/gr_logger.cc b/gnuradio-runtime/lib/gr_logger.cc new file mode 100644 index 0000000000..7e0116d036 --- /dev/null +++ b/gnuradio-runtime/lib/gr_logger.cc @@ -0,0 +1,291 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 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. + */ + +/******************************************************************************* +* Author: Mark Plett +* Description: +* The gr_log module wraps the log4cpp library for logging in gnuradio. +*******************************************************************************/ + +#include <gr_logger.h> +#include <stdexcept> +#include <algorithm> + +#ifdef ENABLE_GR_LOG +#ifdef HAVE_LOG4CPP + +/**************************** BEGIN LOG4CPP HELPERS ***************************/ +/* Logger config class. This is a singleton that controls how log4cpp is configured + * If watch_period>0 a thread is started to watch teh config file for changes. + */ + +// Getters of logger_config +logger_config& +logger_config::get_instance(void){ + static logger_config instance; + return instance; +}; + +std::string +logger_config::get_filename(){ + logger_config& in=get_instance(); + return in.filename; +}; + +unsigned int +logger_config::get_watch_period(){ + logger_config& in=get_instance(); + return in.watch_period; +}; + +// Method to watch config file for changes +void logger_config::watch_file(std::string filename,unsigned int watch_period){ + std::time_t last_write(boost::filesystem::last_write_time(filename)); + std::time_t current_time(0); + while(true){ + try{ + current_time = boost::filesystem::last_write_time(filename); + if(current_time>last_write){ + std::cout<<"GNURadio Reloading logger configuration:"<<filename<<std::endl; + last_write = current_time; +// Should we wipe out all old configuration or just add the new? Just adding... +// logger_reset_config(); + logger_load_config(filename); + }; + boost::this_thread::sleep(boost::posix_time::time_duration(0,0,watch_period,0)); + } + catch(const boost::thread_interrupted&){ + std::cout<<"GNURadio leaving logger config file watch."<<std::endl; + break; + }; + }; +}; + +// Method to load the confifuration. It only loads if the filename or watch has changed +void logger_config::load_config(std::string filename,unsigned int watch_period){ + logger_config& instance = get_instance(); +// Only reconfigure if filename or watch has changed + if(instance.filename!=filename || watch_period!=instance.watch_period){ + instance.filename = filename; + instance.watch_period = watch_period; +// Stop any file watching thread + if(instance.watch_thread!=NULL) stop_watch(); +// Load configuration + std::cout<<"GNURadio Loading logger configuration:"<<instance.filename<<std::endl; + logger_load_config(instance.filename); +// Start watch if required + if(instance.watch_period>0){ + instance.watch_thread = new boost::thread(watch_file,instance.filename,instance.watch_period); + } + }; +}; + +// Method to stop the watcher thread +void logger_config::stop_watch(){ + logger_config& instance = get_instance(); + if(instance.watch_thread){ + instance.watch_thread->interrupt(); + instance.watch_thread->join(); + delete(instance.watch_thread); + instance.watch_thread=NULL; + }; +}; + +// Method to reset logger configuration +void +logger_config::reset_config(void){ + logger_config& instance = get_instance(); + stop_watch(); + std::vector<log4cpp::Category*> *loggers = log4cpp::Category::getCurrentCategories(); + std::vector<log4cpp::Category*>::iterator logger = loggers->begin(); +// We can't destroy categories but we can neuter them by removing all appenders. + for (;logger!=loggers->end();logger++){ + (*logger)->removeAllAppenders(); + }; + instance.filename=std::string(""); + instance.watch_period=0; +} + +/***************** Functions to call log4cpp methods *************************/ + +gr_logger_ptr +logger_get_logger(std::string name) +{ + if(log4cpp::Category::exists(name)){ + gr_logger_ptr logger = &log4cpp::Category::getInstance(name); + return logger; + } + else + { + gr_logger_ptr logger = &log4cpp::Category::getInstance(name); + logger->setPriority(log4cpp::Priority::NOTSET); + return logger; + }; +}; + +void +logger_load_config(const std::string &config_filename) +{ + if(config_filename.size() != 0) { + try + { + log4cpp::PropertyConfigurator::configure(config_filename); + } + catch( log4cpp::ConfigureFailure &e ) + { + std::cout << "Logger config failed :" << e.what() << std::endl; + } + }; +} + +void +logger_set_level(gr_logger_ptr logger, const std::string &level) +{ + std::string nocase = level; + std::transform(level.begin(), level.end(), nocase.begin(), ::tolower); + + if(nocase == "off" || nocase == "notset") + logger_set_level(logger, log4cpp::Priority::NOTSET); + else if(nocase == "all" || nocase == "debug") + logger_set_level(logger, log4cpp::Priority::DEBUG); + else if(nocase == "info") + logger_set_level(logger, log4cpp::Priority::INFO); + else if(nocase == "notice") + logger_set_level(logger, log4cpp::Priority::NOTICE); + else if(nocase == "warn") + logger_set_level(logger, log4cpp::Priority::WARN); + else if(nocase == "error") + logger_set_level(logger, log4cpp::Priority::ERROR); + else if(nocase == "crit") + logger_set_level(logger, log4cpp::Priority::CRIT); + else if(nocase == "alert") + logger_set_level(logger, log4cpp::Priority::ALERT); + else if(nocase=="fatal") + logger_set_level(logger, log4cpp::Priority::FATAL); + else if(nocase == "emerg") + logger_set_level(logger, log4cpp::Priority::EMERG); + else + throw std::runtime_error("logger_set_level: Bad level type.\n"); +} + +void +logger_set_level(gr_logger_ptr logger, log4cpp::Priority::Value level) +{ + logger->setPriority(level); +} + +void +logger_get_level(gr_logger_ptr logger, std::string &level) +{ + log4cpp::Priority::Value levelPtr = logger->getPriority(); + if(levelPtr == log4cpp::Priority::NOTSET) level = "noset"; + if(levelPtr == log4cpp::Priority::DEBUG) level = "debug"; + if(levelPtr == log4cpp::Priority::INFO) level = "info"; + if(levelPtr == log4cpp::Priority::NOTICE) level = "notice"; + if(levelPtr == log4cpp::Priority::WARN) level = "warn"; + if(levelPtr == log4cpp::Priority::ERROR) level = "error"; + if(levelPtr == log4cpp::Priority::CRIT) level = "crit"; + if(levelPtr == log4cpp::Priority::ALERT) level = "alert"; + if(levelPtr == log4cpp::Priority::FATAL) level = "fatal"; + if(levelPtr == log4cpp::Priority::EMERG) level = "emerg"; +}; + +void +logger_get_level(gr_logger_ptr logger,log4cpp::Priority::Value level) +{ + level = logger->getPriority(); +} + +void +logger_add_console_appender(gr_logger_ptr logger,std::string target,std::string pattern) +{ + + log4cpp::PatternLayout* layout = new log4cpp::PatternLayout(); + log4cpp::Appender* app; + if(target=="stdout") + app = new log4cpp::OstreamAppender("ConsoleAppender::",&std::cout); + else + app = new log4cpp::OstreamAppender("ConsoleAppender::",&std::cerr); + + layout->setConversionPattern(pattern); + app->setLayout(layout); + logger->setAppender(app); + +} + +void +logger_add_file_appender(gr_logger_ptr logger,std::string filename,bool append,std::string pattern) +{ + + log4cpp::PatternLayout* layout = new log4cpp::PatternLayout(); + log4cpp::Appender* app = new + log4cpp::FileAppender("FileAppender::"+filename, + filename); + layout->setConversionPattern(pattern); + app->setLayout(layout); + logger->setAppender(app); + +} + +void +logger_add_rollingfile_appender(gr_logger_ptr logger,std::string filename, + size_t filesize,int bkup_index,bool append,mode_t mode,std::string pattern) +{ + log4cpp::PatternLayout* layout = new log4cpp::PatternLayout(); + log4cpp::Appender* app = new + log4cpp::RollingFileAppender("RollFileAppender::"+filename,filename,filesize,bkup_index,append,mode); + layout->setConversionPattern(pattern); + app->setLayout(layout); + logger->setAppender(app); +} + +std::vector<std::string> +logger_get_logger_names(void){ + std::vector<std::string> names; + std::vector<log4cpp::Category*> *loggers = log4cpp::Category::getCurrentCategories(); + std::vector<log4cpp::Category*>::iterator logger = loggers->begin(); + + for (;logger!=loggers->end();logger++){ + names.push_back((*logger)->getName()); + }; + return names; + +} + +#endif /* HAVE_LOG4CPP */ + +/****** Start Methods to provide Python the capabilities of the macros ********/ +void gr_logger_config(const std::string config_filename, unsigned int watch_period){ + GR_CONFIG_AND_WATCH_LOGGER(config_filename,watch_period); +}; +std::vector<std::string> gr_logger_get_logger_names(void){ + std::vector<std::string> names; + GR_GET_LOGGER_NAMES(names); + return names; +}; +void gr_logger_reset_config(void){ + GR_RESET_CONFIGURATION(); +}; + +// Remaining capability provided by gr_logger class in gr_logger.h + +#endif /* ENABLE_GR_LOGGER */ diff --git a/gnuradio-runtime/lib/gr_message.cc b/gnuradio-runtime/lib/gr_message.cc new file mode 100644 index 0000000000..a99dcd7653 --- /dev/null +++ b/gnuradio-runtime/lib/gr_message.cc @@ -0,0 +1,78 @@ +/* -*- 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 <gr_message.h> +#include <assert.h> +#include <string.h> + +static long s_ncurrently_allocated = 0; + +gr_message_sptr +gr_make_message (long type, double arg1, double arg2, size_t length) +{ + return gr_message_sptr (new gr_message (type, arg1, arg2, length)); +} + +gr_message_sptr +gr_make_message_from_string(const std::string s, long type, double arg1, double arg2) +{ + gr_message_sptr m = gr_make_message(type, arg1, arg2, s.size()); + memcpy(m->msg(), s.data(), s.size()); + return m; +} + + +gr_message::gr_message (long type, double arg1, double arg2, size_t length) + : d_type(type), d_arg1(arg1), d_arg2(arg2) +{ + if (length == 0) + d_buf_start = d_msg_start = d_msg_end = d_buf_end = 0; + else { + d_buf_start = new unsigned char [length]; + d_msg_start = d_buf_start; + d_msg_end = d_buf_end = d_buf_start + length; + } + s_ncurrently_allocated++; +} + +gr_message::~gr_message () +{ + assert (d_next == 0); + delete [] d_buf_start; + d_msg_start = d_msg_end = d_buf_end = 0; + s_ncurrently_allocated--; +} + +std::string +gr_message::to_string() const +{ + return std::string((char *)d_msg_start, length()); +} + +long +gr_message_ncurrently_allocated () +{ + return s_ncurrently_allocated; +} diff --git a/gnuradio-runtime/lib/gr_misc.cc b/gnuradio-runtime/lib/gr_misc.cc new file mode 100644 index 0000000000..1ed2a03d7f --- /dev/null +++ b/gnuradio-runtime/lib/gr_misc.cc @@ -0,0 +1,65 @@ +/* -*- 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 <gr_misc.h> + +unsigned int +gr_rounduppow2(unsigned int n) +{ + int i; + for (i=0;((n-1)>>i) != 0;i++) + ; + return 1<<i; +} + +// ---------------------------------------------------------------- + +void +gr_zero_vector(std::vector<float> &v) +{ + for(unsigned int i=0; i < v.size(); i++) + v[i] = 0; +} + +void +gr_zero_vector(std::vector<double> &v) +{ + for(unsigned int i=0; i < v.size(); i++) + v[i] = 0; +} + +void +gr_zero_vector(std::vector<int> &v) +{ + for(unsigned int i=0; i < v.size(); i++) + v[i] = 0; +} + +void +gr_zero_vector(std::vector<gr_complex> &v) +{ + for(unsigned int i=0; i < v.size(); i++) + v[i] = 0; +} diff --git a/gnuradio-runtime/lib/gr_misc.h b/gnuradio-runtime/lib/gr_misc.h new file mode 100644 index 0000000000..182ae87de6 --- /dev/null +++ b/gnuradio-runtime/lib/gr_misc.h @@ -0,0 +1,39 @@ +/* -*- 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_GR_MISC_H +#define INCLUDED_GR_MISC_H + +#include <gr_runtime_api.h> +#include <gr_types.h> + +GR_RUNTIME_API unsigned int +gr_rounduppow2(unsigned int n); + +// FIXME should be template +GR_RUNTIME_API void gr_zero_vector(std::vector<float> &v); +GR_RUNTIME_API void gr_zero_vector(std::vector<double> &v); +GR_RUNTIME_API void gr_zero_vector(std::vector<int> &v); +GR_RUNTIME_API void gr_zero_vector(std::vector<gr_complex> &v); + + +#endif /* INCLUDED_GR_MISC_H */ diff --git a/gnuradio-runtime/lib/gr_msg_accepter.cc b/gnuradio-runtime/lib/gr_msg_accepter.cc new file mode 100644 index 0000000000..93d5fb20e8 --- /dev/null +++ b/gnuradio-runtime/lib/gr_msg_accepter.cc @@ -0,0 +1,59 @@ +/* -*- c++ -*- */ +/* + * Copyright 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <gr_msg_accepter.h> +#include <gr_block.h> +#include <gr_block_detail.h> +#include <gr_hier_block2.h> +#include <stdexcept> + +using namespace pmt; + +gr_msg_accepter::gr_msg_accepter() +{ +} + +gr_msg_accepter::~gr_msg_accepter() +{ + // NOP, required as virtual destructor +} + +void +gr_msg_accepter::post(pmt_t which_port, pmt_t msg) +{ + // Notify derived class, handled case by case + gr_block *p = dynamic_cast<gr_block *>(this); + if (p) { + p->_post(which_port,msg); + return; + } + gr_hier_block2 *p2 = dynamic_cast<gr_hier_block2 *>(this); + if (p2){ + // FIXME do the right thing + return; + } + + throw std::runtime_error("unknown derived class"); +} diff --git a/gnuradio-runtime/lib/gr_msg_handler.cc b/gnuradio-runtime/lib/gr_msg_handler.cc new file mode 100644 index 0000000000..0f93497088 --- /dev/null +++ b/gnuradio-runtime/lib/gr_msg_handler.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 <gr_msg_handler.h> + +gr_msg_handler::~gr_msg_handler () +{ +} diff --git a/gnuradio-runtime/lib/gr_msg_queue.cc b/gnuradio-runtime/lib/gr_msg_queue.cc new file mode 100644 index 0000000000..0cf0467715 --- /dev/null +++ b/gnuradio-runtime/lib/gr_msg_queue.cc @@ -0,0 +1,125 @@ +/* -*- 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include <gr_msg_queue.h> +#include <stdexcept> + +gr_msg_queue_sptr +gr_make_msg_queue(unsigned int limit) +{ + return gr_msg_queue_sptr (new gr_msg_queue(limit)); +} + +gr_msg_queue::gr_msg_queue(unsigned int limit) + : d_not_empty(), d_not_full(), + /*d_head(0), d_tail(0),*/ d_count(0), d_limit(limit) +{ +} + +gr_msg_queue::~gr_msg_queue() +{ + flush (); +} + +void +gr_msg_queue::insert_tail(gr_message_sptr msg) +{ + if (msg->d_next) + throw std::invalid_argument("gr_msg_queue::insert_tail: msg already in queue"); + + gruel::scoped_lock guard(d_mutex); + + while (full_p()) + d_not_full.wait(guard); + + if (d_tail == 0){ + d_tail = d_head = msg; + //msg->d_next = 0; + msg->d_next.reset(); + } + else { + d_tail->d_next = msg; + d_tail = msg; + //msg->d_next = 0; + msg->d_next.reset(); + } + d_count++; + d_not_empty.notify_one(); +} + +gr_message_sptr +gr_msg_queue::delete_head() +{ + gruel::scoped_lock guard(d_mutex); + gr_message_sptr m; + + while ((m = d_head) == 0) + d_not_empty.wait(guard); + + d_head = m->d_next; + if (d_head == 0){ + //d_tail = 0; + d_tail.reset(); + } + + d_count--; + // m->d_next = 0; + m->d_next.reset(); + d_not_full.notify_one(); + return m; +} + +gr_message_sptr +gr_msg_queue::delete_head_nowait() +{ + gruel::scoped_lock guard(d_mutex); + gr_message_sptr m; + + if ((m = d_head) == 0){ + //return 0; + return gr_message_sptr(); + } + + d_head = m->d_next; + if (d_head == 0){ + //d_tail = 0; + d_tail.reset(); + } + + d_count--; + //m->d_next = 0; + m->d_next.reset(); + d_not_full.notify_one(); + return m; +} + +void +gr_msg_queue::flush() +{ + gr_message_sptr m; + + while ((m = delete_head_nowait ()) != 0) + ; +} diff --git a/gnuradio-runtime/lib/gr_pagesize.cc b/gnuradio-runtime/lib/gr_pagesize.cc new file mode 100644 index 0000000000..e31e05ca70 --- /dev/null +++ b/gnuradio-runtime/lib/gr_pagesize.cc @@ -0,0 +1,56 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 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 <gr_pagesize.h> +#include <unistd.h> +#include <stdio.h> + +#if defined(_WIN32) && defined(HAVE_GETPAGESIZE) +extern "C" size_t getpagesize(void); +#endif + +int +gr_pagesize () +{ + static int s_pagesize = -1; + + if (s_pagesize == -1){ +#if defined(HAVE_GETPAGESIZE) + s_pagesize = getpagesize (); +#elif defined (HAVE_SYSCONF) + s_pagesize = sysconf (_SC_PAGESIZE); + if (s_pagesize == -1){ + perror ("_SC_PAGESIZE"); + s_pagesize = 4096; + } +#else + fprintf (stderr, "gr_pagesize: no info; setting pagesize = 4096\n"); + s_pagesize = 4096; +#endif + } + return s_pagesize; +} + diff --git a/gnuradio-runtime/lib/gr_pagesize.h b/gnuradio-runtime/lib/gr_pagesize.h new file mode 100644 index 0000000000..d14cb22b1b --- /dev/null +++ b/gnuradio-runtime/lib/gr_pagesize.h @@ -0,0 +1,34 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 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 _GR_PAGESIZE_H_ +#define _GR_PAGESIZE_H_ + +#include <gr_runtime_api.h> + +/*! + * \brief return the page size in bytes + */ + +GR_RUNTIME_API int gr_pagesize (); + + +#endif /* _GR_PAGESIZE_H_ */
\ No newline at end of file diff --git a/gnuradio-runtime/lib/gr_preferences.cc b/gnuradio-runtime/lib/gr_preferences.cc new file mode 100644 index 0000000000..a0f5616603 --- /dev/null +++ b/gnuradio-runtime/lib/gr_preferences.cc @@ -0,0 +1,108 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2010,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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_preferences.h> +#include <gr_sys_paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> + +#include <boost/filesystem/operations.hpp> +#include <boost/filesystem/path.hpp> +namespace fs = boost::filesystem; + +/* + * The simplest thing that could possibly work: + * the key is the filename; the value is the file contents. + */ + +static const char * +pathname (const char *key) +{ + static fs::path path; + path = fs::path(gr_appdata_path()) / ".gnuradio" / "prefs" / key; + return path.string().c_str(); +} + +static void +ensure_dir_path () +{ + fs::path path = fs::path(gr_appdata_path()) / ".gnuradio"; + if (!fs::is_directory(path)) fs::create_directory(path); + + path = path / "prefs"; + if (!fs::is_directory(path)) fs::create_directory(path); +} + +const char * +gr_preferences::get (const char *key) +{ + static char buf[1024]; + + FILE *fp = fopen (pathname (key), "r"); + if (fp == 0) { + perror (pathname (key)); + return 0; + } + + memset (buf, 0, sizeof (buf)); + size_t ret = fread (buf, 1, sizeof (buf) - 1, fp); + if(ret == 0) { + if(ferror(fp) != 0) { + perror (pathname (key)); + fclose (fp); + return 0; + } + } + fclose (fp); + return buf; +} + +void +gr_preferences::set (const char *key, const char *value) +{ + ensure_dir_path (); + + FILE *fp = fopen (pathname (key), "w"); + if (fp == 0){ + perror (pathname (key)); + return; + } + + size_t ret = fwrite (value, 1, strlen (value), fp); + if(ret == 0) { + if(ferror(fp) != 0) { + perror (pathname (key)); + fclose (fp); + return; + } + } + fclose (fp); +}; diff --git a/gnuradio-runtime/lib/gr_prefs.cc b/gnuradio-runtime/lib/gr_prefs.cc new file mode 100644 index 0000000000..8a79c3335f --- /dev/null +++ b/gnuradio-runtime/lib/gr_prefs.cc @@ -0,0 +1,391 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,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 <gr_prefs.h> +#include <gr_sys_paths.h> +#include <gr_constants.h> +#include <algorithm> + +#include <boost/filesystem/operations.hpp> +#include <boost/filesystem/path.hpp> +#include <boost/filesystem/fstream.hpp> +namespace fs = boost::filesystem; + +/* + * Stub implementations + */ + +static gr_prefs s_default_singleton; +static gr_prefs *s_singleton = &s_default_singleton; + +gr_prefs * +gr_prefs::singleton() +{ + return s_singleton; +} + +void +gr_prefs::set_singleton(gr_prefs *p) +{ + s_singleton = p; +} + +gr_prefs::gr_prefs() +{ + _read_files(); +} + +gr_prefs::~gr_prefs() +{ + // nop +} + +std::vector<std::string> +gr_prefs::_sys_prefs_filenames() +{ + std::vector<std::string> fnames; + + fs::path dir = gr_prefsdir(); + if(!fs::is_directory(dir)) + return fnames; + + fs::directory_iterator diritr(dir); + while(diritr != fs::directory_iterator()) { + fs::path p = *diritr++; + if(p.extension() != ".swp") + fnames.push_back(p.string()); + } + std::sort(fnames.begin(), fnames.end()); + + // Find if there is a ~/.gnuradio/config.conf file and add this to + // the end of the file list to override any preferences in the + // installed path config files. + fs::path homedir = fs::path(gr_appdata_path()); + homedir = homedir/".gnuradio/config.conf"; + if(fs::exists(homedir)) { + fnames.push_back(homedir.string()); + } + + return fnames; +} + +void +gr_prefs::_read_files() +{ + std::string config; + + std::vector<std::string> filenames = _sys_prefs_filenames(); + std::vector<std::string>::iterator sitr; + char tmp[1024]; + for(sitr = filenames.begin(); sitr != filenames.end(); sitr++) { + fs::ifstream fin(*sitr); + while(!fin.eof()) { + fin.getline(tmp, 1024); + std::string t(tmp); + // ignore empty lines or lines of just comments + if((t.size() > 0) && (t[0] != '#')) { + // remove any comments in the line + size_t hash = t.find("#"); + + // Use hash marks at the end of each segment as a delimiter + config += t.substr(0, hash) + '#'; + } + } + fin.close(); + } + + // Remove all whitespace. + config.erase(std::remove_if(config.begin(), config.end(), ::isspace), config.end()); + + // Convert the string into a map + _convert_to_map(config); +} + +void +gr_prefs::_convert_to_map(const std::string &conf) +{ + // Convert the string into an map of maps + // Map is structured as {section name: map of options} + // And options map is simply: {option name: option value} + std::string sub = conf; + size_t sec_start = sub.find("["); + while(sec_start != std::string::npos) { + sub = sub.substr(sec_start); + + size_t sec_end = sub.find("]"); + if(sec_end == std::string::npos) + throw std::runtime_error("Config file error: Mismatched section label.\n"); + + std::string sec = sub.substr(1, sec_end-1); + size_t next_sec_start = sub.find("[", sec_end); + std::string subsec = sub.substr(sec_end+1, next_sec_start-sec_end-2); + + std::transform(sec.begin(), sec.end(), sec.begin(), ::tolower); + + std::map<std::string, std::string> options_map = d_config_map[sec]; + size_t next_opt = 0; + size_t next_val = 0; + next_opt = subsec.find("#"); + while(next_opt < subsec.size()-1) { + next_val = subsec.find("=", next_opt); + std::string option = subsec.substr(next_opt+1, next_val-next_opt-1); + + next_opt = subsec.find("#", next_val); + std::string value = subsec.substr(next_val+1, next_opt-next_val-1); + + std::transform(option.begin(), option.end(), option.begin(), ::tolower); + options_map[option] = value; + } + + d_config_map[sec] = options_map; + + sec_start = sub.find("[", sec_end); + } +} + +std::string +gr_prefs::to_string() +{ + gr_config_map_itr sections; + gr_config_map_elem_itr options; + std::stringstream s; + + for(sections = d_config_map.begin(); sections != d_config_map.end(); sections++) { + s << "[" << sections->first << "]" << std::endl; + for(options = sections->second.begin(); options != sections->second.end(); options++) { + s << options->first << " = " << options->second << std::endl; + } + s << std::endl; + } + + return s.str(); +} + +void +gr_prefs::save() +{ + std::string conf = to_string(); + + fs::path homedir = fs::path(gr_appdata_path()); + homedir = homedir/".gnuradio/config.conf"; + fs::ofstream fout(homedir); + fout << conf; + fout.close(); +} + +char * +gr_prefs::option_to_env(std::string section, std::string option) +{ + std::stringstream envname; + std::string secname=section, optname=option; + + std::transform(section.begin(), section.end(), secname.begin(), ::toupper); + std::transform(option.begin(), option.end(), optname.begin(), ::toupper); + envname << "GR_CONF_" << secname << "_" << optname; + + return getenv(envname.str().c_str()); +} + +bool +gr_prefs::has_section(const std::string §ion) +{ + std::string s = section; + std::transform(section.begin(), section.end(), s.begin(), ::tolower); + return d_config_map.count(s) > 0; +} + +bool +gr_prefs::has_option(const std::string §ion, const std::string &option) +{ + if(option_to_env(section, option)) + return true; + + if(has_section(section)) { + std::string s = section; + std::transform(section.begin(), section.end(), s.begin(), ::tolower); + + std::string o = option; + std::transform(option.begin(), option.end(), o.begin(), ::tolower); + + gr_config_map_itr sec = d_config_map.find(s); + return sec->second.count(o) > 0; + } + else { + return false; + } +} + +const std::string +gr_prefs::get_string(const std::string §ion, const std::string &option, + const std::string &default_val) +{ + char *env = option_to_env(section, option); + if(env) + return std::string(env); + + if(has_option(section, option)) { + std::string s = section; + std::transform(section.begin(), section.end(), s.begin(), ::tolower); + + std::string o = option; + std::transform(option.begin(), option.end(), o.begin(), ::tolower); + + gr_config_map_itr sec = d_config_map.find(s); + gr_config_map_elem_itr opt = sec->second.find(o); + return opt->second; + } + else { + return default_val; + } +} + +void +gr_prefs::set_string(const std::string §ion, const std::string &option, + const std::string &val) +{ + std::string s = section; + std::transform(section.begin(), section.end(), s.begin(), ::tolower); + + std::string o = option; + std::transform(option.begin(), option.end(), o.begin(), ::tolower); + + std::map<std::string, std::string> opt_map = d_config_map[s]; + + opt_map[o] = val; + + d_config_map[s] = opt_map; +} + +bool +gr_prefs::get_bool(const std::string §ion, const std::string &option, bool default_val) +{ + if(has_option(section, option)) { + std::string str = get_string(section, option, ""); + if(str == "") { + return default_val; + } + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + if((str == "true") || (str == "on") || (str == "1")) + return true; + else if((str == "false") || (str == "off") || (str == "0")) + return false; + else + return default_val; + } + else { + return default_val; + } +} + +void +gr_prefs::set_bool(const std::string §ion, const std::string &option, bool val) +{ + std::string s = section; + std::transform(section.begin(), section.end(), s.begin(), ::tolower); + + std::string o = option; + std::transform(option.begin(), option.end(), o.begin(), ::tolower); + + std::map<std::string, std::string> opt_map = d_config_map[s]; + + std::stringstream sstr; + sstr << (val == true); + opt_map[o] = sstr.str(); + + d_config_map[s] = opt_map; +} + +long +gr_prefs::get_long(const std::string §ion, const std::string &option, long default_val) +{ + if(has_option(section, option)) { + std::string str = get_string(section, option, ""); + if(str == "") { + return default_val; + } + std::stringstream sstr(str); + long n; + sstr >> n; + return n; + } + else { + return default_val; + } +} + +void +gr_prefs::set_long(const std::string §ion, const std::string &option, long val) +{ + std::string s = section; + std::transform(section.begin(), section.end(), s.begin(), ::tolower); + + std::string o = option; + std::transform(option.begin(), option.end(), o.begin(), ::tolower); + + std::map<std::string, std::string> opt_map = d_config_map[s]; + + std::stringstream sstr; + sstr << val; + opt_map[o] = sstr.str(); + + d_config_map[s] = opt_map; +} + +double +gr_prefs::get_double(const std::string §ion, const std::string &option, double default_val) +{ + if(has_option(section, option)) { + std::string str = get_string(section, option, ""); + if(str == "") { + return default_val; + } + std::stringstream sstr(str); + double n; + sstr >> n; + return n; + } + else { + return default_val; + } +} + +void +gr_prefs::set_double(const std::string §ion, const std::string &option, double val) +{ + std::string s = section; + std::transform(section.begin(), section.end(), s.begin(), ::tolower); + + std::string o = option; + std::transform(option.begin(), option.end(), o.begin(), ::tolower); + + std::map<std::string, std::string> opt_map = d_config_map[s]; + + std::stringstream sstr; + sstr << val; + opt_map[o] = sstr.str(); + + d_config_map[s] = opt_map; +} diff --git a/gnuradio-runtime/lib/gr_random.cc b/gnuradio-runtime/lib/gr_random.cc new file mode 100644 index 0000000000..323839acc7 --- /dev/null +++ b/gnuradio-runtime/lib/gr_random.cc @@ -0,0 +1,183 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002 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. + */ + +/* + * Copyright 1997 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <math.h> +#include <gr_random.h> + +#define IA 16807 +#define IM 2147483647 +#define AM (1.0/IM) +#define IQ 127773 +#define IR 2836 +#define NDIV (1+(IM-1)/NTAB) +#define EPS 1.2e-7 +#define RNMX (1.0-EPS) + + +gr_random::gr_random (long seed) +{ + reseed (seed); +} + +void +gr_random::reseed (long seed) +{ + d_seed = seed; + d_iy = 0; + for (int i = 0; i < NTAB; i++) + d_iv[i] = 0; + d_iset = 0; + d_gset = 0; +} + +/* + * This looks like it returns a uniform random deviate between 0.0 and 1.0 + * It looks similar to code from "Numerical Recipes in C". + */ +float gr_random::ran1() +{ + int j; + long k; + float temp; + + if (d_seed <= 0 || !d_iy) { + if (-d_seed < 1) + d_seed=1; + else + d_seed = -d_seed; + for (j=NTAB+7;j>=0;j--) { + k=d_seed/IQ; + d_seed=IA*(d_seed-k*IQ)-IR*k; + if (d_seed < 0) + d_seed += IM; + if (j < NTAB) + d_iv[j] = d_seed; + } + d_iy=d_iv[0]; + } + k=(d_seed)/IQ; + d_seed=IA*(d_seed-k*IQ)-IR*k; + if (d_seed < 0) + d_seed += IM; + j=d_iy/NDIV; + d_iy=d_iv[j]; + d_iv[j] = d_seed; + temp=AM * d_iy; + if (temp > RNMX) + temp = RNMX; + return temp; +} + +/* + * Returns a normally distributed deviate with zero mean and variance 1. + * Also looks like it's from "Numerical Recipes in C". + */ +float gr_random::gasdev() +{ + float fac,rsq,v1,v2; + d_iset = 1 - d_iset; + if (d_iset) { + do { + v1=2.0*ran1()-1.0; + v2=2.0*ran1()-1.0; + rsq=v1*v1+v2*v2; + } while (rsq >= 1.0 || rsq == 0.0); + fac= sqrt(-2.0*log(rsq)/rsq); + d_gset=v1*fac; + return v2*fac; + } + return d_gset; +} + +/* + * Copied from The KC7WW / OH2BNS Channel Simulator + * FIXME Need to check how good this is at some point + */ + +float gr_random::laplacian() +{ + float z = ran1(); + if (z < 0.5) + return log(2.0 * z) / M_SQRT2; + else + return -log(2.0 * (1.0 - z)) / M_SQRT2; +} + +/* + * Copied from The KC7WW / OH2BNS Channel Simulator + * FIXME Need to check how good this is at some point + */ + + // 5 => scratchy, 8 => Geiger + +float gr_random::impulse(float factor = 5) +{ + float z = -M_SQRT2 * log(ran1()); + if (fabsf(z) <= factor) + return 0.0; + else + return z; +} + +/* + * Complex rayleigh is really gaussian I and gaussian Q + * It can also be generated by real rayleigh magnitude and + * uniform random angle + * Adapted from The KC7WW / OH2BNS Channel Simulator + * FIXME Need to check how good this is at some point + */ + +gr_complex gr_random::rayleigh_complex() +{ + return gr_complex(gasdev(),gasdev()); +} + +/* Other option + mag = rayleigh(); + ang = 2.0 * M_PI * RNG(); + *Rx = rxx * cos(z); + *Iy = rxx * sin(z); +*/ + + +float gr_random::rayleigh() +{ + return sqrt(-2.0 * log(ran1())); +} diff --git a/gnuradio-runtime/lib/gr_random.h b/gnuradio-runtime/lib/gr_random.h new file mode 100644 index 0000000000..783c05f920 --- /dev/null +++ b/gnuradio-runtime/lib/gr_random.h @@ -0,0 +1,65 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002 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_RANDOM_H +#define INCLUDED_GR_RANDOM_H + +#include <gr_runtime_api.h> +#include <gr_complex.h> + +/*! + * \brief pseudo random number generator + * \ingroup math_blk + */ +class GR_RUNTIME_API gr_random { +protected: + static const int NTAB = 32; + long d_seed; + long d_iy; + long d_iv[NTAB]; + int d_iset; + float d_gset; + + +public: + gr_random (long seed=3021); + + void reseed (long seed); + + /*! + * \brief uniform random deviate in the range [0.0, 1.0) + */ + float ran1 (); + + /*! + * \brief normally distributed deviate with zero mean and variance 1 + */ + float gasdev (); + + float laplacian (); + float impulse (float factor); + float rayleigh (); + gr_complex rayleigh_complex (); +}; + +#endif /* INCLUDED_GR_RANDOM_H */ + diff --git a/gnuradio-runtime/lib/gr_realtime.cc b/gnuradio-runtime/lib/gr_realtime.cc new file mode 100644 index 0000000000..75b497999d --- /dev/null +++ b/gnuradio-runtime/lib/gr_realtime.cc @@ -0,0 +1,32 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2007,2008 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 <gr_realtime.h> + +gr_rt_status_t +gr_enable_realtime_scheduling() +{ + return gruel::enable_realtime_scheduling(); +} diff --git a/gnuradio-runtime/lib/gr_reverse.cc b/gnuradio-runtime/lib/gr_reverse.cc new file mode 100644 index 0000000000..08c588cb55 --- /dev/null +++ b/gnuradio-runtime/lib/gr_reverse.cc @@ -0,0 +1,60 @@ +/* -*- 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 <gr_reverse.h> + + +std::vector<float> +gr_reverse (const std::vector<float> &taps) +{ + int size = taps.size (); + std::vector<float> new_taps(size); + + if (size == 0) + return new_taps; + + for (int i = 0; i < size; i++) + new_taps[i] = taps[size - i - 1]; + + return new_taps; +} + + +std::vector<gr_complex> +gr_reverse (const std::vector<gr_complex> &taps) +{ + int size = taps.size (); + std::vector<gr_complex> new_taps(size); + + if (size == 0) + return new_taps; + + for (int i = 0; i < size; i++) + new_taps[i] = taps[size - i - 1]; + + return new_taps; +} + diff --git a/gnuradio-runtime/lib/gr_reverse.h b/gnuradio-runtime/lib/gr_reverse.h new file mode 100644 index 0000000000..aa8619619f --- /dev/null +++ b/gnuradio-runtime/lib/gr_reverse.h @@ -0,0 +1,34 @@ +/* -*- 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_GR_REVERSE_H +#define INCLUDED_GR_REVERSE_H + +#include <gr_runtime_api.h> +#include <vector> +#include <gr_complex.h> + +// reverse the order of taps +std::vector<float> gr_reverse (const std::vector<float> &taps); +std::vector<gr_complex> gr_reverse (const std::vector<gr_complex> &taps); + + +#endif /* INCLUDED_GR_REVERSE_H */ diff --git a/gnuradio-runtime/lib/gr_scheduler.cc b/gnuradio-runtime/lib/gr_scheduler.cc new file mode 100644 index 0000000000..c691f5d99f --- /dev/null +++ b/gnuradio-runtime/lib/gr_scheduler.cc @@ -0,0 +1,33 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <gr_scheduler.h> + +gr_scheduler::gr_scheduler(gr_flat_flowgraph_sptr ffg, int max_noutput_items) +{ +} + +gr_scheduler::~gr_scheduler() +{ +} diff --git a/gnuradio-runtime/lib/gr_scheduler.h b/gnuradio-runtime/lib/gr_scheduler.h new file mode 100644 index 0000000000..097f575c21 --- /dev/null +++ b/gnuradio-runtime/lib/gr_scheduler.h @@ -0,0 +1,65 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef INCLUDED_GR_SCHEDULER_H +#define INCLUDED_GR_SCHEDULER_H + +#include <gr_runtime_api.h> +#include <boost/utility.hpp> +#include <gr_block.h> +#include <gr_flat_flowgraph.h> + + +class gr_scheduler; +typedef boost::shared_ptr<gr_scheduler> gr_scheduler_sptr; + + +/*! + * \brief Abstract scheduler that takes a flattened flow graph and runs it. + * + * Preconditions: details, buffers and buffer readers have been assigned. + */ +class GR_RUNTIME_API gr_scheduler : boost::noncopyable +{ + +public: + /*! + * \brief Construct a scheduler and begin evaluating the graph. + * + * The scheduler will continue running until all blocks until they + * report that they are done or the stop method is called. + */ + gr_scheduler(gr_flat_flowgraph_sptr ffg, int max_noutput_items); + + virtual ~gr_scheduler(); + + /*! + * \brief Tell the scheduler to stop executing. + */ + virtual void stop() = 0; + + /*! + * \brief Block until the graph is done. + */ + virtual void wait() = 0; +}; + +#endif /* INCLUDED_GR_SCHEDULER_H */ diff --git a/gnuradio-runtime/lib/gr_scheduler_sts.cc b/gnuradio-runtime/lib/gr_scheduler_sts.cc new file mode 100644 index 0000000000..2c96def6d1 --- /dev/null +++ b/gnuradio-runtime/lib/gr_scheduler_sts.cc @@ -0,0 +1,87 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <gr_scheduler_sts.h> +#include <gr_single_threaded_scheduler.h> +#include <gruel/thread_body_wrapper.h> + +class sts_container +{ + gr_block_vector_t d_blocks; + +public: + + sts_container(gr_block_vector_t blocks) + : d_blocks(blocks) {} + + void operator()() + { + gr_make_single_threaded_scheduler(d_blocks)->run(); + } +}; + + +gr_scheduler_sptr +gr_scheduler_sts::make(gr_flat_flowgraph_sptr ffg, int max_noutput_items) +{ + return gr_scheduler_sptr(new gr_scheduler_sts(ffg, max_noutput_items)); +} + +gr_scheduler_sts::gr_scheduler_sts(gr_flat_flowgraph_sptr ffg, int max_noutput_items) + : gr_scheduler(ffg, max_noutput_items) +{ + // Split the flattened flow graph into discrete partitions, each + // of which is topologically sorted. + + std::vector<gr_basic_block_vector_t> graphs = ffg->partition(); + + // For each partition, create a thread to evaluate it using + // an instance of the gr_single_threaded_scheduler + + for (std::vector<gr_basic_block_vector_t>::iterator p = graphs.begin(); + p != graphs.end(); p++) { + + gr_block_vector_t blocks = gr_flat_flowgraph::make_block_vector(*p); + d_threads.create_thread( + gruel::thread_body_wrapper<sts_container>(sts_container(blocks), + "single-threaded-scheduler")); + } +} + +gr_scheduler_sts::~gr_scheduler_sts() +{ + stop(); +} + +void +gr_scheduler_sts::stop() +{ + d_threads.interrupt_all(); +} + +void +gr_scheduler_sts::wait() +{ + d_threads.join_all(); +} diff --git a/gnuradio-runtime/lib/gr_scheduler_sts.h b/gnuradio-runtime/lib/gr_scheduler_sts.h new file mode 100644 index 0000000000..43b97b62c1 --- /dev/null +++ b/gnuradio-runtime/lib/gr_scheduler_sts.h @@ -0,0 +1,63 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef INCLUDED_GR_SCHEDULER_STS_H +#define INCLUDED_GR_SCHEDULER_STS_H + +#include <gr_runtime_api.h> +#include <gr_scheduler.h> +#include <gruel/thread_group.h> + +/*! + * \brief Concrete scheduler that uses the single_threaded_scheduler + */ +class GR_RUNTIME_API gr_scheduler_sts : public gr_scheduler +{ + gruel::thread_group d_threads; + +protected: + /*! + * \brief Construct a scheduler and begin evaluating the graph. + * + * The scheduler will continue running until all blocks until they + * report that they are done or the stop method is called. + */ + gr_scheduler_sts(gr_flat_flowgraph_sptr ffg, int max_noutput_items); + +public: + static gr_scheduler_sptr make(gr_flat_flowgraph_sptr ffg, int max_noutput_items); + + ~gr_scheduler_sts(); + + /*! + * \brief Tell the scheduler to stop executing. + */ + void stop(); + + /*! + * \brief Block until the graph is done. + */ + void wait(); +}; + + + + +#endif /* INCLUDED_GR_SCHEDULER_STS_H */ diff --git a/gnuradio-runtime/lib/gr_scheduler_tpb.cc b/gnuradio-runtime/lib/gr_scheduler_tpb.cc new file mode 100644 index 0000000000..2824eb1b3b --- /dev/null +++ b/gnuradio-runtime/lib/gr_scheduler_tpb.cc @@ -0,0 +1,103 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <gr_scheduler_tpb.h> +#include <gr_tpb_thread_body.h> +#include <gruel/thread_body_wrapper.h> +#include <sstream> + +/* + * You know, a lambda expression would be sooo much easier... + */ +class tpb_container +{ + gr_block_sptr d_block; + int d_max_noutput_items; + +public: + tpb_container(gr_block_sptr block, int max_noutput_items) + : d_block(block), d_max_noutput_items(max_noutput_items) {} + + void operator()() + { + gr_tpb_thread_body body(d_block, d_max_noutput_items); + } +}; + + +gr_scheduler_sptr +gr_scheduler_tpb::make(gr_flat_flowgraph_sptr ffg, int max_noutput_items) +{ + return gr_scheduler_sptr(new gr_scheduler_tpb(ffg, max_noutput_items)); +} + +gr_scheduler_tpb::gr_scheduler_tpb(gr_flat_flowgraph_sptr ffg, int max_noutput_items) + : gr_scheduler(ffg, max_noutput_items) +{ + // Get a topologically sorted vector of all the blocks in use. + // Being topologically sorted probably isn't going to matter, but + // there's a non-zero chance it might help... + + gr_basic_block_vector_t used_blocks = ffg->calc_used_blocks(); + used_blocks = ffg->topological_sort(used_blocks); + gr_block_vector_t blocks = gr_flat_flowgraph::make_block_vector(used_blocks); + + // Ensure that the done flag is clear on all blocks + + for (size_t i = 0; i < blocks.size(); i++){ + blocks[i]->detail()->set_done(false); + } + + // Fire off a thead for each block + + for (size_t i = 0; i < blocks.size(); i++){ + std::stringstream name; + name << "thread-per-block[" << i << "]: " << blocks[i]; + + // If set, use internal value instead of global value + if(blocks[i]->is_set_max_noutput_items()) + max_noutput_items = blocks[i]->max_noutput_items(); + + d_threads.create_thread( + gruel::thread_body_wrapper<tpb_container>(tpb_container(blocks[i], max_noutput_items), + name.str())); + } +} + +gr_scheduler_tpb::~gr_scheduler_tpb() +{ + stop(); +} + +void +gr_scheduler_tpb::stop() +{ + d_threads.interrupt_all(); +} + +void +gr_scheduler_tpb::wait() +{ + d_threads.join_all(); +} diff --git a/gnuradio-runtime/lib/gr_scheduler_tpb.h b/gnuradio-runtime/lib/gr_scheduler_tpb.h new file mode 100644 index 0000000000..d978dd28e1 --- /dev/null +++ b/gnuradio-runtime/lib/gr_scheduler_tpb.h @@ -0,0 +1,61 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef INCLUDED_GR_SCHEDULER_TPB_H +#define INCLUDED_GR_SCHEDULER_TPB_H + +#include <gr_runtime_api.h> +#include <gr_scheduler.h> +#include <gruel/thread_group.h> + +/*! + * \brief Concrete scheduler that uses a kernel thread-per-block + */ +class GR_RUNTIME_API gr_scheduler_tpb : public gr_scheduler +{ + gruel::thread_group d_threads; + +protected: + /*! + * \brief Construct a scheduler and begin evaluating the graph. + * + * The scheduler will continue running until all blocks until they + * report that they are done or the stop method is called. + */ + gr_scheduler_tpb(gr_flat_flowgraph_sptr ffg, int max_noutput_items); + +public: + static gr_scheduler_sptr make(gr_flat_flowgraph_sptr ffg, int max_noutput_items=100000); + + ~gr_scheduler_tpb(); + + /*! + * \brief Tell the scheduler to stop executing. + */ + void stop(); + + /*! + * \brief Block until the graph is done. + */ + void wait(); +}; + + +#endif /* INCLUDED_GR_SCHEDULER_TPB_H */ diff --git a/gnuradio-runtime/lib/gr_select_handler.cc b/gnuradio-runtime/lib/gr_select_handler.cc new file mode 100644 index 0000000000..0fc86354a6 --- /dev/null +++ b/gnuradio-runtime/lib/gr_select_handler.cc @@ -0,0 +1,36 @@ +/* -*- 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 <gr_select_handler.h> + +gr_select_handler::gr_select_handler(int fd) + : d_fd(fd) +{ +} + +gr_select_handler::~gr_select_handler() +{ +} diff --git a/gnuradio-runtime/lib/gr_sincos.c b/gnuradio-runtime/lib/gr_sincos.c new file mode 100644 index 0000000000..a8d01b0da4 --- /dev/null +++ b/gnuradio-runtime/lib/gr_sincos.c @@ -0,0 +1,83 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,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 + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE // ask for GNU extensions if available +#endif + +#include <gr_sincos.h> +#include <math.h> + +// ---------------------------------------------------------------- + +#if defined (HAVE_SINCOS) + +void +gr_sincos (double x, double *sinx, double *cosx) +{ + sincos (x, sinx, cosx); +} + +#else + +void +gr_sincos (double x, double *sinx, double *cosx) +{ + *sinx = sin (x); + *cosx = cos (x); +} + +#endif + +// ---------------------------------------------------------------- + +#if defined (HAVE_SINCOSF) + +void +gr_sincosf (float x, float *sinx, float *cosx) +{ + sincosf (x, sinx, cosx); +} + +#elif defined (HAVE_SINF) && defined (HAVE_COSF) + +void +gr_sincosf (float x, float *sinx, float *cosx) +{ + *sinx = sinf (x); + *cosx = cosf (x); +} + +#else + +void +gr_sincosf (float x, float *sinx, float *cosx) +{ + *sinx = sin (x); + *cosx = cos (x); +} + +#endif diff --git a/gnuradio-runtime/lib/gr_single_threaded_scheduler.cc b/gnuradio-runtime/lib/gr_single_threaded_scheduler.cc new file mode 100644 index 0000000000..1bb9e9b0a8 --- /dev/null +++ b/gnuradio-runtime/lib/gr_single_threaded_scheduler.cc @@ -0,0 +1,364 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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 <gr_single_threaded_scheduler.h> +#include <gr_block.h> +#include <gr_block_detail.h> +#include <gr_buffer.h> +#include <boost/thread.hpp> +#include <boost/format.hpp> +#include <iostream> +#include <limits> +#include <assert.h> +#include <stdio.h> + +// must be defined to either 0 or 1 +#define ENABLE_LOGGING 0 + +#if (ENABLE_LOGGING) +#define LOG(x) do { x; } while(0) +#else +#define LOG(x) do {;} while(0) +#endif + +static int which_scheduler = 0; + +gr_single_threaded_scheduler_sptr +gr_make_single_threaded_scheduler (const std::vector<gr_block_sptr> &blocks) +{ + return + gr_single_threaded_scheduler_sptr (new gr_single_threaded_scheduler (blocks)); +} + +gr_single_threaded_scheduler::gr_single_threaded_scheduler ( + const std::vector<gr_block_sptr> &blocks) + : d_blocks (blocks), d_enabled (true), d_log(0) +{ + if (ENABLE_LOGGING){ + std::string name = str(boost::format("sst-%d.log") % which_scheduler++); + d_log = new std::ofstream(name.c_str()); + *d_log << "gr_single_threaded_scheduler: " + << d_blocks.size () + << " blocks\n"; + } +} + +gr_single_threaded_scheduler::~gr_single_threaded_scheduler () +{ + if (ENABLE_LOGGING) + delete d_log; +} + +void +gr_single_threaded_scheduler::run () +{ + // d_enabled = true; // KLUDGE + main_loop (); +} + +void +gr_single_threaded_scheduler::stop () +{ + if (0) + std::cout << "gr_singled_threaded_scheduler::stop() " + << this << std::endl; + d_enabled = false; +} + +inline static unsigned int +round_up (unsigned int n, unsigned int multiple) +{ + return ((n + multiple - 1) / multiple) * multiple; +} + +inline static unsigned int +round_down (unsigned int n, unsigned int multiple) +{ + return (n / multiple) * multiple; +} + +// +// Return minimum available write space in all our downstream buffers +// or -1 if we're output blocked and the output we're blocked +// on is done. +// +static int +min_available_space (gr_block_detail *d, int output_multiple) +{ + int min_space = std::numeric_limits<int>::max(); + + for (int i = 0; i < d->noutputs (); i++){ + int n = round_down (d->output(i)->space_available (), output_multiple); + if (n == 0){ // We're blocked on output. + if (d->output(i)->done()){ // Downstream is done, therefore we're done. + return -1; + } + return 0; + } + min_space = std::min (min_space, n); + } + return min_space; +} + +void +gr_single_threaded_scheduler::main_loop () +{ + static const int DEFAULT_CAPACITY = 16; + + int noutput_items; + gr_vector_int ninput_items_required (DEFAULT_CAPACITY); + gr_vector_int ninput_items (DEFAULT_CAPACITY); + gr_vector_const_void_star input_items (DEFAULT_CAPACITY); + gr_vector_void_star output_items (DEFAULT_CAPACITY); + unsigned int bi; + unsigned int nalive; + int max_items_avail; + bool made_progress_last_pass; + bool making_progress; + + for (unsigned i = 0; i < d_blocks.size (); i++) + d_blocks[i]->detail()->set_done (false); // reset any done flags + + for (unsigned i = 0; i < d_blocks.size (); i++) // enable any drivers, etc. + d_blocks[i]->start(); + + + bi = 0; + made_progress_last_pass = true; + making_progress = false; + + // Loop while there are still blocks alive + + nalive = d_blocks.size (); + while (d_enabled && nalive > 0){ + + if (boost::this_thread::interruption_requested()) + break; + + gr_block *m = d_blocks[bi].get (); + gr_block_detail *d = m->detail().get (); + + LOG(*d_log << std::endl << m); + + if (d->done ()) + goto next_block; + + if (d->source_p ()){ + // Invoke sources as a last resort. As long as the previous pass + // made progress, don't call a source. + if (made_progress_last_pass){ + LOG(*d_log << " Skipping source\n"); + goto next_block; + } + + ninput_items_required.resize (0); + ninput_items.resize (0); + input_items.resize (0); + output_items.resize (d->noutputs ()); + + // determine the minimum available output space + noutput_items = min_available_space (d, m->output_multiple ()); + LOG(*d_log << " source\n noutput_items = " << noutput_items << std::endl); + if (noutput_items == -1) // we're done + goto were_done; + + if (noutput_items == 0){ // we're output blocked + LOG(*d_log << " BLKD_OUT\n"); + goto next_block; + } + + goto setup_call_to_work; // jump to common code + } + + else if (d->sink_p ()){ + ninput_items_required.resize (d->ninputs ()); + ninput_items.resize (d->ninputs ()); + input_items.resize (d->ninputs ()); + output_items.resize (0); + LOG(*d_log << " sink\n"); + + max_items_avail = 0; + for (int i = 0; i < d->ninputs (); i++){ + ninput_items[i] = d->input(i)->items_available(); + //if (ninput_items[i] == 0 && d->input(i)->done()) + if (ninput_items[i] < m->output_multiple() && d->input(i)->done()) + goto were_done; + + max_items_avail = std::max (max_items_avail, ninput_items[i]); + } + + // take a swag at how much output we can sink + noutput_items = (int) (max_items_avail * m->relative_rate ()); + noutput_items = round_down (noutput_items, m->output_multiple ()); + LOG(*d_log << " max_items_avail = " << max_items_avail << std::endl); + LOG(*d_log << " noutput_items = " << noutput_items << std::endl); + + if (noutput_items == 0){ // we're blocked on input + LOG(*d_log << " BLKD_IN\n"); + goto next_block; + } + + goto try_again; // Jump to code shared with regular case. + } + + else { + // do the regular thing + ninput_items_required.resize (d->ninputs ()); + ninput_items.resize (d->ninputs ()); + input_items.resize (d->ninputs ()); + output_items.resize (d->noutputs ()); + + max_items_avail = 0; + for (int i = 0; i < d->ninputs (); i++){ + ninput_items[i] = d->input(i)->items_available (); + max_items_avail = std::max (max_items_avail, ninput_items[i]); + } + + // determine the minimum available output space + noutput_items = min_available_space (d, m->output_multiple ()); + if (ENABLE_LOGGING){ + *d_log << " regular "; + if (m->relative_rate() >= 1.0) + *d_log << "1:" << m->relative_rate() << std::endl; + else + *d_log << 1.0/m->relative_rate() << ":1\n"; + *d_log << " max_items_avail = " << max_items_avail << std::endl; + *d_log << " noutput_items = " << noutput_items << std::endl; + } + if (noutput_items == -1) // we're done + goto were_done; + + if (noutput_items == 0){ // we're output blocked + LOG(*d_log << " BLKD_OUT\n"); + goto next_block; + } + +#if 0 + // Compute best estimate of noutput_items that we can really use. + noutput_items = + std::min ((unsigned) noutput_items, + std::max ((unsigned) m->output_multiple(), + round_up ((unsigned) (max_items_avail * m->relative_rate()), + m->output_multiple ()))); + + LOG(*d_log << " revised noutput_items = " << noutput_items << std::endl); +#endif + + try_again: + if (m->fixed_rate()){ + // try to work it forward starting with max_items_avail. + // We want to try to consume all the input we've got. + int reqd_noutput_items = m->fixed_rate_ninput_to_noutput(max_items_avail); + reqd_noutput_items = round_up(reqd_noutput_items, m->output_multiple()); + if (reqd_noutput_items > 0 && reqd_noutput_items <= noutput_items) + noutput_items = reqd_noutput_items; + } + + // ask the block how much input they need to produce noutput_items + m->forecast (noutput_items, ninput_items_required); + + // See if we've got sufficient input available + + int i; + for (i = 0; i < d->ninputs (); i++) + if (ninput_items_required[i] > ninput_items[i]) // not enough + break; + + if (i < d->ninputs ()){ // not enough input on input[i] + // if we can, try reducing the size of our output request + if (noutput_items > m->output_multiple ()){ + noutput_items /= 2; + noutput_items = round_up (noutput_items, m->output_multiple ()); + goto try_again; + } + + // We're blocked on input + LOG(*d_log << " BLKD_IN\n"); + if (d->input(i)->done()) // If the upstream block is done, we're done + goto were_done; + + // Is it possible to ever fulfill this request? + if (ninput_items_required[i] > d->input(i)->max_possible_items_available ()){ + // Nope, never going to happen... + std::cerr << "\nsched: <gr_block " << m->name() + << " (" << m->unique_id() << ")>" + << " is requesting more input data\n" + << " than we can provide.\n" + << " ninput_items_required = " + << ninput_items_required[i] << "\n" + << " max_possible_items_available = " + << d->input(i)->max_possible_items_available() << "\n" + << " If this is a filter, consider reducing the number of taps.\n"; + goto were_done; + } + + goto next_block; + } + + // We've got enough data on each input to produce noutput_items. + // Finish setting up the call to work. + + for (int i = 0; i < d->ninputs (); i++) + input_items[i] = d->input(i)->read_pointer(); + + setup_call_to_work: + + for (int i = 0; i < d->noutputs (); i++) + output_items[i] = d->output(i)->write_pointer(); + + // Do the actual work of the block + int n = m->general_work (noutput_items, ninput_items, + input_items, output_items); + LOG(*d_log << " general_work: noutput_items = " << noutput_items + << " result = " << n << std::endl); + + if (n == -1) // block is done + goto were_done; + + d->produce_each (n); // advance write pointers + if (n > 0) + making_progress = true; + + goto next_block; + } + assert (0); + + were_done: + LOG(*d_log << " were_done\n"); + d->set_done (true); + nalive--; + + next_block: + if (++bi >= d_blocks.size ()){ + bi = 0; + made_progress_last_pass = making_progress; + making_progress = false; + } + } + + for (unsigned i = 0; i < d_blocks.size (); i++) // disable any drivers, etc. + d_blocks[i]->stop(); +} diff --git a/gnuradio-runtime/lib/gr_sptr_magic.cc b/gnuradio-runtime/lib/gr_sptr_magic.cc new file mode 100644 index 0000000000..7fdadf24a2 --- /dev/null +++ b/gnuradio-runtime/lib/gr_sptr_magic.cc @@ -0,0 +1,72 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <gr_sptr_magic.h> +#include <gr_hier_block2.h> +#include <map> +#include <stdexcept> + + +#include <gruel/thread.h> + +namespace gnuradio { + + static gruel::mutex s_mutex; + typedef std::map<gr_basic_block*, gr_basic_block_sptr> sptr_map; + static sptr_map s_map; + + void + detail::sptr_magic::create_and_stash_initial_sptr(gr_hier_block2 *p) + { + gr_basic_block_sptr sptr(p); + gruel::scoped_lock guard(s_mutex); + s_map.insert(sptr_map::value_type(static_cast<gr_basic_block *>(p), sptr)); + } + + + gr_basic_block_sptr + detail::sptr_magic::fetch_initial_sptr(gr_basic_block *p) + { + /* + * If p isn't a subclass of gr_hier_block2, just create the + * shared ptr and return it. + */ + gr_hier_block2 *hb2 = dynamic_cast<gr_hier_block2 *>(p); + if (!hb2){ + return gr_basic_block_sptr(p); + } + + /* + * p is a subclass of gr_hier_block2, thus we've already created the shared pointer + * and stashed it away. Fish it out and return it. + */ + gruel::scoped_lock guard(s_mutex); + sptr_map::iterator pos = s_map.find(static_cast<gr_basic_block *>(p)); + if (pos == s_map.end()) + throw std::invalid_argument("gr_sptr_magic: invalid pointer!"); + + gr_basic_block_sptr sptr = pos->second; + s_map.erase(pos); + return sptr; + } +}; diff --git a/gnuradio-runtime/lib/gr_sync_block.cc b/gnuradio-runtime/lib/gr_sync_block.cc new file mode 100644 index 0000000000..94efcdc8ee --- /dev/null +++ b/gnuradio-runtime/lib/gr_sync_block.cc @@ -0,0 +1,68 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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 <gr_sync_block.h> + +gr_sync_block::gr_sync_block (const std::string &name, + gr_io_signature_sptr input_signature, + gr_io_signature_sptr output_signature) + : gr_block(name, input_signature, output_signature) +{ + set_fixed_rate(true); +} + + +void +gr_sync_block::forecast (int noutput_items, gr_vector_int &ninput_items_required) +{ + unsigned ninputs = ninput_items_required.size(); + for (unsigned i = 0; i < ninputs; i++) + ninput_items_required[i] = fixed_rate_noutput_to_ninput (noutput_items); +} + +int +gr_sync_block::fixed_rate_noutput_to_ninput(int noutput_items) +{ + return noutput_items + history() - 1; +} + +int +gr_sync_block::fixed_rate_ninput_to_noutput(int ninput_items) +{ + return std::max(0, ninput_items - (int)history() + 1); +} + +int +gr_sync_block::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + int r = work (noutput_items, input_items, output_items); + if (r > 0) + consume_each (r); + return r; +} diff --git a/gnuradio-runtime/lib/gr_sync_decimator.cc b/gnuradio-runtime/lib/gr_sync_decimator.cc new file mode 100644 index 0000000000..a0f907db53 --- /dev/null +++ b/gnuradio-runtime/lib/gr_sync_decimator.cc @@ -0,0 +1,69 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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 <gr_sync_decimator.h> + +gr_sync_decimator::gr_sync_decimator (const std::string &name, + gr_io_signature_sptr input_signature, + gr_io_signature_sptr output_signature, + unsigned decimation) + : gr_sync_block (name, input_signature, output_signature) +{ + set_decimation (decimation); +} + +void +gr_sync_decimator::forecast (int noutput_items, gr_vector_int &ninput_items_required) +{ + unsigned ninputs = ninput_items_required.size (); + for (unsigned i = 0; i < ninputs; i++) + ninput_items_required[i] = fixed_rate_noutput_to_ninput(noutput_items); +} + +int +gr_sync_decimator::fixed_rate_noutput_to_ninput(int noutput_items) +{ + return noutput_items * decimation() + history() - 1; +} + +int +gr_sync_decimator::fixed_rate_ninput_to_noutput(int ninput_items) +{ + return std::max(0, ninput_items - (int)history() + 1) / decimation(); +} + +int +gr_sync_decimator::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + int r = work (noutput_items, input_items, output_items); + if (r > 0) + consume_each (r * decimation ()); + return r; +} + diff --git a/gnuradio-runtime/lib/gr_sync_interpolator.cc b/gnuradio-runtime/lib/gr_sync_interpolator.cc new file mode 100644 index 0000000000..ece873c14a --- /dev/null +++ b/gnuradio-runtime/lib/gr_sync_interpolator.cc @@ -0,0 +1,70 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2008 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 <gr_sync_interpolator.h> + +gr_sync_interpolator::gr_sync_interpolator (const std::string &name, + gr_io_signature_sptr input_signature, + gr_io_signature_sptr output_signature, + unsigned interpolation) + : gr_sync_block (name, input_signature, output_signature) +{ + set_interpolation (interpolation); +} + +void +gr_sync_interpolator::forecast (int noutput_items, gr_vector_int &ninput_items_required) +{ + unsigned ninputs = ninput_items_required.size (); + for (unsigned i = 0; i < ninputs; i++) + ninput_items_required[i] = fixed_rate_noutput_to_ninput(noutput_items); +} + +int +gr_sync_interpolator::fixed_rate_noutput_to_ninput(int noutput_items) +{ + return noutput_items / interpolation() + history() - 1; +} + +int +gr_sync_interpolator::fixed_rate_ninput_to_noutput(int ninput_items) +{ + return std::max(0, ninput_items - (int)history() + 1) * interpolation(); +} + +int +gr_sync_interpolator::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + int r = work (noutput_items, input_items, output_items); + if (r > 0) + consume_each (r / interpolation ()); + return r; +} + + diff --git a/gnuradio-runtime/lib/gr_sys_paths.cc b/gnuradio-runtime/lib/gr_sys_paths.cc new file mode 100644 index 0000000000..b4918af33d --- /dev/null +++ b/gnuradio-runtime/lib/gr_sys_paths.cc @@ -0,0 +1,55 @@ +/* + * 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. + */ + +#include <gr_sys_paths.h> +#include <cstdlib> //getenv +#include <cstdio> //P_tmpdir (maybe) + +const char *gr_tmp_path(){ + const char *path; + + //first case, try TMP environment variable + path = getenv("TMP"); + if (path) return path; + + //second case, try P_tmpdir when its defined + #ifdef P_tmpdir + if (P_tmpdir) return P_tmpdir; + #endif /*P_tmpdir*/ + + //fall-through case, nothing worked + return "/tmp"; +} + +const char *gr_appdata_path(){ + const char *path; + + //first case, try HOME environment variable (unix) + path = getenv("HOME"); + if (path) return path; + + //second case, try APPDATA environment variable (windows) + path = getenv("APPDATA"); + if (path) return path; + + //fall-through case, nothing worked + return gr_tmp_path(); +} diff --git a/gnuradio-runtime/lib/gr_tagged_stream_block.cc b/gnuradio-runtime/lib/gr_tagged_stream_block.cc new file mode 100644 index 0000000000..32b6a09033 --- /dev/null +++ b/gnuradio-runtime/lib/gr_tagged_stream_block.cc @@ -0,0 +1,144 @@ +/* -*- c++ -*- */ +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_tagged_stream_block.h> + +gr_tagged_stream_block::gr_tagged_stream_block (const std::string &name, + gr_io_signature_sptr input_signature, + gr_io_signature_sptr output_signature, + const std::string &length_tag_key) + : gr_block(name, input_signature, output_signature), + d_length_tag_key(pmt::string_to_symbol(length_tag_key)), + d_n_input_items_reqd(input_signature->min_streams(), 0), + d_length_tag_key_str(length_tag_key) +{ +} + + +// This is evil hackery: We trick the scheduler into creating the right number of input items +void +gr_tagged_stream_block::forecast (int noutput_items, gr_vector_int &ninput_items_required) +{ + unsigned ninputs = ninput_items_required.size(); + for (unsigned i = 0; i < ninputs; i++) { + if (i < d_n_input_items_reqd.size() && d_n_input_items_reqd[i] != 0) { + ninput_items_required[i] = d_n_input_items_reqd[i]; + } else { + // If there's no item, there's no tag--so there must at least be one! + ninput_items_required[i] = std::max(1, (int) std::floor((double) noutput_items / relative_rate() + 0.5)); + } + } +} + + +void +gr_tagged_stream_block::parse_length_tags( + const std::vector<std::vector<gr_tag_t> > &tags, + gr_vector_int &n_input_items_reqd +){ + for (unsigned i = 0; i < tags.size(); i++) { + for (unsigned k = 0; k < tags[i].size(); k++) { + if (tags[i][k].key == d_length_tag_key) { + n_input_items_reqd[i] = pmt::to_long(tags[i][k].value); + remove_item_tag(i, tags[i][k]); + } + } + } +} + + +int +gr_tagged_stream_block::calculate_output_stream_length(const gr_vector_int &ninput_items) +{ + int noutput_items = *std::max_element(ninput_items.begin(), ninput_items.end()); + return (int) std::floor(relative_rate() * noutput_items + 0.5); +} + + +void +gr_tagged_stream_block::update_length_tags(int n_produced, int n_ports) +{ + for (int i = 0; i < n_ports; i++) { + add_item_tag(i, nitems_written(i), + d_length_tag_key, + pmt::from_long(n_produced) + ); + } + return; +} + + +int +gr_tagged_stream_block::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + if (d_length_tag_key_str.empty()) { + return work(noutput_items, ninput_items, input_items, output_items); + } + + if (d_n_input_items_reqd[0] == 0) { // Otherwise, it's already set from a previous call + std::vector<std::vector<gr_tag_t> > tags(input_items.size(), std::vector<gr_tag_t>()); + for (unsigned i = 0; i < input_items.size(); i++) { + get_tags_in_range(tags[i], i, nitems_read(i), nitems_read(i)+1); + } + d_n_input_items_reqd.assign(input_items.size(), -1); + parse_length_tags(tags, d_n_input_items_reqd); + } + for (unsigned i = 0; i < input_items.size(); i++) { + if (d_n_input_items_reqd[i] == -1) { + throw std::runtime_error("Missing length tag."); + } + if (d_n_input_items_reqd[i] > ninput_items[i]) { + return 0; + } + } + + int min_output_size = calculate_output_stream_length(d_n_input_items_reqd); + if (noutput_items < min_output_size) { + set_min_noutput_items(min_output_size); + return 0; + } + set_min_noutput_items(1); + + // WORK CALLED HERE // + int n_produced = work(noutput_items, d_n_input_items_reqd, input_items, output_items); + ////////////////////// + + if (n_produced == WORK_DONE) { + return n_produced; + } + for (int i = 0; i < (int) d_n_input_items_reqd.size(); i++) { + consume(i, d_n_input_items_reqd[i]); + } + update_length_tags(n_produced, output_items.size()); + + d_n_input_items_reqd.assign(input_items.size(), 0); + + return n_produced; +} + diff --git a/gnuradio-runtime/lib/gr_test.cc b/gnuradio-runtime/lib/gr_test.cc new file mode 100644 index 0000000000..cd5ef83611 --- /dev/null +++ b/gnuradio-runtime/lib/gr_test.cc @@ -0,0 +1,177 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2008,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 <gr_test.h> +#include <gr_io_signature.h> +#include <stdexcept> +#include <iostream> +#include <string.h> + +gr_test_sptr gr_make_test (const std::string &name, + int min_inputs, int max_inputs, unsigned int sizeof_input_item, + int min_outputs, int max_outputs, unsigned int sizeof_output_item, + unsigned int history,unsigned int output_multiple,double relative_rate, + bool fixed_rate,gr_consume_type_t cons_type, gr_produce_type_t prod_type) +{ + return gnuradio::get_initial_sptr(new gr_test (name, min_inputs,max_inputs,sizeof_input_item, + min_outputs,max_outputs,sizeof_output_item, + history,output_multiple,relative_rate,fixed_rate,cons_type, prod_type)); +} + + gr_test::gr_test (const std::string &name,int min_inputs, int max_inputs, unsigned int sizeof_input_item, + int min_outputs, int max_outputs, unsigned int sizeof_output_item, + unsigned int history,unsigned int output_multiple,double relative_rate, + bool fixed_rate,gr_consume_type_t cons_type, gr_produce_type_t prod_type): gr_block (name, + gr_make_io_signature (min_inputs, max_inputs, sizeof_input_item), + gr_make_io_signature (min_outputs, max_outputs, sizeof_output_item)), + d_sizeof_input_item(sizeof_input_item), + d_sizeof_output_item(sizeof_output_item), + d_check_topology(true), + d_consume_type(cons_type), + d_min_consume(0), + d_max_consume(0), + d_produce_type(prod_type), + d_min_produce(0), + d_max_produce(0) + { + set_history(history); + set_output_multiple(output_multiple); + set_relative_rate(relative_rate); + set_fixed_rate(fixed_rate); + } + +int +gr_test::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + //touch all inputs and outputs to detect segfaults + unsigned ninputs = input_items.size (); + unsigned noutputs= output_items.size(); + for (unsigned i = 0; i < ninputs; i++) + { + char * in=(char *)input_items[i]; + if (ninput_items[i]< (int)(noutput_items+history())) + { + std::cerr << "ERROR: ninput_items[" << i << "] < noutput_items+history()" << std::endl; + std::cerr << "ninput_items[" << i << "] = " << ninput_items[i] << std::endl; + std::cerr << "noutput_items+history() = " << noutput_items+history() << std::endl; + std::cerr << "noutput_items = " << noutput_items << std::endl; + std::cerr << "history() = " << history() << std::endl; + throw std::runtime_error ("gr_test"); + } else + { + for (int j=0;j<ninput_items[i];j++) + { + //Touch every available input_item + //We use a class variable to avoid the compiler to optimize this away + for(unsigned int k=0;k<d_sizeof_input_item;k++) + d_temp= in[j*d_sizeof_input_item+k]; + } + switch (d_consume_type) + { + case CONSUME_NOUTPUT_ITEMS: + consume(i,noutput_items); + break; + case CONSUME_NOUTPUT_ITEMS_LIMIT_MAX: + consume(i,std::min(noutput_items,d_max_consume)); + break; + case CONSUME_NOUTPUT_ITEMS_LIMIT_MIN: + consume(i,std::min(std::max(noutput_items,d_min_consume),ninput_items[i])); + break; + case CONSUME_ALL_AVAILABLE: + consume(i,ninput_items[i]); + break; + case CONSUME_ALL_AVAILABLE_LIMIT_MAX: + consume(i,std::min(ninput_items[i],d_max_consume)); + break; +/* //This could result in segfault, uncomment if you want to test this + case CONSUME_ALL_AVAILABLE_LIMIT_MIN: + consume(i,std::max(ninput_items[i],d_max_consume)); + break;*/ + case CONSUME_ZERO: + consume(i,0); + break; + case CONSUME_ONE: + consume(i,1); + break; + case CONSUME_MINUS_ONE: + consume(i,-1); + break; + default: + consume(i,noutput_items); + } + } + } + for (unsigned i = 0; i < noutputs; i++) + { + char * out=(char *)output_items[i]; + { + for (int j=0;j<noutput_items;j++) + { + //Touch every available output_item + for(unsigned int k=0;k<d_sizeof_output_item;k++) + out[j*d_sizeof_input_item+k]=0; + } + } + } + //Now copy input to output until max ninputs or max noutputs is reached + int common_nports=std::min(ninputs,noutputs); + if(d_sizeof_output_item==d_sizeof_input_item) + for (int i = 0; i < common_nports; i++) + { + memcpy(output_items[i],input_items[i],noutput_items*d_sizeof_input_item); + } + int noutput_items_produced=0; + switch (d_produce_type){ + case PRODUCE_NOUTPUT_ITEMS: + noutput_items_produced=noutput_items; + break; + case PRODUCE_NOUTPUT_ITEMS_LIMIT_MAX: + noutput_items_produced=std::min(noutput_items,d_max_produce); + break; +/* //This could result in segfault, uncomment if you want to test this + case PRODUCE_NOUTPUT_ITEMS_LIMIT_MIN: + noutput_items_produced=std::max(noutput_items,d_min_produce); + break;*/ + case PRODUCE_ZERO: + noutput_items_produced=0; + break; + case PRODUCE_ONE: + noutput_items_produced=1; + break; + case PRODUCE_MINUS_ONE: + noutput_items_produced=-1; + break; + default: + noutput_items_produced=noutput_items; + } + return noutput_items_produced; + } + + + diff --git a/gnuradio-runtime/lib/gr_test.h b/gnuradio-runtime/lib/gr_test.h new file mode 100644 index 0000000000..2276ab1967 --- /dev/null +++ b/gnuradio-runtime/lib/gr_test.h @@ -0,0 +1,195 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 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_TEST_H +#define INCLUDED_GR_TEST_H + +#include <gr_runtime_api.h> +#include <gr_block.h> +#include <string> +#include "gr_test_types.h" + +class gr_test; +typedef boost::shared_ptr<gr_test> gr_test_sptr; + +// public constructor +GR_RUNTIME_API gr_test_sptr gr_make_test (const std::string &name=std::string("gr_test"), + int min_inputs=1, int max_inputs=1, unsigned int sizeof_input_item=1, + int min_outputs=1, int max_outputs=1, unsigned int sizeof_output_item=1, + unsigned int history=1,unsigned int output_multiple=1,double relative_rate=1.0, + bool fixed_rate=true,gr_consume_type_t cons_type=CONSUME_NOUTPUT_ITEMS, gr_produce_type_t prod_type=PRODUCE_NOUTPUT_ITEMS); + +/*! + * \brief Test class for testing runtime system (setting up buffers and such.) + * \ingroup misc + * + * This block does not do any usefull actual data processing. + * It just exposes setting all standard block parameters using the contructor or public methods. + * + * This block can be usefull when testing the runtime system. + * You can force this block to have a large history, decimation + * factor and/or large output_multiple. + * The runtime system should detect this and create large enough buffers + * all through the signal chain. + */ +class GR_RUNTIME_API gr_test : public gr_block { + + public: + + ~gr_test (){} + +int general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + // ---------------------------------------------------------------- + // override these to define your behavior + // ---------------------------------------------------------------- + + /*! + * \brief Estimate input requirements given output request + * + * \param noutput_items number of output items to produce + * \param ninput_items_required number of input items required on each input stream + * + * Given a request to product \p noutput_items, estimate the number of + * data items required on each input stream. The estimate doesn't have + * to be exact, but should be close. + */ + void forecast (int noutput_items, + gr_vector_int &ninput_items_required) + { + unsigned ninputs = ninput_items_required.size (); + for (unsigned i = 0; i < ninputs; i++) + ninput_items_required[i] = (int)((double)noutput_items / relative_rate()) + (int)history(); + } + + + /*! + * \brief Force check topology to return true or false. + * + * \param check_topology value to return when check_topology is called (true or false) + * default check_topology returns true + * + */ + void set_check_topology (bool check_topology){ d_check_topology=check_topology;} + + /*! + * \brief Confirm that ninputs and noutputs is an acceptable combination. + * + * \param ninputs number of input streams connected + * \param noutputs number of output streams connected + * + * \returns true if this is a valid configuration for this block. + * + * This function is called by the runtime system whenever the + * topology changes. Most classes do not need to override this. + * This check is in addition to the constraints specified by the input + * and output gr_io_signatures. + */ + bool check_topology (int ninputs, int noutputs) { return d_check_topology;} + + // ---------------------------------------------------------------- + /* + * The following two methods provide special case info to the + * scheduler in the event that a block has a fixed input to output + * ratio. gr_sync_block, gr_sync_decimator and gr_sync_interpolator + * override these. If you're fixed rate, subclass one of those. + */ + /*! + * \brief Given ninput samples, return number of output samples that will be produced. + * N.B. this is only defined if fixed_rate returns true. + * Generally speaking, you don't need to override this. + */ + int fixed_rate_ninput_to_noutput(int ninput) { return (int)((double)ninput/relative_rate()); } + + /*! + * \brief Given noutput samples, return number of input samples required to produce noutput. + * N.B. this is only defined if fixed_rate returns true. + */ + int fixed_rate_noutput_to_ninput(int noutput) { return (int)((double)noutput*relative_rate()); } + + /*! + * \brief Set if fixed rate should return true. + * N.B. This is normally a private method but we make it available here as public. + */ + void set_fixed_rate_public(bool fixed_rate){ set_fixed_rate(fixed_rate);} + + /*! + * \brief Set the consume pattern. + * + * \param cons_type which consume pattern to use + */ + void set_consume_type (gr_consume_type_t cons_type) { d_consume_type=cons_type;} + + /*! + * \brief Set the consume limit. + * + * \param limit min or maximum items to consume (depending on consume_type) + */ + void set_consume_limit (unsigned int limit) { d_min_consume=limit; d_max_consume=limit;} + + /*! + * \brief Set the produce pattern. + * + * \param prod_type which produce pattern to use + */ + void set_produce_type (gr_produce_type_t prod_type) { d_produce_type=prod_type;} + + /*! + * \brief Set the produce limit. + * + * \param limit min or maximum items to produce (depending on produce_type) + */ + void set_produce_limit (unsigned int limit) { d_min_produce=limit; d_max_produce=limit;} + + // ---------------------------------------------------------------------------- + + + + protected: + unsigned int d_sizeof_input_item; + unsigned int d_sizeof_output_item; + bool d_check_topology; + char d_temp; + gr_consume_type_t d_consume_type; + int d_min_consume; + int d_max_consume; + gr_produce_type_t d_produce_type; + int d_min_produce; + int d_max_produce; + gr_test (const std::string &name,int min_inputs, int max_inputs, unsigned int sizeof_input_item, + int min_outputs, int max_outputs, unsigned int sizeof_output_item, + unsigned int history,unsigned int output_multiple,double relative_rate, + bool fixed_rate,gr_consume_type_t cons_type, gr_produce_type_t prod_type); + + + + friend GR_RUNTIME_API gr_test_sptr gr_make_test (const std::string &name,int min_inputs, int max_inputs, unsigned int sizeof_input_item, + int min_outputs, int max_outputs, unsigned int sizeof_output_item, + unsigned int history,unsigned int output_multiple,double relative_rate, + bool fixed_rate,gr_consume_type_t cons_type, gr_produce_type_t prod_type); +}; + + + +#endif /* INCLUDED_GR_TEST_H */ diff --git a/gnuradio-runtime/lib/gr_test_types.h b/gnuradio-runtime/lib/gr_test_types.h new file mode 100644 index 0000000000..04f38f7b26 --- /dev/null +++ b/gnuradio-runtime/lib/gr_test_types.h @@ -0,0 +1,46 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 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_TEST_TYPES_H +#define INCLUDED_GR_TEST_TYPES_H + +typedef enum { + CONSUME_NOUTPUT_ITEMS=0, + CONSUME_NOUTPUT_ITEMS_LIMIT_MAX=1, + CONSUME_NOUTPUT_ITEMS_LIMIT_MIN=2, + CONSUME_ALL_AVAILABLE=3, + CONSUME_ALL_AVAILABLE_LIMIT_MAX=4, + /*CONSUME_ALL_AVAILABLE_LIMIT_MIN=5,*/ + CONSUME_ZERO=6, + CONSUME_ONE=7, + CONSUME_MINUS_ONE=8 + } gr_consume_type_t; + +typedef enum { + PRODUCE_NOUTPUT_ITEMS=0, + PRODUCE_NOUTPUT_ITEMS_LIMIT_MAX=1, + /*PRODUCE_NOUTPUT_ITEMS_LIMIT_MIN=2,*/ + PRODUCE_ZERO=6, + PRODUCE_ONE=7, + PRODUCE_MINUS_ONE=8 + } gr_produce_type_t; + +#endif /* INCLUDED_GR_TEST_TYPES_H */ diff --git a/gnuradio-runtime/lib/gr_top_block.cc b/gnuradio-runtime/lib/gr_top_block.cc new file mode 100644 index 0000000000..c6118bcfdd --- /dev/null +++ b/gnuradio-runtime/lib/gr_top_block.cc @@ -0,0 +1,160 @@ +/* -*- c++ -*- */ +/* + * Copyright 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <unistd.h> +#include <gr_top_block.h> +#include <gr_top_block_impl.h> +#include <gr_io_signature.h> +#include <gr_prefs.h> +#include <iostream> + +gr_top_block_sptr +gr_make_top_block(const std::string &name) +{ + return gnuradio::get_initial_sptr(new gr_top_block(name)); +} + +gr_top_block::gr_top_block(const std::string &name) + : gr_hier_block2(name, + gr_make_io_signature(0,0,0), + gr_make_io_signature(0,0,0)) + +{ + d_impl = new gr_top_block_impl(this); +} + +gr_top_block::~gr_top_block() +{ + stop(); + wait(); + + delete d_impl; +} + +void +gr_top_block::start(int max_noutput_items) +{ + d_impl->start(max_noutput_items); + + if(gr_prefs::singleton()->get_bool("ControlPort", "on", false)) { + setup_rpc(); + } +} + +void +gr_top_block::stop() +{ + d_impl->stop(); +} + +void +gr_top_block::wait() +{ + d_impl->wait(); +} + +void +gr_top_block::run(int max_noutput_items) +{ + start(max_noutput_items); + wait(); +} + +void +gr_top_block::lock() +{ + d_impl->lock(); +} + +void +gr_top_block::unlock() +{ + d_impl->unlock(); +} + +std::string +gr_top_block::edge_list() +{ + return d_impl->edge_list(); +} + +void +gr_top_block::dump() +{ + d_impl->dump(); +} + +int +gr_top_block::max_noutput_items() +{ + return d_impl->max_noutput_items(); +} + +void +gr_top_block::set_max_noutput_items(int nmax) +{ + d_impl->set_max_noutput_items(nmax); +} + +gr_top_block_sptr +gr_top_block::to_top_block() +{ + return cast_to_top_block_sptr(shared_from_this()); +} + +void +gr_top_block::setup_rpc() +{ +#ifdef GR_CTRLPORT + // Getters + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<gr_top_block, int>( + alias(), "max nouptut_items", + &gr_top_block::max_noutput_items, + pmt::mp(0), pmt::mp(8192), pmt::mp(8192), + "items", "Max number of output items", + RPC_PRIVLVL_MIN, DISPNULL))); + + if(gr_prefs::singleton()->get_bool("ControlPort", "edges_list", false)) { + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<gr_top_block, std::string>( + alias(), "edge list", + &gr_top_block::edge_list, + pmt::mp(""), pmt::mp(""), pmt::mp(""), + "edges", "List of edges in the graph", + RPC_PRIVLVL_MIN, DISPNULL))); + } + + // Setters + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_set<gr_top_block, int>( + alias(), "max noutput_items", + &gr_top_block::set_max_noutput_items, + pmt::mp(0), pmt::mp(8192), pmt::mp(8192), + "items", "Max number of output items", + RPC_PRIVLVL_MIN, DISPNULL))); +#endif /* GR_CTRLPORT */ +} diff --git a/gnuradio-runtime/lib/gr_top_block_impl.cc b/gnuradio-runtime/lib/gr_top_block_impl.cc new file mode 100644 index 0000000000..b6d427ce27 --- /dev/null +++ b/gnuradio-runtime/lib/gr_top_block_impl.cc @@ -0,0 +1,211 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2008 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 <gr_top_block.h> +#include <gr_top_block_impl.h> +#include <gr_flat_flowgraph.h> +#include <gr_scheduler_sts.h> +#include <gr_scheduler_tpb.h> +#include <gr_prefs.h> + +#include <stdexcept> +#include <iostream> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> + +#define GR_TOP_BLOCK_IMPL_DEBUG 0 + + +typedef gr_scheduler_sptr (*scheduler_maker)(gr_flat_flowgraph_sptr ffg, + int max_noutput_items); + +static struct scheduler_table { + const char *name; + scheduler_maker f; +} scheduler_table[] = { + { "TPB", gr_scheduler_tpb::make }, // first entry is default + { "STS", gr_scheduler_sts::make } +}; + +static gr_scheduler_sptr +make_scheduler(gr_flat_flowgraph_sptr ffg, int max_noutput_items) +{ + static scheduler_maker factory = 0; + + if (factory == 0){ + char *v = getenv("GR_SCHEDULER"); + if (!v) + factory = scheduler_table[0].f; // use default + else { + for (size_t i = 0; i < sizeof(scheduler_table)/sizeof(scheduler_table[0]); i++){ + if (strcmp(v, scheduler_table[i].name) == 0){ + factory = scheduler_table[i].f; + break; + } + } + if (factory == 0){ + std::cerr << "warning: Invalid GR_SCHEDULER environment variable value \"" + << v << "\". Using \"" << scheduler_table[0].name << "\"\n"; + factory = scheduler_table[0].f; + } + } + } + return factory(ffg, max_noutput_items); +} + + +gr_top_block_impl::gr_top_block_impl(gr_top_block *owner) + : d_owner(owner), d_ffg(), + d_state(IDLE), d_lock_count(0) +{ +} + +gr_top_block_impl::~gr_top_block_impl() +{ + d_owner = 0; +} + +void +gr_top_block_impl::start(int max_noutput_items) +{ + gruel::scoped_lock l(d_mutex); + + d_max_noutput_items = max_noutput_items; + + if (d_state != IDLE) + throw std::runtime_error("top_block::start: top block already running or wait() not called after previous stop()"); + + if (d_lock_count > 0) + throw std::runtime_error("top_block::start: can't start with flow graph locked"); + + // Create new flat flow graph by flattening hierarchy + d_ffg = d_owner->flatten(); + + // Validate new simple flow graph and wire it up + d_ffg->validate(); + d_ffg->setup_connections(); + + // Only export perf. counters if ControlPort config param is enabled + // and if the PerfCounter option 'export' is turned on. + gr_prefs *p = gr_prefs::singleton(); + if(p->get_bool("ControlPort", "on", false) && p->get_bool("PerfCounters", "export", false)) + d_ffg->enable_pc_rpc(); + + d_scheduler = make_scheduler(d_ffg, d_max_noutput_items); + d_state = RUNNING; +} + +void +gr_top_block_impl::stop() +{ + if (d_scheduler) + d_scheduler->stop(); +} + + +void +gr_top_block_impl::wait() +{ + if (d_scheduler) + d_scheduler->wait(); + + d_state = IDLE; +} + +// N.B. lock() and unlock() cannot be called from a flow graph thread or +// deadlock will occur when reconfiguration happens +void +gr_top_block_impl::lock() +{ + gruel::scoped_lock lock(d_mutex); + d_lock_count++; +} + +void +gr_top_block_impl::unlock() +{ + gruel::scoped_lock lock(d_mutex); + + if (d_lock_count <= 0){ + d_lock_count = 0; // fix it, then complain + throw std::runtime_error("unpaired unlock() call"); + } + + d_lock_count--; + if (d_lock_count > 0 || d_state == IDLE) // nothing to do + return; + + restart(); +} + +/* + * restart is called with d_mutex held + */ +void +gr_top_block_impl::restart() +{ + stop(); // Stop scheduler and wait for completion + wait(); + + // Create new simple flow graph + gr_flat_flowgraph_sptr new_ffg = d_owner->flatten(); + new_ffg->validate(); // check consistency, sanity, etc + new_ffg->merge_connections(d_ffg); // reuse buffers, etc + d_ffg = new_ffg; + + // Create a new scheduler to execute it + d_scheduler = make_scheduler(d_ffg, d_max_noutput_items); + d_state = RUNNING; +} + +std::string +gr_top_block_impl::edge_list() +{ + if(d_ffg) + return d_ffg->edge_list(); + else + return ""; +} + +void +gr_top_block_impl::dump() +{ + if (d_ffg) + d_ffg->dump(); +} + +int +gr_top_block_impl::max_noutput_items() +{ + return d_max_noutput_items; +} + +void +gr_top_block_impl::set_max_noutput_items(int nmax) +{ + d_max_noutput_items = nmax; +} diff --git a/gnuradio-runtime/lib/gr_top_block_impl.h b/gnuradio-runtime/lib/gr_top_block_impl.h new file mode 100644 index 0000000000..7293531090 --- /dev/null +++ b/gnuradio-runtime/lib/gr_top_block_impl.h @@ -0,0 +1,88 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2008 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_TOP_BLOCK_IMPL_H +#define INCLUDED_GR_TOP_BLOCK_IMPL_H + +#include <gr_runtime_api.h> +#include <gr_scheduler.h> +#include <gruel/thread.h> + +/*! + *\brief Abstract implementation details of gr_top_block + * \ingroup internal + * + * The actual implementation of gr_top_block. Separate class allows + * decoupling of changes from dependent classes. + * + */ +class GR_RUNTIME_API gr_top_block_impl +{ +public: + gr_top_block_impl(gr_top_block *owner); + ~gr_top_block_impl(); + + // Create and start scheduler threads + void start(int max_noutput_items=100000000); + + // Signal scheduler threads to stop + void stop(); + + // Wait for scheduler threads to exit + void wait(); + + // Lock the top block to allow reconfiguration + void lock(); + + // Unlock the top block at end of reconfiguration + void unlock(); + + // Return a string list of edges + std::string edge_list(); + + // Dump the flowgraph to stdout + void dump(); + + // Get the number of max noutput_items in the flowgraph + int max_noutput_items(); + + // Set the maximum number of noutput_items in the flowgraph + void set_max_noutput_items(int nmax); + +protected: + + enum tb_state { IDLE, RUNNING }; + + gr_top_block *d_owner; + gr_flat_flowgraph_sptr d_ffg; + gr_scheduler_sptr d_scheduler; + + gruel::mutex d_mutex; // protects d_state and d_lock_count + tb_state d_state; + int d_lock_count; + int d_max_noutput_items; + +private: + void restart(); +}; + +#endif /* INCLUDED_GR_TOP_BLOCK_IMPL_H */ diff --git a/gnuradio-runtime/lib/gr_tpb_detail.cc b/gnuradio-runtime/lib/gr_tpb_detail.cc new file mode 100644 index 0000000000..46eb6bbe0d --- /dev/null +++ b/gnuradio-runtime/lib/gr_tpb_detail.cc @@ -0,0 +1,70 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <gr_tpb_detail.h> +#include <gr_block.h> +#include <gr_block_detail.h> +#include <gr_buffer.h> + +using namespace pmt; + +/* + * We assume that no worker threads are ever running when the + * graph structure is being manipulated, thus it's safe for us to poke + * around in our neighbors w/o holding any locks. + */ + +void +gr_tpb_detail::notify_upstream(gr_block_detail *d) +{ + // For each of our inputs, tell the guy upstream that we've consumed + // some input, and that he most likely has more output buffer space + // available. + + for (size_t i = 0; i < d->d_input.size(); i++){ + // Can you say, "pointer chasing?" + d->d_input[i]->buffer()->link()->detail()->d_tpb.set_output_changed(); + } +} + +void +gr_tpb_detail::notify_downstream(gr_block_detail *d) +{ + // For each of our outputs, tell the guys downstream that they have + // new input available. + + for (size_t i = 0; i < d->d_output.size(); i++){ + gr_buffer_sptr buf = d->d_output[i]; + for (size_t j = 0, k = buf->nreaders(); j < k; j++) + buf->reader(j)->link()->detail()->d_tpb.set_input_changed(); + } +} + +void +gr_tpb_detail::notify_neighbors(gr_block_detail *d) +{ + notify_downstream(d); + notify_upstream(d); +} + diff --git a/gnuradio-runtime/lib/gr_tpb_thread_body.cc b/gnuradio-runtime/lib/gr_tpb_thread_body.cc new file mode 100644 index 0000000000..679fd15124 --- /dev/null +++ b/gnuradio-runtime/lib/gr_tpb_thread_body.cc @@ -0,0 +1,151 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009,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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <gr_tpb_thread_body.h> +#include <gr_prefs.h> +#include <iostream> +#include <boost/thread.hpp> +#include <gruel/pmt.h> +#include <boost/foreach.hpp> + +using namespace pmt; + +gr_tpb_thread_body::gr_tpb_thread_body(gr_block_sptr block, int max_noutput_items) + : d_exec(block, max_noutput_items) +{ + //std::cerr << "gr_tpb_thread_body: " << block << std::endl; + + gr_block_detail *d = block->detail().get(); + gr_block_executor::state s; + pmt_t msg; + + d->threaded = true; + d->thread = gruel::get_current_thread_id(); + + gr_prefs *p = gr_prefs::singleton(); + size_t max_nmsgs = static_cast<size_t>(p->get_long("DEFAULT", "max_messages", 100)); + + // Set thread affinity if it was set before fg was started. + if(block->processor_affinity().size() > 0) { + gruel::thread_bind_to_processor(d->thread, block->processor_affinity()); + } + + while (1){ + boost::this_thread::interruption_point(); + + // handle any queued up messages + //BOOST_FOREACH( pmt::pmt_t port, block->msg_queue.keys() ) + + BOOST_FOREACH( gr_basic_block::msg_queue_map_t::value_type &i, block->msg_queue ) + { + // Check if we have a message handler attached before getting + // any messages. This is mostly a protection for the unknown + // startup sequence of the threads. + if(block->has_msg_handler(i.first)) { + while ((msg = block->delete_head_nowait(i.first))){ + block->dispatch_msg(i.first,msg); + } + } + else { + // If we don't have a handler but are building up messages, + // prune the queue from the front to keep memory in check. + if(block->nmsgs(i.first) > max_nmsgs) + msg = block->delete_head_nowait(i.first); + } + } + + d->d_tpb.clear_changed(); + // run one iteration if we are a connected stream block + if(d->noutputs() >0 || d->ninputs()>0){ + s = d_exec.run_one_iteration(); + } else { + s = gr_block_executor::BLKD_IN; + } + + switch(s){ + case gr_block_executor::READY: // Tell neighbors we made progress. + d->d_tpb.notify_neighbors(d); + break; + + case gr_block_executor::READY_NO_OUTPUT: // Notify upstream only + d->d_tpb.notify_upstream(d); + break; + + case gr_block_executor::DONE: // Game over. + d->d_tpb.notify_neighbors(d); + return; + + case gr_block_executor::BLKD_IN: // Wait for input. + { + gruel::scoped_lock guard(d->d_tpb.mutex); + while (!d->d_tpb.input_changed){ + + // wait for input or message + while(!d->d_tpb.input_changed && block->empty_p()) + d->d_tpb.input_cond.wait(guard); + + // handle all pending messages + BOOST_FOREACH( gr_basic_block::msg_queue_map_t::value_type &i, block->msg_queue ) + { + while ((msg = block->delete_head_nowait(i.first))){ + guard.unlock(); // release lock while processing msg + block->dispatch_msg(i.first, msg); + guard.lock(); + } + } + } + } + break; + + + case gr_block_executor::BLKD_OUT: // Wait for output buffer space. + { + gruel::scoped_lock guard(d->d_tpb.mutex); + while (!d->d_tpb.output_changed){ + + // wait for output room or message + while(!d->d_tpb.output_changed && block->empty_p()) + d->d_tpb.output_cond.wait(guard); + + // handle all pending messages + BOOST_FOREACH( gr_basic_block::msg_queue_map_t::value_type &i, block->msg_queue ) + { + while ((msg = block->delete_head_nowait(i.first))){ + guard.unlock(); // release lock while processing msg + block->dispatch_msg(i.first,msg); + guard.lock(); + } + } + } + } + break; + + default: + assert(0); + } + } +} + +gr_tpb_thread_body::~gr_tpb_thread_body() +{ +} diff --git a/gnuradio-runtime/lib/gr_tpb_thread_body.h b/gnuradio-runtime/lib/gr_tpb_thread_body.h new file mode 100644 index 0000000000..6ecb022f69 --- /dev/null +++ b/gnuradio-runtime/lib/gr_tpb_thread_body.h @@ -0,0 +1,46 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef INCLUDED_GR_TPB_THREAD_BODY_H +#define INCLUDED_GR_TPB_THREAD_BODY_H + +#include <gr_runtime_api.h> +#include <gr_block_executor.h> +#include <gr_block.h> +#include <gr_block_detail.h> + +/*! + * \brief The body of each thread-per-block thread. + * + * One of these is instantiated in its own thread for each block. The + * constructor turns into the main loop which returns when the block is + * done or is interrupted. + */ + +class GR_RUNTIME_API gr_tpb_thread_body { + gr_block_executor d_exec; + +public: + gr_tpb_thread_body(gr_block_sptr block, int max_noutput_items=100000); + ~gr_tpb_thread_body(); +}; + + +#endif /* INCLUDED_GR_TPB_THREAD_BODY_H */ diff --git a/gnuradio-runtime/lib/gr_vco.h b/gnuradio-runtime/lib/gr_vco.h new file mode 100644 index 0000000000..3ceaf15dd4 --- /dev/null +++ b/gnuradio-runtime/lib/gr_vco.h @@ -0,0 +1,94 @@ +/* -*- 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 _GR_VCO_H_ +#define _GR_VCO_H_ + + +#include <vector> +#include <gr_sincos.h> +#include <cmath> +#include <gr_complex.h> + +/*! + * \brief base class template for Voltage Controlled Oscillator (VCO) + * \ingroup misc + */ + +//FIXME Eventually generalize this to fixed point + +template<class o_type, class i_type> +class gr_vco { +public: + gr_vco () : d_phase (0) {} + + virtual ~gr_vco () {} + + // radians + void set_phase (double angle) { + d_phase = angle; + } + + void adjust_phase (double delta_phase) { + d_phase += delta_phase; + if (fabs (d_phase) > M_PI){ + + while (d_phase > M_PI) + d_phase -= 2*M_PI; + + while (d_phase < -M_PI) + d_phase += 2*M_PI; + } + } + + double get_phase () const { return d_phase; } + + // compute sin and cos for current phase angle + void sincos (float *sinx, float *cosx) const; + + // compute cos or sin for current phase angle + float cos () const { return std::cos (d_phase); } + float sin () const { return std::sin (d_phase); } + + // compute a block at a time + void cos (float *output, const float *input, int noutput_items, double k, double ampl = 1.0); + +protected: + double d_phase; +}; + +template<class o_type, class i_type> +void +gr_vco<o_type,i_type>::sincos (float *sinx, float *cosx) const +{ + gr_sincosf (d_phase, sinx, cosx); +} + +template<class o_type, class i_type> +void +gr_vco<o_type,i_type>::cos (float *output, const float *input, int noutput_items, double k, double ampl) +{ + for (int i = 0; i < noutput_items; i++){ + output[i] = cos() * ampl; + adjust_phase(input[i] * k); + } +} +#endif /* _GR_VCO_H_ */ diff --git a/gnuradio-runtime/lib/gr_vmcircbuf.cc b/gnuradio-runtime/lib/gr_vmcircbuf.cc new file mode 100644 index 0000000000..522d9515d0 --- /dev/null +++ b/gnuradio-runtime/lib/gr_vmcircbuf.cc @@ -0,0 +1,295 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 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 <gr_vmcircbuf.h> +#include <assert.h> +#include <stdexcept> +#include <gr_preferences.h> +#include <stdio.h> +#include <string.h> +#include <gr_local_sighandler.h> +#include <vector> +#include <boost/format.hpp> + +// all the factories we know about +#include <gr_vmcircbuf_createfilemapping.h> +#include <gr_vmcircbuf_sysv_shm.h> +#include <gr_vmcircbuf_mmap_shm_open.h> +#include <gr_vmcircbuf_mmap_tmpfile.h> + +static const char *FACTORY_PREF_KEY = "gr_vmcircbuf_default_factory"; + +gr_vmcircbuf::~gr_vmcircbuf () +{ +} + +gr_vmcircbuf_factory::~gr_vmcircbuf_factory () +{ +} + +// ---------------------------------------------------------------- + +static gr_vmcircbuf_factory *s_default_factory = 0; + +gr_vmcircbuf_factory * +gr_vmcircbuf_sysconfig::get_default_factory () +{ + if (s_default_factory) + return s_default_factory; + + bool verbose = false; + + std::vector<gr_vmcircbuf_factory *> all = all_factories (); + + const char *name = gr_preferences::get (FACTORY_PREF_KEY); + + if (name){ + for (unsigned int i = 0; i < all.size (); i++){ + if (strcmp (name, all[i]->name ()) == 0){ + s_default_factory = all[i]; + if (verbose) + fprintf (stderr, "gr_vmcircbuf_sysconfig: using %s\n", + s_default_factory->name ()); + return s_default_factory; + } + } + } + + // either we don't have a default, or the default named is not in our + // list of factories. Find the first factory that works. + + if (verbose) + fprintf (stderr, "gr_vmcircbuf_sysconfig: finding a working factory...\n"); + + for (unsigned int i = 0; i < all.size (); i++){ + if (test_factory (all[i], verbose)){ + set_default_factory (all[i]); + return s_default_factory; + } + } + + // We're screwed! + + fprintf (stderr, "gr_vmcircbuf_sysconfig: unable to find a working factory!\n"); + throw std::runtime_error ("gr_vmcircbuf_sysconfig"); +} + +std::vector<gr_vmcircbuf_factory *> +gr_vmcircbuf_sysconfig::all_factories () +{ + std::vector<gr_vmcircbuf_factory *> result; + + result.push_back (gr_vmcircbuf_createfilemapping_factory::singleton ()); +#ifdef TRY_SHM_VMCIRCBUF + result.push_back (gr_vmcircbuf_sysv_shm_factory::singleton ()); + result.push_back (gr_vmcircbuf_mmap_shm_open_factory::singleton ()); +#endif + result.push_back (gr_vmcircbuf_mmap_tmpfile_factory::singleton ()); + + return result; +} + +void +gr_vmcircbuf_sysconfig::set_default_factory (gr_vmcircbuf_factory *f) +{ + gr_preferences::set (FACTORY_PREF_KEY, f->name ()); + s_default_factory = f; +} + + +// ------------------------------------------------------------------------ +// test code for vmcircbuf factories +// ------------------------------------------------------------------------ + +static void +init_buffer (gr_vmcircbuf *c, int counter, int size) +{ + unsigned int *p = (unsigned int *) c->pointer_to_first_copy (); + for (unsigned int i = 0; i < size / sizeof (int); i++) + p[i] = counter + i; +} + +static bool +check_mapping (gr_vmcircbuf *c, int counter, int size, const char *msg, bool verbose) +{ + bool ok = true; + + if (verbose) + fprintf (stderr, "... %s", msg); + + unsigned int *p1 = (unsigned int *) c->pointer_to_first_copy (); + unsigned int *p2 = (unsigned int *) c->pointer_to_second_copy (); + + // fprintf (stderr, "p1 = %p, p2 = %p\n", p1, p2); + + for (unsigned int i = 0; i < size / sizeof (int); i++){ + if (p1[i] != counter + i){ + ok = false; + if (verbose) + fprintf (stderr, " p1[%d] == %u, expected %u\n", i, p1[i], counter + i); + break; + } + if (p2[i] != counter + i){ + if (verbose) + fprintf (stderr, " p2[%d] == %u, expected %u\n", i, p2[i], counter + i); + ok = false; + break; + } + } + + if (ok && verbose){ + fprintf (stderr, " OK\n"); + } + return ok; +} + +static const char * +memsize (int size) +{ + static std::string buf; + if (size >= (1 << 20)){ + buf = str(boost::format("%dMB") % (size / (1 << 20))); + } + else if (size >= (1 << 10)){ + buf = str(boost::format("%dKB") % (size / (1 << 10))); + } + else { + buf = str(boost::format("%d") % size); + } + return buf.c_str(); +} + +static bool +test_a_bunch (gr_vmcircbuf_factory *factory, int n, int size, int *start_ptr, bool verbose) +{ + bool ok = true; + std::vector<int> counter(n); + std::vector<gr_vmcircbuf *> c(n); + int cum_size = 0; + + for (int i = 0; i < n; i++){ + counter[i] = *start_ptr; + *start_ptr += size; + if ((c[i] = factory->make (size)) == 0){ + if (verbose) + fprintf (stderr, + "Failed to allocate gr_vmcircbuf number %d of size %d (cum = %s)\n", + i + 1, size, memsize (cum_size)); + return false; + } + init_buffer (c[i], counter[i], size); + cum_size += size; + } + + for (int i = 0; i < n; i++){ + std::string msg = str(boost::format("test_a_bunch_%dx%s[%d]") % n % memsize (size) % i); + ok &= check_mapping (c[i], counter[i], size, msg.c_str(), verbose); + } + + for (int i = 0; i < n; i++){ + delete c[i]; + c[i] = 0; + } + + return ok; +} + +static bool +standard_tests (gr_vmcircbuf_factory *f, int verbose) +{ + if (verbose >= 1) + fprintf (stderr, "Testing %s...\n", f->name ()); + + bool v = verbose >= 2; + int granularity = f->granularity (); + int start = 0; + bool ok = true; + + ok &= test_a_bunch (f, 1, 1 * granularity, &start, v); // 1 x 4KB = 4KB + + if (ok){ + ok &= test_a_bunch (f, 64, 4 * granularity, &start, v); // 64 x 16KB = 1MB + ok &= test_a_bunch (f, 4, 4 * (1L << 20), &start, v); // 4 x 4MB = 16MB +// ok &= test_a_bunch (f, 256, 256 * (1L << 10), &start, v); // 256 x 256KB = 64MB + } + + if (verbose >= 1) + fprintf (stderr, "....... %s: %s", f->name (), ok ? "OK\n" : "Doesn't work\n"); + + return ok; +} + +bool +gr_vmcircbuf_sysconfig::test_factory (gr_vmcircbuf_factory *f, int verbose) +{ + // Install local signal handlers for SIGSEGV and SIGBUS. + // If something goes wrong, these signals may be invoked. + +#ifdef SIGSEGV + gr_local_sighandler sigsegv (SIGSEGV, gr_local_sighandler::throw_signal); +#endif +#ifdef SIGBUS + gr_local_sighandler sigbus (SIGBUS, gr_local_sighandler::throw_signal); +#endif +#ifdef SIGSYS + gr_local_sighandler sigsys (SIGSYS, gr_local_sighandler::throw_signal); +#endif + + try { + return standard_tests (f, verbose); + } + catch (gr_signal &sig){ + if (verbose){ + fprintf (stderr, "....... %s: %s", f->name (), "Doesn't work\n"); + fprintf (stderr, + "gr_vmcircbuf_factory::test_factory (%s): caught %s\n", + f->name (), sig.name().c_str()); + return false; + } + } + catch (...){ + if (verbose){ + fprintf (stderr, "....... %s: %s", f->name (), "Doesn't work\n"); + fprintf (stderr, + "gr_vmcircbuf_factory::test_factory (%s): some kind of uncaught exception\n", + f->name ()); + } + return false; + } + return false; // never gets here. shut compiler up. +} + +bool +gr_vmcircbuf_sysconfig::test_all_factories (int verbose) +{ + bool ok = false; + + std::vector<gr_vmcircbuf_factory *> all = all_factories (); + + for (unsigned int i = 0; i < all.size (); i++) + ok |= test_factory (all[i], verbose); + + return ok; +} diff --git a/gnuradio-runtime/lib/gr_vmcircbuf.h b/gnuradio-runtime/lib/gr_vmcircbuf.h new file mode 100644 index 0000000000..e7f492a8bd --- /dev/null +++ b/gnuradio-runtime/lib/gr_vmcircbuf.h @@ -0,0 +1,122 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 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 _GR_VMCIRCBUF_H_ +#define _GR_VMCIRCBUF_H_ + +#include <gr_runtime_api.h> +#include <vector> + +/*! + * \brief abstract class to implement doubly mapped virtual memory circular buffers + * \ingroup internal + */ +class GR_RUNTIME_API gr_vmcircbuf { + protected: + int d_size; + char *d_base; + + // CREATORS + gr_vmcircbuf (int size) : d_size (size), d_base (0) {}; + + public: + virtual ~gr_vmcircbuf (); + + // ACCESSORS + void *pointer_to_first_copy () const { return d_base; } + void *pointer_to_second_copy () const { return d_base + d_size; } +}; + +/*! + * \brief abstract factory for creating circular buffers + */ +class GR_RUNTIME_API gr_vmcircbuf_factory { + protected: + gr_vmcircbuf_factory () {}; + virtual ~gr_vmcircbuf_factory (); + + public: + + /*! + * \brief return name of this factory + */ + virtual const char *name () const = 0; + + /*! + * \brief return granularity of mapping, typically equal to page size + */ + virtual int granularity () = 0; + + /*! + * \brief return a gr_vmcircbuf, or 0 if unable. + * + * Call this to create a doubly mapped circular buffer. + */ + virtual gr_vmcircbuf *make (int size) = 0; +}; + +/* + * \brief pulls together all implementations of gr_vmcircbuf + */ +class GR_RUNTIME_API gr_vmcircbuf_sysconfig { + public: + + /* + * \brief return the single instance of the default factory. + * + * returns the default factory to use if it's already defined, + * else find the first working factory and use it. + */ + static gr_vmcircbuf_factory *get_default_factory (); + + + static int granularity () { return get_default_factory()->granularity(); } + static gr_vmcircbuf *make (int size) { return get_default_factory()->make(size); } + + + // N.B. not all factories are guaranteed to work. + // It's too hard to check everything at config time, so we check at runtime + static std::vector<gr_vmcircbuf_factory *> all_factories (); + + // make this factory the default + static void set_default_factory (gr_vmcircbuf_factory *f); + + /*! + * \brief Does this factory really work? + * + * verbose = 0: silent + * verbose = 1: names of factories tested and results + * verbose = 2: all intermediate results + */ + static bool test_factory (gr_vmcircbuf_factory *f, int verbose); + + /*! + * \brief Test all factories, return true if at least one of them works + * verbose = 0: silent + * verbose = 1: names of factories tested and results + * verbose = 2: all intermediate results + */ + static bool test_all_factories (int verbose); +}; + + +#endif /* _GR_VMCIRCBUF_H_ */ diff --git a/gnuradio-runtime/lib/gr_vmcircbuf_createfilemapping.cc b/gnuradio-runtime/lib/gr_vmcircbuf_createfilemapping.cc new file mode 100644 index 0000000000..1b4d9700a5 --- /dev/null +++ b/gnuradio-runtime/lib/gr_vmcircbuf_createfilemapping.cc @@ -0,0 +1,204 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2005,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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include <stdexcept> +#include <assert.h> +#include <unistd.h> +#include <fcntl.h> +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif +#include <errno.h> +#include <stdio.h> +#include <gr_pagesize.h> +#include <gr_vmcircbuf_createfilemapping.h> +#include <boost/format.hpp> + +#ifdef HAVE_CREATEFILEMAPPING +// Print Windows error (could/should be global?) +static void +werror( char *where, DWORD last_error ) +{ + char buf[1024]; + + FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + last_error, + 0, // default language + buf, + sizeof(buf)/sizeof(TCHAR), // buffer size + NULL ); + fprintf( stderr, "%s: Error %d: %s", where, last_error, buf ); + return; +} +#endif + + +gr_vmcircbuf_createfilemapping::gr_vmcircbuf_createfilemapping (int size) + : gr_vmcircbuf (size) +{ +#if !defined(HAVE_CREATEFILEMAPPING) + fprintf (stderr, "%s: createfilemapping is not available\n",__FUNCTION__); + throw std::runtime_error ("gr_vmcircbuf_createfilemapping"); +#else + static int s_seg_counter = 0; + + if (size <= 0 || (size % gr_pagesize ()) != 0){ + fprintf (stderr, "gr_vmcircbuf_createfilemapping: invalid size = %d\n", size); + throw std::runtime_error ("gr_vmcircbuf_createfilemapping"); + } + + std::string seg_name = str(boost::format("/gnuradio-%d-%d") % getpid () % s_seg_counter); + + d_handle = CreateFileMapping(INVALID_HANDLE_VALUE, // use paging file + NULL, // default security + PAGE_READWRITE, // read/write access + 0, // max. object size + size, // buffer size + seg_name.c_str()); // name of mapping object + + s_seg_counter++; + if (d_handle == NULL || d_handle == INVALID_HANDLE_VALUE){ + std::string msg = str(boost::format( + "gr_vmcircbuf_mmap_createfilemapping: CreateFileMapping [%s]") % + seg_name ); + werror((char *) msg.c_str(), GetLastError() ); + throw std::runtime_error ("gr_vmcircbuf_mmap_createfilemapping"); + } + + // Allocate virtual memory of the needed size, then free it so we can use it + LPVOID first_tmp; + first_tmp = VirtualAlloc( NULL, 2*size, MEM_RESERVE, PAGE_NOACCESS ); + if (first_tmp == NULL){ + werror( "gr_vmcircbuf_mmap_createfilemapping: VirtualAlloc", GetLastError()); + CloseHandle(d_handle); // cleanup + throw std::runtime_error ("gr_vmcircbuf_mmap_createfilemapping"); + } + + if (VirtualFree(first_tmp, 0, MEM_RELEASE) == 0){ + werror( "gr_vmcircbuf_mmap_createfilemapping: VirtualFree", GetLastError()); + CloseHandle(d_handle); // cleanup + throw std::runtime_error ("gr_vmcircbuf_mmap_createfilemapping"); + } + + d_first_copy = MapViewOfFileEx((HANDLE)d_handle, // handle to map object + FILE_MAP_WRITE, // read/write permission + 0, + 0, + size, + first_tmp); + if (d_first_copy != first_tmp){ + werror( "gr_vmcircbuf_mmap_createfilemapping: MapViewOfFileEx(1)", GetLastError()); + CloseHandle(d_handle); // cleanup + throw std::runtime_error ("gr_vmcircbuf_mmap_createfilemapping"); + } + + d_second_copy = MapViewOfFileEx((HANDLE)d_handle, // handle to map object + FILE_MAP_WRITE, // read/write permission + 0, + 0, + size, + (char *)first_tmp + size);//(LPVOID) ((char *)d_first_copy + size)); + + if (d_second_copy != (char *)first_tmp + size){ + werror( "gr_vmcircbuf_mmap_createfilemapping: MapViewOfFileEx(2)", GetLastError()); + UnmapViewOfFile(d_first_copy); + CloseHandle(d_handle); // cleanup + throw std::runtime_error ("gr_vmcircbuf_mmap_createfilemapping"); + } + +#ifdef DEBUG + fprintf (stderr,"gr_vmcircbuf_mmap_createfilemapping: contiguous? mmap %p %p %p %p\n", + (char *)d_first_copy, (char *)d_second_copy, size, (char *)d_first_copy + size); +#endif + + // Now remember the important stuff + d_base = (char *) d_first_copy; + d_size = size; +#endif /*HAVE_CREATEFILEMAPPING*/ +} + +gr_vmcircbuf_createfilemapping::~gr_vmcircbuf_createfilemapping () +{ +#ifdef HAVE_CREATEFILEMAPPING + if (UnmapViewOfFile(d_first_copy) == 0) + { + werror("gr_vmcircbuf_createfilemapping: UnmapViewOfFile(d_first_copy)", GetLastError()); + } + d_base=NULL; + if (UnmapViewOfFile(d_second_copy) == 0) + { + werror("gr_vmcircbuf_createfilemapping: UnmapViewOfFile(d_second_copy)", GetLastError()); + } + //d_second=NULL; + CloseHandle(d_handle); +#endif +} + +// ---------------------------------------------------------------- +// The factory interface +// ---------------------------------------------------------------- + + +gr_vmcircbuf_factory *gr_vmcircbuf_createfilemapping_factory::s_the_factory = 0; + +gr_vmcircbuf_factory * +gr_vmcircbuf_createfilemapping_factory::singleton () +{ + if (s_the_factory) + return s_the_factory; + s_the_factory = new gr_vmcircbuf_createfilemapping_factory (); + return s_the_factory; +} + +int +gr_vmcircbuf_createfilemapping_factory::granularity () +{ +#ifdef HAVE_CREATEFILEMAPPING + // return 65536;//TODO, check, is this needed or can we just use gr_pagesize() + SYSTEM_INFO system_info; + GetSystemInfo(&system_info); + //fprintf(stderr,"win32 AllocationGranularity %p\n",(int)system_info.dwAllocationGranularity); + return (int)system_info.dwAllocationGranularity; +#else + return gr_pagesize (); +#endif +} + +gr_vmcircbuf * +gr_vmcircbuf_createfilemapping_factory::make (int size) +{ + try + { + return new gr_vmcircbuf_createfilemapping (size); + } + catch (...) + { + return 0; + } +} diff --git a/gnuradio-runtime/lib/gr_vmcircbuf_createfilemapping.h b/gnuradio-runtime/lib/gr_vmcircbuf_createfilemapping.h new file mode 100644 index 0000000000..a4bb5cbe92 --- /dev/null +++ b/gnuradio-runtime/lib/gr_vmcircbuf_createfilemapping.h @@ -0,0 +1,76 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,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 _GR_VMCIRCBUF_CREATEFILEMAPPING_H_ +#define _GR_VMCIRCBUF_CREATEFILEMAPPING_H_ + +#include <gr_runtime_api.h> +#include <gr_vmcircbuf.h> + +#ifdef HAVE_CREATEFILEMAPPING +#include <windows.h> +#endif +/*! + * \brief concrete class to implement circular buffers with mmap and shm_open + * \ingroup internal + */ +class GR_RUNTIME_API gr_vmcircbuf_createfilemapping : public gr_vmcircbuf +{ + public: + // CREATORS + gr_vmcircbuf_createfilemapping (int size); + virtual ~gr_vmcircbuf_createfilemapping (); +#ifdef HAVE_CREATEFILEMAPPING + private: + HANDLE d_handle; + LPVOID d_first_copy; + LPVOID d_second_copy; +#endif +}; + +/*! + * \brief concrete factory for circular buffers built using mmap and shm_open + */ +class GR_RUNTIME_API gr_vmcircbuf_createfilemapping_factory : public gr_vmcircbuf_factory +{ + private: + static gr_vmcircbuf_factory *s_the_factory; + + public: + static gr_vmcircbuf_factory *singleton (); + + virtual const char *name () const { return "gr_vmcircbuf_createfilemapping_factory"; } + + /*! + * \brief return granularity of mapping, typically equal to page size + */ + virtual int granularity (); + + /*! + * \brief return a gr_vmcircbuf, or 0 if unable. + * + * Call this to create a doubly mapped circular buffer. + */ + virtual gr_vmcircbuf *make (int size); +}; + +#endif /* _GR_VMCIRCBUF_CREATEFILEMAPPING_H_ */ diff --git a/gnuradio-runtime/lib/gr_vmcircbuf_mmap_shm_open.cc b/gnuradio-runtime/lib/gr_vmcircbuf_mmap_shm_open.cc new file mode 100644 index 0000000000..3d170081d0 --- /dev/null +++ b/gnuradio-runtime/lib/gr_vmcircbuf_mmap_shm_open.cc @@ -0,0 +1,205 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include <gr_vmcircbuf_mmap_shm_open.h> +#include <stdexcept> +#include <assert.h> +#include <unistd.h> +#include <fcntl.h> +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif +#include <errno.h> +#include <stdio.h> +#include <gr_pagesize.h> +#include <gr_sys_paths.h> + + +gr_vmcircbuf_mmap_shm_open::gr_vmcircbuf_mmap_shm_open (int size) + : gr_vmcircbuf (size) +{ +#if !defined(HAVE_MMAP) || !defined(HAVE_SHM_OPEN) + fprintf (stderr, "gr_vmcircbuf_mmap_shm_open: mmap or shm_open is not available\n"); + throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open"); +#else + static int s_seg_counter = 0; + + if (size <= 0 || (size % gr_pagesize ()) != 0){ + fprintf (stderr, "gr_vmcircbuf_mmap_shm_open: invalid size = %d\n", size); + throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open"); + } + + int shm_fd = -1; + char seg_name[1024]; + static bool portable_format = true; + + // open a new named shared memory segment + + while (1){ + if (portable_format){ + + // This is the POSIX recommended "portable format". + // Of course the "portable format" doesn't work on some systems... + + snprintf (seg_name, sizeof (seg_name), + "/gnuradio-%d-%d", getpid (), s_seg_counter); + } + else { + + // Where the "portable format" doesn't work, we try building + // a full filesystem pathname pointing into a suitable temporary directory. + + snprintf (seg_name, sizeof (seg_name), + "%s/gnuradio-%d-%d", gr_tmp_path (), getpid (), s_seg_counter); + } + + shm_fd = shm_open (seg_name, O_RDWR | O_CREAT | O_EXCL, 0600); + if (shm_fd == -1 && errno == EACCES && portable_format){ + portable_format = false; + continue; // try again using "non-portable format" + } + + s_seg_counter++; + + if (shm_fd == -1){ + if (errno == EEXIST) // Named segment already exists (shouldn't happen). Try again + continue; + + char msg[1024]; + snprintf (msg, sizeof (msg), "gr_vmcircbuf_mmap_shm_open: shm_open [%s]", seg_name); + perror (msg); + throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open"); + } + break; + } + + // We've got a new shared memory segment fd open. + // Now set it's length to 2x what we really want and mmap it in. + + if (ftruncate (shm_fd, (off_t) 2 * size) == -1){ + close (shm_fd); // cleanup + perror ("gr_vmcircbuf_mmap_shm_open: ftruncate (1)"); + throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open"); + } + + void *first_copy = mmap (0, 2 * size, + PROT_READ | PROT_WRITE, MAP_SHARED, + shm_fd, (off_t) 0); + + if (first_copy == MAP_FAILED){ + close (shm_fd); // cleanup + perror ("gr_vmcircbuf_mmap_shm_open: mmap (1)"); + throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open"); + } + + // unmap the 2nd half + if (munmap ((char *) first_copy + size, size) == -1){ + close (shm_fd); // cleanup + perror ("gr_vmcircbuf_mmap_shm_open: munmap (1)"); + throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open"); + } + + // map the first half into the now available hole where the + // second half used to be. + + void *second_copy = mmap ((char *) first_copy + size, size, + PROT_READ | PROT_WRITE, MAP_SHARED, + shm_fd, (off_t) 0); + + if (second_copy == MAP_FAILED){ + close (shm_fd); // cleanup + perror ("gr_vmcircbuf_mmap_shm_open: mmap (2)"); + throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open"); + } + +#if 0 // OS/X doesn't allow you to resize the segment + + // cut the shared memory segment down to size + if (ftruncate (shm_fd, (off_t) size) == -1){ + close (shm_fd); // cleanup + perror ("gr_vmcircbuf_mmap_shm_open: ftruncate (2)"); + throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open"); + } +#endif + + close (shm_fd); // fd no longer needed. The mapping is retained. + + if (shm_unlink (seg_name) == -1){ // unlink the seg_name. + perror ("gr_vmcircbuf_mmap_shm_open: shm_unlink"); + throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open"); + } + + // Now remember the important stuff + + d_base = (char *) first_copy; + d_size = size; +#endif +} + +gr_vmcircbuf_mmap_shm_open::~gr_vmcircbuf_mmap_shm_open () +{ +#if defined(HAVE_MMAP) + if (munmap (d_base, 2 * d_size) == -1){ + perror ("gr_vmcircbuf_mmap_shm_open: munmap (2)"); + } +#endif +} + +// ---------------------------------------------------------------- +// The factory interface +// ---------------------------------------------------------------- + + +gr_vmcircbuf_factory *gr_vmcircbuf_mmap_shm_open_factory::s_the_factory = 0; + +gr_vmcircbuf_factory * +gr_vmcircbuf_mmap_shm_open_factory::singleton () +{ + if (s_the_factory) + return s_the_factory; + + s_the_factory = new gr_vmcircbuf_mmap_shm_open_factory (); + return s_the_factory; +} + +int +gr_vmcircbuf_mmap_shm_open_factory::granularity () +{ + return gr_pagesize (); +} + +gr_vmcircbuf * +gr_vmcircbuf_mmap_shm_open_factory::make (int size) +{ + try { + return new gr_vmcircbuf_mmap_shm_open (size); + } + catch (...){ + return 0; + } +} diff --git a/gnuradio-runtime/lib/gr_vmcircbuf_mmap_shm_open.h b/gnuradio-runtime/lib/gr_vmcircbuf_mmap_shm_open.h new file mode 100644 index 0000000000..d35df80839 --- /dev/null +++ b/gnuradio-runtime/lib/gr_vmcircbuf_mmap_shm_open.h @@ -0,0 +1,67 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 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 _GR_VMCIRCBUF_MMAP_SHM_OPEN_H_ +#define _GR_VMCIRCBUF_MMAP_SHM_OPEN_H_ + +#include <gr_runtime_api.h> +#include <gr_vmcircbuf.h> + +/*! + * \brief concrete class to implement circular buffers with mmap and shm_open + * \ingroup internal + */ +class GR_RUNTIME_API gr_vmcircbuf_mmap_shm_open : public gr_vmcircbuf { + public: + + // CREATORS + + gr_vmcircbuf_mmap_shm_open (int size); + virtual ~gr_vmcircbuf_mmap_shm_open (); +}; + +/*! + * \brief concrete factory for circular buffers built using mmap and shm_open + */ +class GR_RUNTIME_API gr_vmcircbuf_mmap_shm_open_factory : public gr_vmcircbuf_factory { + private: + static gr_vmcircbuf_factory *s_the_factory; + + public: + static gr_vmcircbuf_factory *singleton (); + + virtual const char *name () const { return "gr_vmcircbuf_mmap_shm_open_factory"; } + + /*! + * \brief return granularity of mapping, typically equal to page size + */ + virtual int granularity (); + + /*! + * \brief return a gr_vmcircbuf, or 0 if unable. + * + * Call this to create a doubly mapped circular buffer. + */ + virtual gr_vmcircbuf *make (int size); +}; + +#endif /* _GR_VMCIRCBUF_MMAP_SHM_OPEN_H_ */ diff --git a/gnuradio-runtime/lib/gr_vmcircbuf_mmap_tmpfile.cc b/gnuradio-runtime/lib/gr_vmcircbuf_mmap_tmpfile.cc new file mode 100644 index 0000000000..35de64699e --- /dev/null +++ b/gnuradio-runtime/lib/gr_vmcircbuf_mmap_tmpfile.cc @@ -0,0 +1,197 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include <gr_vmcircbuf_mmap_tmpfile.h> +#include <stdexcept> +#include <assert.h> +#include <unistd.h> +#include <stdlib.h> +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <gr_pagesize.h> +#include <gr_sys_paths.h> + +gr_vmcircbuf_mmap_tmpfile::gr_vmcircbuf_mmap_tmpfile (int size) + : gr_vmcircbuf (size) +{ +#if !defined(HAVE_MMAP) + fprintf (stderr, "gr_vmcircbuf_mmap_tmpfile: mmap or mkstemp is not available\n"); + throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); +#else + + if (size <= 0 || (size % gr_pagesize ()) != 0){ + fprintf (stderr, "gr_vmcircbuf_mmap_tmpfile: invalid size = %d\n", size); + throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); + } + + int seg_fd = -1; + char seg_name[1024]; + + static int s_seg_counter = 0; + + + // open a temporary file that we'll map in a bit later + + while (1){ + snprintf (seg_name, sizeof (seg_name), + "%s/gnuradio-%d-%d-XXXXXX", gr_tmp_path (), getpid (), s_seg_counter); + s_seg_counter++; + + seg_fd = open (seg_name, O_RDWR | O_CREAT | O_EXCL, 0600); + if (seg_fd == -1){ + if (errno == EEXIST) // File already exists (shouldn't happen). Try again + continue; + + char msg[1024]; + snprintf (msg, sizeof (msg), + "gr_vmcircbuf_mmap_tmpfile: open [%s]", seg_name); + perror (msg); + throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); + } + break; + } + + if (unlink (seg_name) == -1){ + perror ("gr_vmcircbuf_mmap_tmpfile: unlink"); + throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); + } + + // We've got a valid file descriptor to a tmp file. + // Now set it's length to 2x what we really want and mmap it in. + + if (ftruncate (seg_fd, (off_t) 2 * size) == -1){ + close (seg_fd); // cleanup + perror ("gr_vmcircbuf_mmap_tmpfile: ftruncate (1)"); + throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); + } + + void *first_copy = mmap (0, 2 * size, + PROT_READ | PROT_WRITE, MAP_SHARED, + seg_fd, (off_t) 0); + + if (first_copy == MAP_FAILED){ + close (seg_fd); // cleanup + perror ("gr_vmcircbuf_mmap_tmpfile: mmap (1)"); + throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); + } + + // unmap the 2nd half + if (munmap ((char *) first_copy + size, size) == -1){ + close (seg_fd); // cleanup + perror ("gr_vmcircbuf_mmap_tmpfile: munmap (1)"); + throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); + } + + // map the first half into the now available hole where the + // second half used to be. + + void *second_copy = mmap ((char *) first_copy + size, size, + PROT_READ | PROT_WRITE, MAP_SHARED, + seg_fd, (off_t) 0); + + if (second_copy == MAP_FAILED){ + munmap(first_copy, size); // cleanup + close (seg_fd); + perror ("gr_vmcircbuf_mmap_tmpfile: mmap (2)"); + throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); + } + + // check for contiguity + if ((char *) second_copy != (char *) first_copy + size){ + munmap(first_copy, size); // cleanup + munmap(second_copy, size); + close (seg_fd); + perror ("gr_vmcircbuf_mmap_tmpfile: non-contiguous second copy"); + throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); + } + + // cut the tmp file down to size + if (ftruncate (seg_fd, (off_t) size) == -1){ + munmap(first_copy, size); // cleanup + munmap(second_copy, size); + close (seg_fd); + perror ("gr_vmcircbuf_mmap_tmpfile: ftruncate (2)"); + throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); + } + + close (seg_fd); // fd no longer needed. The mapping is retained. + + // Now remember the important stuff + + d_base = (char *) first_copy; + d_size = size; +#endif +} + +gr_vmcircbuf_mmap_tmpfile::~gr_vmcircbuf_mmap_tmpfile () +{ +#if defined(HAVE_MMAP) + if (munmap (d_base, 2 * d_size) == -1){ + perror ("gr_vmcircbuf_mmap_tmpfile: munmap (2)"); + } +#endif +} + +// ---------------------------------------------------------------- +// The factory interface +// ---------------------------------------------------------------- + + +gr_vmcircbuf_factory *gr_vmcircbuf_mmap_tmpfile_factory::s_the_factory = 0; + +gr_vmcircbuf_factory * +gr_vmcircbuf_mmap_tmpfile_factory::singleton () +{ + if (s_the_factory) + return s_the_factory; + + s_the_factory = new gr_vmcircbuf_mmap_tmpfile_factory (); + return s_the_factory; +} + +int +gr_vmcircbuf_mmap_tmpfile_factory::granularity () +{ + return gr_pagesize (); +} + +gr_vmcircbuf * +gr_vmcircbuf_mmap_tmpfile_factory::make (int size) +{ + try { + return new gr_vmcircbuf_mmap_tmpfile (size); + } + catch (...){ + return 0; + } +} diff --git a/gnuradio-runtime/lib/gr_vmcircbuf_mmap_tmpfile.h b/gnuradio-runtime/lib/gr_vmcircbuf_mmap_tmpfile.h new file mode 100644 index 0000000000..cd865734f2 --- /dev/null +++ b/gnuradio-runtime/lib/gr_vmcircbuf_mmap_tmpfile.h @@ -0,0 +1,67 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 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 _GR_VMCIRCBUF_MMAP_TMPFILE_H_ +#define _GR_VMCIRCBUF_MMAP_TMPFILE_H_ + +#include <gr_runtime_api.h> +#include <gr_vmcircbuf.h> + +/*! + * \brief concrete class to implement circular buffers with mmap and shm_open + * \ingroup internal + */ +class GR_RUNTIME_API gr_vmcircbuf_mmap_tmpfile : public gr_vmcircbuf { + public: + + // CREATORS + + gr_vmcircbuf_mmap_tmpfile (int size); + virtual ~gr_vmcircbuf_mmap_tmpfile (); +}; + +/*! + * \brief concrete factory for circular buffers built using mmap and shm_open + */ +class GR_RUNTIME_API gr_vmcircbuf_mmap_tmpfile_factory : public gr_vmcircbuf_factory { + private: + static gr_vmcircbuf_factory *s_the_factory; + + public: + static gr_vmcircbuf_factory *singleton (); + + virtual const char *name () const { return "gr_vmcircbuf_mmap_tmpfile_factory"; } + + /*! + * \brief return granularity of mapping, typically equal to page size + */ + virtual int granularity (); + + /*! + * \brief return a gr_vmcircbuf, or 0 if unable. + * + * Call this to create a doubly mapped circular buffer. + */ + virtual gr_vmcircbuf *make (int size); +}; + +#endif /* _GR_VMCIRCBUF_MMAP_TMPFILE_H_ */ diff --git a/gnuradio-runtime/lib/gr_vmcircbuf_sysv_shm.cc b/gnuradio-runtime/lib/gr_vmcircbuf_sysv_shm.cc new file mode 100644 index 0000000000..d9cf75e70f --- /dev/null +++ b/gnuradio-runtime/lib/gr_vmcircbuf_sysv_shm.cc @@ -0,0 +1,194 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 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 <gr_vmcircbuf_sysv_shm.h> +#include <stdexcept> +#include <assert.h> +#include <unistd.h> +#include <stdlib.h> +#include <fcntl.h> +#ifdef HAVE_SYS_IPC_H +#include <sys/ipc.h> +#endif +#ifdef HAVE_SYS_SHM_H +#include <sys/shm.h> +#endif +#include <errno.h> +#include <stdio.h> +#include <gr_pagesize.h> + + +gr_vmcircbuf_sysv_shm::gr_vmcircbuf_sysv_shm (int size) + : gr_vmcircbuf (size) +{ +#if !defined(HAVE_SYS_SHM_H) + fprintf (stderr, "gr_vmcircbuf_sysv_shm: sysv shared memory is not available\n"); + throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); +#else + + int pagesize = gr_pagesize(); + + if (size <= 0 || (size % pagesize) != 0){ + fprintf (stderr, "gr_vmcircbuf_sysv_shm: invalid size = %d\n", size); + throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); + } + + int shmid_guard = -1; + int shmid1 = -1; + int shmid2 = -1; + + // We use this as a guard page. We'll map it read-only on both ends of the buffer. + // Ideally we'd map it no access, but I don't think that's possible with SysV + if ((shmid_guard = shmget (IPC_PRIVATE, pagesize, IPC_CREAT | 0400)) == -1){ + perror ("gr_vmcircbuf_sysv_shm: shmget (0)"); + throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); + } + + if ((shmid2 = shmget (IPC_PRIVATE, 2 * size + 2 * pagesize, IPC_CREAT | 0700)) == -1){ + perror ("gr_vmcircbuf_sysv_shm: shmget (1)"); + shmctl (shmid_guard, IPC_RMID, 0); + throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); + } + + if ((shmid1 = shmget (IPC_PRIVATE, size, IPC_CREAT | 0700)) == -1){ + perror ("gr_vmcircbuf_sysv_shm: shmget (2)"); + shmctl (shmid_guard, IPC_RMID, 0); + shmctl (shmid2, IPC_RMID, 0); + throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); + } + + void *first_copy = shmat (shmid2, 0, 0); + if (first_copy == (void *) -1){ + perror ("gr_vmcircbuf_sysv_shm: shmat (1)"); + shmctl (shmid_guard, IPC_RMID, 0); + shmctl (shmid2, IPC_RMID, 0); + shmctl (shmid1, IPC_RMID, 0); + throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); + } + + shmctl (shmid2, IPC_RMID, 0); + + // There may be a race between our detach and attach. + // + // If the system allocates all shared memory segments at the same + // virtual addresses in all processes and if the system allocates + // some other segment to first_copy or first_copoy + size between + // our detach and attach, the attaches below could fail [I've never + // seen it fail for this reason]. + + shmdt (first_copy); + + // first read-only guard page + if (shmat (shmid_guard, first_copy, SHM_RDONLY) == (void *) -1){ + perror ("gr_vmcircbuf_sysv_shm: shmat (2)"); + shmctl (shmid_guard, IPC_RMID, 0); + shmctl (shmid1, IPC_RMID, 0); + throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); + } + + // first copy + if (shmat (shmid1, (char *) first_copy + pagesize, 0) == (void *) -1){ + perror ("gr_vmcircbuf_sysv_shm: shmat (3)"); + shmctl (shmid_guard, IPC_RMID, 0); + shmctl (shmid1, IPC_RMID, 0); + shmdt (first_copy); + throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); + } + + // second copy + if (shmat (shmid1, (char *) first_copy + pagesize + size, 0) == (void *) -1){ + perror ("gr_vmcircbuf_sysv_shm: shmat (4)"); + shmctl (shmid_guard, IPC_RMID, 0); + shmctl (shmid1, IPC_RMID, 0); + shmdt ((char *)first_copy + pagesize); + throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); + } + + // second read-only guard page + if (shmat (shmid_guard, (char *) first_copy + pagesize + 2 * size, SHM_RDONLY) == (void *) -1){ + perror ("gr_vmcircbuf_sysv_shm: shmat (5)"); + shmctl (shmid_guard, IPC_RMID, 0); + shmctl (shmid1, IPC_RMID, 0); + shmdt (first_copy); + shmdt ((char *)first_copy + pagesize); + shmdt ((char *)first_copy + pagesize + size); + throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); + } + + shmctl (shmid1, IPC_RMID, 0); + shmctl (shmid_guard, IPC_RMID, 0); + + // Now remember the important stuff + + d_base = (char *) first_copy + pagesize; + d_size = size; +#endif +} + +gr_vmcircbuf_sysv_shm::~gr_vmcircbuf_sysv_shm () +{ +#if defined(HAVE_SYS_SHM_H) + if (shmdt (d_base - gr_pagesize()) == -1 + || shmdt (d_base) == -1 + || shmdt (d_base + d_size) == -1 + || shmdt (d_base + 2 * d_size) == -1){ + perror ("gr_vmcircbuf_sysv_shm: shmdt (2)"); + } +#endif +} + +// ---------------------------------------------------------------- +// The factory interface +// ---------------------------------------------------------------- + + +gr_vmcircbuf_factory *gr_vmcircbuf_sysv_shm_factory::s_the_factory = 0; + +gr_vmcircbuf_factory * +gr_vmcircbuf_sysv_shm_factory::singleton () +{ + if (s_the_factory) + return s_the_factory; + + s_the_factory = new gr_vmcircbuf_sysv_shm_factory (); + return s_the_factory; +} + +int +gr_vmcircbuf_sysv_shm_factory::granularity () +{ + return gr_pagesize (); +} + +gr_vmcircbuf * +gr_vmcircbuf_sysv_shm_factory::make (int size) +{ + try { + return new gr_vmcircbuf_sysv_shm (size); + } + catch (...){ + return 0; + } +} diff --git a/gnuradio-runtime/lib/gr_vmcircbuf_sysv_shm.h b/gnuradio-runtime/lib/gr_vmcircbuf_sysv_shm.h new file mode 100644 index 0000000000..abebd93f1c --- /dev/null +++ b/gnuradio-runtime/lib/gr_vmcircbuf_sysv_shm.h @@ -0,0 +1,67 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 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 _GR_VMCIRCBUF_SYSV_SHM_H_ +#define _GR_VMCIRCBUF_SYSV_SHM_H_ + +#include <gr_runtime_api.h> +#include <gr_vmcircbuf.h> + +/*! + * \brief concrete class to implement circular buffers with mmap and shm_open + * \ingroup internal + */ +class GR_RUNTIME_API gr_vmcircbuf_sysv_shm : public gr_vmcircbuf { + public: + + // CREATORS + + gr_vmcircbuf_sysv_shm (int size); + virtual ~gr_vmcircbuf_sysv_shm (); +}; + +/*! + * \brief concrete factory for circular buffers built using mmap and shm_open + */ +class GR_RUNTIME_API gr_vmcircbuf_sysv_shm_factory : public gr_vmcircbuf_factory { + private: + static gr_vmcircbuf_factory *s_the_factory; + + public: + static gr_vmcircbuf_factory *singleton (); + + virtual const char *name () const { return "gr_vmcircbuf_sysv_shm_factory"; } + + /*! + * \brief return granularity of mapping, typically equal to page size + */ + virtual int granularity (); + + /*! + * \brief return a gr_vmcircbuf, or 0 if unable. + * + * Call this to create a doubly mapped circular buffer. + */ + virtual gr_vmcircbuf *make (int size); +}; + +#endif /* _GR_VMCIRCBUF_SYSV_SHM_H_ */ diff --git a/gnuradio-runtime/lib/gri_debugger_hook.cc b/gnuradio-runtime/lib/gri_debugger_hook.cc new file mode 100644 index 0000000000..d9270c435f --- /dev/null +++ b/gnuradio-runtime/lib/gri_debugger_hook.cc @@ -0,0 +1,29 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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 <gri_debugger_hook.h> + +void +gri_debugger_hook () +{ + // nop. set a breakpoint here +} diff --git a/gnuradio-runtime/lib/gri_debugger_hook.h b/gnuradio-runtime/lib/gri_debugger_hook.h new file mode 100644 index 0000000000..6d31ed1b2c --- /dev/null +++ b/gnuradio-runtime/lib/gri_debugger_hook.h @@ -0,0 +1,30 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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_DEBUGGER_HOOK_H +#define INCLUDED_GRI_DEBUGGER_HOOK_H + +#include <gr_runtime_api.h> + +GR_RUNTIME_API void gri_debugger_hook (); + +#endif /* INCLUDED_GRI_DEBUGGER_HOOK_H */
\ No newline at end of file diff --git a/gnuradio-runtime/lib/ice_application_base.cc b/gnuradio-runtime/lib/ice_application_base.cc new file mode 100644 index 0000000000..88db6056c1 --- /dev/null +++ b/gnuradio-runtime/lib/ice_application_base.cc @@ -0,0 +1,43 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 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 <ice_application_base.h> + +int ice_application_common::d_reacquire_attributes(0); +bool ice_application_common::d_main_called(false); +bool ice_application_common::d_have_ice_config(false); +boost::shared_ptr<boost::thread> ice_application_common::d_thread; +std::string ice_application_common::d_endpointStr(""); + +boost::shared_ptr<ice_application_common> +ice_application_common::Instance() +{ + static boost::shared_ptr<ice_application_common> + instance(new ice_application_common()); + return instance; +} + +int ice_application_common::run(int, char**) +{ + communicator()->waitForShutdown(); + return EXIT_SUCCESS; +} diff --git a/gnuradio-runtime/lib/malloc16.c b/gnuradio-runtime/lib/malloc16.c new file mode 100644 index 0000000000..2cc6135e77 --- /dev/null +++ b/gnuradio-runtime/lib/malloc16.c @@ -0,0 +1,46 @@ +/* Wrapper functions for malloc/free that force 16-byte alignment + * See http://perso.club-internet.fr/matmac/sourcesc.htm + + * Copyright 2001 Phil Karn, KA9Q + * May be used under the terms of the GNU Public License (GPL) + */ + +#include "malloc16.h" +#include <string.h> + +void *malloc16Align(int size){ + void *p; + void **p1; + + if((p = malloc(size+31)) == NULL) + return NULL; + + /* Round up to next 16-byte boundary */ + p1 = (void **)(((long)p + 31) & (~15)); + + /* Stash actual start of block just before ptr we return */ + p1[-1] = p; + + /* Return 16-byte aligned address */ + return (void *)p1; +} + +void *calloc16Align(size_t nmemb,size_t size){ + int nbytes; + void *p; + + nbytes = nmemb*size; + if((p = malloc16Align(nbytes)) == NULL) + return NULL; + + memset(p,0,nbytes); + return p; +} + +void free16Align(void *p){ + + if(p != NULL){ + /* Retrieve pointer to actual start of block and free it */ + free(((void **)p)[-1]); + } +} diff --git a/gnuradio-runtime/lib/malloc16.h b/gnuradio-runtime/lib/malloc16.h new file mode 100644 index 0000000000..90d1eca77a --- /dev/null +++ b/gnuradio-runtime/lib/malloc16.h @@ -0,0 +1,37 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002 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 <gr_runtime_api.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdlib.h> + +GR_RUNTIME_API void *malloc16Align(int size); +GR_RUNTIME_API void *calloc16Align(size_t nmemb,size_t size); +GR_RUNTIME_API void free16Align(void *p); + +#ifdef __cplusplus +} +#endif diff --git a/gnuradio-runtime/lib/posix_memalign.cc b/gnuradio-runtime/lib/posix_memalign.cc new file mode 100644 index 0000000000..aaeff78042 --- /dev/null +++ b/gnuradio-runtime/lib/posix_memalign.cc @@ -0,0 +1,114 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "posix_memalign.h" + +#ifdef HAVE_MALLOC_H +// for Cygwin valloc () prototype +#include <malloc.h> +#endif + +#ifndef HAVE_POSIX_MEMALIGN + +/* emulate posix_memalign functionality, to some degree */ + +#include <errno.h> +#include "gr_pagesize.h" + +int posix_memalign +(void **memptr, size_t alignment, size_t size) +{ + /* emulate posix_memalign functionality, to some degree */ + + /* make sure the return handle is valid; return "bad address" if not valid */ + if (memptr == 0) + return (EFAULT); + *memptr = (void*) 0; + + /* make sure 'alignment' is a power of 2 + * and multiple of sizeof (void*) + */ + + /* make sure 'alignment' is a multiple of sizeof (void*) */ + if ((alignment % sizeof (void*)) != 0) + return (EINVAL); + + /* make sure 'alignment' is a power of 2 */ + if ((alignment & (alignment - 1)) != 0) + return (EINVAL); + + /* good alignment */ + +#if (ALIGNED_MALLOC != 0) + + /* if 'malloc' is known to be aligned, and the desired 'alignment' + * matches is <= that provided by 'malloc', then use 'malloc'. This + * works on, e.g., Darwin 8 & 9: for which malloc is 16-byte aligned. + */ + size_t am = (size_t) ALIGNED_MALLOC; + if (alignment <= am) { + /* make sure ALIGNED_MALLOC is a power of 2, to guarantee that the + * alignment is correct (since 'alignment' must be a power of 2). + */ + if ((am & (am - 1)) != 0) + return (EINVAL); + /* good malloc alignment */ + *memptr = malloc (size); + } + +#endif /* (ALIGNED_MALLOC != 0) */ +#ifdef HAVE_VALLOC + + if (*memptr == (void*) 0) { + /* try valloc if it exists */ + /* cheap and easy way to make sure alignment is met, so long as it + * is <= pagesize () */ + if (alignment <= (size_t) gr_pagesize ()) { + *memptr = valloc (size); + } + } + +#endif /* HAVE_VALLOC */ + +#if (ALIGNED_MALLOC == 0) && !defined (HAVE_VALLOC) + /* no posix_memalign, valloc, and malloc isn't known to be aligned + * (enough for the input arguments); no idea what to do. + */ + +#error gnuradio-core/src/libmissing/posix_memalign.cc: Cannot find a way to alloc aligned memory. + +#endif + + /* if the pointer wasn't allocated properly, return that there was + * not enough memory to allocate; otherwise, return OK (0). + */ + if (*memptr == (void*) 0) + return (ENOMEM); + else + return (0); +}; + +#endif /* ! HAVE_POSIX_MEMALIGN */ diff --git a/gnuradio-runtime/lib/posix_memalign.h b/gnuradio-runtime/lib/posix_memalign.h new file mode 100644 index 0000000000..ea79ced2ef --- /dev/null +++ b/gnuradio-runtime/lib/posix_memalign.h @@ -0,0 +1,42 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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 _POSIX_MEMALIGN_H_ +#define _POSIX_MEMALIGN_H_ + +#include <stdlib.h> + +#ifndef HAVE_POSIX_MEMALIGN + +#ifdef __cplusplus +extern "C" { +#endif + +extern int posix_memalign (void** memptr, size_t alignment, size_t size); + +#ifdef __cplusplus +}; +#endif + +#endif /* ! HAVE_POSIX_MEMALIGN */ + +#endif /* _POSIX_MEMALIGN_H_ */ diff --git a/gnuradio-runtime/lib/qa_gr_buffer.cc b/gnuradio-runtime/lib/qa_gr_buffer.cc new file mode 100644 index 0000000000..c74baf398e --- /dev/null +++ b/gnuradio-runtime/lib/qa_gr_buffer.cc @@ -0,0 +1,307 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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 <qa_gr_buffer.h> +#include <gr_buffer.h> +#include <cppunit/TestAssert.h> +#include <stdlib.h> +#include <gr_random.h> + +static void +leak_check (void f ()) +{ + long buffer_count = gr_buffer_ncurrently_allocated (); + long buffer_reader_count = gr_buffer_reader_ncurrently_allocated (); + + f (); + + CPPUNIT_ASSERT_EQUAL (buffer_reader_count, gr_buffer_reader_ncurrently_allocated ()); + CPPUNIT_ASSERT_EQUAL (buffer_count, gr_buffer_ncurrently_allocated ()); +} + + +// ---------------------------------------------------------------------------- +// test single writer, no readers... +// + +static void +t0_body () +{ + int nitems = 4000 / sizeof (int); + int counter = 0; + + gr_buffer_sptr buf(gr_make_buffer(nitems, sizeof (int), gr_block_sptr())); + + int last_sa; + int sa; + + sa = buf->space_available (); + CPPUNIT_ASSERT (sa > 0); + last_sa = sa; + + for (int i = 0; i < 5; i++){ + sa = buf->space_available (); + CPPUNIT_ASSERT_EQUAL (last_sa, sa); + last_sa = sa; + + int *p = (int *) buf->write_pointer (); + CPPUNIT_ASSERT (p != 0); + + for (int j = 0; j < sa; j++) + *p++ = counter++; + + buf->update_write_pointer (sa); + } +} + +// ---------------------------------------------------------------------------- +// test single writer, single reader +// + +static void +t1_body () + { + int nitems = 4000 / sizeof (int); + int write_counter = 0; + int read_counter = 0; + + gr_buffer_sptr buf(gr_make_buffer(nitems, sizeof (int), gr_block_sptr())); + gr_buffer_reader_sptr r1 (gr_buffer_add_reader (buf, 0, gr_block_sptr())); + + + int sa; + + // write 1/3 of buffer + + sa = buf->space_available (); + CPPUNIT_ASSERT (sa > 0); + + int *p = (int *) buf->write_pointer (); + CPPUNIT_ASSERT (p != 0); + + for (int j = 0; j < sa/3; j++){ + *p++ = write_counter++; + } + buf->update_write_pointer (sa/3); + + + // write the next 1/3 (1/2 of what's left) + + sa = buf->space_available (); + CPPUNIT_ASSERT (sa > 0); + + p = (int *) buf->write_pointer (); + CPPUNIT_ASSERT (p != 0); + + for (int j = 0; j < sa/2; j++){ + *p++ = write_counter++; + } + buf->update_write_pointer (sa/2); + + + // check that we can read it OK + + int ia = r1->items_available (); + CPPUNIT_ASSERT_EQUAL (write_counter, ia); + + int *rp = (int *) r1->read_pointer (); + CPPUNIT_ASSERT (rp != 0); + + for (int i = 0; i < ia/2; i++){ + CPPUNIT_ASSERT_EQUAL (read_counter, *rp); + read_counter++; + rp++; + } + r1->update_read_pointer (ia/2); + + // read the rest + + ia = r1->items_available (); + rp = (int *) r1->read_pointer (); + CPPUNIT_ASSERT (rp != 0); + + for (int i = 0; i < ia; i++){ + CPPUNIT_ASSERT_EQUAL (read_counter, *rp); + read_counter++; + rp++; + } + r1->update_read_pointer (ia); +} + +// ---------------------------------------------------------------------------- +// single writer, single reader: check wrap-around +// + +static void +t2_body () +{ + // 64K is the largest granularity we've seen so far (MS windows file mapping). + // This allows a bit of "white box testing" + + int nitems = (64 * (1L << 10)) / sizeof (int); // 64K worth of ints + + gr_buffer_sptr buf(gr_make_buffer (nitems, sizeof (int), gr_block_sptr())); + gr_buffer_reader_sptr r1 (gr_buffer_add_reader (buf, 0, gr_block_sptr())); + + int read_counter = 0; + int write_counter = 0; + int n; + int *wp = 0; + int *rp = 0; + + // Write 3/4 of buffer + + n = (int) (buf->space_available () * 0.75); + wp = (int *) buf->write_pointer (); + + for (int i = 0; i < n; i++) + *wp++ = write_counter++; + buf->update_write_pointer (n); + + // Now read it all + + int m = r1->items_available (); + CPPUNIT_ASSERT_EQUAL (n, m); + rp = (int *) r1->read_pointer (); + + for (int i = 0; i < m; i++){ + CPPUNIT_ASSERT_EQUAL (read_counter, *rp); + read_counter++; + rp++; + } + r1->update_read_pointer (m); + + // Now write as much as we can. + // This will wrap around the buffer + + n = buf->space_available (); + CPPUNIT_ASSERT_EQUAL (nitems - 1, n); // white box test + wp = (int *) buf->write_pointer (); + + for (int i = 0; i < n; i++) + *wp++ = write_counter++; + buf->update_write_pointer (n); + + // now read it all + + m = r1->items_available (); + CPPUNIT_ASSERT_EQUAL (n, m); + rp = (int *) r1->read_pointer (); + + for (int i = 0; i < m; i++){ + CPPUNIT_ASSERT_EQUAL (read_counter, *rp); + read_counter++; + rp++; + } + r1->update_read_pointer (m); + +} + +// ---------------------------------------------------------------------------- +// single writer, N readers, randomized order and lengths +// ---------------------------------------------------------------------------- + +static void +t3_body () +{ + int nitems = (64 * (1L << 10)) / sizeof (int); + + static const int N = 5; + gr_buffer_sptr buf(gr_make_buffer(nitems, sizeof (int), gr_block_sptr())); + gr_buffer_reader_sptr reader[N]; + int read_counter[N]; + int write_counter = 0; + gr_random random; + + for (int i = 0; i < N; i++){ + read_counter[i] = 0; + reader[i] = gr_buffer_add_reader (buf, 0, gr_block_sptr()); + } + + for (int lc = 0; lc < 1000; lc++){ + + // write some + + int n = (int) (buf->space_available () * random.ran1 ()); + int *wp = (int *) buf->write_pointer (); + + for (int i = 0; i < n; i++) + *wp++ = write_counter++; + + buf->update_write_pointer (n); + + // pick a random reader and read some + + int r = (int) (N * random.ran1 ()); + CPPUNIT_ASSERT (0 <= r && r < N); + + int m = reader[r]->items_available (); + int *rp = (int *) reader[r]->read_pointer (); + + for (int i = 0; i < m; i++){ + CPPUNIT_ASSERT_EQUAL (read_counter[r], *rp); + read_counter[r]++; + rp++; + } + reader[r]->update_read_pointer (m); + } +} + + +// ---------------------------------------------------------------------------- + +void +qa_gr_buffer::t0 () +{ + leak_check (t0_body); +} + +void +qa_gr_buffer::t1 () +{ + leak_check (t1_body); +} + +void +qa_gr_buffer::t2 () +{ + leak_check (t2_body); +} + +void +qa_gr_buffer::t3 () +{ + leak_check (t3_body); +} + +void +qa_gr_buffer::t4 () +{ +} + +void +qa_gr_buffer::t5 () +{ +} diff --git a/gnuradio-runtime/lib/qa_gr_buffer.h b/gnuradio-runtime/lib/qa_gr_buffer.h new file mode 100644 index 0000000000..2937c24b68 --- /dev/null +++ b/gnuradio-runtime/lib/qa_gr_buffer.h @@ -0,0 +1,53 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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_QA_GR_BUFFER_H +#define INCLUDED_QA_GR_BUFFER_H + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> + +class qa_gr_buffer : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE (qa_gr_buffer); + CPPUNIT_TEST (t0); + CPPUNIT_TEST (t1); + CPPUNIT_TEST (t2); + CPPUNIT_TEST (t3); + CPPUNIT_TEST (t4); + CPPUNIT_TEST (t5); + CPPUNIT_TEST_SUITE_END (); + + + private: + + void t0 (); + void t1 (); + void t2 (); + void t3 (); + void t4 (); + void t5 (); +}; + + + +#endif /* INCLUDED_QA_GR_BUFFER_H */ diff --git a/gnuradio-runtime/lib/qa_gr_circular_file.cc b/gnuradio-runtime/lib/qa_gr_circular_file.cc new file mode 100644 index 0000000000..243e44784b --- /dev/null +++ b/gnuradio-runtime/lib/qa_gr_circular_file.cc @@ -0,0 +1,72 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002 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 <qa_gr_circular_file.h> +#include <gr_circular_file.h> +#include <cppunit/TestAssert.h> +#include <iostream> +#include <stdio.h> +#include <unistd.h> + +static const char *test_file = "qa_gr_circular_file.data"; +static const int BUFFER_SIZE = 8192; +static const int NWRITE = 8192 * 9 / 8; + +void +qa_gr_circular_file::t1 () +{ +#ifdef HAVE_MMAP + gr_circular_file *cf_writer; + gr_circular_file *cf_reader; + + // write the data... + + cf_writer = new gr_circular_file (test_file, true, BUFFER_SIZE * sizeof (short)); + + short sd; + for (int i = 0; i < NWRITE; i++){ + sd = i; + cf_writer->write (&sd, sizeof (sd)); + } + + delete cf_writer; + + // now read it back... + + cf_reader = new gr_circular_file (test_file); + for (int i = 0; i < BUFFER_SIZE; i++){ + int n = cf_reader->read (&sd, sizeof (sd)); + CPPUNIT_ASSERT_EQUAL ((int) sizeof (sd), n); + CPPUNIT_ASSERT_EQUAL (NWRITE - BUFFER_SIZE + i, (int) sd); + } + + int n = cf_reader->read (&sd, sizeof (sd)); + CPPUNIT_ASSERT_EQUAL (0, n); + + delete cf_reader; + unlink (test_file); +#endif // HAVE_MMAP +} + diff --git a/gnuradio-runtime/lib/qa_gr_circular_file.h b/gnuradio-runtime/lib/qa_gr_circular_file.h new file mode 100644 index 0000000000..df35ab077b --- /dev/null +++ b/gnuradio-runtime/lib/qa_gr_circular_file.h @@ -0,0 +1,40 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002 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 _QA_GR_CIRCULAR_FILE_H_ +#define _QA_GR_CIRCULAR_FILE_H_ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> + +class qa_gr_circular_file : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE (qa_gr_circular_file); + CPPUNIT_TEST (t1); + CPPUNIT_TEST_SUITE_END (); + + private: + void t1 (); + +}; + + +#endif /* _QA_GR_CIRCULAR_FILE_H_ */ diff --git a/gnuradio-runtime/lib/qa_gr_fxpt.cc b/gnuradio-runtime/lib/qa_gr_fxpt.cc new file mode 100644 index 0000000000..7eac0d8964 --- /dev/null +++ b/gnuradio-runtime/lib/qa_gr_fxpt.cc @@ -0,0 +1,103 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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 <qa_gr_fxpt.h> +#include <gr_fxpt.h> +#include <cppunit/TestAssert.h> +#include <iostream> +#include <stdio.h> +#include <unistd.h> +#include <math.h> + +static const float SIN_COS_TOLERANCE = 1e-5; + +void +qa_gr_fxpt::t0 () +{ + CPPUNIT_ASSERT_DOUBLES_EQUAL (M_PI/2, gr_fxpt::fixed_to_float (0x40000000), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL (0.0, gr_fxpt::fixed_to_float (0x00000000), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL (-M_PI, gr_fxpt::fixed_to_float (0x80000000), SIN_COS_TOLERANCE); + + if (0){ + /* + * These are disabled because of some precision issues. + * + * Different compilers seem to have different opinions on whether + * the calulations are done single or double (or extended) + * precision. Any of the answers are fine for our real purpose, but + * sometimes the answer is off by a few bits at the bottom. + * Hence, the disabled check. + */ + CPPUNIT_ASSERT_EQUAL ((gr_int32) 0x40000000, gr_fxpt::float_to_fixed (M_PI/2)); + CPPUNIT_ASSERT_EQUAL ((gr_int32) 0, gr_fxpt::float_to_fixed (0)); + CPPUNIT_ASSERT_EQUAL ((gr_int32) 0x80000000, gr_fxpt::float_to_fixed (-M_PI)); + } +} + +void +qa_gr_fxpt::t1 () +{ + + CPPUNIT_ASSERT_DOUBLES_EQUAL ( 0, gr_fxpt::sin (0x00000000), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL ( 0.707106781, gr_fxpt::sin (0x20000000), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL ( 1, gr_fxpt::sin (0x40000000), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL ( 0.707106781, gr_fxpt::sin (0x60000000), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL ( 0, gr_fxpt::sin (0x7fffffff), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL ( 0, gr_fxpt::sin (0x80000000), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL ( 0, gr_fxpt::sin (0x80000001), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL (-1, gr_fxpt::sin (-0x40000000), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL (-0.707106781, gr_fxpt::sin (-0x20000000), SIN_COS_TOLERANCE); + + + for (float p = -M_PI; p < M_PI; p += 2 * M_PI / 3600){ + float expected = sin (p); + float actual = gr_fxpt::sin (gr_fxpt::float_to_fixed (p)); + CPPUNIT_ASSERT_DOUBLES_EQUAL (expected, actual, SIN_COS_TOLERANCE); + } +} + +void +qa_gr_fxpt::t2 () +{ + for (float p = -M_PI; p < M_PI; p += 2 * M_PI / 3600){ + float expected = cos (p); + float actual = gr_fxpt::cos (gr_fxpt::float_to_fixed (p)); + CPPUNIT_ASSERT_DOUBLES_EQUAL (expected, actual, SIN_COS_TOLERANCE); + } +} + +void +qa_gr_fxpt::t3 () +{ + for (float p = -M_PI; p < M_PI; p += 2 * M_PI / 3600){ + float expected_sin = sin (p); + float expected_cos = cos (p); + float actual_sin; + float actual_cos; + gr_fxpt::sincos (gr_fxpt::float_to_fixed (p), &actual_sin, &actual_cos); + CPPUNIT_ASSERT_DOUBLES_EQUAL (expected_sin, actual_sin, SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL (expected_cos, actual_cos, SIN_COS_TOLERANCE); + } +} diff --git a/gnuradio-runtime/lib/qa_gr_fxpt.h b/gnuradio-runtime/lib/qa_gr_fxpt.h new file mode 100644 index 0000000000..72211563e7 --- /dev/null +++ b/gnuradio-runtime/lib/qa_gr_fxpt.h @@ -0,0 +1,48 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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_QA_GR_FXPT_H +#define INCLUDED_QA_GR_FXPT_H + + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> + +class qa_gr_fxpt : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE (qa_gr_fxpt); + CPPUNIT_TEST (t0); + CPPUNIT_TEST (t1); + CPPUNIT_TEST (t2); + CPPUNIT_TEST (t3); + CPPUNIT_TEST_SUITE_END (); + + private: + void t0 (); + void t1 (); + void t2 (); + void t3 (); + +}; + +#endif /* INCLUDED_QA_GR_FXPT_H */ + + diff --git a/gnuradio-runtime/lib/qa_gr_fxpt_nco.cc b/gnuradio-runtime/lib/qa_gr_fxpt_nco.cc new file mode 100644 index 0000000000..6f208eac80 --- /dev/null +++ b/gnuradio-runtime/lib/qa_gr_fxpt_nco.cc @@ -0,0 +1,119 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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 <qa_gr_fxpt_nco.h> +#include <gr_fxpt_nco.h> +#include <gr_nco.h> +#include <cppunit/TestAssert.h> +#include <iostream> +#include <stdio.h> +#include <unistd.h> +#include <math.h> + +static const float SIN_COS_TOLERANCE = 1e-5; + +//static const float SIN_COS_FREQ = 5003; +static const float SIN_COS_FREQ = 4096; + +static const int SIN_COS_BLOCK_SIZE = 100000; + +static double max_d(double a, double b) +{ + return fabs(a) > fabs(b) ? a : b; +} + +void +qa_gr_fxpt_nco::t0 () +{ + gr_nco<float,float> ref_nco; + gr_fxpt_nco new_nco; + double max_error = 0, max_phase_error = 0; + + ref_nco.set_freq ((float)(2 * M_PI / SIN_COS_FREQ)); + new_nco.set_freq ((float)(2 * M_PI / SIN_COS_FREQ)); + + CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_nco.get_freq(), new_nco.get_freq(), SIN_COS_TOLERANCE); + + for (int i = 0; i < SIN_COS_BLOCK_SIZE; i++){ + float ref_sin = ref_nco.sin (); + float new_sin = new_nco.sin (); + //printf ("i = %6d\n", i); + CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_sin, new_sin, SIN_COS_TOLERANCE); + + max_error = max_d (max_error, ref_sin-new_sin); + + float ref_cos = ref_nco.cos (); + float new_cos = new_nco.cos (); + CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_cos, new_cos, SIN_COS_TOLERANCE); + + max_error = max_d (max_error, ref_cos-new_cos); + + ref_nco.step (); + new_nco.step (); + + CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_nco.get_phase(), new_nco.get_phase(), SIN_COS_TOLERANCE); + + max_phase_error = max_d (max_phase_error, ref_nco.get_phase()-new_nco.get_phase()); + } + // printf ("Fxpt max error %.9f, max phase error %.9f\n", max_error, max_phase_error); +} + +void +qa_gr_fxpt_nco::t1 () +{ + gr_nco<float,float> ref_nco; + gr_fxpt_nco new_nco; + gr_complex ref_block[SIN_COS_BLOCK_SIZE]; + gr_complex new_block[SIN_COS_BLOCK_SIZE]; + double max_error = 0; + + ref_nco.set_freq ((float)(2 * M_PI / SIN_COS_FREQ)); + new_nco.set_freq ((float)(2 * M_PI / SIN_COS_FREQ)); + + CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_nco.get_freq(), new_nco.get_freq(), SIN_COS_TOLERANCE); + + ref_nco.sincos ((gr_complex*)ref_block, SIN_COS_BLOCK_SIZE); + new_nco.sincos ((gr_complex*)new_block, SIN_COS_BLOCK_SIZE); + + for (int i = 0; i < SIN_COS_BLOCK_SIZE; i++){ + CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_block[i].real(), new_block[i].real(), SIN_COS_TOLERANCE); + max_error = max_d (max_error, ref_block[i].real()-new_block[i].real()); + + CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_block[i].imag(), new_block[i].imag(), SIN_COS_TOLERANCE); + max_error = max_d (max_error, ref_block[i].imag()-new_block[i].imag()); + } + CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_nco.get_phase(), new_nco.get_phase(), SIN_COS_TOLERANCE); + // printf ("Fxpt max error %.9f, max phase error %.9f\n", max_error, max_phase_error); +} + +void +qa_gr_fxpt_nco::t2 () +{ +} + +void +qa_gr_fxpt_nco::t3 () +{ +} diff --git a/gnuradio-runtime/lib/qa_gr_fxpt_nco.h b/gnuradio-runtime/lib/qa_gr_fxpt_nco.h new file mode 100644 index 0000000000..8998922bbb --- /dev/null +++ b/gnuradio-runtime/lib/qa_gr_fxpt_nco.h @@ -0,0 +1,48 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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_QA_GR_FXPT_NCO_H +#define INCLUDED_QA_GR_FXPT_NCO_H + + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> + +class qa_gr_fxpt_nco : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE (qa_gr_fxpt_nco); + CPPUNIT_TEST (t0); + CPPUNIT_TEST (t1); + CPPUNIT_TEST (t2); + CPPUNIT_TEST (t3); + CPPUNIT_TEST_SUITE_END (); + + private: + void t0 (); + void t1 (); + void t2 (); + void t3 (); + +}; + +#endif /* INCLUDED_QA_GR_FXPT_NCO_H */ + + diff --git a/gnuradio-runtime/lib/qa_gr_fxpt_vco.cc b/gnuradio-runtime/lib/qa_gr_fxpt_vco.cc new file mode 100644 index 0000000000..5b6993a30c --- /dev/null +++ b/gnuradio-runtime/lib/qa_gr_fxpt_vco.cc @@ -0,0 +1,110 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,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 <qa_gr_fxpt_vco.h> +#include <gr_fxpt_vco.h> +#include <gr_vco.h> +#include <cppunit/TestAssert.h> +#include <iostream> +#include <stdio.h> +#include <unistd.h> +#include <math.h> + +static const float SIN_COS_TOLERANCE = 1e-5; + +static const float SIN_COS_K = 0.42; +static const float SIN_COS_AMPL = 0.8; + +static const int SIN_COS_BLOCK_SIZE = 100000; + +static double max_d(double a, double b) +{ + return fabs(a) > fabs(b) ? a : b; +} + +void +qa_gr_fxpt_vco::t0 () +{ + gr_vco<float,float> ref_vco; + gr_fxpt_vco new_vco; + double max_error = 0, max_phase_error = 0; + float input[SIN_COS_BLOCK_SIZE]; + + for (int i = 0; i < SIN_COS_BLOCK_SIZE; i++){ + input[i] = sin(double(i)); + } + + for (int i = 0; i < SIN_COS_BLOCK_SIZE; i++){ + float ref_cos = ref_vco.cos (); + float new_cos = new_vco.cos (); + CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_cos, new_cos, SIN_COS_TOLERANCE); + + max_error = max_d (max_error, ref_cos-new_cos); + + ref_vco.adjust_phase (input[i]); + new_vco.adjust_phase (input[i]); + + CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_vco.get_phase(), new_vco.get_phase(), SIN_COS_TOLERANCE); + + max_phase_error = max_d (max_phase_error, ref_vco.get_phase()-new_vco.get_phase()); + } + // printf ("Fxpt max error %.9f, max phase error %.9f\n", max_error, max_phase_error); +} + + +void +qa_gr_fxpt_vco::t1 () +{ + gr_vco<float,float> ref_vco; + gr_fxpt_vco new_vco; + float ref_block[SIN_COS_BLOCK_SIZE]; + float new_block[SIN_COS_BLOCK_SIZE]; + float input[SIN_COS_BLOCK_SIZE]; + double max_error = 0; + + for (int i = 0; i < SIN_COS_BLOCK_SIZE; i++){ + input[i] = sin(double(i)); + } + + ref_vco.cos (ref_block, input, SIN_COS_BLOCK_SIZE, SIN_COS_K, SIN_COS_AMPL); + new_vco.cos (new_block, input, SIN_COS_BLOCK_SIZE, SIN_COS_K, SIN_COS_AMPL); + + for (int i = 0; i < SIN_COS_BLOCK_SIZE; i++){ + CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_block[i], new_block[i], SIN_COS_TOLERANCE); + max_error = max_d (max_error, ref_block[i]-new_block[i]); + } + CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_vco.get_phase(), new_vco.get_phase(), SIN_COS_TOLERANCE); + // printf ("Fxpt max error %.9f, max phase error %.9f\n", max_error, ref_vco.get_phase()-new_vco.get_phase()); +} + +void +qa_gr_fxpt_vco::t2 () +{ +} + +void +qa_gr_fxpt_vco::t3 () +{ +} diff --git a/gnuradio-runtime/lib/qa_gr_fxpt_vco.h b/gnuradio-runtime/lib/qa_gr_fxpt_vco.h new file mode 100644 index 0000000000..fab8022e36 --- /dev/null +++ b/gnuradio-runtime/lib/qa_gr_fxpt_vco.h @@ -0,0 +1,48 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,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_QA_GR_FXPT_VCO_H +#define INCLUDED_QA_GR_FXPT_VCO_H + + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> + +class qa_gr_fxpt_vco : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE (qa_gr_fxpt_vco); + CPPUNIT_TEST (t0); + CPPUNIT_TEST (t1); + CPPUNIT_TEST (t2); + CPPUNIT_TEST (t3); + CPPUNIT_TEST_SUITE_END (); + + private: + void t0 (); + void t1 (); + void t2 (); + void t3 (); + +}; + +#endif /* INCLUDED_QA_GR_FXPT_VCO_H */ + + diff --git a/gnuradio-runtime/lib/qa_gr_io_signature.cc b/gnuradio-runtime/lib/qa_gr_io_signature.cc new file mode 100644 index 0000000000..c1737ffb8e --- /dev/null +++ b/gnuradio-runtime/lib/qa_gr_io_signature.cc @@ -0,0 +1,64 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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 <qa_gr_io_signature.h> +#include <gr_io_signature.h> + +void +qa_gr_io_signature::t0 () +{ + gr_make_io_signature (1, 1, sizeof (int)); +} + +void +qa_gr_io_signature::t1 () +{ + gr_make_io_signature (3, 1, sizeof (int)); // throws std::invalid_argument +} + +void +qa_gr_io_signature::t2 () +{ + gr_io_signature_sptr p = + gr_make_io_signature (3, gr_io_signature::IO_INFINITE, sizeof (int)); + + CPPUNIT_ASSERT_EQUAL (p->min_streams (), 3); + CPPUNIT_ASSERT_EQUAL (p->sizeof_stream_item (0), (int) sizeof (int)); +} + +void +qa_gr_io_signature::t3 () +{ + gr_io_signature_sptr p = + gr_make_io_signature3 (0, 5, 1, 2, 3); + + CPPUNIT_ASSERT_EQUAL (p->min_streams (), 0); + CPPUNIT_ASSERT_EQUAL (p->max_streams (), 5); + CPPUNIT_ASSERT_EQUAL (p->sizeof_stream_item(0), 1); + CPPUNIT_ASSERT_EQUAL (p->sizeof_stream_item(1), 2); + CPPUNIT_ASSERT_EQUAL (p->sizeof_stream_item(2), 3); + CPPUNIT_ASSERT_EQUAL (p->sizeof_stream_item(3), 3); + CPPUNIT_ASSERT_EQUAL (p->sizeof_stream_item(4), 3); +} diff --git a/gnuradio-runtime/lib/qa_gr_io_signature.h b/gnuradio-runtime/lib/qa_gr_io_signature.h new file mode 100644 index 0000000000..9cd6bb5247 --- /dev/null +++ b/gnuradio-runtime/lib/qa_gr_io_signature.h @@ -0,0 +1,46 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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_QA_GR_IO_SIGNATURE_H +#define INCLUDED_QA_GR_IO_SIGNATURE_H + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> +#include <stdexcept> + +class qa_gr_io_signature : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE (qa_gr_io_signature); + CPPUNIT_TEST (t0); + CPPUNIT_TEST_EXCEPTION (t1, std::invalid_argument); + CPPUNIT_TEST (t2); + CPPUNIT_TEST (t3); + CPPUNIT_TEST_SUITE_END (); + + private: + void t0 (); + void t1 (); + void t2 (); + void t3 (); +}; + +#endif /* INCLUDED_QA_GR_IO_SIGNATURE_H */ diff --git a/gnuradio-runtime/lib/qa_gr_logger.cc b/gnuradio-runtime/lib/qa_gr_logger.cc new file mode 100644 index 0000000000..a8e4a1d766 --- /dev/null +++ b/gnuradio-runtime/lib/qa_gr_logger.cc @@ -0,0 +1,52 @@ +/* + * Copyright 2012 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. + */ + +/* + * This class gathers together all the test cases for the example + * directory into a single test suite. As you create new test cases, + * add them here. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qa_gr_logger.h> +#include <gr_logger.h> + +void +qa_gr_logger::t1() +{ +#ifdef ENABLE_GR_LOG + // This doesn't really test anything, more just + // making sure nothing's gone horribly wrong. + + GR_LOG_GETLOGGER(LOG,"main"); + GR_ADD_CONSOLE_APPENDER("main","cout","%d{%H:%M:%S} : %m%n"); + GR_LOG_NOTICE(LOG,"test from c++ NOTICE"); + GR_LOG_DEBUG(LOG,"test from c++ DEBUG"); + GR_LOG_INFO(LOG,"test from c++ INFO"); + GR_LOG_WARN(LOG,"test from c++ WARN"); + GR_LOG_ERROR(LOG,"test from c++ ERROR"); + GR_LOG_FATAL(LOG,"test from c++ FATAL"); + CPPUNIT_ASSERT(true); +#endif +} diff --git a/gnuradio-runtime/lib/qa_gr_logger.h b/gnuradio-runtime/lib/qa_gr_logger.h new file mode 100644 index 0000000000..b0d3711523 --- /dev/null +++ b/gnuradio-runtime/lib/qa_gr_logger.h @@ -0,0 +1,42 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 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 Example 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 Example Public License for more details. + * + * You should have received a copy of the GNU Example 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_QA_GR_LOG_H +#define INCLUDED_QA_GR_LOG_H + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestSuite.h> + +//! collect all the tests for the example directory + +class qa_gr_logger : public CppUnit::TestCase { + public: + CPPUNIT_TEST_SUITE(qa_gr_logger); + CPPUNIT_TEST(t1); + CPPUNIT_TEST_SUITE_END(); + + private: + void t1(); + +}; + +#endif /* INCLUDED_QA_GR_LOG_H */ diff --git a/gnuradio-runtime/lib/qa_gr_math.cc b/gnuradio-runtime/lib/qa_gr_math.cc new file mode 100644 index 0000000000..74d51b536e --- /dev/null +++ b/gnuradio-runtime/lib/qa_gr_math.cc @@ -0,0 +1,105 @@ +/* + * Copyright 2008 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 <gr_math.h> +#include <qa_gr_math.h> +#include <cppunit/TestAssert.h> +#include <stdio.h> + +void +qa_gr_math::test_binary_slicer1 () +{ + float x[5] = {-1, -0.5, 0, 0.5, 1.0}; + unsigned int z[5] = {0, 0, 1, 1, 1}; + unsigned int y; + + //printf("\nBinary\n"); + for (unsigned int i = 0; i < 5; i++) { + y = gr_binary_slicer(x[i]); + //printf("in: %f out: %d desired: %d\n", x[i], y, z[i]); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(y, z[i], 1e-9); + } + + //printf("\nBranchless Binary\n"); + for (unsigned int i = 0; i < 5; i++) { + y = gr_branchless_binary_slicer(x[i]); + //printf("in: %f out: %d desired: %d\n", x[i], y, z[i]); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(y, z[i], 1e-9); + } +} + +void +qa_gr_math::test_quad_0deg_slicer1 () +{ + gr_complex x[4] = {gr_complex(1, 0), + gr_complex(0, 1), + gr_complex(-1, 0), + gr_complex(0, -1)}; + + unsigned int z[4] = {0, 1, 2, 3}; + unsigned int y; + + //printf("\nQuad0\n"); + for (unsigned int i = 0; i < 4; i++) { + y = gr_quad_0deg_slicer(x[i]); + //printf("in: %.4f+j%.4f out: %d desired: %d\n", x[i].real(), x[i].imag(), y, z[i]); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(y, z[i], 1e-9); + } + + //printf("\nBranchless Quad0\n"); + for (unsigned int i = 0; i < 4; i++) { + y = gr_branchless_quad_0deg_slicer(x[i]); + //printf("in: %.4f+j%.4f out: %d desired: %d\n", x[i].real(), x[i].imag(), y, z[i]); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(y, z[i], 1e-9); + } +} + +void +qa_gr_math::test_quad_45deg_slicer1 () +{ + gr_complex x[4] = {gr_complex(0.707, 0.707), + gr_complex(-0.707, 0.707), + gr_complex(-0.707, -0.707), + gr_complex(0.707, -0.707)}; + + unsigned int z[4] = {0, 1, 2, 3}; + unsigned int y; + + //printf("\nQuad45\n"); + for (unsigned int i = 0; i < 4; i++) { + y = gr_quad_45deg_slicer(x[i]); + //printf("in: %.4f+j%.4f out: %d desired: %d\n", x[i].real(), x[i].imag(), y, z[i]); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(y, z[i], 1e-9); + } + + //printf("\nBranchless Quad45\n"); + for (unsigned int i = 0; i < 4; i++) { + y = gr_branchless_quad_45deg_slicer(x[i]); + //printf("in: %.4f+j%.4f out: %d desired: %d\n", x[i].real(), x[i].imag(), y, z[i]); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(y, z[i], 1e-9); + } +} diff --git a/gnuradio-runtime/lib/qa_gr_math.h b/gnuradio-runtime/lib/qa_gr_math.h new file mode 100644 index 0000000000..86858c03d5 --- /dev/null +++ b/gnuradio-runtime/lib/qa_gr_math.h @@ -0,0 +1,42 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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 _QA_GR_MATH_H_ +#define _QA_GR_MATH_H_ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> + +class qa_gr_math : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE(qa_gr_math); + CPPUNIT_TEST(test_binary_slicer1); + CPPUNIT_TEST(test_quad_0deg_slicer1); + CPPUNIT_TEST(test_quad_45deg_slicer1); + CPPUNIT_TEST_SUITE_END(); + + private: + void test_binary_slicer1(); + void test_quad_0deg_slicer1(); + void test_quad_45deg_slicer1(); +}; + +#endif /* _QA_GR_MATH_H_ */ diff --git a/gnuradio-runtime/lib/qa_gr_vmcircbuf.cc b/gnuradio-runtime/lib/qa_gr_vmcircbuf.cc new file mode 100644 index 0000000000..e3b36d8829 --- /dev/null +++ b/gnuradio-runtime/lib/qa_gr_vmcircbuf.cc @@ -0,0 +1,40 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002 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 <qa_gr_vmcircbuf.h> +#include <cppunit/TestAssert.h> +#include <gr_vmcircbuf.h> +#include <stdio.h> + +void +qa_gr_vmcircbuf::test_all () +{ + int verbose = 1; // summary + + bool ok = gr_vmcircbuf_sysconfig::test_all_factories (verbose); + + CPPUNIT_ASSERT_EQUAL (true, ok); +} diff --git a/gnuradio-runtime/lib/qa_gr_vmcircbuf.h b/gnuradio-runtime/lib/qa_gr_vmcircbuf.h new file mode 100644 index 0000000000..3576660d5a --- /dev/null +++ b/gnuradio-runtime/lib/qa_gr_vmcircbuf.h @@ -0,0 +1,39 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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 _QA_GR_VMCIRCBUF_H_ +#define _QA_GR_VMCIRCBUF_H_ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> + +class qa_gr_vmcircbuf : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE (qa_gr_vmcircbuf); + CPPUNIT_TEST (test_all); + CPPUNIT_TEST_SUITE_END (); + + private: + void test_all (); +}; + + +#endif /* _QA_GR_VMCIRCBUF_H_ */ diff --git a/gnuradio-runtime/lib/qa_runtime.cc b/gnuradio-runtime/lib/qa_runtime.cc new file mode 100644 index 0000000000..b15051c2ad --- /dev/null +++ b/gnuradio-runtime/lib/qa_runtime.cc @@ -0,0 +1,61 @@ +/* + * Copyright 2002,2007,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. + */ + +/* + * This class gathers together all the test cases for the gr + * directory into a single test suite. As you create new test cases, + * add them here. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <qa_runtime.h> +#include <qa_gr_buffer.h> +#include <qa_gr_circular_file.h> +#include <qa_gr_fxpt.h> +#include <qa_gr_fxpt_nco.h> +#include <qa_gr_fxpt_vco.h> +#include <qa_gr_io_signature.h> +#include <qa_gr_logger.h> +#include <qa_gr_math.h> +#include <qa_gr_vmcircbuf.h> +#include <qa_sincos.h> + +CppUnit::TestSuite * +qa_runtime::suite () +{ + CppUnit::TestSuite *s = new CppUnit::TestSuite ("runtime"); + + s->addTest (qa_gr_buffer::suite ()); + s->addTest (qa_gr_circular_file::suite ()); + s->addTest (qa_gr_fxpt::suite ()); + s->addTest (qa_gr_fxpt_nco::suite ()); + s->addTest (qa_gr_fxpt_vco::suite ()); + s->addTest (qa_gr_io_signature::suite ()); + s->addTest (qa_gr_logger::suite ()); + s->addTest (qa_gr_math::suite ()); + s->addTest (qa_gr_vmcircbuf::suite ()); + s->addTest (qa_sincos::suite ()); + + return s; +} diff --git a/gnuradio-runtime/lib/qa_runtime.h b/gnuradio-runtime/lib/qa_runtime.h new file mode 100644 index 0000000000..da71cbd0f4 --- /dev/null +++ b/gnuradio-runtime/lib/qa_runtime.h @@ -0,0 +1,38 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002 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 _QA_RUNTIME_H_ +#define _QA_RUNTIME_H_ + +#include <gruel/attributes.h> +#include <cppunit/TestSuite.h> + +//! collect all the tests for the runtime directory + +class __GR_ATTR_EXPORT qa_runtime { + public: + //! return suite of tests for all of runtime directory + static CppUnit::TestSuite *suite (); +}; + + +#endif /* _QA_RUNTIME_H_ */ diff --git a/gnuradio-runtime/lib/qa_sincos.cc b/gnuradio-runtime/lib/qa_sincos.cc new file mode 100644 index 0000000000..54be957546 --- /dev/null +++ b/gnuradio-runtime/lib/qa_sincos.cc @@ -0,0 +1,69 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 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 <qa_sincos.h> +#include <gr_sincos.h> +#include <gruel/attributes.h> +#include <cppunit/TestAssert.h> +#include <cmath> + +void +qa_sincos::t1() +{ + static const unsigned int N = 1000; + double c_sin, c_cos; + double gr_sin, gr_cos; + + for(unsigned i = 0; i < N; i++) { + double x = i/100.0; + c_sin = sin(x); + c_cos = cos(x); + + gr_sincos(x, &gr_sin, &gr_cos); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(c_sin, gr_sin, 0.0001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(c_cos, gr_cos, 0.0001); + } +} + +void +qa_sincos::t2() +{ + static const unsigned int N = 1000; + float c_sin, c_cos; + float gr_sin, gr_cos; + + for(unsigned i = 0; i < N; i++) { + float x = i/100.0; + c_sin = sinf(x); + c_cos = cosf(x); + + gr_sincosf(x, &gr_sin, &gr_cos); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(c_sin, gr_sin, 0.0001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(c_cos, gr_cos, 0.0001); + } +} diff --git a/gnuradio-runtime/lib/qa_sincos.h b/gnuradio-runtime/lib/qa_sincos.h new file mode 100644 index 0000000000..c54b75f97f --- /dev/null +++ b/gnuradio-runtime/lib/qa_sincos.h @@ -0,0 +1,41 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 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 _QA_SINCOS_H_ +#define _QA_SINCOS_H_ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> + +class qa_sincos : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(qa_sincos); + CPPUNIT_TEST(t1); + CPPUNIT_TEST(t2); + CPPUNIT_TEST_SUITE_END(); + +private: + void t1(); + void t2(); +}; + +#endif /* _QA_SINCOS_H_ */ diff --git a/gnuradio-runtime/lib/random.h b/gnuradio-runtime/lib/random.h new file mode 100644 index 0000000000..c643c3e422 --- /dev/null +++ b/gnuradio-runtime/lib/random.h @@ -0,0 +1,38 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003, 2008 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 _RANDOM_H_ +#define _RANDOM_H_ + +// While rand(3) specifies RAND_MAX, random(3) says that the output +// ranges from 0 to 2^31-1 but does not specify a macro to denote +// this. We define RANDOM_MAX for cleanliness. We must omit the +// definition for systems that have made the same choice. (Note that +// random(3) is from 4.2BSD, and not specified by POSIX.) + +#ifndef RANDOM_MAX +static const int RANDOM_MAX = 2147483647; // 2^31-1 +#endif /* RANDOM_MAX */ + +#include <stdlib.h> + +#endif // _RANDOM_H_ diff --git a/gnuradio-runtime/lib/rpcmanager.cc b/gnuradio-runtime/lib/rpcmanager.cc new file mode 100644 index 0000000000..4d164b63f3 --- /dev/null +++ b/gnuradio-runtime/lib/rpcmanager.cc @@ -0,0 +1,72 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 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 <rpcmanager.h> +#include <iostream> +#include <stdexcept> + +bool rpcmanager::booter_registered(false); +bool rpcmanager::aggregator_registered(false); +rpcserver_booter_base* rpcmanager::boot(0); +std::auto_ptr<rpcserver_booter_aggregator> rpcmanager::aggregator(0); + +rpcmanager::rpcmanager() {;} + +rpcmanager::~rpcmanager() +{ + if(boot) + delete boot; +} + +rpcserver_booter_base* +rpcmanager::get() +{ + if(aggregator_registered) { + return aggregator.get(); + } + else if(booter_registered) { + return boot; + } + assert(booter_registered || aggregator_registered); + return boot; +} + +void +rpcmanager::register_booter(rpcserver_booter_base* booter) +{ + if(make_aggregator && !aggregator_registered) { + aggregator.reset(new rpcserver_booter_aggregator()); + aggregator_registered = true; + } + + if(aggregator_registered) { + rpcmanager::rpcserver_booter_base_sptr bootreg(booter); + aggregator->agg()->registerServer(bootreg); + } + else if(!booter_registered) { + boot = booter; + booter_registered = true; + } + else { + throw std::runtime_error("rpcmanager: Aggregator not in use, and a rpc booter is already registered\n"); + } +} diff --git a/gnuradio-runtime/lib/rpcpmtconverters_ice.cc b/gnuradio-runtime/lib/rpcpmtconverters_ice.cc new file mode 100644 index 0000000000..7c8b6041e9 --- /dev/null +++ b/gnuradio-runtime/lib/rpcpmtconverters_ice.cc @@ -0,0 +1,123 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 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 <rpcpmtconverters_ice.h> +#include <Ice/Ice.h> +#include <gnuradio.h> + +GNURadio::KnobPtr +rpcpmtconverter::from_pmt(const pmt::pmt_t& knob, const Ice::Current& c) +{ + if(pmt::is_real(knob)) { + return new GNURadio::KnobD(Ice::Double(pmt::to_double(knob))); + } + else if(pmt::is_symbol(knob)) { + std::string stuff = pmt::symbol_to_string(knob); + return new GNURadio::KnobS(stuff); + } + else if(pmt::is_integer(knob)) { + return new GNURadio::KnobI(pmt::to_long(knob)); + } + else if(pmt::is_bool(knob)) { + return new GNURadio::KnobB(pmt::to_bool(knob)); + } + else if(pmt::is_uint64(knob)) { + return new GNURadio::KnobL(pmt::to_uint64(knob)); + //const std::complex<float> *c32vector_elements(pmt_t v, size_t &len); //< len is in elements + } + else if(pmt::is_c32vector(knob)) { // c32 sent as interleaved floats + size_t size(pmt::length(knob)); + const float* start((const float*) pmt::c32vector_elements(knob,size)); + return new GNURadio::KnobVecF(std::vector<float>(start,start+size*2)); + } + else if (pmt::is_s32vector(knob)) { + size_t size(pmt::length(knob)); + const int* start((const int*) pmt::s32vector_elements(knob,size)); + return new GNURadio::KnobVecI(std::vector<int>(start,start+size)); + } + else if(pmt::is_f32vector(knob)) { + size_t size(pmt::length(knob)); + const float* start((const float*) pmt::f32vector_elements(knob,size)); + return new GNURadio::KnobVecF(std::vector<float>(start,start+size)); + } + else if (pmt::is_u8vector(knob)) { + size_t size(pmt::length(knob)); + const uint8_t* start((const uint8_t*) pmt::u8vector_elements(knob,size)); + return new GNURadio::KnobVecC(std::vector<Ice::Byte>(start,start+size)); + } + else { + std::cerr << "Error: Don't know how to handle Knob Type (from): " << std::endl; assert(0);} + //TODO: VECTORS!!! + return new GNURadio::Knob(); +} + +pmt::pmt_t +rpcpmtconverter::to_pmt(const GNURadio::KnobPtr& knob, const Ice::Current& c) +{ + std::string id(knob->ice_id(c).substr(12)); + if(id == "KnobD") { + GNURadio::KnobDPtr k(GNURadio::KnobDPtr::dynamicCast(knob)); + return pmt::mp(k->value); + } + else if(id == "KnobF") { + GNURadio::KnobFPtr k(GNURadio::KnobFPtr::dynamicCast(knob)); + return pmt::mp(k->value); + } + else if(id == "KnobI") { + GNURadio::KnobIPtr k(GNURadio::KnobIPtr::dynamicCast(knob)); + return pmt::mp(k->value); + } + else if(id == "KnobS") { + GNURadio::KnobSPtr k(GNURadio::KnobSPtr::dynamicCast(knob)); + return pmt::string_to_symbol(k->value); + } + else if(id == "KnobB") { + GNURadio::KnobBPtr k(GNURadio::KnobBPtr::dynamicCast(knob)); + return pmt::mp(k->value); + } + else if(id == "KnobC") { + GNURadio::KnobCPtr k(GNURadio::KnobCPtr::dynamicCast(knob)); + return pmt::mp(k->value); + } + else if(id == "KnobL") { + GNURadio::KnobLPtr k(GNURadio::KnobLPtr::dynamicCast(knob)); + return pmt::mp((long)k->value); + } + else if(id == "KnobVecC") { + GNURadio::KnobVecCPtr k(GNURadio::KnobVecCPtr::dynamicCast(knob)); + return pmt::init_u8vector(k->value.size(), &k->value[0]); + } + else if(id == "KnobVecI") { + GNURadio::KnobVecIPtr k(GNURadio::KnobVecIPtr::dynamicCast(knob)); + return pmt::init_s32vector(k->value.size(), &k->value[0]); + } + //else if(id == "KnobVecF") { + // GNURadio::KnobVecFPtr k(GNURadio::KnobVecFPtr::dynamicCast(knob)); + // return pmt::mp(k->value); + //TODO: FLOAT!!! + //TODO: VECTORS!!! + else { + std::cerr << "Error: Don't know how to handle Knob Type: " << id << std::endl; assert(0); + } + + return pmt::pmt_t(); +} diff --git a/gnuradio-runtime/lib/rpcserver_aggregator.cc b/gnuradio-runtime/lib/rpcserver_aggregator.cc new file mode 100644 index 0000000000..d750d64905 --- /dev/null +++ b/gnuradio-runtime/lib/rpcserver_aggregator.cc @@ -0,0 +1,93 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 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 <rpcserver_aggregator.h> +#include <rpcserver_booter_base.h> +#include <iostream> +#include <sstream> +#include <stdexcept> + +rpcserver_aggregator::rpcserver_aggregator() + : d_type(std::string("aggregator")) +{;} + +rpcserver_aggregator::~rpcserver_aggregator() +{;} + +const std::string& +rpcserver_aggregator::type() +{ + return d_type; +} + +const std::vector<std::string>& +rpcserver_aggregator::registeredServers() +{ + return d_registeredServers; +} + +void +rpcserver_aggregator::registerConfigureCallback(const std::string &id, + const configureCallback_t callback) +{ + std::for_each(d_serverlist.begin(), d_serverlist.end(), + registerConfigureCallback_f<rpcmanager_base::rpcserver_booter_base_sptr, configureCallback_t>(id, callback)); +} + +void +rpcserver_aggregator::unregisterConfigureCallback(const std::string &id) +{ + std::for_each(d_serverlist.begin(), d_serverlist.end(), + unregisterConfigureCallback_f<rpcmanager_base::rpcserver_booter_base_sptr, configureCallback_t>(id)); +} + +void +rpcserver_aggregator::registerQueryCallback(const std::string &id, const queryCallback_t callback) +{ + std::for_each(d_serverlist.begin(), d_serverlist.end(), + registerQueryCallback_f<rpcmanager_base::rpcserver_booter_base_sptr, queryCallback_t>(id, callback)); +} + +void +rpcserver_aggregator::unregisterQueryCallback(const std::string &id) +{ + std::for_each(d_serverlist.begin(), d_serverlist.end(), + unregisterQueryCallback_f<rpcmanager_base::rpcserver_booter_base_sptr, queryCallback_t>(id)); +} + +void +rpcserver_aggregator::registerServer(rpcmanager_base::rpcserver_booter_base_sptr server) +{ + std::vector<std::string>::iterator it(std::find(d_registeredServers.begin(), + d_registeredServers.end(), + server->type())); + if(it != d_registeredServers.end()) { + d_serverlist.push_back(server); + d_registeredServers.push_back(server->type()); + } + else { + std::stringstream s; + s << "rpcserver_aggregator::registerServer: server of type " + << server->type() << " already registered" << std::endl; + throw std::runtime_error(s.str().c_str()); + } +} diff --git a/gnuradio-runtime/lib/rpcserver_booter_aggregator.cc b/gnuradio-runtime/lib/rpcserver_booter_aggregator.cc new file mode 100644 index 0000000000..c4c1b03c15 --- /dev/null +++ b/gnuradio-runtime/lib/rpcserver_booter_aggregator.cc @@ -0,0 +1,62 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 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 <rpcserver_booter_aggregator.h> + +rpcserver_booter_aggregator::rpcserver_booter_aggregator() : + d_type(std::string("aggregator")), server(new rpcserver_aggregator()) +{;} + +rpcserver_booter_aggregator::~rpcserver_booter_aggregator() +{;} + +rpcserver_base* +rpcserver_booter_aggregator::i() +{ + return &(*server); +} + +const std::string& +rpcserver_booter_aggregator::type() +{ + return d_type; +} + +const std::vector<std::string> +rpcserver_booter_aggregator::endpoints() +{ + std::vector<std::string> ep; + ep.push_back(std::string("TODO")); + return ep; +} + +const std::vector<std::string>& +rpcserver_booter_aggregator::registeredServers() +{ + return server->registeredServers(); +} + +rpcserver_aggregator* +rpcserver_booter_aggregator::agg() +{ + return &(*server); +} diff --git a/gnuradio-runtime/lib/rpcserver_booter_ice.cc b/gnuradio-runtime/lib/rpcserver_booter_ice.cc new file mode 100644 index 0000000000..7cc8cc8938 --- /dev/null +++ b/gnuradio-runtime/lib/rpcserver_booter_ice.cc @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 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 <rpcserver_ice.h> +#include <rpcserver_booter_ice.h> + +namespace { + static const char* const CONTROL_PORT_CLASS("ice"); + static const char* const CONTROL_PORT_NAME("ControlPort"); + static const char* const ENDPOINT_NAME("gnuradio"); +}; + +rpcserver_booter_ice::rpcserver_booter_ice() : + ice_server_template<rpcserver_base, rpcserver_ice, + rpcserver_booter_ice, GNURadio::ControlPortPtr> + (this, std::string(CONTROL_PORT_NAME), std::string(ENDPOINT_NAME)), + d_type(std::string(CONTROL_PORT_CLASS)) +{;} + +rpcserver_booter_ice::~rpcserver_booter_ice() +{;} + +rpcserver_base* +rpcserver_booter_ice::i() +{ + return ice_server_template<rpcserver_base, rpcserver_ice, + rpcserver_booter_ice, GNURadio::ControlPortPtr>::i(); +} + +const std::vector<std::string> +rpcserver_booter_ice::endpoints() +{ + return ice_server_template<rpcserver_base, rpcserver_ice, + rpcserver_booter_ice, GNURadio::ControlPortPtr>::endpoints(); +} diff --git a/gnuradio-runtime/lib/rpcserver_ice.cc b/gnuradio-runtime/lib/rpcserver_ice.cc new file mode 100644 index 0000000000..12229a0688 --- /dev/null +++ b/gnuradio-runtime/lib/rpcserver_ice.cc @@ -0,0 +1,165 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 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 <rpcserver_ice.h> +#include <IceUtil/IceUtil.h> +#include <Ice/Ice.h> +#include <iostream> +#include <sstream> +#include <stdexcept> +#include <gruel/pmt.h> + +#define DEBUG 0 + +using namespace rpcpmtconverter; + +rpcserver_ice::rpcserver_ice() +{} + +rpcserver_ice::~rpcserver_ice() +{} + +void +rpcserver_ice::registerConfigureCallback(const std::string &id, + const configureCallback_t callback) +{ + { + ConfigureCallbackMap_t::const_iterator iter(d_setcallbackmap.find(id)); + if(iter != d_setcallbackmap.end()) { + std::stringstream s; + s << "rpcserver_ice:: rpcserver_ice ERROR registering set, already registered: " + << id << std::endl; + throw std::runtime_error(s.str().c_str()); + } + } + + if(DEBUG) + std::cout << "rpcserver_ice registering set: " << id << std::endl; + + d_setcallbackmap.insert(ConfigureCallbackMap_t::value_type(id, callback)); +} + +void +rpcserver_ice::unregisterConfigureCallback(const std::string &id) +{ + ConfigureCallbackMap_t::iterator iter(d_setcallbackmap.find(id)); + if(iter == d_setcallbackmap.end()) { + std::stringstream s; + s << "rpcserver_ice:: rpcserver_ice ERROR unregistering set, not registered: " + << id << std::endl; + throw std::runtime_error(s.str().c_str()); + } + + if(DEBUG) + std::cout << "rpcserver_ice unregistering set: " << id << std::endl; + + d_setcallbackmap.erase(iter); +} + +void +rpcserver_ice::registerQueryCallback(const std::string &id, + const queryCallback_t callback) +{ + { + QueryCallbackMap_t::const_iterator iter(d_getcallbackmap.find(id)); + if(iter != d_getcallbackmap.end()) { + std::stringstream s; + s << "rpcserver_ice:: rpcserver_ice ERROR registering get, already registered: " + << id << std::endl; + throw std::runtime_error(s.str().c_str()); + } + } + + if(DEBUG) + std::cout << "rpcserver_ice registering get: " << id << std::endl; + + d_getcallbackmap.insert(QueryCallbackMap_t::value_type(id, callback)); +} + +void +rpcserver_ice::unregisterQueryCallback(const std::string &id) +{ + QueryCallbackMap_t::iterator iter(d_getcallbackmap.find(id)); + if(iter == d_getcallbackmap.end()) { + std::stringstream s; + s << "rpcserver_ice:: rpcserver_ice ERROR unregistering get, registered: " + << id << std::endl; + throw std::runtime_error(s.str().c_str()); + } + + if(DEBUG) + std::cout << "rpcserver_ice unregistering get: " << id << std::endl; + + d_getcallbackmap.erase(iter); +} + +void +rpcserver_ice::set(const GNURadio::KnobMap& knobs, const Ice::Current& c) +{ + std::for_each(knobs.begin(), knobs.end(), + set_f<GNURadio::KnobMap::value_type,ConfigureCallbackMap_t> + (c, d_setcallbackmap, cur_priv)); +} + +GNURadio::KnobMap +rpcserver_ice::get(const GNURadio::KnobIDList& knobs, const Ice::Current& c) +{ + GNURadio::KnobMap outknobs; + + if(knobs.size() == 0) { + std::for_each(d_getcallbackmap.begin(), d_getcallbackmap.end(), + get_all_f<QueryCallbackMap_t::value_type, QueryCallbackMap_t, GNURadio::KnobMap> + (c, d_getcallbackmap, cur_priv, outknobs)); + } + else { + std::for_each(knobs.begin(), knobs.end(), + get_f<GNURadio::KnobIDList::value_type, QueryCallbackMap_t> + (c, d_getcallbackmap, cur_priv, outknobs)); + } + return outknobs; +} + +GNURadio::KnobPropMap +rpcserver_ice::properties(const GNURadio::KnobIDList& knobs, const Ice::Current& c) +{ + GNURadio::KnobPropMap outknobs; + + if(knobs.size() == 0) { + std::for_each(d_getcallbackmap.begin(), d_getcallbackmap.end(), + properties_all_f<QueryCallbackMap_t::value_type, + QueryCallbackMap_t,GNURadio::KnobPropMap>(c, d_getcallbackmap, cur_priv, outknobs)); + } + else { + std::for_each(knobs.begin(), knobs.end(), + properties_f<GNURadio::KnobIDList::value_type, + QueryCallbackMap_t, GNURadio::KnobPropMap>(c, d_getcallbackmap, cur_priv, outknobs)); + } + return outknobs; +} + +void +rpcserver_ice::shutdown(const Ice::Current& c) +{ + if(DEBUG) + std::cout << "Shutting down..." << std::endl; + c.adapter->getCommunicator()->shutdown(); +} diff --git a/gnuradio-runtime/lib/rpcserver_selector.cc b/gnuradio-runtime/lib/rpcserver_selector.cc new file mode 100644 index 0000000000..362d5f060a --- /dev/null +++ b/gnuradio-runtime/lib/rpcserver_selector.cc @@ -0,0 +1,40 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 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 <rpcserver_booter_aggregator.h> +#include <rpcmanager.h> +#include <rpcserver_selector.h> + +bool rpcmanager::make_aggregator(false); + +#ifdef RPCSERVER_ICE + #include <rpcserver_booter_ice.h> + rpcmanager::rpcserver_booter_register_helper<rpcserver_booter_ice> boot_ice; +#endif + +#ifdef RPCSERVER_ERLANG + #error TODO ERLANG +#endif + +#ifdef RPCSERVER_XMLRPC + #error TODO XMLRPC +#endif diff --git a/gnuradio-runtime/lib/sine_table.h b/gnuradio-runtime/lib/sine_table.h new file mode 100644 index 0000000000..69834943bc --- /dev/null +++ b/gnuradio-runtime/lib/sine_table.h @@ -0,0 +1,1025 @@ + // max_error = 2.353084136763606e-06 + { 2.925817799165007e-09, 7.219194364267018e-09 }, + { 2.925707643778599e-09, 2.526699001579799e-07 }, + { 2.925487337153070e-09, 1.191140162167675e-06 }, + { 2.925156887582842e-09, 3.284585035595589e-06 }, + { 2.924716307509151e-09, 6.994872605695784e-06 }, + { 2.924165613519592e-09, 1.278374920658798e-05 }, + { 2.923504826347475e-09, 2.111280464718590e-05 }, + { 2.922733970871080e-09, 3.244343744537165e-05 }, + { 2.921853076112655e-09, 4.723682007436170e-05 }, + { 2.920862175237416e-09, 6.595386421935634e-05 }, + { 2.919761305552202e-09, 8.905518605213658e-05 }, + { 2.918550508504146e-09, 1.170010715193098e-04 }, + { 2.917229829679050e-09, 1.502514416517192e-04 }, + { 2.915799318799769e-09, 1.892658178912071e-04 }, + { 2.914259029724184e-09, 2.345032874456615e-04 }, + { 2.912609020443340e-09, 2.864224686607020e-04 }, + { 2.910849353079123e-09, 3.454814764261432e-04 }, + { 2.908980093882049e-09, 4.121378876027343e-04 }, + { 2.907001313228646e-09, 4.868487064877691e-04 }, + { 2.904913085618902e-09, 5.700703303049837e-04 }, + { 2.902715489673383e-09, 6.622585147355725e-04 }, + { 2.900408608130373e-09, 7.638683394782519e-04 }, + { 2.897992527842612e-09, 8.753541738578119e-04 }, + { 2.895467339774186e-09, 9.971696424604937e-04 }, + { 2.892833138996999e-09, 1.129767590823255e-03 }, + { 2.890090024687216e-09, 1.273600051161478e-03 }, + { 2.887238100121550e-09, 1.429118208142094e-03 }, + { 2.884277472673313e-09, 1.596772364709564e-03 }, + { 2.881208253808507e-09, 1.777011907950626e-03 }, + { 2.878030559081432e-09, 1.970285275029487e-03 }, + { 2.874744508130554e-09, 2.177039919152579e-03 }, + { 2.871350224673798e-09, 2.397722275614272e-03 }, + { 2.867847836504030e-09, 2.632777727878843e-03 }, + { 2.864237475484149e-09, 2.882650573737405e-03 }, + { 2.860519277542297e-09, 3.147783991507308e-03 }, + { 2.856693382666432e-09, 3.428620006328931e-03 }, + { 2.852759934899389e-09, 3.725599456482154e-03 }, + { 2.848719082333207e-09, 4.039161959812243e-03 }, + { 2.844570977103752e-09, 4.369745880190706e-03 }, + { 2.840315775384800e-09, 4.717788294077374e-03 }, + { 2.835953637382310e-09, 5.083724957128360e-03 }, + { 2.831484727328322e-09, 5.467990270896617e-03 }, + { 2.826909213474759e-09, 5.871017249604038e-03 }, + { 2.822227268087134e-09, 6.293237486988512e-03 }, + { 2.817439067438018e-09, 6.735081123237729e-03 }, + { 2.812544791800534e-09, 7.196976811989608e-03 }, + { 2.807544625441273e-09, 7.679351687456759e-03 }, + { 2.802438756613836e-09, 8.182631331563162e-03 }, + { 2.797227377551135e-09, 8.707239741274575e-03 }, + { 2.791910684458716e-09, 9.253599295902304e-03 }, + { 2.786488877507140e-09, 9.822130724578715e-03 }, + { 2.780962160824228e-09, 1.041325307382490e-02 }, + { 2.775330742487884e-09, 1.102738367513773e-02 }, + { 2.769594834517682e-09, 1.166493811278924e-02 }, + { 2.763754652867477e-09, 1.232633019159818e-02 }, + { 2.757810417416620e-09, 1.301197190494069e-02 }, + { 2.751762351962413e-09, 1.372227340270610e-02 }, + { 2.745610684210923e-09, 1.445764295952962e-02 }, + { 2.739355645769094e-09, 1.521848694296229e-02 }, + { 2.732997472135539e-09, 1.600520978188769e-02 }, + { 2.726536402691907e-09, 1.681821393496225e-02 }, + { 2.719972680693777e-09, 1.765789985920713e-02 }, + { 2.713306553261610e-09, 1.852466597868779e-02 }, + { 2.706538271371373e-09, 1.941890865333146e-02 }, + { 2.699668089844909e-09, 2.034102214787814e-02 }, + { 2.692696267340880e-09, 2.129139860085272e-02 }, + { 2.685623066344263e-09, 2.227042799383416e-02 }, + { 2.678448753157212e-09, 2.327849812064098e-02 }, + { 2.671173597888530e-09, 2.431599455681316e-02 }, + { 2.663797874443630e-09, 2.538330062913108e-02 }, + { 2.656321860514457e-09, 2.648079738524795e-02 }, + { 2.648745837568575e-09, 2.760886356354952e-02 }, + { 2.641070090839117e-09, 2.876787556300114e-02 }, + { 2.633294909313421e-09, 2.995820741329835e-02 }, + { 2.625420585722845e-09, 3.118023074495535e-02 }, + { 2.617447416531143e-09, 3.243431475972608e-02 }, + { 2.609375701923643e-09, 3.372082620101990e-02 }, + { 2.601205745795833e-09, 3.504012932452527e-02 }, + { 2.592937855741933e-09, 3.639258586895711e-02 }, + { 2.584572343043400e-09, 3.777855502693250e-02 }, + { 2.576109522656942e-09, 3.919839341605197e-02 }, + { 2.567549713203028e-09, 4.065245505002102e-02 }, + { 2.558893236953688e-09, 4.214109131001403e-02 }, + { 2.550140419820252e-09, 4.366465091617666e-02 }, + { 2.541291591341445e-09, 4.522347989919473e-02 }, + { 2.532347084670572e-09, 4.681792157215026e-02 }, + { 2.523307236563343e-09, 4.844831650239501e-02 }, + { 2.514172387364900e-09, 5.011500248369893e-02 }, + { 2.504942880997064e-09, 5.181831450849345e-02 }, + { 2.495619064945627e-09, 5.355858474024022e-02 }, + { 2.486201290246928e-09, 5.533614248606705e-02 }, + { 2.476689911475047e-09, 5.715131416942842e-02 }, + { 2.467085286727668e-09, 5.900442330315692e-02 }, + { 2.457387777613798e-09, 6.089579046229943e-02 }, + { 2.447597749239101e-09, 6.282573325755320e-02 }, + { 2.437715570192557e-09, 6.479456630859221e-02 }, + { 2.427741612532542e-09, 6.680260121764925e-02 }, + { 2.417676251773166e-09, 6.885014654319160e-02 }, + { 2.407519866869294e-09, 7.093750777401114e-02 }, + { 2.397272840203310e-09, 7.306498730310884e-02 }, + { 2.386935557569868e-09, 7.523288440214027e-02 }, + { 2.376508408161815e-09, 7.744149519577415e-02 }, + { 2.365991784555363e-09, 7.969111263635709e-02 }, + { 2.355386082695641e-09, 8.198202647865405e-02 }, + { 2.344691701881232e-09, 8.431452325495814e-02 }, + { 2.333909044749407e-09, 8.668888625021409e-02 }, + { 2.323038517261246e-09, 8.910539547731611e-02 }, + { 2.312080528685971e-09, 9.156432765274414e-02 }, + { 2.301035491585642e-09, 9.406595617227698e-02 }, + { 2.289903821799651e-09, 9.661055108691619e-02 }, + { 2.278685938428940e-09, 9.919837907903295e-02 }, + { 2.267382263820762e-09, 1.018297034385580e-01 }, + { 2.255993223551837e-09, 1.045047840397028e-01 }, + { 2.244519246413220e-09, 1.072238773174577e-01 }, + { 2.232960764393620e-09, 1.099872362446146e-01 }, + { 2.221318212663309e-09, 1.127951103088245e-01 }, + { 2.209592029557811e-09, 1.156477454898748e-01 }, + { 2.197782656561395e-09, 1.185453842371912e-01 }, + { 2.185890538290176e-09, 1.214882654476019e-01 }, + { 2.173916122475606e-09, 1.244766244431883e-01 }, + { 2.161859859947797e-09, 1.275106929493488e-01 }, + { 2.149722204618256e-09, 1.305906990731841e-01 }, + { 2.137503613462743e-09, 1.337168672820376e-01 }, + { 2.125204546504321e-09, 1.368894183821595e-01 }, + { 2.112825466795944e-09, 1.401085694976751e-01 }, + { 2.100366840402933e-09, 1.433745340497602e-01 }, + { 2.087829136385612e-09, 1.466875217359607e-01 }, + { 2.075212826781308e-09, 1.500477385098620e-01 }, + { 2.062518386587093e-09, 1.534553865607503e-01 }, + { 2.049746293741359e-09, 1.569106642937665e-01 }, + { 2.036897029106193e-09, 1.604137663100403e-01 }, + { 2.023971076449323e-09, 1.639648833871233e-01 }, + { 2.010968922425217e-09, 1.675642024598467e-01 }, + { 1.997891056557933e-09, 1.712119066008896e-01 }, + { 1.984737971221581e-09, 1.749081750021970e-01 }, + { 1.971510161622434e-09, 1.786531829561379e-01 }, + { 1.958208125780130e-09, 1.824471018371070e-01 }, + { 1.944832364508511e-09, 1.862900990834311e-01 }, + { 1.931383381397782e-09, 1.901823381790926e-01 }, + { 1.917861682794392e-09, 1.941239786363039e-01 }, + { 1.904267777782611e-09, 1.981151759777950e-01 }, + { 1.890602178165317e-09, 2.021560817195309e-01 }, + { 1.876865398444616e-09, 2.062468433536743e-01 }, + { 1.863057955802572e-09, 2.103876043317229e-01 }, + { 1.849180370081465e-09, 2.145785040479915e-01 }, + { 1.835233163764673e-09, 2.188196778231083e-01 }, + { 1.821216861956509e-09, 2.231112568880342e-01 }, + { 1.807131992362945e-09, 2.274533683680190e-01 }, + { 1.792979085271234e-09, 2.318461352671018e-01 }, + { 1.778758673530482e-09, 2.362896764525300e-01 }, + { 1.764471292530943e-09, 2.407841066397789e-01 }, + { 1.750117480184598e-09, 2.453295363773890e-01 }, + { 1.735697776904342e-09, 2.499260720324433e-01 }, + { 1.721212725583874e-09, 2.545738157760434e-01 }, + { 1.706662871577097e-09, 2.592728655691494e-01 }, + { 1.692048762677849e-09, 2.640233151485341e-01 }, + { 1.677370949099090e-09, 2.688252540131204e-01 }, + { 1.662629983452104e-09, 2.736787674105404e-01 }, + { 1.647826420726167e-09, 2.785839363237506e-01 }, + { 1.632960818266680e-09, 2.835408374583758e-01 }, + { 1.618033735755429e-09, 2.885495432295704e-01 }, + { 1.603045735188609e-09, 2.936101217498361e-01 }, + { 1.587997380855918e-09, 2.987226368167127e-01 }, + { 1.572889239319430e-09, 3.038871479007593e-01 }, + { 1.557721879392051e-09, 3.091037101339017e-01 }, + { 1.542495872116447e-09, 3.143723742978435e-01 }, + { 1.527211790743024e-09, 3.196931868130269e-01 }, + { 1.511870210708909e-09, 3.250661897274744e-01 }, + { 1.496471709615926e-09, 3.304914207062036e-01 }, + { 1.481016867208896e-09, 3.359689130207621e-01 }, + { 1.465506265353924e-09, 3.414986955389885e-01 }, + { 1.449940488016384e-09, 3.470807927151147e-01 }, + { 1.434320121238994e-09, 3.527152245800635e-01 }, + { 1.418645753119802e-09, 3.584020067320109e-01 }, + { 1.402917973789838e-09, 3.641411503272979e-01 }, + { 1.387137375391042e-09, 3.699326620714776e-01 }, + { 1.371304552054134e-09, 3.757765442106153e-01 }, + { 1.355420099875958e-09, 3.816727945230153e-01 }, + { 1.339484616897137e-09, 3.876214063110671e-01 }, + { 1.323498703079580e-09, 3.936223683933865e-01 }, + { 1.307462960283922e-09, 3.996756650972121e-01 }, + { 1.291377992246768e-09, 4.057812762511174e-01 }, + { 1.275244404558188e-09, 4.119391771778626e-01 }, + { 1.259062804638585e-09, 4.181493386877248e-01 }, + { 1.242833801715929e-09, 4.244117270719281e-01 }, + { 1.226558006803155e-09, 4.307263040962509e-01 }, + { 1.210236032674760e-09, 4.370930269951803e-01 }, + { 1.193868493843725e-09, 4.435118484661861e-01 }, + { 1.177456006538695e-09, 4.499827166641340e-01 }, + { 1.160999188680582e-09, 4.565055751961679e-01 }, + { 1.144498659859216e-09, 4.630803631168164e-01 }, + { 1.127955041310214e-09, 4.697070149232604e-01 }, + { 1.111368955891417e-09, 4.763854605510119e-01 }, + { 1.094741028059551e-09, 4.831156253697562e-01 }, + { 1.078071883846871e-09, 4.898974301794375e-01 }, + { 1.061362150836978e-09, 4.967307912069362e-01 }, + { 1.044612458142151e-09, 5.036156201023686e-01 }, + { 1.027823436378632e-09, 5.105518239364775e-01 }, + { 1.010995717643647e-09, 5.175393051975563e-01 }, + { 9.941299354913699e-10, 5.245779617890562e-01 }, + { 9.772267249089968e-10, 5.316676870274011e-01 }, + { 9.602867222926046e-10, 5.388083696401416e-01 }, + { 9.433105654240147e-10, 5.459998937639375e-01 }, + { 9.262988934458084e-10, 5.532421389435711e-01 }, + { 9.092523468378193e-10, 5.605349801305876e-01 }, + { 8.921715673928355e-10, 5.678782876825250e-01 }, + { 8.750571981926701e-10, 5.752719273622372e-01 }, + { 8.579098835836508e-10, 5.827157603377209e-01 }, + { 8.407302691522673e-10, 5.902096431821322e-01 }, + { 8.235190017016133e-10, 5.977534278737073e-01 }, + { 8.062767292259225e-10, 6.053469617967722e-01 }, + { 7.890041008871165e-10, 6.129900877421282e-01 }, + { 7.717017669898175e-10, 6.206826439083659e-01 }, + { 7.543703789572603e-10, 6.284244639030392e-01 }, + { 7.370105893063053e-10, 6.362153767444958e-01 }, + { 7.196230516231919e-10, 6.440552068636356e-01 }, + { 7.022084205389746e-10, 6.519437741060674e-01 }, + { 6.847673517046416e-10, 6.598808937346672e-01 }, + { 6.673005017664976e-10, 6.678663764322770e-01 }, + { 6.498085283416530e-10, 6.759000283046127e-01 }, + { 6.322920899929834e-10, 6.839816508836737e-01 }, + { 6.147518462045659e-10, 6.921110411311926e-01 }, + { 5.971884573565851e-10, 7.002879914425926e-01 }, + { 5.796025847007168e-10, 7.085122896509806e-01 }, + { 5.619948903351406e-10, 7.167837190315758e-01 }, + { 5.443660371796048e-10, 7.251020583063744e-01 }, + { 5.267166889504394e-10, 7.334670816491009e-01 }, + { 5.090475101356742e-10, 7.418785586903696e-01 }, + { 4.913591659698399e-10, 7.503362545232619e-01 }, + { 4.736523224091392e-10, 7.588399297089872e-01 }, + { 4.559276461062478e-10, 7.673893402829834e-01 }, + { 4.381858043851147e-10, 7.759842377612828e-01 }, + { 4.204274652161870e-10, 7.846243691469355e-01 }, + { 4.026532971908398e-10, 7.933094769370790e-01 }, + { 3.848639694963359e-10, 8.020392991300200e-01 }, + { 3.670601518910503e-10, 8.108135692324444e-01 }, + { 3.492425146784233e-10, 8.196320162675177e-01 }, + { 3.314117286825031e-10, 8.284943647824689e-01 }, + { 3.135684652223755e-10, 8.374003348569865e-01 }, + { 2.957133960867535e-10, 8.463496421118015e-01 }, + { 2.778471935089361e-10, 8.553419977173513e-01 }, + { 2.599705301412391e-10, 8.643771084029740e-01 }, + { 2.420840790301135e-10, 8.734546764660205e-01 }, + { 2.241885135902046e-10, 8.825743997817682e-01 }, + { 2.062845075795238e-10, 8.917359718130367e-01 }, + { 1.883727350736140e-10, 9.009390816205823e-01 }, + { 1.704538704408269e-10, 9.101834138731877e-01 }, + { 1.525285883160648e-10, 9.194686488588080e-01 }, + { 1.345975635762696e-10, 9.287944624950824e-01 }, + { 1.166614713141648e-10, 9.381605263410157e-01 }, + { 9.872098681369190e-11, 9.475665076080466e-01 }, + { 8.077678552380464e-11, 9.570120691722380e-01 }, + { 6.282954303364090e-11, 9.664968695860140e-01 }, + { 4.487993504668797e-11, 9.760205630906909e-01 }, + { 2.692863735553042e-11, 9.855827996289697e-01 }, + { 8.976325816439114e-12, 9.951832248577780e-01 }, + { -8.976323676304494e-12, 1.004821480161519e+00 }, + { -2.692863521550168e-11, 1.014497202665280e+00 }, + { -4.487993290681805e-11, 1.024210025248670e+00 }, + { -6.282954089398273e-11, 1.033959576559617e+00 }, + { -8.077678338451706e-11, 1.043745481028715e+00 }, + { -9.872098467477489e-11, 1.053567358883467e+00 }, + { -1.166614691757772e-10, 1.063424826163223e+00 }, + { -1.345975614383584e-10, 1.073317494734013e+00 }, + { -1.525285861788948e-10, 1.083244972303963e+00 }, + { -1.704538683042922e-10, 1.093206862438572e+00 }, + { -1.883727329379793e-10, 1.103202764576806e+00 }, + { -2.062845054446831e-10, 1.113232274046796e+00 }, + { -2.241885114563697e-10, 1.123294982082432e+00 }, + { -2.420840768973375e-10, 1.133390475839767e+00 }, + { -2.599705280096278e-10, 1.143518338413855e+00 }, + { -2.778471913784365e-10, 1.153678148855860e+00 }, + { -2.957133939575774e-10, 1.163869482190458e+00 }, + { -3.135684630945758e-10, 1.174091909433296e+00 }, + { -3.314117265561857e-10, 1.184344997608959e+00 }, + { -3.492425125535882e-10, 1.194628309769018e+00 }, + { -3.670601497678034e-10, 1.204941405010466e+00 }, + { -3.848639673748360e-10, 1.215283838494269e+00 }, + { -4.026532950710339e-10, 1.225655161464298e+00 }, + { -4.204274630982869e-10, 1.236054921266445e+00 }, + { -4.381858022691734e-10, 1.246482661367958e+00 }, + { -4.559276439922654e-10, 1.256937921377146e+00 }, + { -4.736523202972214e-10, 1.267420237063216e+00 }, + { -4.913591638600925e-10, 1.277929140376502e+00 }, + { -5.090475080282032e-10, 1.288464159468706e+00 }, + { -5.267166868452449e-10, 1.299024818713528e+00 }, + { -5.443660350768455e-10, 1.309610638727845e+00 }, + { -5.619948882348695e-10, 1.320221136392390e+00 }, + { -5.796025826029868e-10, 1.330855824873457e+00 }, + { -5.971884552615020e-10, 1.341514213644420e+00 }, + { -6.147518441122357e-10, 1.352195808507556e+00 }, + { -6.322920879034590e-10, 1.362900111616144e+00 }, + { -6.498085262549874e-10, 1.373626621496939e+00 }, + { -6.673004996827436e-10, 1.384374833072571e+00 }, + { -6.847673496239581e-10, 1.395144237684605e+00 }, + { -7.022084184613616e-10, 1.405934323116231e+00 }, + { -7.196230495488082e-10, 1.416744573616104e+00 }, + { -7.370105872352039e-10, 1.427574469921397e+00 }, + { -7.543703768894941e-10, 1.438423489281758e+00 }, + { -7.717017649255453e-10, 1.449291105483472e+00 }, + { -7.890040988262324e-10, 1.460176788873383e+00 }, + { -8.062767271686383e-10, 1.471080006383765e+00 }, + { -8.235189996479819e-10, 1.482000221556656e+00 }, + { -8.407302671024475e-10, 1.492936894569018e+00 }, + { -8.579098815375368e-10, 1.503889482257845e+00 }, + { -8.750571961505266e-10, 1.514857438145604e+00 }, + { -8.921715653546624e-10, 1.525840212465756e+00 }, + { -9.092523448036167e-10, 1.536837252188703e+00 }, + { -9.262988914157881e-10, 1.547848001047890e+00 }, + { -9.433105633981766e-10, 1.558871899565883e+00 }, + { -9.602867202711075e-10, 1.569908385081254e+00 }, + { -9.772267228916820e-10, 1.580956891774897e+00 }, + { -9.941299334786078e-10, 1.592016850697478e+00 }, + { -1.010995715635332e-09, 1.603087689796053e+00 }, + { -1.027823434374870e-09, 1.614168833942028e+00 }, + { -1.044612456143047e-09, 1.625259704958335e+00 }, + { -1.061362148842745e-09, 1.636359721647526e+00 }, + { -1.078071881857297e-09, 1.647468299819543e+00 }, + { -1.094741026074900e-09, 1.658584852320419e+00 }, + { -1.111368953911690e-09, 1.669708789060341e+00 }, + { -1.127955039335462e-09, 1.680839517042381e+00 }, + { -1.144498657889600e-09, 1.691976440391624e+00 }, + { -1.160999186716154e-09, 1.703118960383971e+00 }, + { -1.177456004579561e-09, 1.714266475475616e+00 }, + { -1.193868491889832e-09, 1.725418381332405e+00 }, + { -1.210236030726319e-09, 1.736574070859850e+00 }, + { -1.226558004860220e-09, 1.747732934232508e+00 }, + { -1.242833799778447e-09, 1.758894358924547e+00 }, + { -1.259062802706714e-09, 1.770057729740021e+00 }, + { -1.275244402631982e-09, 1.781222428842935e+00 }, + { -1.291377990326492e-09, 1.792387835788660e+00 }, + { -1.307462958369363e-09, 1.803553327553897e+00 }, + { -1.323498701170897e-09, 1.814718278568759e+00 }, + { -1.339484614994490e-09, 1.825882060747428e+00 }, + { -1.355420097979292e-09, 1.837044043519582e+00 }, + { -1.371304550163662e-09, 1.848203593862598e+00 }, + { -1.387137373506711e-09, 1.859360076332671e+00 }, + { -1.402917971911754e-09, 1.870512853097495e+00 }, + { -1.418645751248018e-09, 1.881661283967967e+00 }, + { -1.434320119373722e-09, 1.892804726431080e+00 }, + { -1.449940486157623e-09, 1.903942535681972e+00 }, + { -1.465506263501516e-09, 1.915074064656886e+00 }, + { -1.481016865363264e-09, 1.926198664066737e+00 }, + { -1.496471707776859e-09, 1.937315682428795e+00 }, + { -1.511870208876724e-09, 1.948424466101625e+00 }, + { -1.527211788917509e-09, 1.959524359317042e+00 }, + { -1.542495870297867e-09, 1.970614704215133e+00 }, + { -1.557721877580406e-09, 1.981694840876775e+00 }, + { -1.572889237514880e-09, 1.992764107358707e+00 }, + { -1.587997379058514e-09, 2.003821839726753e+00 }, + { -1.603045733398246e-09, 2.014867372090665e+00 }, + { -1.618033733972424e-09, 2.025900036638798e+00 }, + { -1.632960816490822e-09, 2.036919163671778e+00 }, + { -1.647826418957721e-09, 2.047924081638631e+00 }, + { -1.662629981691070e-09, 2.058914117170269e+00 }, + { -1.677370947345626e-09, 2.069888595116115e+00 }, + { -1.692048760931849e-09, 2.080846838577820e+00 }, + { -1.706662869838827e-09, 2.091788168946183e+00 }, + { -1.721212723853279e-09, 2.102711905935372e+00 }, + { -1.735697775181424e-09, 2.113617367619504e+00 }, + { -1.750117478469621e-09, 2.124503870468520e+00 }, + { -1.764471290823748e-09, 2.135370729383332e+00 }, + { -1.778758671831281e-09, 2.146217257733207e+00 }, + { -1.792979083579974e-09, 2.157042767390815e+00 }, + { -1.807131990679890e-09, 2.167846568770014e+00 }, + { -1.821216860281448e-09, 2.178627970860822e+00 }, + { -1.835233162097977e-09, 2.189386281268046e+00 }, + { -1.849180368423027e-09, 2.200120806246095e+00 }, + { -1.863057954152340e-09, 2.210830850737588e+00 }, + { -1.876865396802907e-09, 2.221515718409926e+00 }, + { -1.890602176531920e-09, 2.232174711691990e+00 }, + { -1.904267776157843e-09, 2.242807131812679e+00 }, + { -1.917861681178094e-09, 2.253412278837029e+00 }, + { -1.931383379790273e-09, 2.263989451705295e+00 }, + { -1.944832362909578e-09, 2.274537948269257e+00 }, + { -1.958208124189984e-09, 2.285057065331676e+00 }, + { -1.971510160041235e-09, 2.295546098682665e+00 }, + { -1.984737969649064e-09, 2.306004343138794e+00 }, + { -1.997891054994522e-09, 2.316431092581699e+00 }, + { -2.010968920870647e-09, 2.326825639994779e+00 }, + { -2.023971074903858e-09, 2.337187277503834e+00 }, + { -2.036897027569834e-09, 2.347515296413520e+00 }, + { -2.049746292214264e-09, 2.357808987247877e+00 }, + { -2.062518385069210e-09, 2.368067639787542e+00 }, + { -2.075212825272584e-09, 2.378290543109652e+00 }, + { -2.087829134886364e-09, 2.388476985626922e+00 }, + { -2.100366838912949e-09, 2.398626255125417e+00 }, + { -2.112825465315542e-09, 2.408737638805759e+00 }, + { -2.125204545033289e-09, 2.418810423320288e+00 }, + { -2.137503612001452e-09, 2.428843894814472e+00 }, + { -2.149722203166389e-09, 2.438837338964302e+00 }, + { -2.161859858505829e-09, 2.448790041018174e+00 }, + { -2.173916121043380e-09, 2.458701285834241e+00 }, + { -2.185890536867478e-09, 2.468570357921585e+00 }, + { -2.197782655148702e-09, 2.478396541480230e+00 }, + { -2.209592028154913e-09, 2.488179120439544e+00 }, + { -2.221318211270522e-09, 2.497917378500214e+00 }, + { -2.232960763010574e-09, 2.507610599172123e+00 }, + { -2.244519245040444e-09, 2.517258065817044e+00 }, + { -2.255993222189014e-09, 2.526859061686102e+00 }, + { -2.267382262468209e-09, 2.536412869962689e+00 }, + { -2.278685937086658e-09, 2.545918773800664e+00 }, + { -2.289903820467374e-09, 2.555376056366064e+00 }, + { -2.301035490263848e-09, 2.564784000877677e+00 }, + { -2.312080527374447e-09, 2.574141890646339e+00 }, + { -2.323038515960257e-09, 2.583449009117307e+00 }, + { -2.333909043458635e-09, 2.592704639909166e+00 }, + { -2.344691700601153e-09, 2.601908066856634e+00 }, + { -2.355386081425938e-09, 2.611058574048749e+00 }, + { -2.365991783296513e-09, 2.620155445872768e+00 }, + { -2.376508406913500e-09, 2.629197967052127e+00 }, + { -2.386935556332088e-09, 2.638185422689490e+00 }, + { -2.397272838976436e-09, 2.647117098307332e+00 }, + { -2.407519865653114e-09, 2.655992279887846e+00 }, + { -2.417676250567891e-09, 2.664810253915885e+00 }, + { -2.427741611338014e-09, 2.673570307418169e+00 }, + { -2.437715569009093e-09, 2.682271728006635e+00 }, + { -2.447597748066437e-09, 2.690913803917100e+00 }, + { -2.457387776452357e-09, 2.699495824053297e+00 }, + { -2.467085285577292e-09, 2.708017078025636e+00 }, + { -2.476689910335470e-09, 2.716476856194105e+00 }, + { -2.486201289118733e-09, 2.724874449709689e+00 }, + { -2.495619063828443e-09, 2.733209150554255e+00 }, + { -2.504942879891263e-09, 2.741480251583985e+00 }, + { -2.514172386270163e-09, 2.749687046568741e+00 }, + { -2.523307235480146e-09, 2.757828830235740e+00 }, + { -2.532347083598520e-09, 2.765904898308531e+00 }, + { -2.541291590280960e-09, 2.773914547551261e+00 }, + { -2.550140418771202e-09, 2.781857075807392e+00 }, + { -2.558893235915887e-09, 2.789731782043156e+00 }, + { -2.567549712176927e-09, 2.797537966388929e+00 }, + { -2.576109521642196e-09, 2.805274930179221e+00 }, + { -2.584572342040407e-09, 2.812941975996573e+00 }, + { -2.592937854750428e-09, 2.820538407710556e+00 }, + { -2.601205744816134e-09, 2.828063530521908e+00 }, + { -2.609375700955458e-09, 2.835516651001539e+00 }, + { -2.617447415574869e-09, 2.842897077134583e+00 }, + { -2.625420584778350e-09, 2.850204118359573e+00 }, + { -2.633294908380520e-09, 2.857437085611509e+00 }, + { -2.641070089918234e-09, 2.864595291363663e+00 }, + { -2.648745836659391e-09, 2.871678049666939e+00 }, + { -2.656321859617343e-09, 2.878684676194483e+00 }, + { -2.663797873558322e-09, 2.885614488280000e+00 }, + { -2.671173597015318e-09, 2.892466804962122e+00 }, + { -2.678448752295859e-09, 2.899240947023252e+00 }, + { -2.685623065495139e-09, 2.905936237033475e+00 }, + { -2.692696266503800e-09, 2.912551999389617e+00 }, + { -2.699668089019767e-09, 2.919087560358171e+00 }, + { -2.706538270558513e-09, 2.925542248116882e+00 }, + { -2.713306552460767e-09, 2.931915392794031e+00 }, + { -2.719972679905295e-09, 2.938206326512581e+00 }, + { -2.726536401915442e-09, 2.944414383428562e+00 }, + { -2.732997471371516e-09, 2.950538899775061e+00 }, + { -2.739355645017194e-09, 2.956579213900666e+00 }, + { -2.745610683471516e-09, 2.962534666313284e+00 }, + { -2.751762351235315e-09, 2.968404599718795e+00 }, + { -2.757810416701751e-09, 2.974188359063684e+00 }, + { -2.763754652165128e-09, 2.979885291576143e+00 }, + { -2.769594833827588e-09, 2.985494746805227e+00 }, + { -2.775330741810390e-09, 2.991016076664491e+00 }, + { -2.780962160159068e-09, 2.996448635469842e+00 }, + { -2.786488876854607e-09, 3.001791779983262e+00 }, + { -2.791910683818570e-09, 3.007044869450794e+00 }, + { -2.797227376923695e-09, 3.012207265645876e+00 }, + { -2.802438755998943e-09, 3.017278332907412e+00 }, + { -2.807544624838820e-09, 3.022257438182037e+00 }, + { -2.812544791210840e-09, 3.027143951064684e+00 }, + { -2.817439066860792e-09, 3.031937243837070e+00 }, + { -2.822227267522746e-09, 3.036636691510884e+00 }, + { -2.826909212922864e-09, 3.041241671864994e+00 }, + { -2.831484726789317e-09, 3.045751565488710e+00 }, + { -2.835953636855826e-09, 3.050165755818853e+00 }, + { -2.840315774871260e-09, 3.054483629182857e+00 }, + { -2.844570976602957e-09, 3.058704574835744e+00 }, + { -2.848719081844986e-09, 3.062827985002047e+00 }, + { -2.852759934424164e-09, 3.066853254915581e+00 }, + { -2.856693382203833e-09, 3.070779782857041e+00 }, + { -2.860519277092708e-09, 3.074606970196721e+00 }, + { -2.864237475047239e-09, 3.078334221430809e+00 }, + { -2.867847836080156e-09, 3.081960944223928e+00 }, + { -2.871350224262603e-09, 3.085486549445314e+00 }, + { -2.874744507732462e-09, 3.088910451211251e+00 }, + { -2.878030558696270e-09, 3.092232066921130e+00 }, + { -2.881208253436038e-09, 3.095450817298478e+00 }, + { -2.884277472313999e-09, 3.098566126429974e+00 }, + { -2.887238099774968e-09, 3.101577421802070e+00 }, + { -2.890090024353816e-09, 3.104484134342861e+00 }, + { -2.892833138676371e-09, 3.107285698457308e+00 }, + { -2.895467339466766e-09, 3.109981552069083e+00 }, + { -2.897992527547963e-09, 3.112571136655481e+00 }, + { -2.900408607848946e-09, 3.115053897289195e+00 }, + { -2.902715489404992e-09, 3.117429282673042e+00 }, + { -2.904913085363323e-09, 3.119696745180238e+00 }, + { -2.907001312986328e-09, 3.121855740892224e+00 }, + { -2.908980093652563e-09, 3.123905729634218e+00 }, + { -2.910849352862924e-09, 3.125846175016163e+00 }, + { -2.912609020239985e-09, 3.127676544466606e+00 }, + { -2.914259029534118e-09, 3.129396309273659e+00 }, + { -2.915799318622574e-09, 3.131004944618667e+00 }, + { -2.917229829515169e-09, 3.132501929616775e+00 }, + { -2.918550508353347e-09, 3.133886747350606e+00 }, + { -2.919761305414294e-09, 3.135158884909254e+00 }, + { -2.920862175112829e-09, 3.136317833424958e+00 }, + { -2.921853076000972e-09, 3.137363088107359e+00 }, + { -2.922733970772719e-09, 3.138294148283254e+00 }, + { -2.923504826262027e-09, 3.139110517429204e+00 }, + { -2.924165613447473e-09, 3.139811703211207e+00 }, + { -2.924716307449950e-09, 3.140397217517018e+00 }, + { -2.925156887536978e-09, 3.140866576495489e+00 }, + { -2.925487337120335e-09, 3.141219300588825e+00 }, + { -2.925707643758784e-09, 3.141454914570261e+00 }, + { -2.925817799158535e-09, 3.141572947579352e+00 }, + { -2.925817799171455e-09, 3.141572933154836e+00 }, + { -2.925707643798390e-09, 3.141454409272987e+00 }, + { -2.925487337185779e-09, 3.141216918378770e+00 }, + { -2.925156887628892e-09, 3.140860007424112e+00 }, + { -2.924716307568119e-09, 3.140383227898687e+00 }, + { -2.924165613591896e-09, 3.139786135867868e+00 }, + { -2.923504826432903e-09, 3.139068292003385e+00 }, + { -2.922733970969412e-09, 3.138229261619561e+00 }, + { -2.921853076224321e-09, 3.137268614707029e+00 }, + { -2.920862175361976e-09, 3.136185925964038e+00 }, + { -2.919761305690083e-09, 3.134980774833275e+00 }, + { -2.918550508654911e-09, 3.133652745531368e+00 }, + { -2.917229829843137e-09, 3.132201427085629e+00 }, + { -2.915799318976726e-09, 3.130626413363146e+00 }, + { -2.914259029914435e-09, 3.128927303107136e+00 }, + { -2.912609020646661e-09, 3.127103699965947e+00 }, + { -2.910849353295315e-09, 3.125155212527586e+00 }, + { -2.908980094111509e-09, 3.123081454351802e+00 }, + { -2.907001313470937e-09, 3.120882043999591e+00 }, + { -2.904913085874448e-09, 3.118556605068443e+00 }, + { -2.902715489941767e-09, 3.116104766219928e+00 }, + { -2.900408608411958e-09, 3.113526161214776e+00 }, + { -2.897992528137022e-09, 3.110820428940251e+00 }, + { -2.895467340081818e-09, 3.107987213444579e+00 }, + { -2.892833139317615e-09, 3.105026163964191e+00 }, + { -2.890090025020589e-09, 3.101936934956479e+00 }, + { -2.887238100468092e-09, 3.098719186130021e+00 }, + { -2.884277473032614e-09, 3.095372582472161e+00 }, + { -2.881208254180937e-09, 3.091896794282404e+00 }, + { -2.878030559466594e-09, 3.088291497198199e+00 }, + { -2.874744508528832e-09, 3.084556372228054e+00 }, + { -2.871350225084755e-09, 3.080691105776848e+00 }, + { -2.867847836928063e-09, 3.076695389678615e+00 }, + { -2.864237475921086e-09, 3.072568921221621e+00 }, + { -2.860519277991847e-09, 3.068311403179147e+00 }, + { -2.856693383129018e-09, 3.063922543837792e+00 }, + { -2.852759935374575e-09, 3.059402057023109e+00 }, + { -2.848719082821403e-09, 3.054749662130841e+00 }, + { -2.844570977604520e-09, 3.049965084150782e+00 }, + { -2.840315775898525e-09, 3.045048053697736e+00 }, + { -2.835953637908582e-09, 3.039998307034967e+00 }, + { -2.831484727867511e-09, 3.034815586104635e+00 }, + { -2.826909214026628e-09, 3.029499638550941e+00 }, + { -2.822227268651470e-09, 3.024050217748861e+00 }, + { -2.817439068015245e-09, 3.018467082830179e+00 }, + { -2.812544792390175e-09, 3.012749998707001e+00 }, + { -2.807544626043751e-09, 3.006898736100911e+00 }, + { -2.802438757228650e-09, 3.000913071564665e+00 }, + { -2.797227378178760e-09, 2.994792787510961e+00 }, + { -2.791910685098702e-09, 2.988537672233504e+00 }, + { -2.786488878159805e-09, 2.982147519935565e+00 }, + { -2.780962161489413e-09, 2.975622130750641e+00 }, + { -2.775330743165298e-09, 2.968961310769028e+00 }, + { -2.769594835207775e-09, 2.962164872061613e+00 }, + { -2.763754653569747e-09, 2.955232632701135e+00 }, + { -2.757810418131543e-09, 2.948164416789036e+00 }, + { -2.751762352689432e-09, 2.940960054474719e+00 }, + { -2.745610684950541e-09, 2.933619381982341e+00 }, + { -2.739355646520809e-09, 2.926142241629213e+00 }, + { -2.732997472899722e-09, 2.918528481852205e+00 }, + { -2.726536403468318e-09, 2.910777957226018e+00 }, + { -2.719972681482232e-09, 2.902890528487386e+00 }, + { -2.713306554062453e-09, 2.894866062556452e+00 }, + { -2.706538272184154e-09, 2.886704432555728e+00 }, + { -2.699668090670078e-09, 2.878405517834426e+00 }, + { -2.692696268177908e-09, 2.869969203985464e+00 }, + { -2.685623067193599e-09, 2.861395382869544e+00 }, + { -2.678448754018380e-09, 2.852683952631486e+00 }, + { -2.671173598761847e-09, 2.843834817723832e+00 }, + { -2.663797875328991e-09, 2.834847888922988e+00 }, + { -2.656321861411517e-09, 2.825723083350459e+00 }, + { -2.648745838477759e-09, 2.816460324492298e+00 }, + { -2.641070091759922e-09, 2.807059542215146e+00 }, + { -2.633294910246296e-09, 2.797520672788269e+00 }, + { -2.625420586667340e-09, 2.787843658897949e+00 }, + { -2.617447417487602e-09, 2.778028449668942e+00 }, + { -2.609375702891616e-09, 2.768075000678399e+00 }, + { -2.601205746775692e-09, 2.757983273976943e+00 }, + { -2.592937856733464e-09, 2.747753238101915e+00 }, + { -2.584572344046340e-09, 2.737384868096553e+00 }, + { -2.576109523671634e-09, 2.726878145526201e+00 }, + { -2.567549714229129e-09, 2.716233058492422e+00 }, + { -2.558893237991435e-09, 2.705449601651722e+00 }, + { -2.550140420869302e-09, 2.694527776227857e+00 }, + { -2.541291592402089e-09, 2.683467590030445e+00 }, + { -2.532347085742440e-09, 2.672269057466213e+00 }, + { -2.523307237646751e-09, 2.660932199557362e+00 }, + { -2.514172388459584e-09, 2.649457043952206e+00 }, + { -2.504942882102813e-09, 2.637843624941622e+00 }, + { -2.495619066062810e-09, 2.626091983472908e+00 }, + { -2.486201291375123e-09, 2.614202167160335e+00 }, + { -2.476689912614465e-09, 2.602174230302269e+00 }, + { -2.467085287878098e-09, 2.590008233889805e+00 }, + { -2.457387778775451e-09, 2.577704245623143e+00 }, + { -2.447597750411553e-09, 2.565262339920002e+00 }, + { -2.437715571376127e-09, 2.552682597931055e+00 }, + { -2.427741613727123e-09, 2.539965107548168e+00 }, + { -2.417676252978335e-09, 2.527109963417675e+00 }, + { -2.407519868085581e-09, 2.514117266951687e+00 }, + { -2.397272841430131e-09, 2.500987126335739e+00 }, + { -2.386935558807595e-09, 2.487719656543254e+00 }, + { -2.376508409410024e-09, 2.474314979341178e+00 }, + { -2.365991785814531e-09, 2.460773223303822e+00 }, + { -2.355386083965131e-09, 2.447094523817833e+00 }, + { -2.344691703161363e-09, 2.433279023095734e+00 }, + { -2.333909046040126e-09, 2.419326870180582e+00 }, + { -2.323038518562289e-09, 2.405238220956597e+00 }, + { -2.312080529997549e-09, 2.391013238157397e+00 }, + { -2.301035492907384e-09, 2.376652091371587e+00 }, + { -2.289903823131822e-09, 2.362154957053137e+00 }, + { -2.278685939771276e-09, 2.347522018525197e+00 }, + { -2.267382265173420e-09, 2.332753465990296e+00 }, + { -2.255993224914501e-09, 2.317849496533128e+00 }, + { -2.244519247786155e-09, 2.302810314130351e+00 }, + { -2.232960765776561e-09, 2.287636129652823e+00 }, + { -2.221318214056095e-09, 2.272327160873552e+00 }, + { -2.209592030960763e-09, 2.256883632472565e+00 }, + { -2.197782657974034e-09, 2.241305776039511e+00 }, + { -2.185890539712767e-09, 2.225593830081461e+00 }, + { -2.173916123907886e-09, 2.209748040023618e+00 }, + { -2.161859861389976e-09, 2.193768658216360e+00 }, + { -2.149722206070124e-09, 2.177655943935795e+00 }, + { -2.137503614923981e-09, 2.161410163388424e+00 }, + { -2.125204547975352e-09, 2.145031589714984e+00 }, + { -2.112825468276292e-09, 2.128520502989477e+00 }, + { -2.100366841892917e-09, 2.111877190225612e+00 }, + { -2.087829137884807e-09, 2.095101945374541e+00 }, + { -2.075212828290086e-09, 2.078195069329960e+00 }, + { -2.062518388104923e-09, 2.061156869925600e+00 }, + { -2.049746295268559e-09, 2.043987661939897e+00 }, + { -2.036897030642658e-09, 2.026687767092888e+00 }, + { -2.023971077994576e-09, 2.009257514048162e+00 }, + { -2.010968923979840e-09, 1.991697238413571e+00 }, + { -1.997891058121344e-09, 1.974007282737320e+00 }, + { -1.984737972794098e-09, 1.956187996511354e+00 }, + { -1.971510163203686e-09, 1.938239736166060e+00 }, + { -1.958208127370276e-09, 1.920162865072273e+00 }, + { -1.944832366107339e-09, 1.901957753535934e+00 }, + { -1.931383383005451e-09, 1.883624778799427e+00 }, + { -1.917861684410531e-09, 1.865164325035177e+00 }, + { -1.904267779407432e-09, 1.846576783346324e+00 }, + { -1.890602179798714e-09, 1.827862551760622e+00 }, + { -1.876865400086483e-09, 1.809022035228338e+00 }, + { -1.863057957452539e-09, 1.790055645617624e+00 }, + { -1.849180371740008e-09, 1.770963801711725e+00 }, + { -1.835233165431475e-09, 1.751746929201178e+00 }, + { -1.821216863631569e-09, 1.732405460681919e+00 }, + { -1.807131994045840e-09, 1.712939835648088e+00 }, + { -1.792979086962494e-09, 1.693350500488565e+00 }, + { -1.778758675229683e-09, 1.673637908477153e+00 }, + { -1.764471294238191e-09, 1.653802519770021e+00 }, + { -1.750117481899733e-09, 1.633844801396848e+00 }, + { -1.735697778626995e-09, 1.613765227254186e+00 }, + { -1.721212727314574e-09, 1.593564278099856e+00 }, + { -1.706662873315474e-09, 1.573242441540939e+00 }, + { -1.692048764423848e-09, 1.552800212030258e+00 }, + { -1.677370950852395e-09, 1.532238090855187e+00 }, + { -1.662629985213192e-09, 1.511556586131055e+00 }, + { -1.647826422494560e-09, 1.490756212788764e+00 }, + { -1.632960820042537e-09, 1.469837492568651e+00 }, + { -1.618033737538645e-09, 1.448800954008929e+00 }, + { -1.603045736978760e-09, 1.427647132435469e+00 }, + { -1.587997382653428e-09, 1.406376569953373e+00 }, + { -1.572889241124034e-09, 1.384989815432507e+00 }, + { -1.557721881203696e-09, 1.363487424499449e+00 }, + { -1.542495873934815e-09, 1.341869959524515e+00 }, + { -1.527211792568486e-09, 1.320137989611176e+00 }, + { -1.511870212541253e-09, 1.298292090581491e+00 }, + { -1.496471711454994e-09, 1.276332844965754e+00 }, + { -1.481016869054634e-09, 1.254260841988828e+00 }, + { -1.465506267206068e-09, 1.232076677556547e+00 }, + { -1.449940489875303e-09, 1.209780954243628e+00 }, + { -1.434320123104372e-09, 1.187374281276747e+00 }, + { -1.418645754991533e-09, 1.164857274523495e+00 }, + { -1.402917975667710e-09, 1.142230556475749e+00 }, + { -1.387137377275425e-09, 1.119494756236361e+00 }, + { -1.371304553944712e-09, 1.096650509501278e+00 }, + { -1.355420101772623e-09, 1.073698458546610e+00 }, + { -1.339484618799891e-09, 1.050639252211352e+00 }, + { -1.323498704988051e-09, 1.027473545880543e+00 }, + { -1.307462962198534e-09, 1.004202001471034e+00 }, + { -1.291377994167204e-09, 9.808252874104182e-01 }, + { -1.275244406484394e-09, 9.573440786237052e-01 }, + { -1.259062806570190e-09, 9.337590565128454e-01 }, + { -1.242833803653464e-09, 9.100709089414796e-01 }, + { -1.226558008746195e-09, 8.862803302125812e-01 }, + { -1.210236034623253e-09, 8.623880210538113e-01 }, + { -1.193868495797618e-09, 8.383946885959868e-01 }, + { -1.177456008497777e-09, 8.143010463544786e-01 }, + { -1.160999190645010e-09, 7.901078142102129e-01 }, + { -1.144498661828833e-09, 7.658157183877095e-01 }, + { -1.127955043284965e-09, 7.414254914366063e-01 }, + { -1.111368957870986e-09, 7.169378722095157e-01 }, + { -1.094741030044308e-09, 6.923536058430697e-01 }, + { -1.078071885836393e-09, 6.676734437331688e-01 }, + { -1.061362152831423e-09, 6.428981435165511e-01 }, + { -1.044612460141255e-09, 6.180284690466404e-01 }, + { -1.027823438382183e-09, 5.930651903718045e-01 }, + { -1.010995719652015e-09, 5.680090837138436e-01 }, + { -9.941299375042378e-10, 5.428609314418970e-01 }, + { -9.772267269262058e-10, 5.176215220520872e-01 }, + { -9.602867243141016e-10, 4.922916501421032e-01 }, + { -9.433105674499058e-10, 4.668721163885412e-01 }, + { -9.262988954758817e-10, 4.413637275202624e-01 }, + { -9.092523488719689e-10, 4.157672962958654e-01 }, + { -8.921715694311144e-10, 3.900836414778084e-01 }, + { -8.750572002347607e-10, 3.643135878065193e-01 }, + { -8.579098856296589e-10, 3.384579659762392e-01 }, + { -8.407302712022458e-10, 3.125176126069478e-01 }, + { -8.235190037551917e-10, 2.864933702193017e-01 }, + { -8.062767312831008e-10, 2.603860872080448e-01 }, + { -7.890041029479477e-10, 2.341966178147619e-01 }, + { -7.717017690542486e-10, 2.079258220999725e-01 }, + { -7.543703810250266e-10, 1.815745659161734e-01 }, + { -7.370105913774597e-10, 1.551437208801425e-01 }, + { -7.196230536974697e-10, 1.286341643433767e-01 }, + { -7.022084226165876e-10, 1.020467793657360e-01 }, + { -6.847673537853251e-10, 7.538245468350446e-02 }, + { -6.673005038502516e-10, 4.864208468284503e-02 }, + { -6.498085304282128e-10, 2.182656936863137e-02 }, + { -6.322920920826137e-10, -5.063185663820913e-03 }, + { -6.147518482969490e-10, -3.202626926150343e-02 }, + { -5.971884594516681e-10, -5.906176474160862e-02 }, + { -5.796025867984469e-10, -8.616874992366363e-02 }, + { -5.619948924353588e-10, -1.133462971605448e-01 }, + { -5.443660392823640e-10, -1.405934733692621e-01 }, + { -5.267166910556339e-10, -1.679093400638023e-01 }, + { -5.090475122431451e-10, -1.952929533862739e-01 }, + { -4.913591680795342e-10, -2.227433641394564e-01 }, + { -4.736523245210571e-10, -2.502596178194491e-01 }, + { -4.559276482202303e-10, -2.778407546490776e-01 }, + { -4.381858065011618e-10, -3.054858096104932e-01 }, + { -4.204274673340870e-10, -3.331938124792702e-01 }, + { -4.026532993105397e-10, -3.609637878577768e-01 }, + { -3.848639716178888e-10, -3.887947552098022e-01 }, + { -3.670601540142443e-10, -4.166857288948674e-01 }, + { -3.492425168032583e-10, -4.446357182029681e-01 }, + { -3.314117308088734e-10, -4.726437273896633e-01 }, + { -3.135684673501752e-10, -5.007087557112619e-01 }, + { -2.957133982159296e-10, -5.288297974607742e-01 }, + { -2.778471956393828e-10, -5.570058420037128e-01 }, + { -2.599705322729564e-10, -5.852358738143247e-01 }, + { -2.420840811628366e-10, -6.135188725122560e-01 }, + { -2.241885157240923e-10, -6.418538128986450e-01 }, + { -2.062845097142585e-10, -6.702396649949099e-01 }, + { -1.883727372093546e-10, -6.986753940779493e-01 }, + { -1.704538725773087e-10, -7.271599607197149e-01 }, + { -1.525285904532877e-10, -7.556923208240308e-01 }, + { -1.345975657140748e-10, -7.842714256651911e-01 }, + { -1.166614734526054e-10, -8.128962219265712e-01 }, + { -9.872098895260891e-11, -8.415656517393372e-01 }, + { -8.077678766314517e-11, -8.702786527215916e-01 }, + { -6.282954517324612e-11, -8.990341580176152e-01 }, + { -4.487993718655790e-11, -9.278310963373758e-01 }, + { -2.692863949561210e-11, -9.566683919968972e-01 }, + { -8.976327956520795e-12, -9.855449649582175e-01 }, + { 8.976321536169872e-12, -1.014459730869357e+00 }, + { 2.692863307547294e-11, -1.043411601105914e+00 }, + { 4.487993076694813e-11, -1.072399482811314e+00 }, + { 6.282953875437751e-11, -1.101422278938424e+00 }, + { 8.077678124517653e-11, -1.130478888291020e+00 }, + { 9.872098253591082e-11, -1.159568205565684e+00 }, + { 1.166614670373367e-10, -1.188689121393192e+00 }, + { 1.345975593005002e-10, -1.217840522381901e+00 }, + { 1.525285840416718e-10, -1.247021291159495e+00 }, + { 1.704538661678104e-10, -1.276230306415868e+00 }, + { 1.883727308022916e-10, -1.305466442946703e+00 }, + { 2.062845033098954e-10, -1.334728571696106e+00 }, + { 2.241885093225349e-10, -1.364015559800721e+00 }, + { 2.420840747645085e-10, -1.393326270633325e+00 }, + { 2.599705258779635e-10, -1.422659563847049e+00 }, + { 2.778471892479898e-10, -1.452014295419243e+00 }, + { 2.957133918284542e-10, -1.481389317696831e+00 }, + { 3.135684609667761e-10, -1.510783479440191e+00 }, + { 3.314117244297624e-10, -1.540195625869043e+00 }, + { 3.492425104288060e-10, -1.569624598707558e+00 }, + { 3.670601476445565e-10, -1.599069236228850e+00 }, + { 3.848639652533361e-10, -1.628528373302631e+00 }, + { 4.026532929512281e-10, -1.658000841439269e+00 }, + { 4.204274609803869e-10, -1.687485468837799e+00 }, + { 4.381858001531792e-10, -1.716981080430596e+00 }, + { 4.559276418782829e-10, -1.746486497931567e+00 }, + { 4.736523181853565e-10, -1.776000539882225e+00 }, + { 4.913591617503452e-10, -1.805522021699094e+00 }, + { 5.090475059206794e-10, -1.835049755721194e+00 }, + { 5.267166847401562e-10, -1.864582551257262e+00 }, + { 5.443660329740862e-10, -1.894119214633676e+00 }, + { 5.619948861345454e-10, -1.923658549242818e+00 }, + { 5.796025805053097e-10, -1.953199355591180e+00 }, + { 5.971884531664190e-10, -1.982740431347091e+00 }, + { 6.147518420199055e-10, -2.012280571390674e+00 }, + { 6.322920858139346e-10, -2.041818567861395e+00 }, + { 6.498085241682158e-10, -2.071353210208005e+00 }, + { 6.673004975990425e-10, -2.100883285238127e+00 }, + { 6.847673475432746e-10, -2.130407577166309e+00 }, + { 7.022084163838545e-10, -2.159924867664933e+00 }, + { 7.196230474743716e-10, -2.189433935913779e+00 }, + { 7.370105851640495e-10, -2.218933558650552e+00 }, + { 7.543703748217808e-10, -2.248422510220072e+00 }, + { 7.717017628611672e-10, -2.277899562625407e+00 }, + { 7.890040967654542e-10, -2.307363485579104e+00 }, + { 8.062767251113011e-10, -2.336813046552684e+00 }, + { 8.235189975944034e-10, -2.366247010829556e+00 }, + { 8.407302650525749e-10, -2.395664141553858e+00 }, + { 8.579098794915287e-10, -2.425063199784153e+00 }, + { 8.750571941082773e-10, -2.454442944543319e+00 }, + { 8.921715633164894e-10, -2.483802132872044e+00 }, + { 9.092523427695200e-10, -2.513139519878584e+00 }, + { 9.262988893857148e-10, -2.542453858792682e+00 }, + { 9.433105613723914e-10, -2.571743901017465e+00 }, + { 9.602867182493987e-10, -2.601008396180870e+00 }, + { 9.772267208744730e-10, -2.630246092190425e+00 }, + { 9.941299314658458e-10, -2.659455735283526e+00 }, + { 1.010995713627070e-09, -2.688636070081818e+00 }, + { 1.027823432371055e-09, -2.717785839644439e+00 }, + { 1.044612454143997e-09, -2.746903785521352e+00 }, + { 1.061362146848353e-09, -2.775988647805256e+00 }, + { 1.078071879867828e-09, -2.805039165187255e+00 }, + { 1.094741024090249e-09, -2.834054075009077e+00 }, + { 1.111368951931856e-09, -2.863032113318052e+00 }, + { 1.127955037360817e-09, -2.891972014920939e+00 }, + { 1.144498655920037e-09, -2.920872513436805e+00 }, + { 1.160999184751779e-09, -2.949732341353290e+00 }, + { 1.177456002620215e-09, -2.978550230079517e+00 }, + { 1.193868489936097e-09, -3.007324910002949e+00 }, + { 1.210236028777826e-09, -3.036055110540183e+00 }, + { 1.226558002917232e-09, -3.064739560196251e+00 }, + { 1.242833797841123e-09, -3.093376986616735e+00 }, + { 1.259062800774685e-09, -3.121966116643377e+00 }, + { 1.275244400705935e-09, -3.150505676371791e+00 }, + { 1.291377988406056e-09, -3.178994391202159e+00 }, + { 1.307462956454857e-09, -3.207430985899192e+00 }, + { 1.323498699262108e-09, -3.235814184645077e+00 }, + { 1.339484613091842e-09, -3.264142711097884e+00 }, + { 1.355420096082785e-09, -3.292415288443373e+00 }, + { 1.371304548273191e-09, -3.320630639454825e+00 }, + { 1.387137371622433e-09, -3.348787486547389e+00 }, + { 1.402917970033511e-09, -3.376884551834256e+00 }, + { 1.418645749376393e-09, -3.404920557184582e+00 }, + { 1.434320117508396e-09, -3.432894224276359e+00 }, + { 1.449940484298756e-09, -3.460804274656981e+00 }, + { 1.465506261649108e-09, -3.488649429796768e+00 }, + { 1.481016863517580e-09, -3.516428411149154e+00 }, + { 1.496471705937951e-09, -3.544139940202303e+00 }, + { 1.511870207044433e-09, -3.571782738540999e+00 }, + { 1.527211787092206e-09, -3.599355527901174e+00 }, + { 1.542495868479076e-09, -3.626857030226671e+00 }, + { 1.557721875768920e-09, -3.654285967729458e+00 }, + { 1.572889235710329e-09, -3.681641062941412e+00 }, + { 1.587997377261005e-09, -3.708921038776707e+00 }, + { 1.603045731607830e-09, -3.736124618586623e+00 }, + { 1.618033732189314e-09, -3.763250526218862e+00 }, + { 1.632960814715177e-09, -3.790297486071938e+00 }, + { 1.647826417189275e-09, -3.817264223155802e+00 }, + { 1.662629979930247e-09, -3.844149463148589e+00 }, + { 1.677370945591844e-09, -3.870951932452996e+00 }, + { 1.692048759186008e-09, -3.897670358257890e+00 }, + { 1.706662868100504e-09, -3.924303468590212e+00 }, + { 1.721212722122685e-09, -3.950849992378278e+00 }, + { 1.735697773458400e-09, -3.977308659506432e+00 }, + { 1.750117476754591e-09, -4.003678200876669e+00 }, + { 1.764471289116712e-09, -4.029957348461003e+00 }, + { 1.778758670132079e-09, -4.056144835364877e+00 }, + { 1.792979081888926e-09, -4.082239395882965e+00 }, + { 1.807131988996465e-09, -4.108239765556996e+00 }, + { 1.821216858606652e-09, -4.134144681236933e+00 }, + { 1.835233160431175e-09, -4.159952881133585e+00 }, + { 1.849180366764537e-09, -4.185663104882633e+00 }, + { 1.863057952502055e-09, -4.211274093599509e+00 }, + { 1.876865395161145e-09, -4.236784589940537e+00 }, + { 1.890602174898734e-09, -4.262193338157148e+00 }, + { 1.904267774533022e-09, -4.287499084158302e+00 }, + { 1.917861679562008e-09, -4.312700575567174e+00 }, + { 1.931383378182392e-09, -4.337796561778708e+00 }, + { 1.944832361310856e-09, -4.362785794021793e+00 }, + { 1.958208122599839e-09, -4.387667025411434e+00 }, + { 1.971510158459931e-09, -4.412439011013396e+00 }, + { 1.984737968076495e-09, -4.437100507898339e+00 }, + { 1.997891053431005e-09, -4.461650275204912e+00 }, + { 2.010968919316289e-09, -4.486087074191693e+00 }, + { 2.023971073358447e-09, -4.510409668301784e+00 }, + { 2.036897026033634e-09, -4.534616823217992e+00 }, + { 2.049746290686799e-09, -4.558707306921882e+00 }, + { 2.062518383551274e-09, -4.582679889754607e+00 }, + { 2.075212823764071e-09, -4.606533344469879e+00 }, + { 2.087829133387063e-09, -4.630266446298172e+00 }, + { 2.100366837422912e-09, -4.653877973001258e+00 }, + { 2.112825463835087e-09, -4.677366704934605e+00 }, + { 2.125204543562522e-09, -4.700731425099899e+00 }, + { 2.137503610540056e-09, -4.723970919208608e+00 }, + { 2.149722201714786e-09, -4.747083975738060e+00 }, + { 2.161859857063438e-09, -4.770069385989595e+00 }, + { 2.173916119610994e-09, -4.792925944149308e+00 }, + { 2.185890535445098e-09, -4.815652447340950e+00 }, + { 2.197782653735957e-09, -4.838247695689436e+00 }, + { 2.209592026751962e-09, -4.860710492376411e+00 }, + { 2.221318209877576e-09, -4.883039643700314e+00 }, + { 2.232960761627846e-09, -4.905233959130168e+00 }, + { 2.244519243667616e-09, -4.927292251368517e+00 }, + { 2.255993220826402e-09, -4.949213336406265e+00 }, + { 2.267382261115285e-09, -4.970996033581527e+00 }, + { 2.278685935744269e-09, -4.992639165639563e+00 }, + { 2.289903819135414e-09, -5.014141558784778e+00 }, + { 2.301035488942000e-09, -5.035502042744443e+00 }, + { 2.312080526062763e-09, -5.056719450823151e+00 }, + { 2.323038514659161e-09, -5.077792619963239e+00 }, + { 2.333909042168180e-09, -5.098720390796817e+00 }, + { 2.344691699320969e-09, -5.119501607709159e+00 }, + { 2.355386080156553e-09, -5.140135118892792e+00 }, + { 2.365991782037187e-09, -5.160619776404897e+00 }, + { 2.376508405665132e-09, -5.180954436227641e+00 }, + { 2.386935555094626e-09, -5.201137958319343e+00 }, + { 2.397272837749508e-09, -5.221169206676762e+00 }, + { 2.407519864436774e-09, -5.241047049389645e+00 }, + { 2.417676249362563e-09, -5.260770358700167e+00 }, + { 2.427741610143750e-09, -5.280338011053974e+00 }, + { 2.437715567825576e-09, -5.299748887163106e+00 }, + { 2.447597746894037e-09, -5.319001872058887e+00 }, + { 2.457387775290440e-09, -5.338095855149190e+00 }, + { 2.467085284426756e-09, -5.357029730277389e+00 }, + { 2.476689909196263e-09, -5.375802395772283e+00 }, + { 2.486201287990485e-09, -5.394412754510426e+00 }, + { 2.495619062711154e-09, -5.412859713968929e+00 }, + { 2.504942878785408e-09, -5.431142186284682e+00 }, + { 2.514172385175743e-09, -5.449259088303476e+00 }, + { 2.523307234396791e-09, -5.467209341642627e+00 }, + { 2.532347082526785e-09, -5.484991872743321e+00 }, + { 2.541291589219998e-09, -5.502605612925014e+00 }, + { 2.550140417722072e-09, -5.520049498445633e+00 }, + { 2.558893234878378e-09, -5.537322470548212e+00 }, + { 2.567549711150773e-09, -5.554423475524196e+00 }, + { 2.576109520627371e-09, -5.571351464763084e+00 }, + { 2.584572341037361e-09, -5.588105394812198e+00 }, + { 2.592937853759161e-09, -5.604684227423386e+00 }, + { 2.601205743836355e-09, -5.621086929615246e+00 }, + { 2.609375699987564e-09, -5.637312473723475e+00 }, + { 2.617447414618146e-09, -5.653359837454964e+00 }, + { 2.625420583833750e-09, -5.669228003945694e+00 }, + { 2.633294907447937e-09, -5.684915961806963e+00 }, + { 2.641070088997271e-09, -5.700422705186584e+00 }, + { 2.648745835750128e-09, -5.715747233817712e+00 }, + { 2.656321858720176e-09, -5.730888553077074e+00 }, + { 2.663797872673252e-09, -5.745845674030161e+00 }, + { 2.671173596142054e-09, -5.760617613492118e+00 }, + { 2.678448751434797e-09, -5.775203394076705e+00 }, + { 2.685623064645538e-09, -5.789602044248679e+00 }, + { 2.692696265666640e-09, -5.803812598380606e+00 }, + { 2.699668088194915e-09, -5.817834096797069e+00 }, + { 2.706538269745573e-09, -5.831665585834668e+00 }, + { 2.713306551659817e-09, -5.845306117889361e+00 }, + { 2.719972679116734e-09, -5.858754751472542e+00 }, + { 2.726536401139295e-09, -5.872010551255358e+00 }, + { 2.732997470607439e-09, -5.885072588127400e+00 }, + { 2.739355644265558e-09, -5.897939939244211e+00 }, + { 2.745610682731633e-09, -5.910611688078208e+00 }, + { 2.751762350508137e-09, -5.923086924473290e+00 }, + { 2.757810415987146e-09, -5.935364744687794e+00 }, + { 2.763754651462700e-09, -5.947444251452243e+00 }, + { 2.769594833137415e-09, -5.959324554015538e+00 }, + { 2.775330741132843e-09, -5.971004768198829e+00 }, + { 2.780962159494174e-09, -5.982484016437981e+00 }, + { 2.786488876202047e-09, -5.993761427840588e+00 }, + { 2.791910683178690e-09, -6.004836138231525e+00 }, + { 2.797227376295779e-09, -6.015707290202086e+00 }, + { 2.802438755383971e-09, -6.026374033162623e+00 }, + { 2.807544624236659e-09, -6.036835523383457e+00 }, + { 2.812544790621093e-09, -6.047090924050914e+00 }, + { 2.817439066283459e-09, -6.057139405311101e+00 }, + { 2.822227266958278e-09, -6.066980144322601e+00 }, + { 2.826909212371261e-09, -6.076612325295799e+00 }, + { 2.831484726250221e-09, -6.086035139548830e+00 }, + { 2.835953636329660e-09, -6.095247785550617e+00 }, + { 2.840315774357203e-09, -6.104249468967751e+00 }, + { 2.844570976102082e-09, -6.113039402715685e+00 }, + { 2.848719081357095e-09, -6.121616806996519e+00 }, + { 2.852759933948860e-09, -6.129980909353977e+00 }, + { 2.856693381741114e-09, -6.138130944714082e+00 }, + { 2.860519276643053e-09, -6.146066155436312e+00 }, + { 2.864237474610633e-09, -6.153785791350256e+00 }, + { 2.867847835656203e-09, -6.161289109809551e+00 }, + { 2.871350223851726e-09, -6.168575375732642e+00 }, + { 2.874744507333867e-09, -6.175643861647406e+00 }, + { 2.878030558310989e-09, -6.182493847739853e+00 }, + { 2.881208253063899e-09, -6.189124621889823e+00 }, + { 2.884277471954592e-09, -6.195535479723423e+00 }, + { 2.887238099428306e-09, -6.201725724651554e+00 }, + { 2.890090024020323e-09, -6.207694667918394e+00 }, + { 2.892833138356060e-09, -6.213441628635915e+00 }, + { 2.895467339159240e-09, -6.218965933835304e+00 }, + { 2.897992527253659e-09, -6.224266918505075e+00 }, + { 2.900408607567016e-09, -6.229343925633495e+00 }, + { 2.902715489136496e-09, -6.234196306254763e+00 }, + { 2.904913085108075e-09, -6.238823419482017e+00 }, + { 2.907001312743911e-09, -6.243224632557377e+00 }, + { 2.908980093422997e-09, -6.247399320887848e+00 }, + { 2.910849352646620e-09, -6.251346868091392e+00 }, + { 2.912609020036956e-09, -6.255066666028537e+00 }, + { 2.914259029343965e-09, -6.258558114851525e+00 }, + { 2.915799318445710e-09, -6.261820623039620e+00 }, + { 2.917229829350759e-09, -6.264853607438842e+00 }, + { 2.918550508202463e-09, -6.267656493305673e+00 }, + { 2.919761305276718e-09, -6.270228714337005e+00 }, + { 2.920862174988150e-09, -6.272569712717951e+00 }, + { 2.921853075889193e-09, -6.274678939154603e+00 }, + { 2.922733970674264e-09, -6.276555852917634e+00 }, + { 2.923504826176907e-09, -6.278199921870962e+00 }, + { 2.924165613375264e-09, -6.279610622518139e+00 }, + { 2.924716307391075e-09, -6.280787440034993e+00 }, + { 2.925156887490598e-09, -6.281729868306345e+00 }, + { 2.925487337087508e-09, -6.282437409966992e+00 }, + { 2.925707643739298e-09, -6.282909576428774e+00 }, + { 2.925817799151970e-09, -6.283145887925411e+00 }, diff --git a/gnuradio-runtime/lib/test_runtime.cc b/gnuradio-runtime/lib/test_runtime.cc new file mode 100644 index 0000000000..bd5378332e --- /dev/null +++ b/gnuradio-runtime/lib/test_runtime.cc @@ -0,0 +1,42 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2010,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. + */ + +#include <cppunit/TextTestRunner.h> +#include <cppunit/XmlOutputter.h> + +#include <gr_unittests.h> +#include <qa_runtime.h> + +int +main (int argc, char **argv) +{ + CppUnit::TextTestRunner runner; + std::ofstream xmlfile(get_unittest_path("gnuradio_core_runtime.xml").c_str()); + CppUnit::XmlOutputter *xmlout = new CppUnit::XmlOutputter(&runner.result(), xmlfile); + + runner.addTest (qa_runtime::suite ()); + runner.setOutputter(xmlout); + + bool was_successful = runner.run ("", false); + + return was_successful ? 0 : 1; +} |