2018-01-13 20:25:24 -05:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Copyright (C) 2018 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 //
|
2019-04-11 00:57:41 -04:00
|
|
|
// (at your option) any later version. //
|
2018-01-13 20:25:24 -05:00
|
|
|
// //
|
|
|
|
// 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 _TESTSOURCE_TESTSOURCETHREAD_H_
|
|
|
|
#define _TESTSOURCE_TESTSOURCETHREAD_H_
|
|
|
|
|
2019-05-21 15:18:49 -04:00
|
|
|
#include <map>
|
|
|
|
|
2018-01-13 20:25:24 -05:00
|
|
|
#include <QThread>
|
|
|
|
#include <QMutex>
|
|
|
|
#include <QWaitCondition>
|
|
|
|
#include <QTimer>
|
|
|
|
#include <QElapsedTimer>
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
|
|
#include "dsp/samplesinkfifo.h"
|
|
|
|
#include "dsp/decimators.h"
|
|
|
|
#include "dsp/ncof.h"
|
2018-09-06 08:29:14 -04:00
|
|
|
#include "util/message.h"
|
|
|
|
#include "util/messagequeue.h"
|
2018-01-13 20:25:24 -05:00
|
|
|
|
2018-02-11 07:48:17 -05:00
|
|
|
#include "testsourcesettings.h"
|
|
|
|
|
2018-01-13 20:25:24 -05:00
|
|
|
#define TESTSOURCE_THROTTLE_MS 50
|
|
|
|
|
|
|
|
class TestSourceThread : public QThread {
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
public:
|
2018-09-06 08:29:14 -04:00
|
|
|
class MsgStartStop : public Message {
|
|
|
|
MESSAGE_CLASS_DECLARATION
|
|
|
|
|
|
|
|
public:
|
|
|
|
bool getStartStop() const { return m_startStop; }
|
|
|
|
|
|
|
|
static MsgStartStop* create(bool startStop) {
|
|
|
|
return new MsgStartStop(startStop);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
bool m_startStop;
|
|
|
|
|
|
|
|
MsgStartStop(bool startStop) :
|
|
|
|
Message(),
|
|
|
|
m_startStop(startStop)
|
|
|
|
{ }
|
|
|
|
};
|
|
|
|
|
2018-01-13 20:25:24 -05:00
|
|
|
TestSourceThread(SampleSinkFifo* sampleFifo, QObject* parent = 0);
|
|
|
|
~TestSourceThread();
|
|
|
|
|
2018-09-06 08:29:14 -04:00
|
|
|
void startStop(bool start);
|
2018-01-13 20:25:24 -05:00
|
|
|
void setSamplerate(int samplerate);
|
|
|
|
void setLog2Decimation(unsigned int log2_decim);
|
|
|
|
void setFcPos(int fcPos);
|
|
|
|
void setBitSize(uint32_t bitSizeIndex);
|
|
|
|
void setAmplitudeBits(int32_t amplitudeBits);
|
2018-01-14 05:58:36 -05:00
|
|
|
void setDCFactor(float iFactor);
|
|
|
|
void setIFactor(float iFactor);
|
|
|
|
void setQFactor(float qFactor);
|
2018-01-31 16:34:55 -05:00
|
|
|
void setPhaseImbalance(float phaseImbalance);
|
2018-01-13 20:25:24 -05:00
|
|
|
void setFrequencyShift(int shift);
|
2018-02-11 07:48:17 -05:00
|
|
|
void setToneFrequency(int toneFrequency);
|
|
|
|
void setModulation(TestSourceSettings::Modulation modulation);
|
|
|
|
void setAMModulation(float amModulation);
|
|
|
|
void setFMDeviation(float deviation);
|
2018-10-23 18:10:12 -04:00
|
|
|
void setPattern0();
|
|
|
|
void setPattern1();
|
2018-10-25 07:53:58 -04:00
|
|
|
void setPattern2();
|
2018-01-13 20:25:24 -05:00
|
|
|
|
|
|
|
private:
|
|
|
|
QMutex m_startWaitMutex;
|
|
|
|
QWaitCondition m_startWaiter;
|
2018-02-21 12:54:59 -05:00
|
|
|
volatile bool m_running;
|
2018-01-13 20:25:24 -05:00
|
|
|
|
2018-01-13 22:43:24 -05:00
|
|
|
qint16 *m_buf;
|
2018-01-13 20:25:24 -05:00
|
|
|
quint32 m_bufsize;
|
|
|
|
quint32 m_chunksize;
|
|
|
|
SampleVector m_convertBuffer;
|
|
|
|
SampleSinkFifo* m_sampleFifo;
|
|
|
|
NCOF m_nco;
|
2018-02-11 07:48:17 -05:00
|
|
|
NCOF m_toneNco;
|
2018-01-13 22:43:24 -05:00
|
|
|
int m_frequencyShift;
|
2018-02-11 07:48:17 -05:00
|
|
|
int m_toneFrequency;
|
|
|
|
TestSourceSettings::Modulation m_modulation;
|
|
|
|
float m_amModulation;
|
|
|
|
float m_fmDeviationUnit;
|
|
|
|
float m_fmPhasor;
|
2018-10-23 08:34:56 -04:00
|
|
|
uint32_t m_pulseWidth; //!< pulse width in number of samples
|
|
|
|
uint32_t m_pulseSampleCount;
|
|
|
|
uint32_t m_pulsePatternCount;
|
|
|
|
uint32_t m_pulsePatternCycle;
|
|
|
|
uint32_t m_pulsePatternPlaces;
|
2018-01-13 20:25:24 -05:00
|
|
|
|
|
|
|
int m_samplerate;
|
|
|
|
unsigned int m_log2Decim;
|
|
|
|
int m_fcPos;
|
|
|
|
uint32_t m_bitSizeIndex;
|
|
|
|
uint32_t m_bitShift;
|
|
|
|
int32_t m_amplitudeBits;
|
2018-01-14 05:58:36 -05:00
|
|
|
float m_dcBias;
|
|
|
|
float m_iBias;
|
|
|
|
float m_qBias;
|
2018-01-31 16:34:55 -05:00
|
|
|
float m_phaseImbalance;
|
2018-01-14 05:58:36 -05:00
|
|
|
int32_t m_amplitudeBitsDC;
|
|
|
|
int32_t m_amplitudeBitsI;
|
|
|
|
int32_t m_amplitudeBitsQ;
|
2018-01-13 20:25:24 -05:00
|
|
|
|
|
|
|
uint64_t m_frequency;
|
|
|
|
int m_fcPosShift;
|
|
|
|
|
|
|
|
int m_throttlems;
|
2018-09-06 08:29:14 -04:00
|
|
|
QTimer m_timer;
|
2018-01-13 20:25:24 -05:00
|
|
|
QElapsedTimer m_elapsedTimer;
|
|
|
|
bool m_throttleToggle;
|
2018-01-13 22:43:24 -05:00
|
|
|
QMutex m_mutex;
|
2018-01-13 20:25:24 -05:00
|
|
|
|
2018-09-06 08:29:14 -04:00
|
|
|
MessageQueue m_inputMessageQueue;
|
|
|
|
|
2018-01-22 02:46:05 -05:00
|
|
|
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 8> m_decimators_8;
|
|
|
|
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 12> m_decimators_12;
|
|
|
|
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 16> m_decimators_16;
|
2018-01-13 20:25:24 -05:00
|
|
|
|
2019-05-21 15:18:49 -04:00
|
|
|
std::map<int, int> m_timerHistogram;
|
|
|
|
uint32_t m_histoCounter;
|
|
|
|
|
2018-09-06 08:29:14 -04:00
|
|
|
void startWork();
|
|
|
|
void stopWork();
|
2018-01-13 20:25:24 -05:00
|
|
|
void run();
|
2018-01-13 22:43:24 -05:00
|
|
|
void callback(const qint16* buf, qint32 len);
|
2018-01-13 20:25:24 -05:00
|
|
|
void setBuffers(quint32 chunksize);
|
|
|
|
void generate(quint32 chunksize);
|
2018-02-11 07:48:17 -05:00
|
|
|
void pullAF(Real& afSample);
|
2018-01-13 20:25:24 -05:00
|
|
|
|
|
|
|
// Decimate according to specified log2 (ex: log2=4 => decim=16)
|
2018-01-13 22:43:24 -05:00
|
|
|
inline void convert_8(SampleVector::iterator* it, const qint16* buf, qint32 len)
|
2018-01-13 20:25:24 -05:00
|
|
|
{
|
|
|
|
if (m_log2Decim == 0) {
|
|
|
|
m_decimators_8.decimate1(it, buf, len);
|
|
|
|
} else {
|
|
|
|
if (m_fcPos == 0) { // Infradyne
|
|
|
|
switch (m_log2Decim) {
|
|
|
|
case 1:
|
|
|
|
m_decimators_8.decimate2_inf(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
m_decimators_8.decimate4_inf(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
m_decimators_8.decimate8_inf(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
m_decimators_8.decimate16_inf(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
m_decimators_8.decimate32_inf(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
m_decimators_8.decimate64_inf(it, buf, len);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (m_fcPos == 1) {// Supradyne
|
|
|
|
switch (m_log2Decim) {
|
|
|
|
case 1:
|
|
|
|
m_decimators_8.decimate2_sup(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
m_decimators_8.decimate4_sup(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
m_decimators_8.decimate8_sup(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
m_decimators_8.decimate16_sup(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
m_decimators_8.decimate32_sup(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
m_decimators_8.decimate64_sup(it, buf, len);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else { // Centered
|
|
|
|
switch (m_log2Decim) {
|
|
|
|
case 1:
|
|
|
|
m_decimators_8.decimate2_cen(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
m_decimators_8.decimate4_cen(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
m_decimators_8.decimate8_cen(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
m_decimators_8.decimate16_cen(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
m_decimators_8.decimate32_cen(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
m_decimators_8.decimate64_cen(it, buf, len);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-13 22:43:24 -05:00
|
|
|
void convert_12(SampleVector::iterator* it, const qint16* buf, qint32 len)
|
2018-01-13 20:25:24 -05:00
|
|
|
{
|
|
|
|
if (m_log2Decim == 0) {
|
|
|
|
m_decimators_12.decimate1(it, buf, len);
|
|
|
|
} else {
|
|
|
|
if (m_fcPos == 0) { // Infradyne
|
|
|
|
switch (m_log2Decim) {
|
|
|
|
case 1:
|
|
|
|
m_decimators_12.decimate2_inf(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
m_decimators_12.decimate4_inf(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
m_decimators_12.decimate8_inf(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
m_decimators_12.decimate16_inf(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
m_decimators_12.decimate32_inf(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
m_decimators_12.decimate64_inf(it, buf, len);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (m_fcPos == 1) {// Supradyne
|
|
|
|
switch (m_log2Decim) {
|
|
|
|
case 1:
|
|
|
|
m_decimators_12.decimate2_sup(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
m_decimators_12.decimate4_sup(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
m_decimators_12.decimate8_sup(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
m_decimators_12.decimate16_sup(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
m_decimators_12.decimate32_sup(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
m_decimators_12.decimate64_sup(it, buf, len);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else { // Centered
|
|
|
|
switch (m_log2Decim) {
|
|
|
|
case 1:
|
|
|
|
m_decimators_12.decimate2_cen(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
m_decimators_12.decimate4_cen(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
m_decimators_12.decimate8_cen(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
m_decimators_12.decimate16_cen(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
m_decimators_12.decimate32_cen(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
m_decimators_12.decimate64_cen(it, buf, len);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-13 22:43:24 -05:00
|
|
|
void convert_16(SampleVector::iterator* it, const qint16* buf, qint32 len)
|
2018-01-13 20:25:24 -05:00
|
|
|
{
|
|
|
|
if (m_log2Decim == 0) {
|
|
|
|
m_decimators_16.decimate1(it, buf, len);
|
|
|
|
} else {
|
|
|
|
if (m_fcPos == 0) { // Infradyne
|
|
|
|
switch (m_log2Decim) {
|
|
|
|
case 1:
|
|
|
|
m_decimators_16.decimate2_inf(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
m_decimators_16.decimate4_inf(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
m_decimators_16.decimate8_inf(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
m_decimators_16.decimate16_inf(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
m_decimators_16.decimate32_inf(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
m_decimators_16.decimate64_inf(it, buf, len);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (m_fcPos == 1) {// Supradyne
|
|
|
|
switch (m_log2Decim) {
|
|
|
|
case 1:
|
|
|
|
m_decimators_16.decimate2_sup(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
m_decimators_16.decimate4_sup(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
m_decimators_16.decimate8_sup(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
m_decimators_16.decimate16_sup(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
m_decimators_16.decimate32_sup(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
m_decimators_16.decimate64_sup(it, buf, len);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else { // Centered
|
|
|
|
switch (m_log2Decim) {
|
|
|
|
case 1:
|
|
|
|
m_decimators_16.decimate2_cen(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
m_decimators_16.decimate4_cen(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
m_decimators_16.decimate8_cen(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
m_decimators_16.decimate16_cen(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
m_decimators_16.decimate32_cen(it, buf, len);
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
m_decimators_16.decimate64_cen(it, buf, len);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private slots:
|
|
|
|
void tick();
|
2018-09-06 08:29:14 -04:00
|
|
|
void handleInputMessages();
|
2018-01-13 20:25:24 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif // _TESTSOURCE_TESTSOURCETHREAD_H_
|