////////////////////////////////////////////////////////////////////// // Called to display the input pBuf. //Called by thread so no GUI calls! // STEREO 16 bit Data version. ////////////////////////////////////////////////////////////////////// void CTestBench::DisplayData(int length, TYPESTEREO16* pBuf, double samplerate, int profile) { if(!m_Active || (profile!=m_Profile) ) return; if(m_DisplaySampleRate != samplerate) { m_DisplaySampleRate = samplerate; emit ResetSignal(); return; } m_NewDataIsCpx = true; if(! m_TimeDisplay) { //if displaying frequency domain data //accumulate samples into m_FftInBuf until have enough to perform an FFT for(int i=0; i<length; i++) { m_FftInBuf[m_FftBufPos].re = (TYPEREAL)pBuf[i].re; m_FftInBuf[m_FftBufPos++].im = (TYPEREAL)pBuf[i].im; if(m_FftBufPos >= TEST_FFTSIZE ) { m_FftBufPos = 0; if(++m_DisplaySkipCounter >= m_DisplaySkipValue ) { m_DisplaySkipCounter = 0; m_Fft.PutInDisplayFFT( TESTFFT_SIZE, m_FftInBuf); emit NewFftData(); } } } } else { //if displaying time domain data for(int i=0; i<length; i++) { double intime = (double)m_TimeInPos/samplerate; double scrntime = (double)m_TimeScrnPos*m_TimeScrnPixel; m_TimeInPos++; while(intime >= scrntime) { ChkForTrigger( (int)pBuf[i].re ); m_TimeBuf1[m_TimeScrnPos] = pBuf[i].re; m_TimeBuf2[m_TimeScrnPos++] = pBuf[i].im; scrntime = (double)m_TimeScrnPos*m_TimeScrnPixel; if( m_TimeScrnPos >= m_Rect.width() ) { m_TimeScrnPos = 0; m_TimeInPos = 0; break; } } } } }
/////////////////////////////////////////////////////////////////////////////// // Called by worker thread with new I/Q data fom the SDR. // This thread is what is used to perform all the DSP functions // pIQData is ptr to complex I/Q double samples. (order is I then Q) // Length is the number of doubles in pIQData. (2x the number of data samples) // emits "NewFftData()" when it accumulates an entire FFT length of samples // and the display update time is ready /////////////////////////////////////////////////////////////////////////////// void CSdrInterface::ProcessIQData( double* pIQData, int Length) { if(!m_Running) //ignor any incoming data if not running return; g_pTestBench->CreateGeneratorSamples(Length/2, (TYPECPX*)pIQData, m_SampleRate); m_NoiseProc.ProcessBlanker(Length/2, (TYPECPX*)pIQData, (TYPECPX*)pIQData); if(m_NcoSpurCalActive) //if performing NCO spur calibration NcoSpurCalibrate(pIQData, Length); //accumulate samples into m_DataBuf until have enough to perform an FFT for(int i=0; i<Length; i++) { if(m_FftBufPos&1) //apply I/Q DC offset correction to all samples m_DataBuf[m_FftBufPos++] = pIQData[i] - m_NCOSpurOffsetQ; else m_DataBuf[m_FftBufPos++] = pIQData[i] - m_NCOSpurOffsetI; if(m_FftBufPos >= (m_FftSize*2) ) { m_FftBufPos = 0; if(++m_DisplaySkipCounter >= m_DisplaySkipValue ) { m_DisplaySkipCounter = 0; if(m_ScreenUpateFinished) { m_Fft.PutInDisplayFFT(m_FftSize, (TYPECPX*)m_DataBuf); m_ScreenUpateFinished = FALSE; emit NewFftData(); } } } } TYPECPX SoundBuf[8192]; int n; if(m_StereoOut) { n = m_Demodulator.ProcessData(Length/2, (TYPECPX*)pIQData, SoundBuf); m_pSoundCardOut->PutOutQueue(n, SoundBuf); } else { n = m_Demodulator.ProcessData(Length/2, (TYPECPX*)pIQData, (TYPEREAL*)SoundBuf); m_pSoundCardOut->PutOutQueue(n, (TYPEREAL*)SoundBuf); } }
///////////////////////////////////////////////////////////////////// // Constructor/Destructor ///////////////////////////////////////////////////////////////////// MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); setWindowTitle(PROGRAM_TITLE_VERSION); //create SDR interface class m_pSdrInterface = new CSdrInterface; //give GUI plotter access to the sdr interface object ui->framePlot->SetSdrInterface(m_pSdrInterface); //create the global Testbench object if(!g_pTestBench) g_pTestBench = new CTestBench(this); readSettings(); //read persistent settings ui->actionAlwaysOnTop->setChecked(m_AlwaysOnTop); AlwaysOnTop(); //create Demod setup menu for non-modal use(can leave up and still access rest of program) m_pDemodSetupDlg = new CDemodSetupDlg(this); m_pTimer = new QTimer(this); //connect a bunch of signals to the GUI objects connect(m_pTimer, SIGNAL(timeout()), this, SLOT(OnTimer())); connect(ui->frameFreqCtrl, SIGNAL(NewFrequency(qint64)), this, SLOT(OnNewCenterFrequency(qint64))); connect(ui->frameDemodFreqCtrl, SIGNAL(NewFrequency(qint64)), this, SLOT(OnNewDemodFrequency(qint64))); connect(m_pSdrInterface, SIGNAL(NewStatus(int)), this, SLOT( OnStatus(int) ) ); connect(m_pSdrInterface, SIGNAL(NewInfoData()), this, SLOT( OnNewInfoData() ) ); connect(m_pSdrInterface, SIGNAL(NewFftData()), this, SLOT( OnNewFftData() ) ); connect(ui->actionExit, SIGNAL(triggered()), this, SLOT(OnExit())); connect(ui->actionNetwork, SIGNAL(triggered()), this, SLOT(OnNetworkDlg())); connect(ui->actionSoundCard, SIGNAL(triggered()), this, SLOT(OnSoundCardDlg())); connect(ui->actionSDR, SIGNAL(triggered()), this, SLOT(OnSdrDlg())); connect(ui->actionDisplay, SIGNAL(triggered()), this, SLOT(OnDisplayDlg())); connect(ui->actionAlwaysOnTop, SIGNAL(triggered()), this, SLOT(AlwaysOnTop())); connect(ui->actionDemod_Setup, SIGNAL(triggered()), this, SLOT(OnDemodDlg())); connect(ui->actionNoise_Processing, SIGNAL(triggered()), this, SLOT(OnNoiseProcDlg())); connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(OnAbout())); connect(ui->framePlot, SIGNAL(NewDemodFreq(qint64)), this, SLOT( OnNewScreenDemodFreq(qint64) ) ); connect(ui->framePlot, SIGNAL(NewCenterFreq(qint64)), this, SLOT( OnNewScreenCenterFreq(qint64) ) ); connect(ui->framePlot, SIGNAL(NewLowCutFreq(int)), this, SLOT( OnNewLowCutFreq(int) ) ); connect(ui->framePlot, SIGNAL(NewHighCutFreq(int)), this, SLOT( OnNewHighCutFreq(int) ) ); m_pTimer->start(200); //start up status timer m_pSdrInterface->SetRadioType(m_RadioType); quint32 maxspan = m_pSdrInterface->GetMaxBWFromIndex(m_BandwidthIndex); ui->framePlot->SetPercent2DScreen(m_Percent2DScreen); //initialize controls and limits qint32 tmpspan = m_SpanFrequency; //save since setting range triggers control to update ui->SpanspinBox->setMaximum(maxspan/1000); m_SpanFrequency = tmpspan; if(m_SpanFrequency>maxspan) m_SpanFrequency = maxspan; ui->SpanspinBox->setValue(m_SpanFrequency/1000); m_LastSpanKhz = m_SpanFrequency/1000; //tmp save demod freq since gets set to center freq by center freq control inititalization qint64 tmpdemod = m_DemodFrequency; ui->frameFreqCtrl->Setup(9, 100U, 500000000U, 1, UNITS_KHZ ); ui->frameFreqCtrl->SetBkColor(Qt::darkBlue); ui->frameFreqCtrl->SetDigitColor(Qt::cyan); ui->frameFreqCtrl->SetUnitsColor(Qt::lightGray); ui->frameFreqCtrl->SetHighlightColor(Qt::darkGray); ui->frameFreqCtrl->SetFrequency(m_CenterFrequency); m_DemodFrequency = tmpdemod; ui->frameDemodFreqCtrl->Setup(9, 100U, 500000000U, 1, UNITS_KHZ ); ui->frameDemodFreqCtrl->SetBkColor(Qt::darkBlue); ui->frameDemodFreqCtrl->SetDigitColor(Qt::white); ui->frameDemodFreqCtrl->SetUnitsColor(Qt::lightGray); ui->frameDemodFreqCtrl->SetHighlightColor(Qt::darkGray); //limit demod frequency to Center Frequency +/-span frequency ui->frameDemodFreqCtrl->Setup(9, m_CenterFrequency-m_SpanFrequency/2, m_CenterFrequency+m_SpanFrequency/2, 1, UNITS_KHZ ); ui->frameDemodFreqCtrl->SetFrequency(m_DemodFrequency); ui->framePlot->SetSpanFreq( m_SpanFrequency ); ui->framePlot->SetCenterFreq( m_CenterFrequency ); ui->framePlot->SetClickResolution(m_ClickResolution); m_FreqChanged = false; ui->horizontalSliderVol->setValue(m_Volume); m_pSdrInterface->SetVolume(m_Volume); ui->ScalecomboBox->addItem("10 dB/Div", 10); ui->ScalecomboBox->addItem("5 dB/Div", 5); ui->ScalecomboBox->addItem("3 dB/Div", 3); ui->ScalecomboBox->addItem("1 dB/Div", 1); m_dBStepSize = (int)ui->ScalecomboBox->itemData(m_VertScaleIndex).toInt(); ui->ScalecomboBox->setCurrentIndex(m_VertScaleIndex); ui->framePlot->SetdBStepSize(m_dBStepSize); ui->MaxdBspinBox->setValue(m_MaxdB); ui->MaxdBspinBox->setSingleStep(m_dBStepSize); ui->MaxdBspinBox->setMinimum(MIN_FFTDB+VERT_DIVS*m_dBStepSize); ui->MaxdBspinBox->setMaximum(MAX_FFTDB); ui->framePlot->SetMaxdB(m_MaxdB); m_pSdrInterface->SetFftSize( m_FftSize); m_pSdrInterface->SetFftAve( m_FftAve); m_pSdrInterface->SetMaxDisplayRate(m_MaxDisplayRate); m_pSdrInterface->SetSdrBandwidthIndex(m_BandwidthIndex); m_pSdrInterface->SetSdrRfGain( m_RfGain ); m_pSdrInterface->ManageNCOSpurOffsets(CSdrInterface::NCOSPUR_CMD_SET, &m_NCOSpurOffsetI, &m_NCOSpurOffsetQ); m_pSdrInterface->SetSoundCardSelection(m_SoundInIndex, m_SoundOutIndex, m_StereoOut); m_pSdrInterface->SetSpectrumInversion(m_InvertSpectrum); m_pSdrInterface->SetUSFmVersion(m_USFm); InitDemodSettings(); ui->framePlot->SetDemodCenterFreq( m_DemodFrequency ); SetupDemod(m_DemodMode); m_RdsDecode.DecodeReset(m_USFm); SetupNoiseProc(); UpdateInfoBox(); m_ActiveDevice = ""; m_pSdrInterface->SetupNetwork(m_IPAdr,m_Port); m_Status = CSdrInterface::NOT_CONNECTED; m_LastStatus = m_Status; m_pSdrInterface->StartIO(); m_KeepAliveTimer = 0; if(m_UseTestBench) { //make sure top of dialog is visable(0,0 doesn't include menu bar.Qt bug?) if(m_TestBenchRect.top()<30) m_TestBenchRect.setTop(30); g_pTestBench->setGeometry(m_TestBenchRect); g_pTestBench->show(); g_pTestBench->Init(); } }
////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CTestBench::CTestBench(QWidget *parent) : QDialog(parent), ui(new Ui::CTestBench) { m_Active = false; m_2DPixmap = QPixmap(0,0); m_OverlayPixmap = QPixmap(0,0); m_Size = QSize(0,0); m_Rect = QRect(0,0,100,100); m_MaxdB = 10; m_MindB = -120; m_dBStepSize = 10; m_FreqUnits = 1; m_CenterFreq = 0; m_GenSampleRate = 1; m_DisplaySampleRate = 1; m_Span = m_DisplaySampleRate/2; m_FftBufPos = 0; m_GenOn = false; m_PeakOn = false; m_NewDataIsCpx = false; m_CurrentDataIsCpx = true; m_TimeDisplay = false; m_DisplayRate = 10; m_HorzSpan = 100; m_VertRange = 65000; m_TrigLevel = 100; m_TrigBufPos = 0; m_TrigCounter = 0; m_TrigState = TRIGSTATE_WAIT; m_PulseWidth = .01; m_PulsePeriod = .5; m_PulseTimer = 0.0; connect(this, SIGNAL(ResetSignal()), this, SLOT( Reset() ) ); connect(this, SIGNAL(NewFftData()), this, SLOT( DrawFftPlot() ) ); connect(this, SIGNAL(NewTimeData()), this, SLOT( DrawTimePlot() ) ); connect( this, SIGNAL( SendTxt(QString)), this, SLOT( GotTxt(QString) ) ); m_Fft.SetFFTParams( 2048, FALSE, 0.0, m_GenSampleRate); m_Fft.SetFFTAve(0); ui->setupUi(this); setWindowTitle("CuteSDR Test Bench"); ui->textEdit->clear(); m_pTimer = new QTimer(this); connect(m_pTimer, SIGNAL(timeout()), this, SLOT(OnTimer())); #if USE_FILE //test file reading kludge QDir::setCurrent("d:/"); m_File.setFileName(FILE_NAME); if(m_File.open(QIODevice::ReadOnly)) { qDebug()<<"file Opend OK"; if(USE_SVFILE) m_File.seek(0x7e); //SV else if(USE_PERSEUSFILE) m_File.seek(0x7A); //perseus } else qDebug()<<"file Failed to Open"; #endif }