diff --git a/src/svxlink/siglevdetcal/siglevdetcal.cpp b/src/svxlink/siglevdetcal/siglevdetcal.cpp index 0a9ceef02..5327fc8ff 100644 --- a/src/svxlink/siglevdetcal/siglevdetcal.cpp +++ b/src/svxlink/siglevdetcal/siglevdetcal.cpp @@ -290,7 +290,7 @@ int main(int argc, char **argv) cfg.setValue(rx_name, "CTCSS_OPEN_THRESH", "100"); // Make sure we are using the "Noise" siglev detector - cfg.setValue(rx_name, "SIGLEV_DET", "NOISE"); + //cfg.setValue(rx_name, "SIGLEV_DET", "NOISE"); // Read the configured siglev slope and offset, then clear them so that // they cannot affect the measurement. diff --git a/src/svxlink/trx/CMakeLists.txt b/src/svxlink/trx/CMakeLists.txt index 12498c417..04035265c 100644 --- a/src/svxlink/trx/CMakeLists.txt +++ b/src/svxlink/trx/CMakeLists.txt @@ -15,7 +15,7 @@ set(LIBSRC SquelchEvDev.cpp Macho.cpp SquelchGpio.cpp Ptt.cpp PttGpio.cpp PttSerialPin.cpp Pty.cpp PttPty.cpp PtyDtmfDecoder.cpp LocalRxBase.cpp Ddr.cpp RtlTcp.cpp WbRxRtlTcp.cpp - SigLevDet.cpp + SigLevDet.cpp SigLevDetDdr.cpp ) # Which other libraries this library depends on diff --git a/src/svxlink/trx/Ddr.cpp b/src/svxlink/trx/Ddr.cpp index 8d89023e4..60eec2edb 100644 --- a/src/svxlink/trx/Ddr.cpp +++ b/src/svxlink/trx/Ddr.cpp @@ -429,6 +429,7 @@ namespace { iq_dec1.decimate(dec_samp1, samples); iq_dec2.decimate(dec_samp2, dec_samp1); ch_filt.decimate(ch_samp, dec_samp2); + preDemod(ch_samp); //dec_samp = samples; #if 0 outfile.write(reinterpret_cast(&ch_samp[0]), @@ -493,6 +494,8 @@ namespace { */ } + sigc::signal&> preDemod; + private: float iold; float qold; @@ -572,12 +575,13 @@ namespace { }; /* anonymous namespace */ -class Ddr::Channel +class Ddr::Channel : public sigc::trackable { public: Channel(AudioSink &audio_sink, int fq_offset) : fm_demod(audio_sink), trans(960000, fq_offset) { + fm_demod.preDemod.connect(preDemod.make_slot()); } void iq_received(vector samples) @@ -587,6 +591,8 @@ class Ddr::Channel fm_demod.iq_received(translated); }; + sigc::signal&> preDemod; + private: FmDemod fm_demod; Translate trans; @@ -615,6 +621,7 @@ class Ddr::Channel * ****************************************************************************/ +Ddr::DdrMap Ddr::ddr_map; /**************************************************************************** @@ -623,6 +630,17 @@ class Ddr::Channel * ****************************************************************************/ +Ddr *Ddr::find(const std::string &name) +{ + DdrMap::iterator it = ddr_map.find(name); + if (it != ddr_map.end()) + { + return (*it).second; + } + return 0; +} /* Ddr::find */ + + Ddr::Ddr(Config &cfg, const std::string& name) : LocalRxBase(cfg, name), cfg(cfg), audio_pipe(0), channel(0), rtl(0) { @@ -631,6 +649,12 @@ Ddr::Ddr(Config &cfg, const std::string& name) Ddr::~Ddr(void) { + DdrMap::iterator it = ddr_map.find(name()); + if (it != ddr_map.end()) + { + ddr_map.erase(it); + } + delete channel; delete rtl; delete audio_pipe; @@ -639,6 +663,16 @@ Ddr::~Ddr(void) bool Ddr::initialize(void) { + DdrMap::iterator it = ddr_map.find(name()); + if (it != ddr_map.end()) + { + cout << "*** ERROR: The name for a Digital Drop Receiver (DDR) must be " + << "unique. There already is a receiver named \"" << name() + << "\".\n"; + return false; + } + ddr_map[name()] = this; + double fq = 0.0; if (!cfg.getValue(name(), "FQ", fq)) { @@ -665,6 +699,7 @@ bool Ddr::initialize(void) } channel = new Channel(*audio_pipe, fq-rtl->centerFq()); + channel->preDemod.connect(preDemod.make_slot()); rtl->iqReceived.connect(mem_fun(*channel, &Channel::iq_received)); if (!LocalRxBase::initialize()) diff --git a/src/svxlink/trx/Ddr.h b/src/svxlink/trx/Ddr.h index c209b0a46..75e30d0c7 100644 --- a/src/svxlink/trx/Ddr.h +++ b/src/svxlink/trx/Ddr.h @@ -54,6 +54,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ****************************************************************************/ #include "LocalRxBase.h" +#include "RtlTcp.h" /**************************************************************************** @@ -122,6 +123,8 @@ extracted from this wideband signal and a demodulator is applied. class Ddr : public LocalRxBase { public: + static Ddr *find(const std::string &name); + /** * @brief Default constuctor */ @@ -137,6 +140,8 @@ class Ddr : public LocalRxBase * @return Return \em true on success, or \em false on failure */ virtual bool initialize(void); + + sigc::signal&> preDemod; protected: /** @@ -180,6 +185,9 @@ class Ddr : public LocalRxBase private: class Channel; + typedef std::map DdrMap; + + static DdrMap ddr_map; Async::Config &cfg; Async::AudioPassthrough *audio_pipe; diff --git a/src/svxlink/trx/SigLevDet.cpp b/src/svxlink/trx/SigLevDet.cpp index 5fd2931a5..aacb4a292 100644 --- a/src/svxlink/trx/SigLevDet.cpp +++ b/src/svxlink/trx/SigLevDet.cpp @@ -53,6 +53,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "SigLevDet.h" #include "SigLevDetNoise.h" #include "SigLevDetTone.h" +#include "SigLevDetDdr.h" @@ -141,6 +142,7 @@ SigLevDet *SigLevDetFactoryBase::createNamedSigLevDet(Config& cfg, SigLevDetNone::Factory none_siglev_factory; SigLevDetNoise::Factory noise_siglev_factory; SigLevDetTone::Factory tone_siglev_factory; + SigLevDetDdr::Factory ddr_siglev_factory; string det_name; if (!cfg.getValue(name, "SIGLEV_DET", det_name) || det_name.empty()) diff --git a/src/svxlink/trx/SigLevDetDdr.cpp b/src/svxlink/trx/SigLevDetDdr.cpp new file mode 100644 index 000000000..b316036ea --- /dev/null +++ b/src/svxlink/trx/SigLevDetDdr.cpp @@ -0,0 +1,252 @@ +/** +@file SigLevDetDdr.cpp +@brief A signal level detector measuring power levels using a DDR +@author Tobias Blomberg / SM0SVX +@date 2014-07-17 + +\verbatim +SvxLink - A Multi Purpose Voice Services System for Ham Radio Use +Copyright (C) 2003-2014 Tobias Blomberg / SM0SVX + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +\endverbatim +*/ + + + +/**************************************************************************** + * + * System Includes + * + ****************************************************************************/ + +#include +#include +#include + + +/**************************************************************************** + * + * Project Includes + * + ****************************************************************************/ + +#include + + +/**************************************************************************** + * + * Local Includes + * + ****************************************************************************/ + +#include "SigLevDetDdr.h" +#include "Ddr.h" + + + +/**************************************************************************** + * + * Namespaces to use + * + ****************************************************************************/ + +using namespace std; +using namespace Async; + + + +/**************************************************************************** + * + * Defines & typedefs + * + ****************************************************************************/ + + + +/**************************************************************************** + * + * Local class definitions + * + ****************************************************************************/ + + + +/**************************************************************************** + * + * Prototypes + * + ****************************************************************************/ + + + +/**************************************************************************** + * + * Exported Global Variables + * + ****************************************************************************/ + + + +/**************************************************************************** + * + * Local Global Variables + * + ****************************************************************************/ + + + +/**************************************************************************** + * + * Public member functions + * + ****************************************************************************/ + +SigLevDetDdr::SigLevDetDdr(void) + : sample_rate(0), block_idx(0), last_siglev(0), integration_time(1), + update_interval(0), update_counter(0), pwr_sum(0.0), slope(1.0), + offset(0.0) +{ +} /* SigLevDetDdr::SigLevDetDdr */ + + +SigLevDetDdr::~SigLevDetDdr(void) +{ +} /* SigLevDetDdr::~SigLevDetDdr */ + + +bool SigLevDetDdr::initialize(Config &cfg, const string& name, int sample_rate) +{ + Ddr *ddr = Ddr::find(name); + if (ddr == 0) + { + cout << "*** ERROR: Could not find a DDR named \"" << name << "\". " + << "Cannot use DDR signal level detector.\n"; + return false; + } + ddr->preDemod.connect(mem_fun(*this, &SigLevDetDdr::processSamples)); + + this->sample_rate = sample_rate; + + cfg.getValue(name, "SIGLEV_OFFSET", offset); + cfg.getValue(name, "SIGLEV_SLOPE", slope); + + reset(); + + return SigLevDet::initialize(cfg, name, sample_rate); + +} /* SigLevDetDdr::initialize */ + + +void SigLevDetDdr::reset(void) +{ + block_idx = 0; + last_siglev = 0; + update_counter = 0; + siglev_values.clear(); + pwr_sum = 0.0; +} /* SigLevDetDdr::reset */ + + +void SigLevDetDdr::setContinuousUpdateInterval(int interval_ms) +{ + update_interval = interval_ms * sample_rate / 1000; + update_counter = 0; +} /* SigLevDetDdr::setContinuousUpdateInterval */ + + +void SigLevDetDdr::setIntegrationTime(int time_ms) +{ + // Calculate the integration time expressed as the + // number of processing blocks. + integration_time = time_ms * 16000 / 1000 / BLOCK_SIZE; + if (integration_time <= 0) + { + integration_time = 1; + } +} /* SigLevDetDdr::setIntegrationTime */ + + +float SigLevDetDdr::siglevIntegrated(void) const +{ + if (siglev_values.size() > 0) + { + int sum = 0; + deque::const_iterator it; + for (it=siglev_values.begin(); it!=siglev_values.end(); ++it) + { + sum += *it; + } + return sum / siglev_values.size(); + } + return 0; +} /* SigLevDetDdr::siglevIntegrated */ + + + +/**************************************************************************** + * + * Protected member functions + * + ****************************************************************************/ + + + +/**************************************************************************** + * + * Private member functions + * + ****************************************************************************/ + +void SigLevDetDdr::processSamples(const vector &samples) +{ + for (vector::const_iterator it = samples.begin(); + it != samples.end(); + ++it) + { + double mag = abs(*it); + pwr_sum += mag * mag; + if (++block_idx == BLOCK_SIZE) + { + last_siglev = offset + slope * 10.0 * log10(pwr_sum / BLOCK_SIZE); + siglev_values.push_back(last_siglev); + if (siglev_values.size() > integration_time) + { + siglev_values.erase(siglev_values.begin(), + siglev_values.begin()+siglev_values.size()-integration_time); + } + + if (update_interval > 0) + { + update_counter += BLOCK_SIZE; + if (update_counter >= update_interval) + { + signalLevelUpdated(lastSiglev()); + update_counter = 0; + } + } + + block_idx = 0; + pwr_sum = 0.0; + } + } +} /* SigLevDetDdr::processSamples */ + + + +/* + * This file has not been truncated + */ + diff --git a/src/svxlink/trx/SigLevDetDdr.h b/src/svxlink/trx/SigLevDetDdr.h new file mode 100644 index 000000000..9b29f8fa7 --- /dev/null +++ b/src/svxlink/trx/SigLevDetDdr.h @@ -0,0 +1,216 @@ +/** +@file SigLevDetDdr.h +@brief A signal level detector measuring power levels using a DDR +@author Tobias Blomberg / SM0SVX +@date 2014-07-17 + +\verbatim +SvxLink - A Multi Purpose Voice Services System for Ham Radio Use +Copyright (C) 2003-2014 Tobias Blomberg / SM0SVX + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +\endverbatim +*/ + +#ifndef SIG_LEV_DET_DDR_INCLUDED +#define SIG_LEV_DET_DDR_INCLUDED + + +/**************************************************************************** + * + * System Includes + * + ****************************************************************************/ + +#include +#include + + +/**************************************************************************** + * + * Project Includes + * + ****************************************************************************/ + + + +/**************************************************************************** + * + * Local Includes + * + ****************************************************************************/ + +#include "SigLevDet.h" +#include "RtlTcp.h" + + +/**************************************************************************** + * + * Forward declarations + * + ****************************************************************************/ + +namespace Async +{ + class AudioFilter; +}; + + +/**************************************************************************** + * + * Namespace + * + ****************************************************************************/ + +//namespace MyNameSpace +//{ + + +/**************************************************************************** + * + * Forward declarations of classes inside of the declared namespace + * + ****************************************************************************/ + + + +/**************************************************************************** + * + * Defines & typedefs + * + ****************************************************************************/ + + + +/**************************************************************************** + * + * Exported Global Variables + * + ****************************************************************************/ + + + +/**************************************************************************** + * + * Class definitions + * + ****************************************************************************/ + +/** +@brief A signal level detector measuring power levels using a DDR +@author Tobias Blomberg / SM0SVX +@date 2014-07-17 + +*/ +class SigLevDetDdr : public SigLevDet +{ + public: + struct Factory : public SigLevDetFactory + { + Factory(void) : SigLevDetFactory("DDR") {} + }; + + /** + * @brief Constuctor + */ + explicit SigLevDetDdr(void); + + /** + * @brief Destructor + */ + ~SigLevDetDdr(void); + + /** + * @brief Initialize the signal detector + * @param cfg An initialized config object + * @param name The name of the config section to read config from + * @param sample_rate The rate with which samples enter the detector + * @return Return \em true on success, or \em false on failure + */ + virtual bool initialize(Async::Config &cfg, const std::string& name, + int sample_rate); + + /** + * @brief Set the interval for continuous updates + * @param interval_ms The update interval, in milliseconds, to use. + * + * This function will set up how often the signal level detector will + * report the signal strength. + */ + virtual void setContinuousUpdateInterval(int interval_ms); + + /** + * @brief Set the integration time to use + * @param time_ms The integration time in milliseconds + * + * This function will set up the integration time for the signal level + * detector. That is, the detector will build a mean value of the + * detected signal strengths over the given integration time. + */ + virtual void setIntegrationTime(int time_ms); + + /** + * @brief Read the latest measured signal level + * @return Returns the latest measured signal level + */ + virtual float lastSiglev(void) const { return last_siglev; } + + /** + * @brief Read the integrated siglev value + * @return Returns the integrated siglev value + */ + virtual float siglevIntegrated(void) const; + + /** + * @brief Reset the signal level detector + */ + virtual void reset(void); + + protected: + virtual int writeSamples(const float *samples, int count) { return count; } + virtual void flushSamples(void) {} + + + private: + static const unsigned BLOCK_SIZE = 480; // 10ms @ 48kHz + + int sample_rate; + unsigned block_idx; + int last_siglev; + unsigned integration_time; + std::deque siglev_values; + int update_interval; + int update_counter; + double pwr_sum; + double slope; + double offset; + + SigLevDetDdr(const SigLevDetDdr&); + SigLevDetDdr& operator=(const SigLevDetDdr&); + void processSamples(const std::vector &samples); + +}; /* class SigLevDetDdr */ + + +//} /* namespace */ + +#endif /* SIG_LEV_DET_DDR_INCLUDED */ + + + +/* + * This file has not been truncated + */ +