mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-11-03 13:11:20 -05:00 
			
		
		
		
	New scope: interim state (1)
This commit is contained in:
		
							parent
							
								
									6d4c000107
								
							
						
					
					
						commit
						f0f7838765
					
				@ -127,7 +127,9 @@ set(sdrbase_SOURCES
 | 
			
		||||
    sdrbase/dsp/basebandsamplesource.cpp
 | 
			
		||||
    sdrbase/dsp/nullsink.cpp
 | 
			
		||||
    sdrbase/dsp/spectrumscopecombovis.cpp
 | 
			
		||||
    sdrbase/dsp/spectrumscopengcombovis.cpp
 | 
			
		||||
    sdrbase/dsp/scopevis.cpp
 | 
			
		||||
    sdrbase/dsp/scopevisng.cpp
 | 
			
		||||
    sdrbase/dsp/spectrumvis.cpp
 | 
			
		||||
    sdrbase/dsp/threadedbasebandsamplesink.cpp
 | 
			
		||||
    sdrbase/dsp/threadedbasebandsamplesource.cpp
 | 
			
		||||
@ -141,6 +143,8 @@ set(sdrbase_SOURCES
 | 
			
		||||
    sdrbase/gui/cwkeyergui.cpp
 | 
			
		||||
    sdrbase/gui/glscope.cpp
 | 
			
		||||
    sdrbase/gui/glscopegui.cpp
 | 
			
		||||
    sdrbase/gui/glscopeng.cpp
 | 
			
		||||
    sdrbase/gui/glscopenggui.cpp
 | 
			
		||||
    sdrbase/gui/glshadersimple.cpp
 | 
			
		||||
    sdrbase/gui/glshadertextured.cpp
 | 
			
		||||
    sdrbase/gui/glspectrum.cpp
 | 
			
		||||
@ -237,7 +241,10 @@ set(sdrbase_HEADERS
 | 
			
		||||
    sdrbase/dsp/basebandsamplesink.h
 | 
			
		||||
    sdrbase/dsp/basebandsamplesource.h
 | 
			
		||||
    sdrbase/dsp/nullsink.h
 | 
			
		||||
    sdrbase/dsp/spectrumscopecombovis.h
 | 
			
		||||
    sdrbase/dsp/spectrumscopengcombovis.h
 | 
			
		||||
    sdrbase/dsp/scopevis.h
 | 
			
		||||
    sdrbase/dsp/scopevisng.h
 | 
			
		||||
    sdrbase/dsp/spectrumvis.h
 | 
			
		||||
    sdrbase/dsp/threadedbasebandsamplesink.h
 | 
			
		||||
    sdrbase/dsp/threadedbasebandsamplesource.h
 | 
			
		||||
@ -251,6 +258,8 @@ set(sdrbase_HEADERS
 | 
			
		||||
    sdrbase/gui/cwkeyergui.h
 | 
			
		||||
    sdrbase/gui/glscope.h
 | 
			
		||||
    sdrbase/gui/glscopegui.h
 | 
			
		||||
    sdrbase/gui/glscopeng.h
 | 
			
		||||
    sdrbase/gui/glscopenggui.h
 | 
			
		||||
    sdrbase/gui/glshadersimple.h
 | 
			
		||||
    sdrbase/gui/glshadertextured.h
 | 
			
		||||
    sdrbase/gui/glspectrum.h
 | 
			
		||||
@ -282,6 +291,7 @@ set(sdrbase_HEADERS
 | 
			
		||||
 | 
			
		||||
    sdrbase/util/CRC64.h
 | 
			
		||||
    sdrbase/util/db.h
 | 
			
		||||
    sdrbase/util/doublebuffer.h
 | 
			
		||||
    sdrbase/util/export.h
 | 
			
		||||
    sdrbase/util/message.h
 | 
			
		||||
    sdrbase/util/messagequeue.h
 | 
			
		||||
@ -309,6 +319,7 @@ set(sdrbase_FORMS
 | 
			
		||||
    sdrbase/gui/basicchannelsettingswidget.ui
 | 
			
		||||
    sdrbase/gui/cwkeyergui.ui
 | 
			
		||||
    sdrbase/gui/glscopegui.ui
 | 
			
		||||
    sdrbase/gui/glscopenggui.ui
 | 
			
		||||
    sdrbase/gui/glspectrumgui.ui
 | 
			
		||||
    sdrbase/gui/pluginsdialog.ui
 | 
			
		||||
    sdrbase/gui/audiodialog.ui
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@ project(demod)
 | 
			
		||||
 | 
			
		||||
add_subdirectory(demodlora)
 | 
			
		||||
add_subdirectory(demodam)
 | 
			
		||||
add_subdirectory(demodatv)
 | 
			
		||||
add_subdirectory(demodbfm)
 | 
			
		||||
add_subdirectory(demodnfm)
 | 
			
		||||
add_subdirectory(demodssb)
 | 
			
		||||
@ -9,6 +10,7 @@ add_subdirectory(tcpsrc)
 | 
			
		||||
add_subdirectory(udpsrc)
 | 
			
		||||
add_subdirectory(demodwfm)
 | 
			
		||||
add_subdirectory(chanalyzer)
 | 
			
		||||
add_subdirectory(chanalyzerng)
 | 
			
		||||
 | 
			
		||||
if(LIBDSDCC_FOUND AND LIBMBE_FOUND)
 | 
			
		||||
    add_subdirectory(demoddsd)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										45
									
								
								plugins/channelrx/chanalyzerng/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								plugins/channelrx/chanalyzerng/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
			
		||||
project(chanalyzerng)
 | 
			
		||||
 | 
			
		||||
set(chanalyzerng_SOURCES
 | 
			
		||||
	chanalyzerng.cpp
 | 
			
		||||
	chanalyzernggui.cpp
 | 
			
		||||
	chanalyzerngplugin.cpp
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(chanalyzerng_HEADERS
 | 
			
		||||
	chanalyzerng.h
 | 
			
		||||
	chanalyzernggui.h
 | 
			
		||||
	chanalyzerngplugin.h
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(chanalyzerng_FORMS
 | 
			
		||||
	chanalyzernggui.ui
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
include_directories(
 | 
			
		||||
	.
 | 
			
		||||
	${CMAKE_CURRENT_BINARY_DIR}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
#include(${QT_USE_FILE})
 | 
			
		||||
add_definitions(${QT_DEFINITIONS})
 | 
			
		||||
add_definitions(-DQT_PLUGIN)
 | 
			
		||||
add_definitions(-DQT_SHARED)
 | 
			
		||||
 | 
			
		||||
#qt5_wrap_cpp(chanalyzer_HEADERS_MOC ${chanalyzer_HEADERS})
 | 
			
		||||
qt5_wrap_ui(chanalyzerng_FORMS_HEADERS ${chanalyzerng_FORMS})
 | 
			
		||||
 | 
			
		||||
add_library(chanalyzerng SHARED
 | 
			
		||||
	${chanalyzerng_SOURCES}
 | 
			
		||||
	${chanalyzerng_HEADERS_MOC}
 | 
			
		||||
	${chanalyzerng_FORMS_HEADERS}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
target_link_libraries(chanalyzerng
 | 
			
		||||
	${QT_LIBRARIES}
 | 
			
		||||
	sdrbase
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
qt5_use_modules(chanalyzerng Core Widgets )
 | 
			
		||||
 | 
			
		||||
install(TARGETS chanalyzerng DESTINATION lib/plugins/channelrx)
 | 
			
		||||
							
								
								
									
										206
									
								
								plugins/channelrx/chanalyzerng/chanalyzerng.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								plugins/channelrx/chanalyzerng/chanalyzerng.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,206 @@
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Copyright (C) 2017 Edouard Griffiths, F4EXB                                   //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 as version 3 of the License, or                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 V3 for more details.                               //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// You should have received a copy of the GNU General Public License             //
 | 
			
		||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
#include "chanalyzerng.h"
 | 
			
		||||
 | 
			
		||||
#include <dsp/downchannelizer.h>
 | 
			
		||||
#include <QTime>
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include "audio/audiooutput.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelAnalyzer, Message)
 | 
			
		||||
 | 
			
		||||
ChannelAnalyzerNG::ChannelAnalyzerNG(BasebandSampleSink* sampleSink) :
 | 
			
		||||
	m_sampleSink(sampleSink),
 | 
			
		||||
	m_settingsMutex(QMutex::Recursive)
 | 
			
		||||
{
 | 
			
		||||
	m_Bandwidth = 5000;
 | 
			
		||||
	m_LowCutoff = 300;
 | 
			
		||||
	m_spanLog2 = 3;
 | 
			
		||||
	m_sampleRate = 96000;
 | 
			
		||||
	m_frequency = 0;
 | 
			
		||||
	m_nco.setFreq(m_frequency, m_sampleRate);
 | 
			
		||||
	m_undersampleCount = 0;
 | 
			
		||||
	m_sum = 0;
 | 
			
		||||
	m_usb = true;
 | 
			
		||||
	m_ssb = true;
 | 
			
		||||
	m_magsq = 0;
 | 
			
		||||
	SSBFilter = new fftfilt(m_LowCutoff / m_sampleRate, m_Bandwidth / m_sampleRate, ssbFftLen);
 | 
			
		||||
	DSBFilter = new fftfilt(m_Bandwidth / m_sampleRate, 2*ssbFftLen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ChannelAnalyzerNG::~ChannelAnalyzerNG()
 | 
			
		||||
{
 | 
			
		||||
	if (SSBFilter) delete SSBFilter;
 | 
			
		||||
	if (DSBFilter) delete DSBFilter;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNG::configure(MessageQueue* messageQueue,
 | 
			
		||||
		Real Bandwidth,
 | 
			
		||||
		Real LowCutoff,
 | 
			
		||||
		int  spanLog2,
 | 
			
		||||
		bool ssb)
 | 
			
		||||
{
 | 
			
		||||
	Message* cmd = MsgConfigureChannelAnalyzer::create(Bandwidth, LowCutoff, spanLog2, ssb);
 | 
			
		||||
	messageQueue->push(cmd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNG::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly)
 | 
			
		||||
{
 | 
			
		||||
	fftfilt::cmplx *sideband;
 | 
			
		||||
	int n_out;
 | 
			
		||||
	int decim = 1<<m_spanLog2;
 | 
			
		||||
	unsigned char decim_mask = decim - 1; // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1)
 | 
			
		||||
 | 
			
		||||
	m_settingsMutex.lock();
 | 
			
		||||
 | 
			
		||||
	for(SampleVector::const_iterator it = begin; it < end; ++it)
 | 
			
		||||
	{
 | 
			
		||||
		//Complex c(it->real() / 32768.0f, it->imag() / 32768.0f);
 | 
			
		||||
		Complex c(it->real(), it->imag());
 | 
			
		||||
		c *= m_nco.nextIQ();
 | 
			
		||||
 | 
			
		||||
		if (m_ssb)
 | 
			
		||||
		{
 | 
			
		||||
			n_out = SSBFilter->runSSB(c, &sideband, m_usb);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			n_out = DSBFilter->runDSB(c, &sideband);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (int i = 0; i < n_out; i++)
 | 
			
		||||
		{
 | 
			
		||||
			// Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display
 | 
			
		||||
			// smart decimation with bit gain using float arithmetic (23 bits significand)
 | 
			
		||||
 | 
			
		||||
			m_sum += sideband[i];
 | 
			
		||||
 | 
			
		||||
			if (!(m_undersampleCount++ & decim_mask))
 | 
			
		||||
			{
 | 
			
		||||
				m_sum /= decim;
 | 
			
		||||
				m_magsq = (m_sum.real() * m_sum.real() + m_sum.imag() * m_sum.imag())/ (1<<30);
 | 
			
		||||
 | 
			
		||||
				if (m_ssb & !m_usb)
 | 
			
		||||
				{ // invert spectrum for LSB
 | 
			
		||||
					//m_sampleBuffer.push_back(Sample(m_sum.imag() * 32768.0, m_sum.real() * 32768.0));
 | 
			
		||||
					m_sampleBuffer.push_back(Sample(m_sum.imag(), m_sum.real()));
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
					//m_sampleBuffer.push_back(Sample(m_sum.real() * 32768.0, m_sum.imag() * 32768.0));
 | 
			
		||||
					m_sampleBuffer.push_back(Sample(m_sum.real(), m_sum.imag()));
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				m_sum = 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(m_sampleSink != NULL)
 | 
			
		||||
	{
 | 
			
		||||
		m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), m_ssb); // m_ssb = positive only
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m_sampleBuffer.clear();
 | 
			
		||||
 | 
			
		||||
	m_settingsMutex.unlock();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNG::start()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNG::stop()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ChannelAnalyzerNG::handleMessage(const Message& cmd)
 | 
			
		||||
{
 | 
			
		||||
	float band, lowCutoff;
 | 
			
		||||
 | 
			
		||||
	qDebug() << "ChannelAnalyzerNG::handleMessage";
 | 
			
		||||
 | 
			
		||||
	if (DownChannelizer::MsgChannelizerNotification::match(cmd))
 | 
			
		||||
	{
 | 
			
		||||
		DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
 | 
			
		||||
 | 
			
		||||
		m_sampleRate = notif.getSampleRate();
 | 
			
		||||
		m_nco.setFreq(-notif.getFrequencyOffset(), m_sampleRate);
 | 
			
		||||
 | 
			
		||||
		qDebug() << "ChannelAnalyzerNG::handleMessage: MsgChannelizerNotification: m_sampleRate: " << m_sampleRate
 | 
			
		||||
				<< " frequencyOffset: " << notif.getFrequencyOffset();
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	else if (MsgConfigureChannelAnalyzer::match(cmd))
 | 
			
		||||
	{
 | 
			
		||||
		MsgConfigureChannelAnalyzer& cfg = (MsgConfigureChannelAnalyzer&) cmd;
 | 
			
		||||
 | 
			
		||||
		band = cfg.getBandwidth();
 | 
			
		||||
		lowCutoff = cfg.getLoCutoff();
 | 
			
		||||
 | 
			
		||||
		if (band < 0)
 | 
			
		||||
		{
 | 
			
		||||
			band = -band;
 | 
			
		||||
			lowCutoff = -lowCutoff;
 | 
			
		||||
			m_usb = false;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			m_usb = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (band < 100.0f)
 | 
			
		||||
		{
 | 
			
		||||
			band = 100.0f;
 | 
			
		||||
			lowCutoff = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		m_settingsMutex.lock();
 | 
			
		||||
 | 
			
		||||
		m_Bandwidth = band;
 | 
			
		||||
		m_LowCutoff = lowCutoff;
 | 
			
		||||
 | 
			
		||||
		SSBFilter->create_filter(m_LowCutoff / m_sampleRate, m_Bandwidth / m_sampleRate);
 | 
			
		||||
		DSBFilter->create_dsb_filter(m_Bandwidth / m_sampleRate);
 | 
			
		||||
 | 
			
		||||
		m_spanLog2 = cfg.getSpanLog2();
 | 
			
		||||
		m_ssb = cfg.getSSB();
 | 
			
		||||
 | 
			
		||||
		m_settingsMutex.unlock();
 | 
			
		||||
 | 
			
		||||
		qDebug() << "  - MsgConfigureChannelAnalyzer: m_Bandwidth: " << m_Bandwidth
 | 
			
		||||
				<< " m_LowCutoff: " << m_LowCutoff
 | 
			
		||||
				<< " m_spanLog2: " << m_spanLog2
 | 
			
		||||
				<< " m_ssb: " << m_ssb;
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		if (m_sampleSink != 0)
 | 
			
		||||
		{
 | 
			
		||||
		   return m_sampleSink->handleMessage(cmd);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										105
									
								
								plugins/channelrx/chanalyzerng/chanalyzerng.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								plugins/channelrx/chanalyzerng/chanalyzerng.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,105 @@
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Copyright (C) 2017 Edouard Griffiths, F4EXB                                   //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 as version 3 of the License, or                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 V3 for more details.                               //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// You should have received a copy of the GNU General Public License             //
 | 
			
		||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
#ifndef INCLUDE_CHANALYZERNG_H
 | 
			
		||||
#define INCLUDE_CHANALYZERNG_H
 | 
			
		||||
 | 
			
		||||
#include <dsp/basebandsamplesink.h>
 | 
			
		||||
#include <QMutex>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "dsp/ncof.h"
 | 
			
		||||
#include "dsp/fftfilt.h"
 | 
			
		||||
#include "audio/audiofifo.h"
 | 
			
		||||
#include "util/message.h"
 | 
			
		||||
 | 
			
		||||
#define ssbFftLen 1024
 | 
			
		||||
 | 
			
		||||
class ChannelAnalyzerNG : public BasebandSampleSink {
 | 
			
		||||
public:
 | 
			
		||||
    ChannelAnalyzerNG(BasebandSampleSink* m_sampleSink);
 | 
			
		||||
	virtual ~ChannelAnalyzerNG();
 | 
			
		||||
 | 
			
		||||
	void configure(MessageQueue* messageQueue,
 | 
			
		||||
			Real Bandwidth,
 | 
			
		||||
			Real LowCutoff,
 | 
			
		||||
			int spanLog2,
 | 
			
		||||
			bool ssb);
 | 
			
		||||
 | 
			
		||||
	int getSampleRate() const {	return m_sampleRate; }
 | 
			
		||||
	Real getMagSq() const { return m_magsq; }
 | 
			
		||||
 | 
			
		||||
	virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly);
 | 
			
		||||
	virtual void start();
 | 
			
		||||
	virtual void stop();
 | 
			
		||||
	virtual bool handleMessage(const Message& cmd);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	class MsgConfigureChannelAnalyzer : public Message {
 | 
			
		||||
		MESSAGE_CLASS_DECLARATION
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		Real getBandwidth() const { return m_Bandwidth; }
 | 
			
		||||
		Real getLoCutoff() const { return m_LowCutoff; }
 | 
			
		||||
		int  getSpanLog2() const { return m_spanLog2; }
 | 
			
		||||
		bool getSSB() const { return m_ssb; }
 | 
			
		||||
 | 
			
		||||
		static MsgConfigureChannelAnalyzer* create(Real Bandwidth,
 | 
			
		||||
				Real LowCutoff,
 | 
			
		||||
				int spanLog2,
 | 
			
		||||
				bool ssb)
 | 
			
		||||
		{
 | 
			
		||||
			return new MsgConfigureChannelAnalyzer(Bandwidth, LowCutoff, spanLog2, ssb);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		Real m_Bandwidth;
 | 
			
		||||
		Real m_LowCutoff;
 | 
			
		||||
		int  m_spanLog2;
 | 
			
		||||
		bool m_ssb;
 | 
			
		||||
 | 
			
		||||
		MsgConfigureChannelAnalyzer(Real Bandwidth,
 | 
			
		||||
				Real LowCutoff,
 | 
			
		||||
				int spanLog2,
 | 
			
		||||
				bool ssb) :
 | 
			
		||||
			Message(),
 | 
			
		||||
			m_Bandwidth(Bandwidth),
 | 
			
		||||
			m_LowCutoff(LowCutoff),
 | 
			
		||||
			m_spanLog2(spanLog2),
 | 
			
		||||
			m_ssb(ssb)
 | 
			
		||||
		{ }
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Real m_Bandwidth;
 | 
			
		||||
	Real m_LowCutoff;
 | 
			
		||||
	int m_spanLog2;
 | 
			
		||||
	int m_undersampleCount;
 | 
			
		||||
	fftfilt::cmplx m_sum;
 | 
			
		||||
	int m_sampleRate;
 | 
			
		||||
	int m_frequency;
 | 
			
		||||
	bool m_usb;
 | 
			
		||||
	bool m_ssb;
 | 
			
		||||
	Real m_magsq;
 | 
			
		||||
 | 
			
		||||
	NCOF m_nco;
 | 
			
		||||
	fftfilt* SSBFilter;
 | 
			
		||||
	fftfilt* DSBFilter;
 | 
			
		||||
 | 
			
		||||
	BasebandSampleSink* m_sampleSink;
 | 
			
		||||
	SampleVector m_sampleBuffer;
 | 
			
		||||
	QMutex m_settingsMutex;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // INCLUDE_CHANALYZERNG_H
 | 
			
		||||
							
								
								
									
										41
									
								
								plugins/channelrx/chanalyzerng/chanalyzerng.pro
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								plugins/channelrx/chanalyzerng/chanalyzerng.pro
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
#--------------------------------------------------------
 | 
			
		||||
#
 | 
			
		||||
# Pro file for Android and Windows builds with Qt Creator
 | 
			
		||||
#
 | 
			
		||||
#--------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
TEMPLATE = lib
 | 
			
		||||
CONFIG += plugin
 | 
			
		||||
 | 
			
		||||
QT += core gui widgets multimedia opengl
 | 
			
		||||
 | 
			
		||||
TARGET = chanalyzerng
 | 
			
		||||
 | 
			
		||||
DEFINES += USE_SSE2=1
 | 
			
		||||
QMAKE_CXXFLAGS += -msse2
 | 
			
		||||
DEFINES += USE_SSE4_1=1
 | 
			
		||||
QMAKE_CXXFLAGS += -msse4.1
 | 
			
		||||
 | 
			
		||||
INCLUDEPATH += $$PWD
 | 
			
		||||
INCLUDEPATH += ../../../sdrbase
 | 
			
		||||
 | 
			
		||||
CONFIG(ANDROID):INCLUDEPATH += /opt/softs/boost_1_60_0
 | 
			
		||||
CONFIG(MINGW32):INCLUDEPATH += "D:\boost_1_58_0"
 | 
			
		||||
CONFIG(MINGW64):INCLUDEPATH += "D:\boost_1_58_0"
 | 
			
		||||
 | 
			
		||||
CONFIG(Release):build_subdir = release
 | 
			
		||||
CONFIG(Debug):build_subdir = debug
 | 
			
		||||
 | 
			
		||||
SOURCES += chanalyzerng.cpp\
 | 
			
		||||
	chanalyzernggui.cpp\
 | 
			
		||||
	chanalyzerngplugin.cpp
 | 
			
		||||
 | 
			
		||||
HEADERS += chanalyzerng.h\
 | 
			
		||||
chanalyzernggui.h\
 | 
			
		||||
chanalyzerngplugin.h
 | 
			
		||||
 | 
			
		||||
FORMS += chanalyzernggui.ui
 | 
			
		||||
 | 
			
		||||
LIBS += -L../../../sdrbase/$${build_subdir} -lsdrbase
 | 
			
		||||
 | 
			
		||||
RESOURCES = ../../../sdrbase/resources/res.qrc
 | 
			
		||||
							
								
								
									
										485
									
								
								plugins/channelrx/chanalyzerng/chanalyzernggui.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										485
									
								
								plugins/channelrx/chanalyzerng/chanalyzernggui.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,485 @@
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Copyright (C) 2017 Edouard Griffiths, F4EXB                                   //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 as version 3 of the License, or                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 V3 for more details.                               //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// You should have received a copy of the GNU General Public License             //
 | 
			
		||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
#include "chanalyzernggui.h"
 | 
			
		||||
 | 
			
		||||
#include <device/devicesourceapi.h>
 | 
			
		||||
#include <dsp/downchannelizer.h>
 | 
			
		||||
#include <QDockWidget>
 | 
			
		||||
#include <QMainWindow>
 | 
			
		||||
 | 
			
		||||
#include "dsp/threadedbasebandsamplesink.h"
 | 
			
		||||
#include "ui_chanalyzernggui.h"
 | 
			
		||||
#include "dsp/spectrumscopengcombovis.h"
 | 
			
		||||
#include "dsp/spectrumvis.h"
 | 
			
		||||
#include "dsp/scopevis.h"
 | 
			
		||||
#include "gui/glspectrum.h"
 | 
			
		||||
#include "gui/glscopeng.h"
 | 
			
		||||
#include "plugin/pluginapi.h"
 | 
			
		||||
#include "util/simpleserializer.h"
 | 
			
		||||
#include "util/db.h"
 | 
			
		||||
#include "gui/basicchannelsettingswidget.h"
 | 
			
		||||
#include "dsp/dspengine.h"
 | 
			
		||||
#include "mainwindow.h"
 | 
			
		||||
 | 
			
		||||
#include "chanalyzerng.h"
 | 
			
		||||
 | 
			
		||||
const QString ChannelAnalyzerNGGUI::m_channelID = "sdrangel.channel.chanalyzerng";
 | 
			
		||||
 | 
			
		||||
ChannelAnalyzerNGGUI* ChannelAnalyzerNGGUI::create(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI)
 | 
			
		||||
{
 | 
			
		||||
    ChannelAnalyzerNGGUI* gui = new ChannelAnalyzerNGGUI(pluginAPI, deviceAPI);
 | 
			
		||||
	return gui;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGGUI::destroy()
 | 
			
		||||
{
 | 
			
		||||
	delete this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGGUI::setName(const QString& name)
 | 
			
		||||
{
 | 
			
		||||
	setObjectName(name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QString ChannelAnalyzerNGGUI::getName() const
 | 
			
		||||
{
 | 
			
		||||
	return objectName();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
qint64 ChannelAnalyzerNGGUI::getCenterFrequency() const
 | 
			
		||||
{
 | 
			
		||||
	return m_channelMarker.getCenterFrequency();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGGUI::setCenterFrequency(qint64 centerFrequency)
 | 
			
		||||
{
 | 
			
		||||
	m_channelMarker.setCenterFrequency(centerFrequency);
 | 
			
		||||
	applySettings();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGGUI::resetToDefaults()
 | 
			
		||||
{
 | 
			
		||||
	blockApplySettings(true);
 | 
			
		||||
 | 
			
		||||
	ui->BW->setValue(30);
 | 
			
		||||
	ui->deltaFrequency->setValue(0);
 | 
			
		||||
	ui->spanLog2->setValue(3);
 | 
			
		||||
 | 
			
		||||
	blockApplySettings(false);
 | 
			
		||||
	applySettings();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QByteArray ChannelAnalyzerNGGUI::serialize() const
 | 
			
		||||
{
 | 
			
		||||
	SimpleSerializer s(1);
 | 
			
		||||
	s.writeS32(1, m_channelMarker.getCenterFrequency());
 | 
			
		||||
	s.writeS32(2, ui->BW->value());
 | 
			
		||||
	s.writeBlob(3, ui->spectrumGUI->serialize());
 | 
			
		||||
	s.writeU32(4, m_channelMarker.getColor().rgb());
 | 
			
		||||
	s.writeS32(5, ui->lowCut->value());
 | 
			
		||||
	s.writeS32(6, ui->spanLog2->value());
 | 
			
		||||
	s.writeBool(7, ui->ssb->isChecked());
 | 
			
		||||
	s.writeBlob(8, ui->scopeGUI->serialize());
 | 
			
		||||
	return s.final();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ChannelAnalyzerNGGUI::deserialize(const QByteArray& data)
 | 
			
		||||
{
 | 
			
		||||
	SimpleDeserializer d(data);
 | 
			
		||||
 | 
			
		||||
	if(!d.isValid())
 | 
			
		||||
    {
 | 
			
		||||
		resetToDefaults();
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(d.getVersion() == 1)
 | 
			
		||||
    {
 | 
			
		||||
		QByteArray bytetmp;
 | 
			
		||||
		quint32 u32tmp;
 | 
			
		||||
		qint32 tmp, bw, lowCut;
 | 
			
		||||
		bool tmpBool;
 | 
			
		||||
 | 
			
		||||
		blockApplySettings(true);
 | 
			
		||||
	    m_channelMarker.blockSignals(true);
 | 
			
		||||
 | 
			
		||||
		d.readS32(1, &tmp, 0);
 | 
			
		||||
		m_channelMarker.setCenterFrequency(tmp);
 | 
			
		||||
		d.readS32(2, &bw, 30);
 | 
			
		||||
		ui->BW->setValue(bw);
 | 
			
		||||
		d.readBlob(3, &bytetmp);
 | 
			
		||||
		ui->spectrumGUI->deserialize(bytetmp);
 | 
			
		||||
 | 
			
		||||
		if(d.readU32(4, &u32tmp))
 | 
			
		||||
		{
 | 
			
		||||
			m_channelMarker.setColor(u32tmp);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		d.readS32(5, &lowCut, 3);
 | 
			
		||||
		ui->lowCut->setValue(lowCut);
 | 
			
		||||
		d.readS32(6, &tmp, 20);
 | 
			
		||||
		ui->spanLog2->setValue(tmp);
 | 
			
		||||
		setNewRate(tmp);
 | 
			
		||||
		d.readBool(7, &tmpBool, false);
 | 
			
		||||
		ui->ssb->setChecked(tmpBool);
 | 
			
		||||
		d.readBlob(8, &bytetmp);
 | 
			
		||||
		ui->scopeGUI->deserialize(bytetmp);
 | 
			
		||||
 | 
			
		||||
		blockApplySettings(false);
 | 
			
		||||
	    m_channelMarker.blockSignals(false);
 | 
			
		||||
 | 
			
		||||
		ui->BW->setValue(bw);
 | 
			
		||||
		ui->lowCut->setValue(lowCut); // does applySettings();
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
		resetToDefaults();
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ChannelAnalyzerNGGUI::handleMessage(const Message& message)
 | 
			
		||||
{
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGGUI::viewChanged()
 | 
			
		||||
{
 | 
			
		||||
	applySettings();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGGUI::tick()
 | 
			
		||||
{
 | 
			
		||||
	Real powDb = CalcDb::dbPower(m_channelAnalyzer->getMagSq());
 | 
			
		||||
	m_channelPowerDbAvg.feed(powDb);
 | 
			
		||||
	ui->channelPower->setText(QString::number(m_channelPowerDbAvg.average(), 'f', 1));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGGUI::channelSampleRateChanged()
 | 
			
		||||
{
 | 
			
		||||
	setNewRate(m_spanLog2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGGUI::on_deltaMinus_toggled(bool minus)
 | 
			
		||||
{
 | 
			
		||||
	int deltaFrequency = m_channelMarker.getCenterFrequency();
 | 
			
		||||
	bool minusDelta = (deltaFrequency < 0);
 | 
			
		||||
 | 
			
		||||
	if (minus ^ minusDelta) // sign change
 | 
			
		||||
	{
 | 
			
		||||
		m_channelMarker.setCenterFrequency(-deltaFrequency);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGGUI::on_deltaFrequency_changed(quint64 value)
 | 
			
		||||
{
 | 
			
		||||
	if (ui->deltaMinus->isChecked()) {
 | 
			
		||||
		m_channelMarker.setCenterFrequency(-value);
 | 
			
		||||
	} else {
 | 
			
		||||
		m_channelMarker.setCenterFrequency(value);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGGUI::on_BW_valueChanged(int value)
 | 
			
		||||
{
 | 
			
		||||
	QString s = QString::number(value/10.0, 'f', 1);
 | 
			
		||||
	ui->BWText->setText(tr("%1k").arg(s));
 | 
			
		||||
	m_channelMarker.setBandwidth(value * 100 * 2);
 | 
			
		||||
 | 
			
		||||
	if (ui->ssb->isChecked())
 | 
			
		||||
	{
 | 
			
		||||
		if (value < 0) {
 | 
			
		||||
			m_channelMarker.setSidebands(ChannelMarker::lsb);
 | 
			
		||||
		} else {
 | 
			
		||||
			m_channelMarker.setSidebands(ChannelMarker::usb);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		m_channelMarker.setSidebands(ChannelMarker::dsb);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ChannelAnalyzerNGGUI::getEffectiveLowCutoff(int lowCutoff)
 | 
			
		||||
{
 | 
			
		||||
	int ssbBW = m_channelMarker.getBandwidth() / 2;
 | 
			
		||||
	int effectiveLowCutoff = lowCutoff;
 | 
			
		||||
	const int guard = 100;
 | 
			
		||||
 | 
			
		||||
	if (ssbBW < 0) {
 | 
			
		||||
		if (effectiveLowCutoff < ssbBW + guard) {
 | 
			
		||||
			effectiveLowCutoff = ssbBW + guard;
 | 
			
		||||
		}
 | 
			
		||||
		if (effectiveLowCutoff > 0)	{
 | 
			
		||||
			effectiveLowCutoff = 0;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if (effectiveLowCutoff > ssbBW - guard)	{
 | 
			
		||||
			effectiveLowCutoff = ssbBW - guard;
 | 
			
		||||
		}
 | 
			
		||||
		if (effectiveLowCutoff < 0)	{
 | 
			
		||||
			effectiveLowCutoff = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return effectiveLowCutoff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGGUI::on_lowCut_valueChanged(int value)
 | 
			
		||||
{
 | 
			
		||||
	int lowCutoff = getEffectiveLowCutoff(value * 100);
 | 
			
		||||
	m_channelMarker.setLowCutoff(lowCutoff);
 | 
			
		||||
	QString s = QString::number(lowCutoff/1000.0, 'f', 1);
 | 
			
		||||
	ui->lowCutText->setText(tr("%1k").arg(s));
 | 
			
		||||
	ui->lowCut->setValue(lowCutoff/100);
 | 
			
		||||
	applySettings();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGGUI::on_spanLog2_valueChanged(int value)
 | 
			
		||||
{
 | 
			
		||||
	if (setNewRate(value)) {
 | 
			
		||||
		applySettings();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGGUI::on_ssb_toggled(bool checked)
 | 
			
		||||
{
 | 
			
		||||
	if (checked)
 | 
			
		||||
	{
 | 
			
		||||
		if (ui->BW->value() < 0) {
 | 
			
		||||
			m_channelMarker.setSidebands(ChannelMarker::lsb);
 | 
			
		||||
		} else {
 | 
			
		||||
			m_channelMarker.setSidebands(ChannelMarker::usb);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ui->glSpectrum->setCenterFrequency(m_rate/4);
 | 
			
		||||
		ui->glSpectrum->setSampleRate(m_rate/2);
 | 
			
		||||
		ui->glSpectrum->setSsbSpectrum(true);
 | 
			
		||||
 | 
			
		||||
		on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		m_channelMarker.setSidebands(ChannelMarker::dsb);
 | 
			
		||||
 | 
			
		||||
		ui->glSpectrum->setCenterFrequency(0);
 | 
			
		||||
		ui->glSpectrum->setSampleRate(m_rate);
 | 
			
		||||
		ui->glSpectrum->setSsbSpectrum(false);
 | 
			
		||||
 | 
			
		||||
		applySettings();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGGUI::onWidgetRolled(QWidget* widget, bool rollDown)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
	if((widget == ui->spectrumContainer) && (m_ssbDemod != NULL))
 | 
			
		||||
		m_ssbDemod->setSpectrum(m_threadedSampleSink->getMessageQueue(), rollDown);
 | 
			
		||||
	*/
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGGUI::onMenuDoubleClicked()
 | 
			
		||||
{
 | 
			
		||||
	if(!m_basicSettingsShown) {
 | 
			
		||||
		m_basicSettingsShown = true;
 | 
			
		||||
		BasicChannelSettingsWidget* bcsw = new BasicChannelSettingsWidget(&m_channelMarker, this);
 | 
			
		||||
		bcsw->show();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ChannelAnalyzerNGGUI::ChannelAnalyzerNGGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget* parent) :
 | 
			
		||||
	RollupWidget(parent),
 | 
			
		||||
	ui(new Ui::ChannelAnalyzerNGGUI),
 | 
			
		||||
	m_pluginAPI(pluginAPI),
 | 
			
		||||
	m_deviceAPI(deviceAPI),
 | 
			
		||||
	m_channelMarker(this),
 | 
			
		||||
	m_basicSettingsShown(false),
 | 
			
		||||
	m_doApplySettings(true),
 | 
			
		||||
	m_rate(6000),
 | 
			
		||||
	m_spanLog2(3),
 | 
			
		||||
	m_channelPowerDbAvg(40,0)
 | 
			
		||||
{
 | 
			
		||||
	ui->setupUi(this);
 | 
			
		||||
	setAttribute(Qt::WA_DeleteOnClose, true);
 | 
			
		||||
	connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
 | 
			
		||||
	connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked()));
 | 
			
		||||
 | 
			
		||||
	m_spectrumVis = new SpectrumVis(ui->glSpectrum);
 | 
			
		||||
	m_scopeVis = new ScopeVisNG(ui->glScope);
 | 
			
		||||
	m_spectrumScopeComboVis = new SpectrumScopeNGComboVis(m_spectrumVis, m_scopeVis);
 | 
			
		||||
	m_channelAnalyzer = new ChannelAnalyzerNG(m_spectrumScopeComboVis);
 | 
			
		||||
	m_channelizer = new DownChannelizer(m_channelAnalyzer);
 | 
			
		||||
	m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
 | 
			
		||||
	connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged()));
 | 
			
		||||
	m_deviceAPI->addThreadedSink(m_threadedChannelizer);
 | 
			
		||||
 | 
			
		||||
	ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGold));
 | 
			
		||||
	ui->deltaFrequency->setValueRange(7, 0U, 9999999U);
 | 
			
		||||
 | 
			
		||||
	ui->glSpectrum->setCenterFrequency(m_rate/2);
 | 
			
		||||
	ui->glSpectrum->setSampleRate(m_rate);
 | 
			
		||||
	ui->glSpectrum->setDisplayWaterfall(true);
 | 
			
		||||
	ui->glSpectrum->setDisplayMaxHold(true);
 | 
			
		||||
	ui->glSpectrum->setSsbSpectrum(true);
 | 
			
		||||
 | 
			
		||||
	ui->glSpectrum->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer());
 | 
			
		||||
	ui->glScope->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer());
 | 
			
		||||
	connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
 | 
			
		||||
 | 
			
		||||
	//m_channelMarker = new ChannelMarker(this);
 | 
			
		||||
	m_channelMarker.setColor(Qt::gray);
 | 
			
		||||
	m_channelMarker.setBandwidth(m_rate);
 | 
			
		||||
	m_channelMarker.setSidebands(ChannelMarker::usb);
 | 
			
		||||
	m_channelMarker.setCenterFrequency(0);
 | 
			
		||||
	m_channelMarker.setVisible(true);
 | 
			
		||||
 | 
			
		||||
	connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
 | 
			
		||||
 | 
			
		||||
	m_deviceAPI->registerChannelInstance(m_channelID, this);
 | 
			
		||||
	m_deviceAPI->addChannelMarker(&m_channelMarker);
 | 
			
		||||
	m_deviceAPI->addRollupWidget(this);
 | 
			
		||||
 | 
			
		||||
	ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum);
 | 
			
		||||
	ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope);
 | 
			
		||||
 | 
			
		||||
	applySettings();
 | 
			
		||||
	setNewRate(m_spanLog2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ChannelAnalyzerNGGUI::~ChannelAnalyzerNGGUI()
 | 
			
		||||
{
 | 
			
		||||
    m_deviceAPI->removeChannelInstance(this);
 | 
			
		||||
	m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
 | 
			
		||||
	delete m_threadedChannelizer;
 | 
			
		||||
	delete m_channelizer;
 | 
			
		||||
	delete m_channelAnalyzer;
 | 
			
		||||
	delete m_spectrumVis;
 | 
			
		||||
	delete m_scopeVis;
 | 
			
		||||
	delete m_spectrumScopeComboVis;
 | 
			
		||||
	//delete m_channelMarker;
 | 
			
		||||
	delete ui;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ChannelAnalyzerNGGUI::setNewRate(int spanLog2)
 | 
			
		||||
{
 | 
			
		||||
	qDebug("ChannelAnalyzerNGGUI::setNewRate");
 | 
			
		||||
 | 
			
		||||
	if ((spanLog2 < 0) || (spanLog2 > 6)) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m_spanLog2 = spanLog2;
 | 
			
		||||
	//m_rate = 48000 / (1<<spanLog2);
 | 
			
		||||
	m_rate = m_channelAnalyzer->getSampleRate() / (1<<spanLog2);
 | 
			
		||||
 | 
			
		||||
	if (ui->BW->value() < -m_rate/200) {
 | 
			
		||||
		ui->BW->setValue(-m_rate/200);
 | 
			
		||||
		m_channelMarker.setBandwidth(-m_rate*2);
 | 
			
		||||
	} else if (ui->BW->value() > m_rate/200) {
 | 
			
		||||
		ui->BW->setValue(m_rate/200);
 | 
			
		||||
		m_channelMarker.setBandwidth(m_rate*2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (ui->lowCut->value() < -m_rate/200) {
 | 
			
		||||
		ui->lowCut->setValue(-m_rate/200);
 | 
			
		||||
		m_channelMarker.setLowCutoff(-m_rate);
 | 
			
		||||
	} else if (ui->lowCut->value() > m_rate/200) {
 | 
			
		||||
		ui->lowCut->setValue(m_rate/200);
 | 
			
		||||
		m_channelMarker.setLowCutoff(m_rate);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ui->BW->setMinimum(-m_rate/200);
 | 
			
		||||
	ui->lowCut->setMinimum(-m_rate/200);
 | 
			
		||||
	ui->BW->setMaximum(m_rate/200);
 | 
			
		||||
	ui->lowCut->setMaximum(m_rate/200);
 | 
			
		||||
 | 
			
		||||
	QString s = QString::number(m_rate/1000.0, 'f', 1);
 | 
			
		||||
	ui->spanText->setText(tr("%1k").arg(s));
 | 
			
		||||
 | 
			
		||||
	if (ui->ssb->isChecked())
 | 
			
		||||
	{
 | 
			
		||||
		if (ui->BW->value() < 0) {
 | 
			
		||||
			m_channelMarker.setSidebands(ChannelMarker::lsb);
 | 
			
		||||
		} else {
 | 
			
		||||
			m_channelMarker.setSidebands(ChannelMarker::usb);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ui->glSpectrum->setCenterFrequency(m_rate/4);
 | 
			
		||||
		ui->glSpectrum->setSampleRate(m_rate/2);
 | 
			
		||||
		ui->glSpectrum->setSsbSpectrum(true);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		m_channelMarker.setSidebands(ChannelMarker::dsb);
 | 
			
		||||
 | 
			
		||||
		ui->glSpectrum->setCenterFrequency(0);
 | 
			
		||||
		ui->glSpectrum->setSampleRate(m_rate);
 | 
			
		||||
		ui->glSpectrum->setSsbSpectrum(false);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ui->glScope->setSampleRate(m_rate);
 | 
			
		||||
	//m_scopeVis->setSampleRate(m_rate); TODO: not needed anymore?
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGGUI::blockApplySettings(bool block)
 | 
			
		||||
{
 | 
			
		||||
    ui->glScope->blockSignals(block);
 | 
			
		||||
    ui->glSpectrum->blockSignals(block);
 | 
			
		||||
    m_doApplySettings = !block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGGUI::applySettings()
 | 
			
		||||
{
 | 
			
		||||
	if (m_doApplySettings)
 | 
			
		||||
	{
 | 
			
		||||
		setTitleColor(m_channelMarker.getColor());
 | 
			
		||||
		ui->deltaFrequency->setValue(abs(m_channelMarker.getCenterFrequency()));
 | 
			
		||||
		ui->deltaMinus->setChecked(m_channelMarker.getCenterFrequency() < 0);
 | 
			
		||||
 | 
			
		||||
		m_channelizer->configure(m_channelizer->getInputMessageQueue(),
 | 
			
		||||
			m_channelizer->getInputSampleRate(),
 | 
			
		||||
			m_channelMarker.getCenterFrequency());
 | 
			
		||||
 | 
			
		||||
		m_channelAnalyzer->configure(m_channelAnalyzer->getInputMessageQueue(),
 | 
			
		||||
			ui->BW->value() * 100.0,
 | 
			
		||||
			ui->lowCut->value() * 100.0,
 | 
			
		||||
			m_spanLog2,
 | 
			
		||||
			ui->ssb->isChecked());
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGGUI::leaveEvent(QEvent*)
 | 
			
		||||
{
 | 
			
		||||
	blockApplySettings(true);
 | 
			
		||||
	m_channelMarker.setHighlighted(false);
 | 
			
		||||
	blockApplySettings(false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGGUI::enterEvent(QEvent*)
 | 
			
		||||
{
 | 
			
		||||
	blockApplySettings(true);
 | 
			
		||||
	m_channelMarker.setHighlighted(true);
 | 
			
		||||
	blockApplySettings(false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										103
									
								
								plugins/channelrx/chanalyzerng/chanalyzernggui.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								plugins/channelrx/chanalyzerng/chanalyzernggui.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,103 @@
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Copyright (C) 2017 Edouard Griffiths, F4EXB                                   //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 as version 3 of the License, or                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 V3 for more details.                               //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// You should have received a copy of the GNU General Public License             //
 | 
			
		||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
#ifndef INCLUDE_CHANNELANALYZERNGGUI_H
 | 
			
		||||
#define INCLUDE_CHANNELANALYZERNGGUI_H
 | 
			
		||||
 | 
			
		||||
#include "gui/rollupwidget.h"
 | 
			
		||||
#include "plugin/plugingui.h"
 | 
			
		||||
#include "dsp/channelmarker.h"
 | 
			
		||||
#include "dsp/movingaverage.h"
 | 
			
		||||
 | 
			
		||||
class PluginAPI;
 | 
			
		||||
class DeviceSourceAPI;
 | 
			
		||||
 | 
			
		||||
class ThreadedBasebandSampleSink;
 | 
			
		||||
class DownChannelizer;
 | 
			
		||||
class ChannelAnalyzerNG;
 | 
			
		||||
class SpectrumScopeNGComboVis;
 | 
			
		||||
class SpectrumVis;
 | 
			
		||||
class ScopeVisNG;
 | 
			
		||||
 | 
			
		||||
namespace Ui {
 | 
			
		||||
	class ChannelAnalyzerNGGUI;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class ChannelAnalyzerNGGUI : public RollupWidget, public PluginGUI {
 | 
			
		||||
	Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	static ChannelAnalyzerNGGUI* create(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI);
 | 
			
		||||
	void destroy();
 | 
			
		||||
 | 
			
		||||
	void setName(const QString& name);
 | 
			
		||||
	QString getName() const;
 | 
			
		||||
	virtual qint64 getCenterFrequency() const;
 | 
			
		||||
	virtual void setCenterFrequency(qint64 centerFrequency);
 | 
			
		||||
 | 
			
		||||
	void resetToDefaults();
 | 
			
		||||
	QByteArray serialize() const;
 | 
			
		||||
	bool deserialize(const QByteArray& data);
 | 
			
		||||
 | 
			
		||||
	virtual bool handleMessage(const Message& message);
 | 
			
		||||
 | 
			
		||||
	static const QString m_channelID;
 | 
			
		||||
 | 
			
		||||
private slots:
 | 
			
		||||
	void viewChanged();
 | 
			
		||||
	void channelSampleRateChanged();
 | 
			
		||||
	void on_deltaFrequency_changed(quint64 value);
 | 
			
		||||
	void on_deltaMinus_toggled(bool minus);
 | 
			
		||||
	void on_BW_valueChanged(int value);
 | 
			
		||||
	void on_lowCut_valueChanged(int value);
 | 
			
		||||
	void on_spanLog2_valueChanged(int value);
 | 
			
		||||
	void on_ssb_toggled(bool checked);
 | 
			
		||||
	void onWidgetRolled(QWidget* widget, bool rollDown);
 | 
			
		||||
	void onMenuDoubleClicked();
 | 
			
		||||
	void tick();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	Ui::ChannelAnalyzerNGGUI* ui;
 | 
			
		||||
	PluginAPI* m_pluginAPI;
 | 
			
		||||
	DeviceSourceAPI* m_deviceAPI;
 | 
			
		||||
	ChannelMarker m_channelMarker;
 | 
			
		||||
	bool m_basicSettingsShown;
 | 
			
		||||
	bool m_doApplySettings;
 | 
			
		||||
	int m_rate;
 | 
			
		||||
	int m_spanLog2;
 | 
			
		||||
	MovingAverage<Real> m_channelPowerDbAvg;
 | 
			
		||||
 | 
			
		||||
	ThreadedBasebandSampleSink* m_threadedChannelizer;
 | 
			
		||||
	DownChannelizer* m_channelizer;
 | 
			
		||||
	ChannelAnalyzerNG* m_channelAnalyzer;
 | 
			
		||||
	SpectrumScopeNGComboVis* m_spectrumScopeComboVis;
 | 
			
		||||
	SpectrumVis* m_spectrumVis;
 | 
			
		||||
	ScopeVisNG* m_scopeVis;
 | 
			
		||||
 | 
			
		||||
	explicit ChannelAnalyzerNGGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget* parent = NULL);
 | 
			
		||||
	virtual ~ChannelAnalyzerNGGUI();
 | 
			
		||||
 | 
			
		||||
	int  getEffectiveLowCutoff(int lowCutoff);
 | 
			
		||||
	bool setNewRate(int spanLog2);
 | 
			
		||||
 | 
			
		||||
	void blockApplySettings(bool block);
 | 
			
		||||
	void applySettings();
 | 
			
		||||
 | 
			
		||||
	void leaveEvent(QEvent*);
 | 
			
		||||
	void enterEvent(QEvent*);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // INCLUDE_CHANNELANALYZERNGGUI_H
 | 
			
		||||
							
								
								
									
										540
									
								
								plugins/channelrx/chanalyzerng/chanalyzernggui.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										540
									
								
								plugins/channelrx/chanalyzerng/chanalyzernggui.ui
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,540 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<ui version="4.0">
 | 
			
		||||
 <class>ChannelAnalyzerNGGUI</class>
 | 
			
		||||
 <widget class="RollupWidget" name="ChannelAnalyzerNGGUI">
 | 
			
		||||
  <property name="geometry">
 | 
			
		||||
   <rect>
 | 
			
		||||
    <x>0</x>
 | 
			
		||||
    <y>0</y>
 | 
			
		||||
    <width>640</width>
 | 
			
		||||
    <height>814</height>
 | 
			
		||||
   </rect>
 | 
			
		||||
  </property>
 | 
			
		||||
  <property name="minimumSize">
 | 
			
		||||
   <size>
 | 
			
		||||
    <width>640</width>
 | 
			
		||||
    <height>0</height>
 | 
			
		||||
   </size>
 | 
			
		||||
  </property>
 | 
			
		||||
  <property name="font">
 | 
			
		||||
   <font>
 | 
			
		||||
    <family>Sans Serif</family>
 | 
			
		||||
    <pointsize>9</pointsize>
 | 
			
		||||
   </font>
 | 
			
		||||
  </property>
 | 
			
		||||
  <property name="windowTitle">
 | 
			
		||||
   <string>Channel Analyzer NG</string>
 | 
			
		||||
  </property>
 | 
			
		||||
  <widget class="QWidget" name="settingsContainer" native="true">
 | 
			
		||||
   <property name="geometry">
 | 
			
		||||
    <rect>
 | 
			
		||||
     <x>0</x>
 | 
			
		||||
     <y>10</y>
 | 
			
		||||
     <width>301</width>
 | 
			
		||||
     <height>131</height>
 | 
			
		||||
    </rect>
 | 
			
		||||
   </property>
 | 
			
		||||
   <property name="windowTitle">
 | 
			
		||||
    <string>Settings</string>
 | 
			
		||||
   </property>
 | 
			
		||||
   <layout class="QVBoxLayout" name="verticalLayout">
 | 
			
		||||
    <property name="spacing">
 | 
			
		||||
     <number>3</number>
 | 
			
		||||
    </property>
 | 
			
		||||
    <property name="leftMargin">
 | 
			
		||||
     <number>2</number>
 | 
			
		||||
    </property>
 | 
			
		||||
    <property name="topMargin">
 | 
			
		||||
     <number>2</number>
 | 
			
		||||
    </property>
 | 
			
		||||
    <property name="rightMargin">
 | 
			
		||||
     <number>2</number>
 | 
			
		||||
    </property>
 | 
			
		||||
    <property name="bottomMargin">
 | 
			
		||||
     <number>2</number>
 | 
			
		||||
    </property>
 | 
			
		||||
    <item>
 | 
			
		||||
     <layout class="QHBoxLayout" name="DeltaFreqPowLayout">
 | 
			
		||||
      <item>
 | 
			
		||||
       <layout class="QHBoxLayout" name="DeltaFrequencyLayout">
 | 
			
		||||
        <item>
 | 
			
		||||
         <widget class="QToolButton" name="deltaMinus">
 | 
			
		||||
          <property name="toolTip">
 | 
			
		||||
           <string>Frequency shift direction</string>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="text">
 | 
			
		||||
           <string>...</string>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="icon">
 | 
			
		||||
           <iconset>
 | 
			
		||||
            <selectedoff>:/plus.png</selectedoff>
 | 
			
		||||
            <selectedon>:/minus.png</selectedon>
 | 
			
		||||
           </iconset>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="checkable">
 | 
			
		||||
           <bool>true</bool>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="checked">
 | 
			
		||||
           <bool>false</bool>
 | 
			
		||||
          </property>
 | 
			
		||||
         </widget>
 | 
			
		||||
        </item>
 | 
			
		||||
        <item>
 | 
			
		||||
         <widget class="ValueDial" name="deltaFrequency" native="true">
 | 
			
		||||
          <property name="sizePolicy">
 | 
			
		||||
           <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
 | 
			
		||||
            <horstretch>0</horstretch>
 | 
			
		||||
            <verstretch>0</verstretch>
 | 
			
		||||
           </sizepolicy>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="minimumSize">
 | 
			
		||||
           <size>
 | 
			
		||||
            <width>32</width>
 | 
			
		||||
            <height>16</height>
 | 
			
		||||
           </size>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="font">
 | 
			
		||||
           <font>
 | 
			
		||||
            <family>Monospace</family>
 | 
			
		||||
            <pointsize>12</pointsize>
 | 
			
		||||
           </font>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="cursor">
 | 
			
		||||
           <cursorShape>SizeVerCursor</cursorShape>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="focusPolicy">
 | 
			
		||||
           <enum>Qt::StrongFocus</enum>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="toolTip">
 | 
			
		||||
           <string>Demod shift frequency from center in Hz</string>
 | 
			
		||||
          </property>
 | 
			
		||||
         </widget>
 | 
			
		||||
        </item>
 | 
			
		||||
        <item>
 | 
			
		||||
         <widget class="QLabel" name="deltaUnits">
 | 
			
		||||
          <property name="palette">
 | 
			
		||||
           <palette>
 | 
			
		||||
            <active>
 | 
			
		||||
             <colorrole role="Text">
 | 
			
		||||
              <brush brushstyle="SolidPattern">
 | 
			
		||||
               <color alpha="255">
 | 
			
		||||
                <red>26</red>
 | 
			
		||||
                <green>26</green>
 | 
			
		||||
                <blue>26</blue>
 | 
			
		||||
               </color>
 | 
			
		||||
              </brush>
 | 
			
		||||
             </colorrole>
 | 
			
		||||
             <colorrole role="BrightText">
 | 
			
		||||
              <brush brushstyle="SolidPattern">
 | 
			
		||||
               <color alpha="255">
 | 
			
		||||
                <red>255</red>
 | 
			
		||||
                <green>255</green>
 | 
			
		||||
                <blue>255</blue>
 | 
			
		||||
               </color>
 | 
			
		||||
              </brush>
 | 
			
		||||
             </colorrole>
 | 
			
		||||
            </active>
 | 
			
		||||
            <inactive>
 | 
			
		||||
             <colorrole role="Text">
 | 
			
		||||
              <brush brushstyle="SolidPattern">
 | 
			
		||||
               <color alpha="255">
 | 
			
		||||
                <red>26</red>
 | 
			
		||||
                <green>26</green>
 | 
			
		||||
                <blue>26</blue>
 | 
			
		||||
               </color>
 | 
			
		||||
              </brush>
 | 
			
		||||
             </colorrole>
 | 
			
		||||
             <colorrole role="BrightText">
 | 
			
		||||
              <brush brushstyle="SolidPattern">
 | 
			
		||||
               <color alpha="255">
 | 
			
		||||
                <red>255</red>
 | 
			
		||||
                <green>255</green>
 | 
			
		||||
                <blue>255</blue>
 | 
			
		||||
               </color>
 | 
			
		||||
              </brush>
 | 
			
		||||
             </colorrole>
 | 
			
		||||
            </inactive>
 | 
			
		||||
            <disabled>
 | 
			
		||||
             <colorrole role="Text">
 | 
			
		||||
              <brush brushstyle="SolidPattern">
 | 
			
		||||
               <color alpha="255">
 | 
			
		||||
                <red>118</red>
 | 
			
		||||
                <green>118</green>
 | 
			
		||||
                <blue>117</blue>
 | 
			
		||||
               </color>
 | 
			
		||||
              </brush>
 | 
			
		||||
             </colorrole>
 | 
			
		||||
             <colorrole role="BrightText">
 | 
			
		||||
              <brush brushstyle="SolidPattern">
 | 
			
		||||
               <color alpha="255">
 | 
			
		||||
                <red>255</red>
 | 
			
		||||
                <green>255</green>
 | 
			
		||||
                <blue>255</blue>
 | 
			
		||||
               </color>
 | 
			
		||||
              </brush>
 | 
			
		||||
             </colorrole>
 | 
			
		||||
            </disabled>
 | 
			
		||||
           </palette>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="text">
 | 
			
		||||
           <string> Hz</string>
 | 
			
		||||
          </property>
 | 
			
		||||
         </widget>
 | 
			
		||||
        </item>
 | 
			
		||||
       </layout>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item>
 | 
			
		||||
       <spacer name="horizontalSpacer">
 | 
			
		||||
        <property name="orientation">
 | 
			
		||||
         <enum>Qt::Horizontal</enum>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="sizeHint" stdset="0">
 | 
			
		||||
         <size>
 | 
			
		||||
          <width>40</width>
 | 
			
		||||
          <height>20</height>
 | 
			
		||||
         </size>
 | 
			
		||||
        </property>
 | 
			
		||||
       </spacer>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item>
 | 
			
		||||
       <layout class="QHBoxLayout" name="ChannelPowerLayout">
 | 
			
		||||
        <item>
 | 
			
		||||
         <widget class="QLabel" name="channelPower">
 | 
			
		||||
          <property name="toolTip">
 | 
			
		||||
           <string>Channel power</string>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="layoutDirection">
 | 
			
		||||
           <enum>Qt::LeftToRight</enum>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="text">
 | 
			
		||||
           <string>0.0</string>
 | 
			
		||||
          </property>
 | 
			
		||||
         </widget>
 | 
			
		||||
        </item>
 | 
			
		||||
        <item>
 | 
			
		||||
         <widget class="QLabel" name="channelPowerUnits">
 | 
			
		||||
          <property name="text">
 | 
			
		||||
           <string> dB</string>
 | 
			
		||||
          </property>
 | 
			
		||||
         </widget>
 | 
			
		||||
        </item>
 | 
			
		||||
       </layout>
 | 
			
		||||
      </item>
 | 
			
		||||
     </layout>
 | 
			
		||||
    </item>
 | 
			
		||||
    <item>
 | 
			
		||||
     <layout class="QHBoxLayout" name="SpanLayout">
 | 
			
		||||
      <item>
 | 
			
		||||
       <widget class="QLabel" name="spanLabel">
 | 
			
		||||
        <property name="text">
 | 
			
		||||
         <string>Rate</string>
 | 
			
		||||
        </property>
 | 
			
		||||
       </widget>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item>
 | 
			
		||||
       <widget class="QSlider" name="spanLog2">
 | 
			
		||||
        <property name="toolTip">
 | 
			
		||||
         <string>Channel sample rate</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="minimum">
 | 
			
		||||
         <number>0</number>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="maximum">
 | 
			
		||||
         <number>6</number>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="pageStep">
 | 
			
		||||
         <number>1</number>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="value">
 | 
			
		||||
         <number>3</number>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="sliderPosition">
 | 
			
		||||
         <number>3</number>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="orientation">
 | 
			
		||||
         <enum>Qt::Horizontal</enum>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="invertedAppearance">
 | 
			
		||||
         <bool>true</bool>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="invertedControls">
 | 
			
		||||
         <bool>true</bool>
 | 
			
		||||
        </property>
 | 
			
		||||
       </widget>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item>
 | 
			
		||||
       <widget class="QLabel" name="spanText">
 | 
			
		||||
        <property name="text">
 | 
			
		||||
         <string>6.0k</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="alignment">
 | 
			
		||||
         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
 | 
			
		||||
        </property>
 | 
			
		||||
       </widget>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item>
 | 
			
		||||
       <widget class="QCheckBox" name="ssb">
 | 
			
		||||
        <property name="toolTip">
 | 
			
		||||
         <string>SSB/DSB togggle</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="text">
 | 
			
		||||
         <string>SSB</string>
 | 
			
		||||
        </property>
 | 
			
		||||
       </widget>
 | 
			
		||||
      </item>
 | 
			
		||||
     </layout>
 | 
			
		||||
    </item>
 | 
			
		||||
    <item>
 | 
			
		||||
     <layout class="QHBoxLayout" name="BWLayout">
 | 
			
		||||
      <item>
 | 
			
		||||
       <widget class="QLabel" name="BWLabel">
 | 
			
		||||
        <property name="text">
 | 
			
		||||
         <string>BW</string>
 | 
			
		||||
        </property>
 | 
			
		||||
       </widget>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item>
 | 
			
		||||
       <widget class="QSlider" name="BW">
 | 
			
		||||
        <property name="toolTip">
 | 
			
		||||
         <string>Lowpass filter cutoff frequency</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="minimum">
 | 
			
		||||
         <number>-60</number>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="maximum">
 | 
			
		||||
         <number>60</number>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="pageStep">
 | 
			
		||||
         <number>1</number>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="value">
 | 
			
		||||
         <number>30</number>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="orientation">
 | 
			
		||||
         <enum>Qt::Horizontal</enum>
 | 
			
		||||
        </property>
 | 
			
		||||
       </widget>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item>
 | 
			
		||||
       <widget class="QLabel" name="BWText">
 | 
			
		||||
        <property name="minimumSize">
 | 
			
		||||
         <size>
 | 
			
		||||
          <width>50</width>
 | 
			
		||||
          <height>0</height>
 | 
			
		||||
         </size>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="text">
 | 
			
		||||
         <string>3.0k</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="alignment">
 | 
			
		||||
         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
 | 
			
		||||
        </property>
 | 
			
		||||
       </widget>
 | 
			
		||||
      </item>
 | 
			
		||||
     </layout>
 | 
			
		||||
    </item>
 | 
			
		||||
    <item>
 | 
			
		||||
     <layout class="QHBoxLayout" name="LowCutLayout">
 | 
			
		||||
      <item>
 | 
			
		||||
       <widget class="QLabel" name="lowCutLabel">
 | 
			
		||||
        <property name="text">
 | 
			
		||||
         <string>Low cut.</string>
 | 
			
		||||
        </property>
 | 
			
		||||
       </widget>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item>
 | 
			
		||||
       <widget class="QSlider" name="lowCut">
 | 
			
		||||
        <property name="toolTip">
 | 
			
		||||
         <string>Highpass filter cutoff frequency (SSB)</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="minimum">
 | 
			
		||||
         <number>-60</number>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="maximum">
 | 
			
		||||
         <number>60</number>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="pageStep">
 | 
			
		||||
         <number>1</number>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="value">
 | 
			
		||||
         <number>3</number>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="orientation">
 | 
			
		||||
         <enum>Qt::Horizontal</enum>
 | 
			
		||||
        </property>
 | 
			
		||||
       </widget>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item>
 | 
			
		||||
       <widget class="QLabel" name="lowCutText">
 | 
			
		||||
        <property name="minimumSize">
 | 
			
		||||
         <size>
 | 
			
		||||
          <width>50</width>
 | 
			
		||||
          <height>0</height>
 | 
			
		||||
         </size>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="text">
 | 
			
		||||
         <string>0.3k</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="alignment">
 | 
			
		||||
         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
 | 
			
		||||
        </property>
 | 
			
		||||
       </widget>
 | 
			
		||||
      </item>
 | 
			
		||||
     </layout>
 | 
			
		||||
    </item>
 | 
			
		||||
   </layout>
 | 
			
		||||
  </widget>
 | 
			
		||||
  <widget class="QWidget" name="spectrumContainer" native="true">
 | 
			
		||||
   <property name="geometry">
 | 
			
		||||
    <rect>
 | 
			
		||||
     <x>10</x>
 | 
			
		||||
     <y>180</y>
 | 
			
		||||
     <width>636</width>
 | 
			
		||||
     <height>284</height>
 | 
			
		||||
    </rect>
 | 
			
		||||
   </property>
 | 
			
		||||
   <property name="minimumSize">
 | 
			
		||||
    <size>
 | 
			
		||||
     <width>636</width>
 | 
			
		||||
     <height>0</height>
 | 
			
		||||
    </size>
 | 
			
		||||
   </property>
 | 
			
		||||
   <property name="windowTitle">
 | 
			
		||||
    <string>Channel Spectrum</string>
 | 
			
		||||
   </property>
 | 
			
		||||
   <layout class="QVBoxLayout" name="verticalLayoutSpectrum">
 | 
			
		||||
    <property name="spacing">
 | 
			
		||||
     <number>2</number>
 | 
			
		||||
    </property>
 | 
			
		||||
    <property name="leftMargin">
 | 
			
		||||
     <number>2</number>
 | 
			
		||||
    </property>
 | 
			
		||||
    <property name="topMargin">
 | 
			
		||||
     <number>2</number>
 | 
			
		||||
    </property>
 | 
			
		||||
    <property name="rightMargin">
 | 
			
		||||
     <number>2</number>
 | 
			
		||||
    </property>
 | 
			
		||||
    <property name="bottomMargin">
 | 
			
		||||
     <number>2</number>
 | 
			
		||||
    </property>
 | 
			
		||||
    <item>
 | 
			
		||||
     <widget class="GLSpectrum" name="glSpectrum" native="true">
 | 
			
		||||
      <property name="minimumSize">
 | 
			
		||||
       <size>
 | 
			
		||||
        <width>200</width>
 | 
			
		||||
        <height>250</height>
 | 
			
		||||
       </size>
 | 
			
		||||
      </property>
 | 
			
		||||
      <property name="font">
 | 
			
		||||
       <font>
 | 
			
		||||
        <family>Monospace</family>
 | 
			
		||||
        <pointsize>8</pointsize>
 | 
			
		||||
       </font>
 | 
			
		||||
      </property>
 | 
			
		||||
     </widget>
 | 
			
		||||
    </item>
 | 
			
		||||
    <item>
 | 
			
		||||
     <widget class="GLSpectrumGUI" name="spectrumGUI" native="true"/>
 | 
			
		||||
    </item>
 | 
			
		||||
   </layout>
 | 
			
		||||
  </widget>
 | 
			
		||||
  <widget class="QWidget" name="scopeContainer" native="true">
 | 
			
		||||
   <property name="geometry">
 | 
			
		||||
    <rect>
 | 
			
		||||
     <x>0</x>
 | 
			
		||||
     <y>470</y>
 | 
			
		||||
     <width>636</width>
 | 
			
		||||
     <height>284</height>
 | 
			
		||||
    </rect>
 | 
			
		||||
   </property>
 | 
			
		||||
   <property name="minimumSize">
 | 
			
		||||
    <size>
 | 
			
		||||
     <width>636</width>
 | 
			
		||||
     <height>0</height>
 | 
			
		||||
    </size>
 | 
			
		||||
   </property>
 | 
			
		||||
   <property name="windowTitle">
 | 
			
		||||
    <string>Channel Scope</string>
 | 
			
		||||
   </property>
 | 
			
		||||
   <layout class="QVBoxLayout" name="verticalLayoutScope">
 | 
			
		||||
    <property name="spacing">
 | 
			
		||||
     <number>2</number>
 | 
			
		||||
    </property>
 | 
			
		||||
    <property name="leftMargin">
 | 
			
		||||
     <number>3</number>
 | 
			
		||||
    </property>
 | 
			
		||||
    <property name="topMargin">
 | 
			
		||||
     <number>3</number>
 | 
			
		||||
    </property>
 | 
			
		||||
    <property name="rightMargin">
 | 
			
		||||
     <number>3</number>
 | 
			
		||||
    </property>
 | 
			
		||||
    <property name="bottomMargin">
 | 
			
		||||
     <number>3</number>
 | 
			
		||||
    </property>
 | 
			
		||||
    <item>
 | 
			
		||||
     <widget class="GLScopeNG" name="glScope" native="true">
 | 
			
		||||
      <property name="minimumSize">
 | 
			
		||||
       <size>
 | 
			
		||||
        <width>200</width>
 | 
			
		||||
        <height>250</height>
 | 
			
		||||
       </size>
 | 
			
		||||
      </property>
 | 
			
		||||
      <property name="font">
 | 
			
		||||
       <font>
 | 
			
		||||
        <family>Monospace</family>
 | 
			
		||||
        <pointsize>8</pointsize>
 | 
			
		||||
       </font>
 | 
			
		||||
      </property>
 | 
			
		||||
     </widget>
 | 
			
		||||
    </item>
 | 
			
		||||
    <item>
 | 
			
		||||
     <widget class="GLScopeNGGUI" name="scopeGUI" native="true"/>
 | 
			
		||||
    </item>
 | 
			
		||||
   </layout>
 | 
			
		||||
  </widget>
 | 
			
		||||
 </widget>
 | 
			
		||||
 <customwidgets>
 | 
			
		||||
  <customwidget>
 | 
			
		||||
   <class>RollupWidget</class>
 | 
			
		||||
   <extends>QWidget</extends>
 | 
			
		||||
   <header>gui/rollupwidget.h</header>
 | 
			
		||||
   <container>1</container>
 | 
			
		||||
  </customwidget>
 | 
			
		||||
  <customwidget>
 | 
			
		||||
   <class>ValueDial</class>
 | 
			
		||||
   <extends>QWidget</extends>
 | 
			
		||||
   <header>gui/valuedial.h</header>
 | 
			
		||||
   <container>1</container>
 | 
			
		||||
  </customwidget>
 | 
			
		||||
  <customwidget>
 | 
			
		||||
   <class>GLSpectrum</class>
 | 
			
		||||
   <extends>QWidget</extends>
 | 
			
		||||
   <header>gui/glspectrum.h</header>
 | 
			
		||||
   <container>1</container>
 | 
			
		||||
  </customwidget>
 | 
			
		||||
  <customwidget>
 | 
			
		||||
   <class>GLSpectrumGUI</class>
 | 
			
		||||
   <extends>QWidget</extends>
 | 
			
		||||
   <header>gui/glspectrumgui.h</header>
 | 
			
		||||
   <container>1</container>
 | 
			
		||||
  </customwidget>
 | 
			
		||||
  <customwidget>
 | 
			
		||||
   <class>GLScopeNG</class>
 | 
			
		||||
   <extends>QWidget</extends>
 | 
			
		||||
   <header>gui/glscopeng.h</header>
 | 
			
		||||
   <container>1</container>
 | 
			
		||||
  </customwidget>
 | 
			
		||||
  <customwidget>
 | 
			
		||||
   <class>GLScopeNGGUI</class>
 | 
			
		||||
   <extends>QWidget</extends>
 | 
			
		||||
   <header>gui/glscopenggui.h</header>
 | 
			
		||||
   <container>1</container>
 | 
			
		||||
  </customwidget>
 | 
			
		||||
 </customwidgets>
 | 
			
		||||
 <resources>
 | 
			
		||||
  <include location="../../../sdrbase/resources/res.qrc"/>
 | 
			
		||||
 </resources>
 | 
			
		||||
 <connections/>
 | 
			
		||||
</ui>
 | 
			
		||||
							
								
								
									
										64
									
								
								plugins/channelrx/chanalyzerng/chanalyzerngplugin.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								plugins/channelrx/chanalyzerng/chanalyzerngplugin.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,64 @@
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Copyright (C) 2017 Edouard Griffiths, F4EXB                                   //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 as version 3 of the License, or                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 V3 for more details.                               //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// You should have received a copy of the GNU General Public License             //
 | 
			
		||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
#include <QtPlugin>
 | 
			
		||||
 | 
			
		||||
#include "plugin/pluginapi.h"
 | 
			
		||||
#include "chanalyzerngplugin.h"
 | 
			
		||||
#include "chanalyzernggui.h"
 | 
			
		||||
 | 
			
		||||
const PluginDescriptor ChannelAnalyzerNGPlugin::m_pluginDescriptor = {
 | 
			
		||||
	QString("Channel Analyzer NG"),
 | 
			
		||||
	QString("3.2.0"),
 | 
			
		||||
	QString("(c) Edouard Griffiths, F4EXB"),
 | 
			
		||||
	QString("https://github.com/f4exb/sdrangel"),
 | 
			
		||||
	true,
 | 
			
		||||
	QString("https://github.com/f4exb/sdrangel")
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ChannelAnalyzerNGPlugin::ChannelAnalyzerNGPlugin(QObject* parent) :
 | 
			
		||||
	QObject(parent)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const PluginDescriptor& ChannelAnalyzerNGPlugin::getPluginDescriptor() const
 | 
			
		||||
{
 | 
			
		||||
	return m_pluginDescriptor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGPlugin::initPlugin(PluginAPI* pluginAPI)
 | 
			
		||||
{
 | 
			
		||||
	m_pluginAPI = pluginAPI;
 | 
			
		||||
 | 
			
		||||
	// register demodulator
 | 
			
		||||
	m_pluginAPI->registerRxChannel(ChannelAnalyzerNGGUI::m_channelID, this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PluginGUI* ChannelAnalyzerNGPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
 | 
			
		||||
{
 | 
			
		||||
	if(channelName == ChannelAnalyzerNGGUI::m_channelID)
 | 
			
		||||
	{
 | 
			
		||||
	    ChannelAnalyzerNGGUI* gui = ChannelAnalyzerNGGUI::create(m_pluginAPI, deviceAPI);
 | 
			
		||||
		return gui;
 | 
			
		||||
	} else {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChannelAnalyzerNGPlugin::createInstanceChannelAnalyzer(DeviceSourceAPI *deviceAPI)
 | 
			
		||||
{
 | 
			
		||||
    ChannelAnalyzerNGGUI* gui = ChannelAnalyzerNGGUI::create(m_pluginAPI, deviceAPI);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								plugins/channelrx/chanalyzerng/chanalyzerngplugin.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								plugins/channelrx/chanalyzerng/chanalyzerngplugin.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Copyright (C) 2017 Edouard Griffiths, F4EXB                                   //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 as version 3 of the License, or                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 V3 for more details.                               //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// You should have received a copy of the GNU General Public License             //
 | 
			
		||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
#ifndef INCLUDE_CHANALYZERNGPLUGIN_H
 | 
			
		||||
#define INCLUDE_CHANALYZERNGPLUGIN_H
 | 
			
		||||
 | 
			
		||||
#include <QObject>
 | 
			
		||||
 | 
			
		||||
#include "plugin/plugininterface.h"
 | 
			
		||||
 | 
			
		||||
class DeviceSourceAPI;
 | 
			
		||||
 | 
			
		||||
class ChannelAnalyzerNGPlugin : public QObject, PluginInterface {
 | 
			
		||||
	Q_OBJECT
 | 
			
		||||
	Q_INTERFACES(PluginInterface)
 | 
			
		||||
	Q_PLUGIN_METADATA(IID "sdrangel.channel.chanalyzerng")
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	explicit ChannelAnalyzerNGPlugin(QObject* parent = NULL);
 | 
			
		||||
 | 
			
		||||
	const PluginDescriptor& getPluginDescriptor() const;
 | 
			
		||||
	void initPlugin(PluginAPI* pluginAPI);
 | 
			
		||||
 | 
			
		||||
	PluginGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	static const PluginDescriptor m_pluginDescriptor;
 | 
			
		||||
 | 
			
		||||
	PluginAPI* m_pluginAPI;
 | 
			
		||||
 | 
			
		||||
private slots:
 | 
			
		||||
	void createInstanceChannelAnalyzer(DeviceSourceAPI *deviceAPI);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // INCLUDE_CHANALYZERNGPLUGIN_H
 | 
			
		||||
							
								
								
									
										299
									
								
								sdrbase/dsp/scopevisng.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										299
									
								
								sdrbase/dsp/scopevisng.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,299 @@
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Copyright (C) 2017 F4EXB                                                      //
 | 
			
		||||
// written by Edouard Griffiths                                                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 as version 3 of the License, or                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 V3 for more details.                               //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// You should have received a copy of the GNU General Public License             //
 | 
			
		||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
#include "scopevisng.h"
 | 
			
		||||
#include "gui/glscopeng.h"
 | 
			
		||||
 | 
			
		||||
MESSAGE_CLASS_DEFINITION(ScopeVisNG::MsgConfigureScopeVisNG, Message)
 | 
			
		||||
MESSAGE_CLASS_DEFINITION(ScopeVisNG::MsgScopeVisNGAddTrigger, Message)
 | 
			
		||||
MESSAGE_CLASS_DEFINITION(ScopeVisNG::MsgScopeVisNGRemoveTrigger, Message)
 | 
			
		||||
 | 
			
		||||
const uint ScopeVisNG::m_traceChunkSize = 4800;
 | 
			
		||||
const Real ScopeVisNG::ProjectorMagDB::mult = (10.0f / log2f(10.0f));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ScopeVisNG::ScopeVisNG(GLScopeNG* glScope) :
 | 
			
		||||
    m_glScope(glScope),
 | 
			
		||||
	m_preTriggerDelay(0),
 | 
			
		||||
	m_currentTriggerIndex(0),
 | 
			
		||||
	m_triggerState(TriggerUntriggered),
 | 
			
		||||
	m_traceSize(m_traceChunkSize),
 | 
			
		||||
	m_traceStart(true),
 | 
			
		||||
	m_traceFill(0),
 | 
			
		||||
	m_zTraceIndex(-1),
 | 
			
		||||
	m_traceCompleteCount(0)
 | 
			
		||||
{
 | 
			
		||||
    setObjectName("ScopeVisNG");
 | 
			
		||||
    m_tracebackBuffers.resize(1);
 | 
			
		||||
    m_tracebackBuffers[0].resize(4*m_traceChunkSize);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ScopeVisNG::~ScopeVisNG()
 | 
			
		||||
{
 | 
			
		||||
	std::vector<TriggerCondition>::iterator it = m_triggerConditions.begin();
 | 
			
		||||
 | 
			
		||||
	for (; it != m_triggerConditions.end(); ++it)
 | 
			
		||||
	{
 | 
			
		||||
		delete it->m_projector;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ScopeVisNG::configure(MessageQueue* msgQueue,
 | 
			
		||||
        uint traceSize)
 | 
			
		||||
{
 | 
			
		||||
    Message* cmd = MsgConfigureScopeVisNG::create(traceSize);
 | 
			
		||||
    msgQueue->push(cmd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void ScopeVisNG::feed(const SampleVector::const_iterator& cbegin, const SampleVector::const_iterator& end, bool positiveOnly)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t feedIndex = 0; // TODO: redefine feed interface so it can be passed a feed index
 | 
			
		||||
 | 
			
		||||
    if (m_triggerState == TriggerFreeRun) {
 | 
			
		||||
        m_triggerPoint = cbegin;
 | 
			
		||||
    }
 | 
			
		||||
    else if (m_triggerState == TriggerTriggered) {
 | 
			
		||||
        m_triggerPoint = cbegin;
 | 
			
		||||
    }
 | 
			
		||||
    else if (m_triggerState == TriggerUntriggered) {
 | 
			
		||||
        m_triggerPoint = end;
 | 
			
		||||
    }
 | 
			
		||||
    else if (m_triggerState == TriggerWait) {
 | 
			
		||||
        m_triggerPoint = end;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        m_triggerPoint = cbegin;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	if (m_triggerState == TriggerNewConfig)
 | 
			
		||||
	{
 | 
			
		||||
		m_triggerState = TriggerUntriggered;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((m_triggerConditions.size() > 0) && (m_triggerState == TriggerWait)) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m_tracebackBuffers[feedIndex].write(cbegin, end);
 | 
			
		||||
	SampleVector::const_iterator begin(cbegin);
 | 
			
		||||
	TriggerCondition& triggerCondition = m_triggerConditions[m_currentTriggerIndex];
 | 
			
		||||
 | 
			
		||||
	// trigger process
 | 
			
		||||
	if ((m_triggerConditions.size() > 0) && (feedIndex == triggerCondition.m_inputIndex))
 | 
			
		||||
	{
 | 
			
		||||
        while (begin < end)
 | 
			
		||||
        {
 | 
			
		||||
            if (m_triggerState == TriggerUntriggered)
 | 
			
		||||
            {
 | 
			
		||||
				bool condition = triggerCondition.m_projector->run(*begin) > triggerCondition.m_triggerLevel;
 | 
			
		||||
				bool trigger;
 | 
			
		||||
 | 
			
		||||
				if (triggerCondition.m_triggerBothEdges) {
 | 
			
		||||
					trigger = triggerCondition.m_prevCondition ^ condition;
 | 
			
		||||
				} else {
 | 
			
		||||
					trigger = condition ^ !triggerCondition.m_triggerPositiveEdge;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (trigger)
 | 
			
		||||
				{
 | 
			
		||||
					if (triggerCondition.m_triggerDelay > 0)
 | 
			
		||||
					{
 | 
			
		||||
						triggerCondition.m_triggerDelayCount = triggerCondition.m_triggerDelay;
 | 
			
		||||
						m_triggerState == TriggerDelay;
 | 
			
		||||
					}
 | 
			
		||||
					else
 | 
			
		||||
					{
 | 
			
		||||
					    if (triggerCondition.m_triggerCounts > 0)
 | 
			
		||||
					    {
 | 
			
		||||
					        triggerCondition.m_triggerCounts--;
 | 
			
		||||
					        m_triggerState = TriggerUntriggered;
 | 
			
		||||
					    }
 | 
			
		||||
					    else
 | 
			
		||||
					    {
 | 
			
		||||
					        // next trigger
 | 
			
		||||
	                        m_currentTriggerIndex++;
 | 
			
		||||
 | 
			
		||||
	                        if (m_currentTriggerIndex == m_triggerConditions.size())
 | 
			
		||||
	                        {
 | 
			
		||||
	                            m_currentTriggerIndex = 0;
 | 
			
		||||
	                            m_triggerState = TriggerTriggered;
 | 
			
		||||
	                            m_triggerPoint = begin;
 | 
			
		||||
	                            m_traceStart = true;
 | 
			
		||||
	                            break;
 | 
			
		||||
	                        }
 | 
			
		||||
	                        else
 | 
			
		||||
	                        {
 | 
			
		||||
	                            m_triggerState = TriggerUntriggered;
 | 
			
		||||
	                        }
 | 
			
		||||
					    }
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
            else if (m_triggerState == TriggerDelay)
 | 
			
		||||
            {
 | 
			
		||||
                if (triggerCondition.m_triggerDelayCount > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    triggerCondition.m_triggerDelayCount--;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    triggerCondition.m_triggerDelayCount = 0;
 | 
			
		||||
 | 
			
		||||
                    // next trigger
 | 
			
		||||
                    m_currentTriggerIndex++;
 | 
			
		||||
 | 
			
		||||
                    if (m_currentTriggerIndex == m_triggerConditions.size())
 | 
			
		||||
                    {
 | 
			
		||||
                        m_currentTriggerIndex = 0;
 | 
			
		||||
                        m_triggerState = TriggerTriggered;
 | 
			
		||||
                        m_triggerPoint = begin;
 | 
			
		||||
                        m_traceStart = true;
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        // initialize a new trace
 | 
			
		||||
                        m_triggerState = TriggerUntriggered;
 | 
			
		||||
                        m_traceCompleteCount = 0;
 | 
			
		||||
                        m_triggerState = TriggerUntriggered;
 | 
			
		||||
 | 
			
		||||
                        feed(begin, end, positiveOnly); // process the rest of samples
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ++begin;
 | 
			
		||||
		} // begin < end
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// trace process
 | 
			
		||||
	if ((m_triggerConditions.size() == 0) || (m_triggerState == TriggerTriggered))
 | 
			
		||||
	{
 | 
			
		||||
	    // trace back
 | 
			
		||||
 | 
			
		||||
	    if (m_traceStart)
 | 
			
		||||
	    {
 | 
			
		||||
	        int count = begin - cbegin; // number of samples consumed since begin
 | 
			
		||||
	        std::vector<Trace>::iterator itTrace = m_traces.begin();
 | 
			
		||||
 | 
			
		||||
	        for (;itTrace != m_traces.end(); ++itTrace)
 | 
			
		||||
	        {
 | 
			
		||||
	            if (itTrace->m_inputIndex == feedIndex)
 | 
			
		||||
	            {
 | 
			
		||||
	                SampleVector::const_iterator startPoint = m_tracebackBuffers[feedIndex].getCurrent() - count;
 | 
			
		||||
                    SampleVector::const_iterator prevPoint = m_tracebackBuffers[feedIndex].getCurrent() - count - m_preTriggerDelay - itTrace->m_traceDelay;
 | 
			
		||||
                    processPrevTrace(prevPoint, startPoint, itTrace);
 | 
			
		||||
	            }
 | 
			
		||||
	        }
 | 
			
		||||
 | 
			
		||||
	        m_traceStart = false;
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
	    // live trace
 | 
			
		||||
 | 
			
		||||
	    int shift = (m_timeOfsProMill / 1000.0) * m_traceSize;
 | 
			
		||||
 | 
			
		||||
	    while (begin < end)
 | 
			
		||||
	    {
 | 
			
		||||
	        for (std::vector<Trace>::iterator itTrace = m_traces.begin(); itTrace != m_traces.end(); ++itTrace)
 | 
			
		||||
	        {
 | 
			
		||||
	            if (itTrace->m_inputIndex == feedIndex)
 | 
			
		||||
	            {
 | 
			
		||||
	                float posLimit = 1.0 / itTrace->m_amp;
 | 
			
		||||
	                float negLimit = -1.0 / itTrace->m_amp;
 | 
			
		||||
 | 
			
		||||
	                if (itTrace->m_traceCount < m_traceSize)
 | 
			
		||||
	                {
 | 
			
		||||
	                    float v = itTrace->m_projector->run(*begin) * itTrace->m_amp + itTrace->m_shift;
 | 
			
		||||
 | 
			
		||||
	                    if(v > posLimit) {
 | 
			
		||||
	                        v = posLimit;
 | 
			
		||||
	                    } else if (v < negLimit) {
 | 
			
		||||
	                        v = negLimit;
 | 
			
		||||
	                    }
 | 
			
		||||
 | 
			
		||||
	                    itTrace->m_trace[2*(itTrace->m_traceCount)] = itTrace->m_traceCount - shift;
 | 
			
		||||
	                    itTrace->m_trace[2*(itTrace->m_traceCount)+1] = v;
 | 
			
		||||
 | 
			
		||||
	                    itTrace->m_traceCount++;
 | 
			
		||||
	                }
 | 
			
		||||
	                else
 | 
			
		||||
	                {
 | 
			
		||||
	                    itTrace->m_traceCount = 0;
 | 
			
		||||
 | 
			
		||||
	                    if (m_traceCompleteCount < m_traces.size())
 | 
			
		||||
	                    {
 | 
			
		||||
	                        m_traceCompleteCount++;
 | 
			
		||||
	                    }
 | 
			
		||||
	                    else
 | 
			
		||||
	                    {
 | 
			
		||||
	                        //m_glScope->newTraces((DisplayTraces&) m_traces);  // TODO: glScopeNG new traces
 | 
			
		||||
	                        m_traceCompleteCount = 0;
 | 
			
		||||
	                    }
 | 
			
		||||
	                }
 | 
			
		||||
	            }
 | 
			
		||||
	        }
 | 
			
		||||
 | 
			
		||||
	        begin++;
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ScopeVisNG::processPrevTrace(SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, std::vector<Trace>::iterator& trace)
 | 
			
		||||
{
 | 
			
		||||
    int shift = (m_timeOfsProMill / 1000.0) * m_traceSize;
 | 
			
		||||
    float posLimit = 1.0 / trace->m_amp;
 | 
			
		||||
    float negLimit = -1.0 / trace->m_amp;
 | 
			
		||||
 | 
			
		||||
    while (begin < end)
 | 
			
		||||
    {
 | 
			
		||||
        float v = trace->m_projector->run(*begin) * trace->m_amp + trace->m_shift;
 | 
			
		||||
 | 
			
		||||
        if(v > posLimit) {
 | 
			
		||||
            v = posLimit;
 | 
			
		||||
        } else if (v < negLimit) {
 | 
			
		||||
            v = negLimit;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        trace->m_trace[2*(trace->m_traceCount)] = (trace->m_traceCount - shift); // display x
 | 
			
		||||
        trace->m_trace[2*(trace->m_traceCount) + 1] = v;                         // display y
 | 
			
		||||
 | 
			
		||||
        trace->m_traceCount++;
 | 
			
		||||
        begin++;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ScopeVisNG::start()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ScopeVisNG::stop()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ScopeVisNG::handleMessage(const Message& message)
 | 
			
		||||
{
 | 
			
		||||
    qDebug() << "ScopeVisNG::handleMessage" << message.getIdentifier();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										285
									
								
								sdrbase/dsp/scopevisng.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										285
									
								
								sdrbase/dsp/scopevisng.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,285 @@
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Copyright (C) 2017 F4EXB                                                      //
 | 
			
		||||
// written by Edouard Griffiths                                                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 as version 3 of the License, or                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 V3 for more details.                               //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// You should have received a copy of the GNU General Public License             //
 | 
			
		||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
#ifndef SDRBASE_DSP_SCOPEVISNG_H_
 | 
			
		||||
#define SDRBASE_DSP_SCOPEVISNG_H_
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <boost/circular_buffer.hpp>
 | 
			
		||||
#include "dsp/dsptypes.h"
 | 
			
		||||
#include "dsp/basebandsamplesink.h"
 | 
			
		||||
#include "util/export.h"
 | 
			
		||||
#include "util/message.h"
 | 
			
		||||
#include "util/doublebuffer.h"
 | 
			
		||||
 | 
			
		||||
class GLScopeNG;
 | 
			
		||||
 | 
			
		||||
class SDRANGEL_API ScopeVisNG : public BasebandSampleSink {
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	enum ProjectionType
 | 
			
		||||
	{
 | 
			
		||||
		ProjectionReal,    //!< Extract real part
 | 
			
		||||
		ProjectionImag,    //!< Extract imaginary part
 | 
			
		||||
		ProjectionMagLin,  //!< Calculate linear magnitude or modulus
 | 
			
		||||
		ProjectionMagDB,   //!< Calculate logarithmic (dB) of squared magnitude
 | 
			
		||||
		ProjectionPhase,   //!< Calculate phase
 | 
			
		||||
		ProjectionDPhase   //!< Calculate phase derivative i.e. instantaneous frequency scaled to sample rate
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct DisplayTrace
 | 
			
		||||
	{
 | 
			
		||||
	    float *m_trace;                  //!< Displayable trace (interleaved x,y of GLfloat)
 | 
			
		||||
	    ProjectionType m_projectionType; //!< Complex to real projection type
 | 
			
		||||
	    float m_amp;                     //!< Amplification factor
 | 
			
		||||
	    float m_ofs;                     //!< Offset factor
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
    typedef std::vector<DisplayTrace> DisplayTraces;
 | 
			
		||||
 | 
			
		||||
    static const uint m_traceChunkSize;
 | 
			
		||||
    static const uint m_nbTriggers = 10;
 | 
			
		||||
 | 
			
		||||
    ScopeVisNG(GLScopeNG* glScope = 0);
 | 
			
		||||
    virtual ~ScopeVisNG();
 | 
			
		||||
 | 
			
		||||
    void configure(MessageQueue* msgQueue,
 | 
			
		||||
            uint32_t traceSize);
 | 
			
		||||
 | 
			
		||||
    virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly);
 | 
			
		||||
    virtual void start();
 | 
			
		||||
    virtual void stop();
 | 
			
		||||
    virtual bool handleMessage(const Message& message);
 | 
			
		||||
    SampleVector::const_iterator getTriggerPoint() const { return m_triggerPoint; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    typedef DoubleBufferSimple<Sample> TraceBuffer;
 | 
			
		||||
 | 
			
		||||
    class MsgConfigureScopeVisNG : public Message {
 | 
			
		||||
        MESSAGE_CLASS_DECLARATION
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        static MsgConfigureScopeVisNG* create(
 | 
			
		||||
            uint32_t traceSize)
 | 
			
		||||
        {
 | 
			
		||||
            return new MsgConfigureScopeVisNG(traceSize);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        uint32_t m_traceSize;
 | 
			
		||||
 | 
			
		||||
        MsgConfigureScopeVisNG(uint32_t traceSize) :
 | 
			
		||||
            m_traceSize(traceSize)
 | 
			
		||||
        {}
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class MsgScopeVisNGAddTrigger : public Message {
 | 
			
		||||
        MESSAGE_CLASS_DECLARATION
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        static MsgScopeVisNGAddTrigger* create(
 | 
			
		||||
        		ProjectionType projectionType)
 | 
			
		||||
        {
 | 
			
		||||
            return new MsgScopeVisNGAddTrigger(projectionType);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        ProjectionType m_projectionType;
 | 
			
		||||
 | 
			
		||||
        MsgScopeVisNGAddTrigger(ProjectionType projectionType) :
 | 
			
		||||
        	m_projectionType(projectionType)
 | 
			
		||||
        {}
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class MsgScopeVisNGRemoveTrigger : public Message {
 | 
			
		||||
        MESSAGE_CLASS_DECLARATION
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        static MsgScopeVisNGRemoveTrigger* create(
 | 
			
		||||
                uint32_t triggerIndex)
 | 
			
		||||
        {
 | 
			
		||||
            return new MsgScopeVisNGRemoveTrigger(triggerIndex);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        uint32_t m_triggerIndex;
 | 
			
		||||
 | 
			
		||||
        MsgScopeVisNGRemoveTrigger(uint32_t triggerIndex) :
 | 
			
		||||
        	m_triggerIndex(triggerIndex)
 | 
			
		||||
        {}
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class Projector
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        Projector(ProjectionType projectionType) : m_projectionType(projectionType) {}
 | 
			
		||||
 | 
			
		||||
        ProjectionType getProjectionType() const { return m_projectionType; }
 | 
			
		||||
        virtual Real run(const Sample& s) = 0;
 | 
			
		||||
    private:
 | 
			
		||||
        ProjectionType m_projectionType;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class ProjectorReal : public Projector
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        ProjectorReal() : Projector(ProjectionReal) {}
 | 
			
		||||
        virtual Real run(const Sample& s) { return s.m_real / 32768.0f; }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class ProjectorImag : public Projector
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        ProjectorImag() : Projector(ProjectionImag) {}
 | 
			
		||||
        virtual Real run(const Sample& s) { return s.m_imag / 32768.0f; }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class ProjectorMagLin : public Projector
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        ProjectorMagLin() : Projector(ProjectionMagLin) {}
 | 
			
		||||
        virtual Real run(const Sample& s)
 | 
			
		||||
        {
 | 
			
		||||
            uint32_t magsq = s.m_real*s.m_real + s.m_imag*s.m_imag;
 | 
			
		||||
            return std::sqrt(magsq/1073741824.0f);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class ProjectorMagDB : public Projector
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        ProjectorMagDB() : Projector(ProjectionMagDB) {}
 | 
			
		||||
        virtual Real run(const Sample& s)
 | 
			
		||||
        {
 | 
			
		||||
            uint32_t magsq = s.m_real*s.m_real + s.m_imag*s.m_imag;
 | 
			
		||||
            return mult * log2f(magsq/1073741824.0f);
 | 
			
		||||
        }
 | 
			
		||||
    private:
 | 
			
		||||
        static const Real mult;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class ProjectorPhase : public Projector
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        ProjectorPhase() : Projector(ProjectionPhase) {}
 | 
			
		||||
        virtual Real run(const Sample& s) { return std::atan2((float) s.m_imag, (float) s.m_real) / M_PI;  }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class ProjectorDPhase : public Projector
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        ProjectorDPhase() : Projector(ProjectionDPhase), m_prevArg(0.0f) {}
 | 
			
		||||
        virtual Real run(const Sample& s)
 | 
			
		||||
        {
 | 
			
		||||
            Real curArg = std::atan2((float) s.m_imag, (float) s.m_real) / M_PI;
 | 
			
		||||
            Real dPhi = curArg - m_prevArg;
 | 
			
		||||
            m_prevArg = curArg;
 | 
			
		||||
 | 
			
		||||
            if (dPhi < -M_PI) {
 | 
			
		||||
                dPhi += 2.0 * M_PI;
 | 
			
		||||
            } else if (dPhi > M_PI) {
 | 
			
		||||
                dPhi -= 2.0 * M_PI;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return dPhi;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        Real m_prevArg;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    enum TriggerState
 | 
			
		||||
	{
 | 
			
		||||
        TriggerFreeRun,     //!< Trigger is disabled
 | 
			
		||||
    	TriggerUntriggered, //!< Trigger is not kicked off yet (or trigger list is empty)
 | 
			
		||||
		TriggerTriggered,   //!< Trigger has been kicked off
 | 
			
		||||
		TriggerWait,        //!< In one shot mode trigger waits for manual re-enabling
 | 
			
		||||
		TriggerDelay,       //!< Trigger conditions have been kicked off but it is waiting for delay before final kick off
 | 
			
		||||
		TriggerNewConfig,   //!< Special condition when a new configuration has been received
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
    struct TriggerCondition
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
    	Projector *m_projector;       //!< Projector transform from complex trace to reaL trace usable for triggering
 | 
			
		||||
    	uint32_t m_inputIndex;        //!< Input or feed index this trigger is associated with
 | 
			
		||||
        Real m_triggerLevel;          //!< Level in real units
 | 
			
		||||
        bool m_triggerPositiveEdge;   //!< Trigger on the positive edge (else negative)
 | 
			
		||||
        bool m_triggerBothEdges;      //!< Trigger on both edges (else only one)
 | 
			
		||||
        bool m_prevCondition;         //!< Condition (above threshold) at previous sample
 | 
			
		||||
        uint32_t m_triggerDelay;      //!< Delay before the trigger is kicked off in number of samples
 | 
			
		||||
        uint32_t m_triggerDelayCount; //!< Counter of samples for delay
 | 
			
		||||
        uint32_t m_triggerCounts;     //!< Number of trigger conditions before the final decisive trigger
 | 
			
		||||
 | 
			
		||||
        TriggerCondition(Projector *projector) :
 | 
			
		||||
        	m_projector(projector),
 | 
			
		||||
			m_inputIndex(0),
 | 
			
		||||
            m_triggerLevel(0.0f),
 | 
			
		||||
            m_triggerPositiveEdge(true),
 | 
			
		||||
            m_triggerBothEdges(false),
 | 
			
		||||
			m_prevCondition(false),
 | 
			
		||||
            m_triggerDelay(0),
 | 
			
		||||
            m_triggerDelayCount(0),
 | 
			
		||||
            m_triggerCounts(0)
 | 
			
		||||
        {}
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct Trace : public DisplayTrace
 | 
			
		||||
    {
 | 
			
		||||
    	Projector *m_projector; //!< Projector transform from complex trace to real (displayable) trace
 | 
			
		||||
    	uint32_t m_inputIndex;  //!< Input or feed index this trace is associated with
 | 
			
		||||
    	int m_traceDelay;       //!< Trace delay in number of samples
 | 
			
		||||
    	int m_traceCount;       //!< Count of samples processed
 | 
			
		||||
    	float m_amp;            //!< Linear trace amplifier factor
 | 
			
		||||
    	float m_shift;          //!< Linear trace shift
 | 
			
		||||
 | 
			
		||||
    	Trace(Projector *projector, Real *displayTraceBuffer) :
 | 
			
		||||
    		m_projector(projector),
 | 
			
		||||
    		m_inputIndex(0),
 | 
			
		||||
			m_traceDelay(0),
 | 
			
		||||
			m_traceCount(0),
 | 
			
		||||
			m_amp(1.0f),
 | 
			
		||||
			m_shift(0.0f)
 | 
			
		||||
    	{
 | 
			
		||||
    	    m_projectionType = m_projector->getProjectionType();
 | 
			
		||||
    	    m_trace = displayTraceBuffer;
 | 
			
		||||
    	}
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    GLScopeNG* m_glScope;
 | 
			
		||||
    std::vector<TraceBuffer> m_tracebackBuffers; //!< One complex (Sample type) trace buffer per input source or feed
 | 
			
		||||
    DoubleBufferSimple<Sample> m_traceback;      //!< FIFO to handle delayed processes
 | 
			
		||||
    int m_preTriggerDelay;                       //!< Pre-trigger delay in number of samples
 | 
			
		||||
    std::vector<TriggerCondition> m_triggerConditions; //!< Chain of triggers
 | 
			
		||||
    int m_currentTriggerIndex;                   //!< Index of current index in the chain
 | 
			
		||||
    TriggerState m_triggerState;                 //!< Current trigger state
 | 
			
		||||
    std::vector<Trace> m_traces;                 //!< One trace control object per display trace allocated to X, Y[n] or Z
 | 
			
		||||
    int m_traceSize;                             //!< Size of traces in number of samples
 | 
			
		||||
    int m_timeOfsProMill;                        //!< Start trace shift in 1/1000 trace size
 | 
			
		||||
    bool m_traceStart;                           //!< Trace is at start point
 | 
			
		||||
    int m_traceFill;                             //!< Count of samples accumulated into trace
 | 
			
		||||
    int m_zTraceIndex;                           //!< Index of the trace used for Z input (luminance or false colors)
 | 
			
		||||
    int m_traceCompleteCount;                    //!< Count of completed traces
 | 
			
		||||
    SampleVector::const_iterator m_triggerPoint; //!< Trigger start location in the samples vector
 | 
			
		||||
 | 
			
		||||
    void processPrevTrace(SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, std::vector<Trace>::iterator& trace);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* SDRBASE_DSP_SCOPEVISNG_H_ */
 | 
			
		||||
							
								
								
									
										41
									
								
								sdrbase/dsp/spectrumscopengcombovis.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								sdrbase/dsp/spectrumscopengcombovis.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
#include "dsp/spectrumscopengcombovis.h"
 | 
			
		||||
#include "dsp/dspcommands.h"
 | 
			
		||||
#include "util/messagequeue.h"
 | 
			
		||||
 | 
			
		||||
SpectrumScopeNGComboVis::SpectrumScopeNGComboVis(SpectrumVis* spectrumVis, ScopeVisNG* scopeVis) :
 | 
			
		||||
	m_spectrumVis(spectrumVis),
 | 
			
		||||
	m_scopeVis(scopeVis)
 | 
			
		||||
{
 | 
			
		||||
	setObjectName("SpectrumScopeNGComboVis");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SpectrumScopeNGComboVis::~SpectrumScopeNGComboVis()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SpectrumScopeNGComboVis::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly)
 | 
			
		||||
{
 | 
			
		||||
	m_scopeVis->feed(begin, end, false);
 | 
			
		||||
	SampleVector::const_iterator triggerPoint = m_scopeVis->getTriggerPoint();
 | 
			
		||||
	m_spectrumVis->feedTriggered(triggerPoint, begin, end, positiveOnly);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SpectrumScopeNGComboVis::start()
 | 
			
		||||
{
 | 
			
		||||
	m_spectrumVis->start();
 | 
			
		||||
	m_scopeVis->start();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SpectrumScopeNGComboVis::stop()
 | 
			
		||||
{
 | 
			
		||||
	m_spectrumVis->stop();
 | 
			
		||||
	m_scopeVis->stop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SpectrumScopeNGComboVis::handleMessage(const Message& message)
 | 
			
		||||
{
 | 
			
		||||
	bool spectDone = m_spectrumVis->handleMessage(message);
 | 
			
		||||
	bool scopeDone = m_scopeVis->handleMessage(message);
 | 
			
		||||
 | 
			
		||||
	return (spectDone || scopeDone);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								sdrbase/dsp/spectrumscopengcombovis.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								sdrbase/dsp/spectrumscopengcombovis.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
#ifndef INCLUDE_SPECTRUMSCOPENGCOMBOVIS_H
 | 
			
		||||
#define INCLUDE_SPECTRUMSCOPENGCOMBOVIS_H
 | 
			
		||||
 | 
			
		||||
#include <dsp/basebandsamplesink.h>
 | 
			
		||||
#include "dsp/spectrumvis.h"
 | 
			
		||||
#include "dsp/scopevisng.h"
 | 
			
		||||
#include "util/export.h"
 | 
			
		||||
 | 
			
		||||
class Message;
 | 
			
		||||
 | 
			
		||||
class SDRANGEL_API SpectrumScopeNGComboVis : public BasebandSampleSink {
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    SpectrumScopeNGComboVis(SpectrumVis* spectrumVis, ScopeVisNG* scopeVis);
 | 
			
		||||
	virtual ~SpectrumScopeNGComboVis();
 | 
			
		||||
 | 
			
		||||
	virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly);
 | 
			
		||||
	virtual void start();
 | 
			
		||||
	virtual void stop();
 | 
			
		||||
	virtual bool handleMessage(const Message& message);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	SpectrumVis* m_spectrumVis;
 | 
			
		||||
	ScopeVisNG* m_scopeVis;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // INCLUDE_SPECTRUMSCOPENGCOMBOVIS_H
 | 
			
		||||
							
								
								
									
										996
									
								
								sdrbase/gui/glscopeng.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										996
									
								
								sdrbase/gui/glscopeng.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,996 @@
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Copyright (C) 2017 F4EXB                                                      //
 | 
			
		||||
// written by Edouard Griffiths                                                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 as version 3 of the License, or                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 V3 for more details.                               //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// You should have received a copy of the GNU General Public License             //
 | 
			
		||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
#include <QPainter>
 | 
			
		||||
#include <QMouseEvent>
 | 
			
		||||
#include <QOpenGLContext>
 | 
			
		||||
#include <QOpenGLFunctions>
 | 
			
		||||
#include <QSurface>
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
 | 
			
		||||
#include "glscopeng.h"
 | 
			
		||||
 | 
			
		||||
GLScopeNG::GLScopeNG(QWidget* parent) :
 | 
			
		||||
    QGLWidget(parent),
 | 
			
		||||
    m_displayMode(DisplayX),
 | 
			
		||||
    m_dataChanged(false),
 | 
			
		||||
    m_configChanged(false),
 | 
			
		||||
    m_traces(0),
 | 
			
		||||
    m_displayGridIntensity(10),
 | 
			
		||||
    m_displayTraceIntensity(50),
 | 
			
		||||
    m_timeBase(1),
 | 
			
		||||
    m_traceSize(0),
 | 
			
		||||
    m_sampleRate(0),
 | 
			
		||||
    m_triggerPre(0),
 | 
			
		||||
    m_timeOfsProMill(0),
 | 
			
		||||
    m_highlightedTraceIndex(0)
 | 
			
		||||
{
 | 
			
		||||
    setAttribute(Qt::WA_OpaquePaintEvent);
 | 
			
		||||
    connect(&m_timer, SIGNAL(timeout()), this, SLOT(tick()));
 | 
			
		||||
    m_timer.start(50);
 | 
			
		||||
 | 
			
		||||
    m_y1Scale.setFont(font());
 | 
			
		||||
    m_y1Scale.setOrientation(Qt::Vertical);
 | 
			
		||||
    m_y2Scale.setFont(font());
 | 
			
		||||
    m_y2Scale.setOrientation(Qt::Vertical);
 | 
			
		||||
    m_x1Scale.setFont(font());
 | 
			
		||||
    m_x1Scale.setOrientation(Qt::Horizontal);
 | 
			
		||||
    m_x2Scale.setFont(font());
 | 
			
		||||
    m_x2Scale.setOrientation(Qt::Horizontal);
 | 
			
		||||
 | 
			
		||||
    m_powerOverlayFont.setBold(true);
 | 
			
		||||
    m_powerOverlayFont.setPointSize(font().pointSize()+1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GLScopeNG::~GLScopeNG()
 | 
			
		||||
{
 | 
			
		||||
    cleanup();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNG::newTraces()
 | 
			
		||||
{
 | 
			
		||||
    if (m_traces)
 | 
			
		||||
    {
 | 
			
		||||
        if(!m_mutex.tryLock(2))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        m_dataChanged = true;
 | 
			
		||||
 | 
			
		||||
        m_mutex.unlock();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNG::initializeGL()
 | 
			
		||||
{
 | 
			
		||||
    QOpenGLContext *glCurrentContext =  QOpenGLContext::currentContext();
 | 
			
		||||
 | 
			
		||||
    if (glCurrentContext) {
 | 
			
		||||
        if (QOpenGLContext::currentContext()->isValid()) {
 | 
			
		||||
            qDebug() << "GLScopeNG::initializeGL: context:"
 | 
			
		||||
                << " major: " << (QOpenGLContext::currentContext()->format()).majorVersion()
 | 
			
		||||
                << " minor: " << (QOpenGLContext::currentContext()->format()).minorVersion()
 | 
			
		||||
                << " ES: " << (QOpenGLContext::currentContext()->isOpenGLES() ? "yes" : "no");
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            qDebug() << "GLScopeNG::initializeGL: current context is invalid";
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        qCritical() << "GLScopeNG::initializeGL: no current context";
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    QSurface *surface = glCurrentContext->surface();
 | 
			
		||||
 | 
			
		||||
    if (surface == 0)
 | 
			
		||||
    {
 | 
			
		||||
        qCritical() << "GLScopeNG::initializeGL: no surface attached";
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        if (surface->surfaceType() != QSurface::OpenGLSurface)
 | 
			
		||||
        {
 | 
			
		||||
            qCritical() << "GLScopeNG::initializeGL: surface is not an OpenGLSurface: " << surface->surfaceType()
 | 
			
		||||
                << " cannot use an OpenGL context";
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            qDebug() << "GLScopeNG::initializeGL: OpenGL surface:"
 | 
			
		||||
                << " class: " << (surface->surfaceClass() == QSurface::Window ? "Window" : "Offscreen");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    connect(glCurrentContext, &QOpenGLContext::aboutToBeDestroyed, this, &GLScopeNG::cleanup); // TODO: when migrating to QOpenGLWidget
 | 
			
		||||
 | 
			
		||||
    QOpenGLFunctions *glFunctions = QOpenGLContext::currentContext()->functions();
 | 
			
		||||
    glFunctions->initializeOpenGLFunctions();
 | 
			
		||||
 | 
			
		||||
    //glDisable(GL_DEPTH_TEST);
 | 
			
		||||
    m_glShaderSimple.initializeGL();
 | 
			
		||||
    m_glShaderLeft1Scale.initializeGL();
 | 
			
		||||
    m_glShaderBottom1Scale.initializeGL();
 | 
			
		||||
    m_glShaderLeft2Scale.initializeGL();
 | 
			
		||||
    m_glShaderBottom2Scale.initializeGL();
 | 
			
		||||
    m_glShaderPowerOverlay.initializeGL();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNG::resizeGL(int width, int height)
 | 
			
		||||
{
 | 
			
		||||
    QOpenGLFunctions *glFunctions = QOpenGLContext::currentContext()->functions();
 | 
			
		||||
    glFunctions->glViewport(0, 0, width, height);
 | 
			
		||||
    m_configChanged = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNG::paintGL()
 | 
			
		||||
{
 | 
			
		||||
    if(!m_mutex.tryLock(2))
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if(m_configChanged)
 | 
			
		||||
        applyConfig();
 | 
			
		||||
 | 
			
		||||
    QOpenGLFunctions *glFunctions = QOpenGLContext::currentContext()->functions();
 | 
			
		||||
    glFunctions->glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
 | 
			
		||||
    glFunctions->glClear(GL_COLOR_BUFFER_BIT);
 | 
			
		||||
 | 
			
		||||
    if (m_displayMode == DisplayX) // display only trace #0
 | 
			
		||||
    {
 | 
			
		||||
        // draw rect around
 | 
			
		||||
        {
 | 
			
		||||
            GLfloat q3[] {
 | 
			
		||||
                1, 1,
 | 
			
		||||
                0, 1,
 | 
			
		||||
                0, 0,
 | 
			
		||||
                1, 0
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            QVector4D color(1.0f, 1.0f, 1.0f, 0.5f);
 | 
			
		||||
            m_glShaderSimple.drawContour(m_glScopeMatrix1, color, q3, 4);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // paint grid
 | 
			
		||||
        const ScaleEngine::TickList* tickList;
 | 
			
		||||
        const ScaleEngine::Tick* tick;
 | 
			
		||||
 | 
			
		||||
        // Y1 (X trace or trace #0)
 | 
			
		||||
        {
 | 
			
		||||
            tickList = &m_y1Scale.getTickList();
 | 
			
		||||
 | 
			
		||||
            GLfloat q3[4*tickList->count()];
 | 
			
		||||
            int effectiveTicks = 0;
 | 
			
		||||
 | 
			
		||||
            for (int i= 0; i < tickList->count(); i++)
 | 
			
		||||
            {
 | 
			
		||||
                tick = &(*tickList)[i];
 | 
			
		||||
 | 
			
		||||
                if (tick->major)
 | 
			
		||||
                {
 | 
			
		||||
                    if (tick->textSize > 0)
 | 
			
		||||
                    {
 | 
			
		||||
                        float y = 1 - (tick->pos / m_y1Scale.getSize());
 | 
			
		||||
                        q3[4*effectiveTicks] = 0;
 | 
			
		||||
                        q3[4*effectiveTicks+1] = y;
 | 
			
		||||
                        q3[4*effectiveTicks+2] = 1;
 | 
			
		||||
                        q3[4*effectiveTicks+3] = y;
 | 
			
		||||
                        effectiveTicks++;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            float blue = 1.0f;
 | 
			
		||||
            QVector4D color(1.0f, 1.0f, blue, (float) m_displayGridIntensity / 100.0f);
 | 
			
		||||
            m_glShaderSimple.drawSegments(m_glScopeMatrix1, color, q3, 2*effectiveTicks);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // X1 (time)
 | 
			
		||||
        {
 | 
			
		||||
            tickList = &m_x1Scale.getTickList();
 | 
			
		||||
 | 
			
		||||
            GLfloat q3[4*tickList->count()];
 | 
			
		||||
            int effectiveTicks = 0;
 | 
			
		||||
            for(int i= 0; i < tickList->count(); i++) {
 | 
			
		||||
                tick = &(*tickList)[i];
 | 
			
		||||
                if(tick->major) {
 | 
			
		||||
                    if(tick->textSize > 0) {
 | 
			
		||||
                        float x = tick->pos / m_x1Scale.getSize();
 | 
			
		||||
                        q3[4*effectiveTicks] = x;
 | 
			
		||||
                        q3[4*effectiveTicks+1] = 0;
 | 
			
		||||
                        q3[4*effectiveTicks+2] = x;
 | 
			
		||||
                        q3[4*effectiveTicks+3] = 1;
 | 
			
		||||
                        effectiveTicks++;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            QVector4D color(1.0f, 1.0f, 1.0f, (float) m_displayGridIntensity / 100.0f);
 | 
			
		||||
            m_glShaderSimple.drawSegments(m_glScopeMatrix1, color, q3, 2*effectiveTicks);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // paint left #1 scale
 | 
			
		||||
        {
 | 
			
		||||
            GLfloat vtx1[] = {
 | 
			
		||||
                    0, 1,
 | 
			
		||||
                    1, 1,
 | 
			
		||||
                    1, 0,
 | 
			
		||||
                    0, 0
 | 
			
		||||
            };
 | 
			
		||||
            GLfloat tex1[] = {
 | 
			
		||||
                    0, 1,
 | 
			
		||||
                    1, 1,
 | 
			
		||||
                    1, 0,
 | 
			
		||||
                    0, 0
 | 
			
		||||
            };
 | 
			
		||||
            m_glShaderLeft1Scale.drawSurface(m_glLeft1ScaleMatrix, tex1, vtx1, 4);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // paint bottom #1 scale
 | 
			
		||||
        {
 | 
			
		||||
            GLfloat vtx1[] = {
 | 
			
		||||
                    0, 1,
 | 
			
		||||
                    1, 1,
 | 
			
		||||
                    1, 0,
 | 
			
		||||
                    0, 0
 | 
			
		||||
            };
 | 
			
		||||
            GLfloat tex1[] = {
 | 
			
		||||
                    0, 1,
 | 
			
		||||
                    1, 1,
 | 
			
		||||
                    1, 0,
 | 
			
		||||
                    0, 0
 | 
			
		||||
            };
 | 
			
		||||
            m_glShaderBottom1Scale.drawSurface(m_glBot1ScaleMatrix, tex1, vtx1, 4);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // TODO: paint trigger level #1
 | 
			
		||||
 | 
			
		||||
        // paint trace #1
 | 
			
		||||
        if (m_traceSize > 0)
 | 
			
		||||
        {
 | 
			
		||||
            const ScopeVisNG::DisplayTrace& trace = (*m_traces)[0];
 | 
			
		||||
            int start = (m_timeOfsProMill/1000.0) * m_traceSize;
 | 
			
		||||
            int end = std::min(start + m_traceSize/m_timeBase, m_traceSize);
 | 
			
		||||
            if(end - start < 2)
 | 
			
		||||
                start--;
 | 
			
		||||
 | 
			
		||||
            float rectX = m_glScopeRect1.x();
 | 
			
		||||
            float rectY = m_glScopeRect1.y() + m_glScopeRect1.height() / 2.0f;
 | 
			
		||||
            float rectW = m_glScopeRect1.width() * (float)m_timeBase / (float)(m_traceSize - 1);
 | 
			
		||||
            float rectH = -(m_glScopeRect1.height() / 2.0f) * trace.m_amp;
 | 
			
		||||
 | 
			
		||||
            QVector4D color(1.0f, 1.0f, 0.25f, m_displayTraceIntensity / 100.0f);
 | 
			
		||||
            QMatrix4x4 mat;
 | 
			
		||||
            mat.setToIdentity();
 | 
			
		||||
            mat.translate(-1.0f + 2.0f * rectX, 1.0f - 2.0f * rectY);
 | 
			
		||||
            mat.scale(2.0f * rectW, -2.0f * rectH);
 | 
			
		||||
            m_glShaderSimple.drawPolyline(mat, color, (GLfloat *) &trace.m_trace[2*start], end - start);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_dataChanged = false;
 | 
			
		||||
    m_mutex.unlock();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNG::setSampleRate(int sampleRate)
 | 
			
		||||
{
 | 
			
		||||
    m_sampleRate = sampleRate;
 | 
			
		||||
    m_configChanged = true;
 | 
			
		||||
    update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNG::setTimeBase(int timeBase)
 | 
			
		||||
{
 | 
			
		||||
    m_timeBase = timeBase;
 | 
			
		||||
    m_configChanged = true;
 | 
			
		||||
    update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNG::setTriggerPre(Real triggerPre)
 | 
			
		||||
{
 | 
			
		||||
    m_triggerPre = triggerPre;
 | 
			
		||||
    m_configChanged = true;
 | 
			
		||||
    update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNG::setTimeOfsProMill(int timeOfsProMill)
 | 
			
		||||
{
 | 
			
		||||
    m_timeOfsProMill = timeOfsProMill;
 | 
			
		||||
    m_configChanged = true;
 | 
			
		||||
    update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNG::setHighlightedTraceIndex(uint32_t traceIndex)
 | 
			
		||||
{
 | 
			
		||||
    m_highlightedTraceIndex = traceIndex;
 | 
			
		||||
    m_configChanged = true;
 | 
			
		||||
    update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNG::setDisplayMode(DisplayMode displayMode)
 | 
			
		||||
{
 | 
			
		||||
    m_displayMode = displayMode;
 | 
			
		||||
    m_configChanged = true;
 | 
			
		||||
    update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNG::setTraceSize(int traceSize)
 | 
			
		||||
{
 | 
			
		||||
    m_traceSize = traceSize;
 | 
			
		||||
    m_configChanged = true;
 | 
			
		||||
    update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNG::applyConfig()
 | 
			
		||||
{
 | 
			
		||||
    m_configChanged = false;
 | 
			
		||||
 | 
			
		||||
    QFontMetrics fm(font());
 | 
			
		||||
    int M = fm.width("-");
 | 
			
		||||
    float t_start = ((m_timeOfsProMill / 1000.0) - m_triggerPre) * ((float) m_traceSize / m_sampleRate);
 | 
			
		||||
    float t_len = ((float) m_traceSize / m_sampleRate) / (float) m_timeBase;
 | 
			
		||||
 | 
			
		||||
    m_x1Scale.setRange(Unit::Time, t_start, t_start + t_len); // time scale
 | 
			
		||||
    m_x2Scale.setRange(Unit::Time, t_start, t_start + t_len); // time scale
 | 
			
		||||
 | 
			
		||||
    if (m_traces)
 | 
			
		||||
    {
 | 
			
		||||
        if (m_traces->size() > 0)
 | 
			
		||||
        {
 | 
			
		||||
            setYScale(m_y1Scale, 0); // This is always the X trace (trace #0)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ((m_traces->size() > 1) && (m_highlightedTraceIndex < m_traces->size()))
 | 
			
		||||
        {
 | 
			
		||||
            setYScale(m_y2Scale, m_highlightedTraceIndex > 0 ? m_highlightedTraceIndex : 1); // if Highlighted trace is #0 (X trace) set it to first Y trace (trace #1)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((m_displayMode == DisplayX) || (m_displayMode == DisplayY)) // unique display
 | 
			
		||||
    {
 | 
			
		||||
        int scopeHeight = height() - m_topMargin - m_botMargin;
 | 
			
		||||
        int scopeWidth = width() - m_leftMargin - m_rightMargin;
 | 
			
		||||
 | 
			
		||||
        m_glScopeRect1 = QRectF(
 | 
			
		||||
            (float) m_leftMargin / (float) width(),
 | 
			
		||||
            (float) m_topMargin / (float) height(),
 | 
			
		||||
            (float) scopeWidth / (float) width(),
 | 
			
		||||
            (float) scopeHeight / (float) height()
 | 
			
		||||
        );
 | 
			
		||||
        m_glScopeMatrix1.setToIdentity();
 | 
			
		||||
        m_glScopeMatrix1.translate (
 | 
			
		||||
            -1.0f + ((float) 2*m_leftMargin / (float) width()),
 | 
			
		||||
             1.0f - ((float) 2*m_topMargin / (float) height())
 | 
			
		||||
        );
 | 
			
		||||
        m_glScopeMatrix1.scale (
 | 
			
		||||
            (float) 2*scopeWidth / (float) width(),
 | 
			
		||||
            (float) -2*scopeHeight / (float) height()
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        m_glBot1ScaleMatrix.setToIdentity();
 | 
			
		||||
        m_glBot1ScaleMatrix.translate (
 | 
			
		||||
            -1.0f + ((float) 2*m_leftMargin / (float) width()),
 | 
			
		||||
             1.0f - ((float) 2*(scopeHeight + m_topMargin + 1) / (float) height())
 | 
			
		||||
        );
 | 
			
		||||
        m_glBot1ScaleMatrix.scale (
 | 
			
		||||
            (float) 2*scopeWidth / (float) width(),
 | 
			
		||||
            (float) -2*(m_botMargin - 1) / (float) height()
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        m_glLeft1ScaleMatrix.setToIdentity();
 | 
			
		||||
        m_glLeft1ScaleMatrix.translate (
 | 
			
		||||
            -1.0f,
 | 
			
		||||
             1.0f - ((float) 2*m_topMargin / (float) height())
 | 
			
		||||
        );
 | 
			
		||||
        m_glLeft1ScaleMatrix.scale (
 | 
			
		||||
            (float) 2*(m_leftMargin-1) / (float) width(),
 | 
			
		||||
            (float) -2*scopeHeight / (float) height()
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        { // X1 scale
 | 
			
		||||
            m_x1Scale.setSize(scopeWidth);
 | 
			
		||||
 | 
			
		||||
            m_bot1ScalePixmap = QPixmap(
 | 
			
		||||
                scopeWidth,
 | 
			
		||||
                m_botMargin - 1
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            const ScaleEngine::TickList* tickList;
 | 
			
		||||
            const ScaleEngine::Tick* tick;
 | 
			
		||||
 | 
			
		||||
            m_bot1ScalePixmap.fill(Qt::black);
 | 
			
		||||
            QPainter painter(&m_bot1ScalePixmap);
 | 
			
		||||
            painter.setPen(QColor(0xf0, 0xf0, 0xff));
 | 
			
		||||
            painter.setFont(font());
 | 
			
		||||
            tickList = &m_x1Scale.getTickList();
 | 
			
		||||
 | 
			
		||||
            for(int i = 0; i < tickList->count(); i++) {
 | 
			
		||||
                tick = &(*tickList)[i];
 | 
			
		||||
                if(tick->major) {
 | 
			
		||||
                    if(tick->textSize > 0) {
 | 
			
		||||
                        painter.drawText(QPointF(tick->textPos, fm.height() - 1), tick->text);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            m_glShaderBottom1Scale.initTexture(m_bot1ScalePixmap.toImage());
 | 
			
		||||
 | 
			
		||||
        } // X1 scale
 | 
			
		||||
 | 
			
		||||
        if (m_displayMode == DisplayX) // use Y1 scale
 | 
			
		||||
        {
 | 
			
		||||
            m_y1Scale.setSize(scopeHeight);
 | 
			
		||||
 | 
			
		||||
            m_left1ScalePixmap = QPixmap(
 | 
			
		||||
                m_leftMargin - 1,
 | 
			
		||||
                scopeHeight
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            const ScaleEngine::TickList* tickList;
 | 
			
		||||
            const ScaleEngine::Tick* tick;
 | 
			
		||||
 | 
			
		||||
            m_left1ScalePixmap.fill(Qt::black);
 | 
			
		||||
            QPainter painter(&m_left1ScalePixmap);
 | 
			
		||||
            painter.setPen(QColor(0xf0, 0xf0, 0xff));
 | 
			
		||||
            painter.setFont(font());
 | 
			
		||||
            tickList = &m_y1Scale.getTickList();
 | 
			
		||||
 | 
			
		||||
            for(int i = 0; i < tickList->count(); i++) {
 | 
			
		||||
                tick = &(*tickList)[i];
 | 
			
		||||
                if(tick->major) {
 | 
			
		||||
                    if(tick->textSize > 0) {
 | 
			
		||||
                        painter.drawText(QPointF(m_leftMargin - M - tick->textSize, m_topMargin + scopeHeight - tick->textPos - fm.ascent()/2), tick->text);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            m_glShaderLeft1Scale.initTexture(m_left1ScalePixmap.toImage());
 | 
			
		||||
        }
 | 
			
		||||
        else if (m_displayMode == DisplayY) // use Y2 scale
 | 
			
		||||
        {
 | 
			
		||||
            m_y2Scale.setSize(scopeHeight);
 | 
			
		||||
 | 
			
		||||
            m_left2ScalePixmap = QPixmap(
 | 
			
		||||
                m_leftMargin - 1,
 | 
			
		||||
                scopeHeight
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            const ScaleEngine::TickList* tickList;
 | 
			
		||||
            const ScaleEngine::Tick* tick;
 | 
			
		||||
 | 
			
		||||
            m_left2ScalePixmap.fill(Qt::black);
 | 
			
		||||
            QPainter painter(&m_left2ScalePixmap);
 | 
			
		||||
            painter.setPen(QColor(0xf0, 0xf0, 0xff));
 | 
			
		||||
            painter.setFont(font());
 | 
			
		||||
            tickList = &m_y2Scale.getTickList();
 | 
			
		||||
 | 
			
		||||
            for(int i = 0; i < tickList->count(); i++) {
 | 
			
		||||
                tick = &(*tickList)[i];
 | 
			
		||||
                if(tick->major) {
 | 
			
		||||
                    if(tick->textSize > 0) {
 | 
			
		||||
                        painter.drawText(QPointF(m_leftMargin - M - tick->textSize, m_topMargin + scopeHeight - tick->textPos - fm.ascent()/2), tick->text);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            m_glShaderLeft2Scale.initTexture(m_left2ScalePixmap.toImage());
 | 
			
		||||
        } // Y scales
 | 
			
		||||
    } // single display
 | 
			
		||||
    else // dual display (X+Y or polar)
 | 
			
		||||
    {
 | 
			
		||||
        // left (first) display
 | 
			
		||||
        if ((m_displayMode == DisplayXYH) || (m_displayMode == DisplayPol)) // horizontal split of first display
 | 
			
		||||
        {
 | 
			
		||||
            int scopeHeight = height() - m_topMargin - m_botMargin;
 | 
			
		||||
            int scopeWidth = (width() - m_rightMargin)/2 - m_leftMargin;
 | 
			
		||||
 | 
			
		||||
            m_glScopeRect1 = QRectF(
 | 
			
		||||
                (float) m_leftMargin / (float) width(),
 | 
			
		||||
                (float) m_topMargin / (float) height(),
 | 
			
		||||
                (float) scopeWidth / (float) width(),
 | 
			
		||||
                (float) scopeHeight / (float) height()
 | 
			
		||||
            );
 | 
			
		||||
            m_glScopeMatrix1.setToIdentity();
 | 
			
		||||
            m_glScopeMatrix1.translate (
 | 
			
		||||
                -1.0f + ((float) 2*m_leftMargin / (float) width()),
 | 
			
		||||
                 1.0f - ((float) 2*m_topMargin / (float) height())
 | 
			
		||||
            );
 | 
			
		||||
            m_glScopeMatrix1.scale (
 | 
			
		||||
                (float) 2*scopeWidth / (float) width(),
 | 
			
		||||
                (float) -2*scopeHeight / (float) height()
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            m_glBot1ScaleMatrix.setToIdentity();
 | 
			
		||||
            m_glBot1ScaleMatrix.translate (
 | 
			
		||||
                -1.0f + ((float) 2*m_leftMargin / (float) width()),
 | 
			
		||||
                 1.0f - ((float) 2*(scopeHeight + m_topMargin + 1) / (float) height())
 | 
			
		||||
            );
 | 
			
		||||
            m_glBot1ScaleMatrix.scale (
 | 
			
		||||
                (float) 2*scopeWidth / (float) width(),
 | 
			
		||||
                (float) -2*(m_botMargin - 1) / (float) height()
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            m_glLeft1ScaleMatrix.setToIdentity();
 | 
			
		||||
            m_glLeft1ScaleMatrix.translate (
 | 
			
		||||
                -1.0f,
 | 
			
		||||
                 1.0f - ((float) 2*m_topMargin / (float) height())
 | 
			
		||||
            );
 | 
			
		||||
            m_glLeft1ScaleMatrix.scale (
 | 
			
		||||
                (float) 2*(m_leftMargin-1) / (float) width(),
 | 
			
		||||
                (float) -2*scopeHeight / (float) height()
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            { // Y1 scale
 | 
			
		||||
                m_y1Scale.setSize(scopeHeight);
 | 
			
		||||
 | 
			
		||||
                m_left1ScalePixmap = QPixmap(
 | 
			
		||||
                    m_leftMargin - 1,
 | 
			
		||||
                    scopeHeight
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                const ScaleEngine::TickList* tickList;
 | 
			
		||||
                const ScaleEngine::Tick* tick;
 | 
			
		||||
 | 
			
		||||
                m_left1ScalePixmap.fill(Qt::black);
 | 
			
		||||
                QPainter painter(&m_left1ScalePixmap);
 | 
			
		||||
                painter.setPen(QColor(0xf0, 0xf0, 0xff));
 | 
			
		||||
                painter.setFont(font());
 | 
			
		||||
                tickList = &m_y1Scale.getTickList();
 | 
			
		||||
 | 
			
		||||
                for(int i = 0; i < tickList->count(); i++) {
 | 
			
		||||
                    tick = &(*tickList)[i];
 | 
			
		||||
                    if(tick->major) {
 | 
			
		||||
                        if(tick->textSize > 0) {
 | 
			
		||||
                            painter.drawText(QPointF(m_leftMargin - M - tick->textSize, m_topMargin + scopeHeight - tick->textPos - fm.ascent()/2), tick->text);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                m_glShaderLeft1Scale.initTexture(m_left1ScalePixmap.toImage());
 | 
			
		||||
 | 
			
		||||
            } // Y1 scale
 | 
			
		||||
            { // X1 scale
 | 
			
		||||
                m_x1Scale.setSize(scopeWidth);
 | 
			
		||||
 | 
			
		||||
                m_bot1ScalePixmap = QPixmap(
 | 
			
		||||
                    scopeWidth,
 | 
			
		||||
                    m_botMargin - 1
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                const ScaleEngine::TickList* tickList;
 | 
			
		||||
                const ScaleEngine::Tick* tick;
 | 
			
		||||
 | 
			
		||||
                m_bot1ScalePixmap.fill(Qt::black);
 | 
			
		||||
                QPainter painter(&m_bot1ScalePixmap);
 | 
			
		||||
                painter.setPen(QColor(0xf0, 0xf0, 0xff));
 | 
			
		||||
                painter.setFont(font());
 | 
			
		||||
                tickList = &m_x1Scale.getTickList();
 | 
			
		||||
 | 
			
		||||
                for(int i = 0; i < tickList->count(); i++) {
 | 
			
		||||
                    tick = &(*tickList)[i];
 | 
			
		||||
                    if(tick->major) {
 | 
			
		||||
                        if(tick->textSize > 0) {
 | 
			
		||||
                            painter.drawText(QPointF(tick->textPos, fm.height() - 1), tick->text);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                m_glShaderBottom1Scale.initTexture(m_bot1ScalePixmap.toImage());
 | 
			
		||||
 | 
			
		||||
            } // X1 scale
 | 
			
		||||
        }
 | 
			
		||||
        else // vertical split of first display
 | 
			
		||||
        {
 | 
			
		||||
            int scopeHeight = (height() - m_topMargin) / 2 - m_botMargin;
 | 
			
		||||
            int scopeWidth = width() - m_leftMargin - m_rightMargin;
 | 
			
		||||
 | 
			
		||||
            m_glScopeRect1 = QRectF(
 | 
			
		||||
                (float) m_leftMargin / (float) width(),
 | 
			
		||||
                (float) m_topMargin / (float) height(),
 | 
			
		||||
                (float) scopeWidth / (float) width(),
 | 
			
		||||
                (float) scopeHeight / (float) height()
 | 
			
		||||
            );
 | 
			
		||||
            m_glScopeMatrix1.setToIdentity();
 | 
			
		||||
            m_glScopeMatrix1.translate (
 | 
			
		||||
                -1.0f + ((float) 2*m_leftMargin / (float) width()),
 | 
			
		||||
                 1.0f - ((float) 2*m_topMargin / (float) height())
 | 
			
		||||
            );
 | 
			
		||||
            m_glScopeMatrix1.scale (
 | 
			
		||||
                (float) 2*scopeWidth / (float) width(),
 | 
			
		||||
                (float) -2*scopeHeight / (float) height()
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            m_glBot1ScaleMatrix.setToIdentity();
 | 
			
		||||
            m_glBot1ScaleMatrix.translate (
 | 
			
		||||
                -1.0f + ((float) 2*m_leftMargin / (float) width()),
 | 
			
		||||
                 1.0f - ((float) 2*(scopeHeight + m_topMargin + 1) / (float) height())
 | 
			
		||||
            );
 | 
			
		||||
            m_glBot1ScaleMatrix.scale (
 | 
			
		||||
                (float) 2*scopeWidth / (float) width(),
 | 
			
		||||
                (float) -2*(m_botMargin - 1) / (float) height()
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            m_glLeft1ScaleMatrix.setToIdentity();
 | 
			
		||||
            m_glLeft1ScaleMatrix.translate (
 | 
			
		||||
                -1.0f,
 | 
			
		||||
                 1.0f - ((float) 2*m_topMargin / (float) height())
 | 
			
		||||
            );
 | 
			
		||||
            m_glLeft1ScaleMatrix.scale (
 | 
			
		||||
                (float) 2*(m_leftMargin-1) / (float) width(),
 | 
			
		||||
                (float) -2*scopeHeight / (float) height()
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            { // Y1 scale
 | 
			
		||||
                m_y1Scale.setSize(scopeHeight);
 | 
			
		||||
 | 
			
		||||
                m_left1ScalePixmap = QPixmap(
 | 
			
		||||
                    m_leftMargin - 1,
 | 
			
		||||
                    scopeHeight
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                const ScaleEngine::TickList* tickList;
 | 
			
		||||
                const ScaleEngine::Tick* tick;
 | 
			
		||||
 | 
			
		||||
                m_left1ScalePixmap.fill(Qt::black);
 | 
			
		||||
                QPainter painter(&m_left1ScalePixmap);
 | 
			
		||||
                painter.setPen(QColor(0xf0, 0xf0, 0xff));
 | 
			
		||||
                painter.setFont(font());
 | 
			
		||||
                tickList = &m_y1Scale.getTickList();
 | 
			
		||||
 | 
			
		||||
                for(int i = 0; i < tickList->count(); i++) {
 | 
			
		||||
                    tick = &(*tickList)[i];
 | 
			
		||||
                    if(tick->major) {
 | 
			
		||||
                        if(tick->textSize > 0) {
 | 
			
		||||
                            painter.drawText(QPointF(m_leftMargin - M - tick->textSize, m_topMargin + scopeHeight - tick->textPos - fm.ascent()/2), tick->text);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                m_glShaderLeft1Scale.initTexture(m_left1ScalePixmap.toImage());
 | 
			
		||||
 | 
			
		||||
            } // Y1 scale
 | 
			
		||||
            { // X1 scale
 | 
			
		||||
                m_x1Scale.setSize(scopeWidth);
 | 
			
		||||
 | 
			
		||||
                m_bot1ScalePixmap = QPixmap(
 | 
			
		||||
                    scopeWidth,
 | 
			
		||||
                    m_botMargin - 1
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                const ScaleEngine::TickList* tickList;
 | 
			
		||||
                const ScaleEngine::Tick* tick;
 | 
			
		||||
 | 
			
		||||
                m_bot1ScalePixmap.fill(Qt::black);
 | 
			
		||||
                QPainter painter(&m_bot1ScalePixmap);
 | 
			
		||||
                painter.setPen(QColor(0xf0, 0xf0, 0xff));
 | 
			
		||||
                painter.setFont(font());
 | 
			
		||||
                tickList = &m_x1Scale.getTickList();
 | 
			
		||||
 | 
			
		||||
                for(int i = 0; i < tickList->count(); i++) {
 | 
			
		||||
                    tick = &(*tickList)[i];
 | 
			
		||||
                    if(tick->major) {
 | 
			
		||||
                        if(tick->textSize > 0) {
 | 
			
		||||
                            painter.drawText(QPointF(tick->textPos, fm.height() - 1), tick->text);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                m_glShaderBottom1Scale.initTexture(m_bot1ScalePixmap.toImage());
 | 
			
		||||
 | 
			
		||||
            } // X1 scale
 | 
			
		||||
        } // hotizontal or vertical split of first display
 | 
			
		||||
        // right (second) display
 | 
			
		||||
        if (m_displayMode == DisplayPol) // in Polar mode second display is square and split is horizontal
 | 
			
		||||
        {
 | 
			
		||||
            int scopeHeight = height() - m_topMargin - m_botMargin;
 | 
			
		||||
            int scopeWidth = (width() - m_rightMargin)/2 - m_leftMargin;
 | 
			
		||||
 | 
			
		||||
            int scopeDim = std::min(scopeWidth, scopeHeight);
 | 
			
		||||
 | 
			
		||||
            m_glScopeRect2 = QRectF(
 | 
			
		||||
                (float)(m_leftMargin + scopeWidth + m_leftMargin) / (float)width(),
 | 
			
		||||
                (float)m_topMargin / (float)height(),
 | 
			
		||||
                (float) scopeDim / (float)width(),
 | 
			
		||||
                (float)(height() - m_topMargin - m_botMargin) / (float)height()
 | 
			
		||||
            );
 | 
			
		||||
            m_glScopeMatrix2.setToIdentity();
 | 
			
		||||
            m_glScopeMatrix2.translate (
 | 
			
		||||
                -1.0f + ((float) 2*(m_leftMargin + scopeWidth + m_leftMargin) / (float) width()),
 | 
			
		||||
                 1.0f - ((float) 2*m_topMargin / (float) height())
 | 
			
		||||
            );
 | 
			
		||||
            m_glScopeMatrix2.scale (
 | 
			
		||||
                (float) 2*scopeDim / (float) width(),
 | 
			
		||||
                (float) -2*(height() - m_topMargin - m_botMargin) / (float) height()
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            m_glLeft2ScaleMatrix.setToIdentity();
 | 
			
		||||
            m_glLeft2ScaleMatrix.translate (
 | 
			
		||||
                -1.0f + (float) 2*(m_leftMargin + scopeWidth) / (float) width(),
 | 
			
		||||
                 1.0f - ((float) 2*m_topMargin / (float) height())
 | 
			
		||||
            );
 | 
			
		||||
            m_glLeft2ScaleMatrix.scale (
 | 
			
		||||
                (float) 2*(m_leftMargin-1) / (float) width(),
 | 
			
		||||
                (float) -2*scopeHeight / (float) height()
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            m_glBot2ScaleMatrix.setToIdentity();
 | 
			
		||||
            m_glBot2ScaleMatrix.translate (
 | 
			
		||||
                -1.0f + ((float) 2*(m_leftMargin + m_leftMargin + scopeWidth) / (float) width()),
 | 
			
		||||
                 1.0f - ((float) 2*(scopeHeight + m_topMargin + 1) / (float) height())
 | 
			
		||||
            );
 | 
			
		||||
            m_glBot2ScaleMatrix.scale (
 | 
			
		||||
                (float) 2*scopeDim / (float) width(),
 | 
			
		||||
                (float) -2*(m_botMargin - 1) / (float) height()
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        else // both displays are similar and share space equally
 | 
			
		||||
        {
 | 
			
		||||
            if (m_displayMode == DisplayXYH) // horizontal split of second display
 | 
			
		||||
            {
 | 
			
		||||
                int scopeHeight = height() - m_topMargin - m_botMargin;
 | 
			
		||||
                int scopeWidth = (width() - m_rightMargin)/2 - m_leftMargin;
 | 
			
		||||
 | 
			
		||||
                m_glScopeRect2 = QRectF(
 | 
			
		||||
                    (float)(m_leftMargin + m_leftMargin + ((width() - m_leftMargin - m_leftMargin - m_rightMargin) / 2)) / (float)width(),
 | 
			
		||||
                    (float)m_topMargin / (float)height(),
 | 
			
		||||
                    (float)((width() - m_leftMargin - m_leftMargin - m_rightMargin) / 2) / (float)width(),
 | 
			
		||||
                    (float)(height() - m_topMargin - m_botMargin) / (float)height()
 | 
			
		||||
                );
 | 
			
		||||
                m_glScopeMatrix2.setToIdentity();
 | 
			
		||||
                m_glScopeMatrix2.translate (
 | 
			
		||||
                    -1.0f + ((float) 2*(m_leftMargin + m_leftMargin + ((width() - m_leftMargin - m_leftMargin - m_rightMargin) / 2)) / (float) width()),
 | 
			
		||||
                     1.0f - ((float) 2*m_topMargin / (float) height())
 | 
			
		||||
                );
 | 
			
		||||
                m_glScopeMatrix2.scale (
 | 
			
		||||
                    (float) 2*((width() - m_leftMargin - m_leftMargin - m_rightMargin) / 2) / (float) width(),
 | 
			
		||||
                    (float) -2*(height() - m_topMargin - m_botMargin) / (float) height()
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                m_glLeft2ScaleMatrix.setToIdentity();
 | 
			
		||||
                m_glLeft2ScaleMatrix.translate (
 | 
			
		||||
                    -1.0f + (float) 2*(m_leftMargin + scopeWidth) / (float) width(),
 | 
			
		||||
                     1.0f - ((float) 2*m_topMargin / (float) height())
 | 
			
		||||
                );
 | 
			
		||||
                m_glLeft2ScaleMatrix.scale (
 | 
			
		||||
                    (float) 2*(m_leftMargin-1) / (float) width(),
 | 
			
		||||
                    (float) -2*scopeHeight / (float) height()
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                m_glBot2ScaleMatrix.setToIdentity();
 | 
			
		||||
                m_glBot2ScaleMatrix.translate (
 | 
			
		||||
                    -1.0f + ((float) 2*(m_leftMargin + m_leftMargin + scopeWidth) / (float) width()),
 | 
			
		||||
                     1.0f - ((float) 2*(scopeHeight + m_topMargin + 1) / (float) height())
 | 
			
		||||
                );
 | 
			
		||||
                m_glBot2ScaleMatrix.scale (
 | 
			
		||||
                    (float) 2*scopeWidth / (float) width(),
 | 
			
		||||
                    (float) -2*(m_botMargin - 1) / (float) height()
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                { // Y2 scale
 | 
			
		||||
                    m_y2Scale.setSize(scopeHeight);
 | 
			
		||||
 | 
			
		||||
                    m_left2ScalePixmap = QPixmap(
 | 
			
		||||
                        m_leftMargin - 1,
 | 
			
		||||
                        scopeHeight
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                    const ScaleEngine::TickList* tickList;
 | 
			
		||||
                    const ScaleEngine::Tick* tick;
 | 
			
		||||
 | 
			
		||||
                    m_left2ScalePixmap.fill(Qt::black);
 | 
			
		||||
                    QPainter painter(&m_left2ScalePixmap);
 | 
			
		||||
                    painter.setPen(QColor(0xf0, 0xf0, 0xff));
 | 
			
		||||
                    painter.setFont(font());
 | 
			
		||||
                    tickList = &m_y2Scale.getTickList();
 | 
			
		||||
 | 
			
		||||
                    for(int i = 0; i < tickList->count(); i++) {
 | 
			
		||||
                        tick = &(*tickList)[i];
 | 
			
		||||
                        if(tick->major) {
 | 
			
		||||
                            if(tick->textSize > 0) {
 | 
			
		||||
                                painter.drawText(QPointF(m_leftMargin - M - tick->textSize, m_topMargin + scopeHeight - tick->textPos - fm.ascent()/2), tick->text);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    m_glShaderLeft2Scale.initTexture(m_left2ScalePixmap.toImage());
 | 
			
		||||
 | 
			
		||||
                } // Y2 scale
 | 
			
		||||
                { // X2 scale
 | 
			
		||||
                    m_x2Scale.setSize(scopeWidth);
 | 
			
		||||
                    m_bot2ScalePixmap = QPixmap(
 | 
			
		||||
                        scopeWidth,
 | 
			
		||||
                        m_botMargin - 1
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                    const ScaleEngine::TickList* tickList;
 | 
			
		||||
                    const ScaleEngine::Tick* tick;
 | 
			
		||||
 | 
			
		||||
                    m_bot2ScalePixmap.fill(Qt::black);
 | 
			
		||||
                    QPainter painter(&m_bot2ScalePixmap);
 | 
			
		||||
                    painter.setPen(QColor(0xf0, 0xf0, 0xff));
 | 
			
		||||
                    painter.setFont(font());
 | 
			
		||||
                    tickList = &m_x2Scale.getTickList();
 | 
			
		||||
 | 
			
		||||
                    for(int i = 0; i < tickList->count(); i++) {
 | 
			
		||||
                        tick = &(*tickList)[i];
 | 
			
		||||
                        if(tick->major) {
 | 
			
		||||
                            if(tick->textSize > 0) {
 | 
			
		||||
                                painter.drawText(QPointF(tick->textPos, fm.height() - 1), tick->text);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    m_glShaderBottom2Scale.initTexture(m_bot2ScalePixmap.toImage());
 | 
			
		||||
 | 
			
		||||
                } // X2 scale
 | 
			
		||||
            }
 | 
			
		||||
            else // vertical split of second display
 | 
			
		||||
            {
 | 
			
		||||
                int scopeHeight = (height() - m_topMargin) / 2 - m_botMargin;
 | 
			
		||||
                int scopeWidth = width() - m_leftMargin - m_rightMargin;
 | 
			
		||||
 | 
			
		||||
                m_glScopeRect2 = QRectF(
 | 
			
		||||
                    (float) m_leftMargin / (float)width(),
 | 
			
		||||
                    (float) (m_botMargin + m_topMargin + scopeHeight) / (float)height(),
 | 
			
		||||
                    (float) scopeWidth / (float)width(),
 | 
			
		||||
                    (float) scopeHeight / (float)height()
 | 
			
		||||
                );
 | 
			
		||||
                m_glScopeMatrix2.setToIdentity();
 | 
			
		||||
                m_glScopeMatrix2.translate (
 | 
			
		||||
                    -1.0f + ((float) 2*m_leftMargin / (float) width()),
 | 
			
		||||
                     1.0f - ((float) 2*(m_botMargin + m_topMargin + scopeHeight) / (float) height())
 | 
			
		||||
                );
 | 
			
		||||
                m_glScopeMatrix2.scale (
 | 
			
		||||
                    (float) 2*scopeWidth / (float) width(),
 | 
			
		||||
                    (float) -2*scopeHeight / (float) height()
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                m_glLeft2ScaleMatrix.setToIdentity();
 | 
			
		||||
                m_glLeft2ScaleMatrix.translate (
 | 
			
		||||
                    -1.0f,
 | 
			
		||||
                     1.0f - ((float) 2*(m_topMargin + scopeHeight + m_botMargin) / (float) height())
 | 
			
		||||
                );
 | 
			
		||||
                m_glLeft2ScaleMatrix.scale (
 | 
			
		||||
                    (float) 2*(m_leftMargin-1) / (float) width(),
 | 
			
		||||
                    (float) -2*scopeHeight / (float) height()
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                m_glBot2ScaleMatrix.setToIdentity();
 | 
			
		||||
                m_glBot2ScaleMatrix.translate (
 | 
			
		||||
                    -1.0f + ((float) 2*m_leftMargin / (float) width()),
 | 
			
		||||
                     1.0f - ((float) 2*(scopeHeight + m_topMargin + scopeHeight + m_botMargin + 1) / (float) height())
 | 
			
		||||
                );
 | 
			
		||||
                m_glBot2ScaleMatrix.scale (
 | 
			
		||||
                    (float) 2*scopeWidth / (float) width(),
 | 
			
		||||
                    (float) -2*(m_botMargin - 1) / (float) height()
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                { // Y2 scale
 | 
			
		||||
                    m_y2Scale.setSize(scopeHeight);
 | 
			
		||||
 | 
			
		||||
                    m_left2ScalePixmap = QPixmap(
 | 
			
		||||
                        m_leftMargin - 1,
 | 
			
		||||
                        scopeHeight
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                    const ScaleEngine::TickList* tickList;
 | 
			
		||||
                    const ScaleEngine::Tick* tick;
 | 
			
		||||
 | 
			
		||||
                    m_left2ScalePixmap.fill(Qt::black);
 | 
			
		||||
                    QPainter painter(&m_left2ScalePixmap);
 | 
			
		||||
                    painter.setPen(QColor(0xf0, 0xf0, 0xff));
 | 
			
		||||
                    painter.setFont(font());
 | 
			
		||||
                    tickList = &m_y2Scale.getTickList();
 | 
			
		||||
 | 
			
		||||
                    for(int i = 0; i < tickList->count(); i++) {
 | 
			
		||||
                        tick = &(*tickList)[i];
 | 
			
		||||
                        if(tick->major) {
 | 
			
		||||
                            if(tick->textSize > 0) {
 | 
			
		||||
                                painter.drawText(QPointF(m_leftMargin - M - tick->textSize, m_topMargin + scopeHeight - tick->textPos - fm.ascent()/2), tick->text);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    m_glShaderLeft2Scale.initTexture(m_left2ScalePixmap.toImage());
 | 
			
		||||
 | 
			
		||||
                } // Y2 scale
 | 
			
		||||
                { // X2 scale
 | 
			
		||||
                    m_x2Scale.setSize(scopeWidth);
 | 
			
		||||
                    m_bot2ScalePixmap = QPixmap(
 | 
			
		||||
                        scopeWidth,
 | 
			
		||||
                        m_botMargin - 1
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                    const ScaleEngine::TickList* tickList;
 | 
			
		||||
                    const ScaleEngine::Tick* tick;
 | 
			
		||||
 | 
			
		||||
                    m_bot2ScalePixmap.fill(Qt::black);
 | 
			
		||||
                    QPainter painter(&m_bot2ScalePixmap);
 | 
			
		||||
                    painter.setPen(QColor(0xf0, 0xf0, 0xff));
 | 
			
		||||
                    painter.setFont(font());
 | 
			
		||||
                    tickList = &m_x2Scale.getTickList();
 | 
			
		||||
 | 
			
		||||
                    for(int i = 0; i < tickList->count(); i++) {
 | 
			
		||||
                        tick = &(*tickList)[i];
 | 
			
		||||
                        if(tick->major) {
 | 
			
		||||
                            if(tick->textSize > 0) {
 | 
			
		||||
                                painter.drawText(QPointF(tick->textPos, fm.height() - 1), tick->text);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    m_glShaderBottom2Scale.initTexture(m_bot2ScalePixmap.toImage());
 | 
			
		||||
                } // X2 scale
 | 
			
		||||
            } // vertical or horizontal split of second display
 | 
			
		||||
        } // second display square (polar mode) or half space
 | 
			
		||||
    } // single or dual display
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNG::setYScale(ScaleEngine& scale, uint32_t highlightedTraceIndex)
 | 
			
		||||
{
 | 
			
		||||
    ScopeVisNG::DisplayTrace trace = (*m_traces)[highlightedTraceIndex];
 | 
			
		||||
    float amp_range = 2.0 / trace.m_amp;
 | 
			
		||||
    float amp_ofs = trace.m_ofs;
 | 
			
		||||
    float pow_floor = -100.0 + trace.m_ofs * 100.0;
 | 
			
		||||
    float pow_range = 100.0 / trace.m_amp;
 | 
			
		||||
 | 
			
		||||
    switch (trace.m_projectionType)
 | 
			
		||||
    {
 | 
			
		||||
    case ScopeVisNG::ProjectionMagDB: // dB scale
 | 
			
		||||
        scale.setRange(Unit::Decibel, pow_floor, pow_floor + pow_range);
 | 
			
		||||
        break;
 | 
			
		||||
    case ScopeVisNG::ProjectionPhase: // Phase or frequency
 | 
			
		||||
    case ScopeVisNG::ProjectionDPhase:
 | 
			
		||||
        scale.setRange(Unit::None, -1.0/trace.m_amp + amp_ofs, 1.0/trace.m_amp + amp_ofs);
 | 
			
		||||
        break;
 | 
			
		||||
    case ScopeVisNG::ProjectionReal: // Linear generic
 | 
			
		||||
    case ScopeVisNG::ProjectionImag:
 | 
			
		||||
    case ScopeVisNG::ProjectionMagLin:
 | 
			
		||||
    default:
 | 
			
		||||
        if (amp_range < 2.0) {
 | 
			
		||||
            scale.setRange(Unit::None, - amp_range * 500.0 + amp_ofs * 1000.0, amp_range * 500.0 + amp_ofs * 1000.0);
 | 
			
		||||
        } else {
 | 
			
		||||
            scale.setRange(Unit::None, - amp_range * 0.5 + amp_ofs, amp_range * 0.5 + amp_ofs);
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNG::tick()
 | 
			
		||||
{
 | 
			
		||||
    if(m_dataChanged)
 | 
			
		||||
        update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNG::connectTimer(const QTimer& timer)
 | 
			
		||||
{
 | 
			
		||||
    qDebug() << "GLScopeNG::connectTimer";
 | 
			
		||||
    disconnect(&m_timer, SIGNAL(timeout()), this, SLOT(tick()));
 | 
			
		||||
    connect(&timer, SIGNAL(timeout()), this, SLOT(tick()));
 | 
			
		||||
    m_timer.stop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNG::cleanup()
 | 
			
		||||
{
 | 
			
		||||
    //makeCurrent();
 | 
			
		||||
    m_glShaderSimple.cleanup();
 | 
			
		||||
    m_glShaderBottom1Scale.cleanup();
 | 
			
		||||
    m_glShaderBottom2Scale.cleanup();
 | 
			
		||||
    m_glShaderLeft1Scale.cleanup();
 | 
			
		||||
    m_glShaderPowerOverlay.cleanup();
 | 
			
		||||
    //doneCurrent();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										131
									
								
								sdrbase/gui/glscopeng.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								sdrbase/gui/glscopeng.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,131 @@
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Copyright (C) 2017 F4EXB                                                      //
 | 
			
		||||
// written by Edouard Griffiths                                                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 as version 3 of the License, or                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 V3 for more details.                               //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// You should have received a copy of the GNU General Public License             //
 | 
			
		||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
#ifndef SDRBASE_GUI_GLSCOPENG_H_
 | 
			
		||||
#define SDRBASE_GUI_GLSCOPENG_H_
 | 
			
		||||
 | 
			
		||||
#include <QGLWidget>
 | 
			
		||||
#include <QPen>
 | 
			
		||||
#include <QTimer>
 | 
			
		||||
#include <QMutex>
 | 
			
		||||
#include <QFont>
 | 
			
		||||
#include <QMatrix4x4>
 | 
			
		||||
#include "dsp/dsptypes.h"
 | 
			
		||||
#include "dsp/scopevisng.h"
 | 
			
		||||
#include "gui/scaleengine.h"
 | 
			
		||||
#include "gui/glshadersimple.h"
 | 
			
		||||
#include "gui/glshadertextured.h"
 | 
			
		||||
#include "util/export.h"
 | 
			
		||||
#include "util/bitfieldindex.h"
 | 
			
		||||
 | 
			
		||||
class QPainter;
 | 
			
		||||
 | 
			
		||||
class SDRANGEL_API GLScopeNG: public QGLWidget {
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    enum DisplayMode {
 | 
			
		||||
        DisplayXYH,
 | 
			
		||||
        DisplayXYV,
 | 
			
		||||
        DisplayX,
 | 
			
		||||
        DisplayY,
 | 
			
		||||
        DisplayPol
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    GLScopeNG(QWidget* parent = 0);
 | 
			
		||||
    virtual ~GLScopeNG();
 | 
			
		||||
 | 
			
		||||
    void connectTimer(const QTimer& timer);
 | 
			
		||||
 | 
			
		||||
    void setTraces(const ScopeVisNG::DisplayTraces *traces) { m_traces = traces; m_configChanged = true; }
 | 
			
		||||
    void newTraces();
 | 
			
		||||
 | 
			
		||||
    void setTriggerPre(Real triggerPre);
 | 
			
		||||
    void setTimeOfsProMill(int timeOfsProMill);
 | 
			
		||||
    void setSampleRate(int sampleRate);
 | 
			
		||||
    void setTimeBase(int timeBase);
 | 
			
		||||
    void setHighlightedTraceIndex(uint32_t traceIndex);
 | 
			
		||||
    void setDisplayMode(DisplayMode displayMode);
 | 
			
		||||
    void setTraceSize(int trceSize);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    DisplayMode m_displayMode;
 | 
			
		||||
    QTimer m_timer;
 | 
			
		||||
    QMutex m_mutex;
 | 
			
		||||
    bool m_dataChanged;
 | 
			
		||||
    bool m_configChanged;
 | 
			
		||||
    const ScopeVisNG::DisplayTraces *m_traces;
 | 
			
		||||
    int m_sampleRate;
 | 
			
		||||
    int m_timeOfsProMill;
 | 
			
		||||
    Real m_triggerPre;
 | 
			
		||||
    int m_traceSize;
 | 
			
		||||
    int m_timeBase;
 | 
			
		||||
    uint32_t m_highlightedTraceIndex;
 | 
			
		||||
 | 
			
		||||
    // graphics stuff
 | 
			
		||||
    QRectF m_glScopeRect1;
 | 
			
		||||
    QRectF m_glScopeRect2;
 | 
			
		||||
    QMatrix4x4 m_glScopeMatrix1;
 | 
			
		||||
    QMatrix4x4 m_glScopeMatrix2;
 | 
			
		||||
    QMatrix4x4 m_glLeft1ScaleMatrix;
 | 
			
		||||
    QMatrix4x4 m_glRight1ScaleMatrix;
 | 
			
		||||
    QMatrix4x4 m_glLeft2ScaleMatrix;
 | 
			
		||||
    QMatrix4x4 m_glBot1ScaleMatrix;
 | 
			
		||||
    QMatrix4x4 m_glBot2ScaleMatrix;
 | 
			
		||||
 | 
			
		||||
    QPixmap m_left1ScalePixmap;
 | 
			
		||||
    QPixmap m_left2ScalePixmap;
 | 
			
		||||
    QPixmap m_bot1ScalePixmap;
 | 
			
		||||
    QPixmap m_bot2ScalePixmap;
 | 
			
		||||
    QPixmap m_powerOverlayPixmap1;
 | 
			
		||||
 | 
			
		||||
    int m_displayGridIntensity;
 | 
			
		||||
    int m_displayTraceIntensity;
 | 
			
		||||
 | 
			
		||||
    ScaleEngine m_x1Scale; //!< Display #1 X scale. Time scale
 | 
			
		||||
    ScaleEngine m_x2Scale; //!< Display #2 X scale. Time scale
 | 
			
		||||
    ScaleEngine m_y1Scale; //!< Display #1 Y scale. Always connected to trace #0 (X trace)
 | 
			
		||||
    ScaleEngine m_y2Scale; //!< Display #2 Y scale. Connected to highlighted Y trace (#1..n)
 | 
			
		||||
 | 
			
		||||
    QFont m_powerOverlayFont;
 | 
			
		||||
 | 
			
		||||
    GLShaderSimple m_glShaderSimple;
 | 
			
		||||
    GLShaderTextured m_glShaderLeft1Scale;
 | 
			
		||||
    GLShaderTextured m_glShaderBottom1Scale;
 | 
			
		||||
    GLShaderTextured m_glShaderLeft2Scale;
 | 
			
		||||
    GLShaderTextured m_glShaderBottom2Scale;
 | 
			
		||||
    GLShaderTextured m_glShaderPowerOverlay;
 | 
			
		||||
 | 
			
		||||
    static const int m_topMargin = 5;
 | 
			
		||||
    static const int m_botMargin = 20;
 | 
			
		||||
    static const int m_leftMargin = 35;
 | 
			
		||||
    static const int m_rightMargin = 5;
 | 
			
		||||
 | 
			
		||||
    void initializeGL();
 | 
			
		||||
    void resizeGL(int width, int height);
 | 
			
		||||
    void paintGL();
 | 
			
		||||
 | 
			
		||||
    void applyConfig();
 | 
			
		||||
    void setYScale(ScaleEngine& scale, uint32_t highlightedTraceIndex);
 | 
			
		||||
 | 
			
		||||
protected slots:
 | 
			
		||||
    void cleanup();
 | 
			
		||||
    void tick();
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* SDRBASE_GUI_GLSCOPENG_H_ */
 | 
			
		||||
							
								
								
									
										88
									
								
								sdrbase/gui/glscopenggui.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								sdrbase/gui/glscopenggui.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,88 @@
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Copyright (C) 2017 F4EXB                                                      //
 | 
			
		||||
// written by Edouard Griffiths                                                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 as version 3 of the License, or                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 V3 for more details.                               //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// You should have received a copy of the GNU General Public License             //
 | 
			
		||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
#include "glscopenggui.h"
 | 
			
		||||
#include "ui_glscopenggui.h"
 | 
			
		||||
#include "util/simpleserializer.h"
 | 
			
		||||
 | 
			
		||||
GLScopeNGGUI::GLScopeNGGUI(QWidget* parent) :
 | 
			
		||||
    QWidget(parent),
 | 
			
		||||
    ui(new Ui::GLScopeNGGUI),
 | 
			
		||||
    m_messageQueue(0),
 | 
			
		||||
    m_glScope(0),
 | 
			
		||||
    m_scopeVis(0),
 | 
			
		||||
    m_sampleRate(0)
 | 
			
		||||
{
 | 
			
		||||
    ui->setupUi(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GLScopeNGGUI::~GLScopeNGGUI()
 | 
			
		||||
{
 | 
			
		||||
    delete ui;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNGGUI::setBuddies(MessageQueue* messageQueue, ScopeVisNG* scopeVis, GLScopeNG* glScope)
 | 
			
		||||
{
 | 
			
		||||
    m_messageQueue = messageQueue;
 | 
			
		||||
    m_scopeVis = scopeVis;
 | 
			
		||||
    m_glScope = glScope;
 | 
			
		||||
    applySettings();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNGGUI::setSampleRate(int sampleRate)
 | 
			
		||||
{
 | 
			
		||||
    m_sampleRate = sampleRate;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNGGUI::resetToDefaults()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
QByteArray GLScopeNGGUI::serialize() const
 | 
			
		||||
{
 | 
			
		||||
    // TODO
 | 
			
		||||
    SimpleSerializer s(1);
 | 
			
		||||
    return s.final();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GLScopeNGGUI::deserialize(const QByteArray& data)
 | 
			
		||||
{
 | 
			
		||||
    // TODO
 | 
			
		||||
    SimpleDeserializer d(data);
 | 
			
		||||
 | 
			
		||||
    if(!d.isValid()) {
 | 
			
		||||
        resetToDefaults();
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(d.getVersion() == 1) {
 | 
			
		||||
        return true;
 | 
			
		||||
    } else {
 | 
			
		||||
        resetToDefaults();
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScopeNGGUI::applySettings()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GLScopeNGGUI::handleMessage(Message* message)
 | 
			
		||||
{
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										64
									
								
								sdrbase/gui/glscopenggui.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								sdrbase/gui/glscopenggui.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,64 @@
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Copyright (C) 2017 F4EXB                                                      //
 | 
			
		||||
// written by Edouard Griffiths                                                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 as version 3 of the License, or                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 V3 for more details.                               //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// You should have received a copy of the GNU General Public License             //
 | 
			
		||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
#ifndef SDRBASE_GUI_GLSCOPENGGUI_H_
 | 
			
		||||
#define SDRBASE_GUI_GLSCOPENGGUI_H_
 | 
			
		||||
 | 
			
		||||
#include <QWidget>
 | 
			
		||||
#include "dsp/dsptypes.h"
 | 
			
		||||
#include "util/export.h"
 | 
			
		||||
#include "util/message.h"
 | 
			
		||||
 | 
			
		||||
namespace Ui {
 | 
			
		||||
    class GLScopeNGGUI;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class MessageQueue;
 | 
			
		||||
class GLScopeNG;
 | 
			
		||||
class ScopeVisNG;
 | 
			
		||||
 | 
			
		||||
class SDRANGEL_API GLScopeNGGUI : public QWidget {
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    explicit GLScopeNGGUI(QWidget* parent = 0);
 | 
			
		||||
    ~GLScopeNGGUI();
 | 
			
		||||
 | 
			
		||||
    void setBuddies(MessageQueue* messageQueue, ScopeVisNG* scopeVis, GLScopeNG* glScope);
 | 
			
		||||
 | 
			
		||||
    void setSampleRate(int sampleRate);
 | 
			
		||||
    void resetToDefaults();
 | 
			
		||||
    QByteArray serialize() const;
 | 
			
		||||
    bool deserialize(const QByteArray& data);
 | 
			
		||||
 | 
			
		||||
    bool handleMessage(Message* message);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Ui::GLScopeNGGUI* ui;
 | 
			
		||||
 | 
			
		||||
    MessageQueue* m_messageQueue;
 | 
			
		||||
    ScopeVisNG* m_scopeVis;
 | 
			
		||||
    GLScopeNG* m_glScope;
 | 
			
		||||
 | 
			
		||||
    int m_sampleRate;
 | 
			
		||||
 | 
			
		||||
    void applySettings();
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* SDRBASE_GUI_GLSCOPENGGUI_H_ */
 | 
			
		||||
							
								
								
									
										1481
									
								
								sdrbase/gui/glscopenggui.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1481
									
								
								sdrbase/gui/glscopenggui.ui
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -72,6 +72,7 @@ SOURCES += mainwindow.cpp\
 | 
			
		||||
        dsp/basebandsamplesource.cpp\
 | 
			
		||||
        dsp/nullsink.cpp\
 | 
			
		||||
        dsp/spectrumscopecombovis.cpp\
 | 
			
		||||
        dsp/spectrumscopengcombovis.cpp\
 | 
			
		||||
        dsp/scopevis.cpp\
 | 
			
		||||
        dsp/spectrumvis.cpp\
 | 
			
		||||
        dsp/threadedbasebandsamplesink.cpp\
 | 
			
		||||
@ -85,6 +86,8 @@ SOURCES += mainwindow.cpp\
 | 
			
		||||
        gui/cwkeyergui.cpp\
 | 
			
		||||
        gui/glscope.cpp\
 | 
			
		||||
        gui/glscopegui.cpp\
 | 
			
		||||
        gui/glscopeng.cpp\
 | 
			
		||||
        gui/glscopenggui.cpp\
 | 
			
		||||
        gui/glshadersimple.cpp\
 | 
			
		||||
        gui/glshadertextured.cpp\
 | 
			
		||||
        gui/glspectrum.cpp\
 | 
			
		||||
@ -172,6 +175,8 @@ HEADERS  += mainwindow.h\
 | 
			
		||||
        dsp/basebandsamplesink.h\
 | 
			
		||||
        dsp/basebandsamplesource.h\
 | 
			
		||||
        dsp/nullsink.h\
 | 
			
		||||
        dsp/spectrumscopecombovis.h\
 | 
			
		||||
        dsp/spectrumscopengcombovis.h\        
 | 
			
		||||
        dsp/scopevis.h\
 | 
			
		||||
        dsp/spectrumvis.h\
 | 
			
		||||
        dsp/threadedbasebandsamplesink.h\
 | 
			
		||||
@ -186,6 +191,8 @@ HEADERS  += mainwindow.h\
 | 
			
		||||
        gui/cwkeyergui.h\
 | 
			
		||||
        gui/glscope.h\
 | 
			
		||||
        gui/glscopegui.h\
 | 
			
		||||
        gui/glscopeng.h\
 | 
			
		||||
        gui/glscopenggui.h\
 | 
			
		||||
        gui/glshadersimple.h\
 | 
			
		||||
        gui/glshadertextured.h\
 | 
			
		||||
        gui/glspectrum.h\
 | 
			
		||||
@ -227,6 +234,7 @@ FORMS    += mainwindow.ui\
 | 
			
		||||
        gui/cwkeyergui.ui\
 | 
			
		||||
        gui/audiodialog.ui\
 | 
			
		||||
        gui/glscopegui.ui\
 | 
			
		||||
        gui/glscopenggui.ui\
 | 
			
		||||
        gui/aboutdialog.ui\
 | 
			
		||||
        gui/pluginsdialog.ui\
 | 
			
		||||
        gui/samplingdevicecontrol.ui\
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										77
									
								
								sdrbase/util/doublebuffer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								sdrbase/util/doublebuffer.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,77 @@
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Copyright (C) 2016 Edouard Griffiths, F4EXB                                   //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 as version 3 of the License, or                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// 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 V3 for more details.                               //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// You should have received a copy of the GNU General Public License             //
 | 
			
		||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
#ifndef SDRBASE_UTIL_DOUBLEBUFFER_H_
 | 
			
		||||
#define SDRBASE_UTIL_DOUBLEBUFFER_H_
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
class DoubleBufferSimple
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	DoubleBufferSimple()
 | 
			
		||||
    {
 | 
			
		||||
	    m_size = 0;
 | 
			
		||||
        m_current = m_data.end();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~DoubleBufferSimple() {}
 | 
			
		||||
 | 
			
		||||
	void resize(int size)
 | 
			
		||||
	{
 | 
			
		||||
	    m_size = size;
 | 
			
		||||
        m_data.resize(2*size);
 | 
			
		||||
        m_current = m_data.begin();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void write(const typename std::vector<T>::const_iterator& begin, const typename std::vector<T>::const_iterator& cend)
 | 
			
		||||
	{
 | 
			
		||||
		typename std::vector<T>::const_iterator end = cend;
 | 
			
		||||
 | 
			
		||||
		if ((end - begin) > m_size)
 | 
			
		||||
		{
 | 
			
		||||
			end = begin + m_size;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		int insize = end - begin;
 | 
			
		||||
 | 
			
		||||
		std::copy(begin, end, m_current);
 | 
			
		||||
 | 
			
		||||
		if (((m_current - m_data.begin()) + insize) > m_size)
 | 
			
		||||
		{
 | 
			
		||||
			int sizeLeft = m_size - (m_current - m_data.begin());
 | 
			
		||||
			std::copy(begin, begin + sizeLeft, m_current + m_size);
 | 
			
		||||
			std::copy(begin + sizeLeft, end, m_data.begin());
 | 
			
		||||
			m_current = m_data.begin() + (insize - sizeLeft);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			std::copy(begin, end, m_current + m_size);
 | 
			
		||||
			m_current += insize;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	typename std::vector<T>::iterator getCurrent() const { return m_current + m_size; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	int m_size;
 | 
			
		||||
	std::vector<T> m_data;
 | 
			
		||||
	typename std::vector<T>::iterator m_current;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* SDRBASE_UTIL_DOUBLEBUFFER_H_ */
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user