diff --git a/plugins/samplesource/bladerf/bladerfgui.cpp b/plugins/samplesource/bladerf/bladerfgui.cpp index 507ac39a6..e5685f50c 100644 --- a/plugins/samplesource/bladerf/bladerfgui.cpp +++ b/plugins/samplesource/bladerf/bladerfgui.cpp @@ -130,6 +130,8 @@ void BladerfGui::displaySettings() ui->decimText->setText(tr("%1").arg(1<decim->setValue(m_settings.m_log2Decim); + ui->fcPos->setCurrentIndex((int) m_settings.m_fcPos); + ui->lnaGainText->setText(tr("%1").arg(m_settings.m_lnaGain)); ui->lna->setValue(m_settings.m_lnaGain); @@ -179,6 +181,17 @@ void BladerfGui::on_decim_valueChanged(int value) sendSettings(); } +void BladerfGui::on_fcPos_currentIndexChanged(int index) +{ + if (index == 0) { + m_settings.m_fcPos = BladerfInput::FC_POS_INFRA; + sendSettings(); + } else if (index == 1) { + m_settings.m_fcPos = BladerfInput::FC_POS_SUPRA; + sendSettings(); + } +} + void BladerfGui::on_lna_valueChanged(int value) { std::cerr << "BladerfGui: LNA gain = " << value << std::endl; diff --git a/plugins/samplesource/bladerf/bladerfgui.h b/plugins/samplesource/bladerf/bladerfgui.h index 402dc880a..a88c6acb3 100644 --- a/plugins/samplesource/bladerf/bladerfgui.h +++ b/plugins/samplesource/bladerf/bladerfgui.h @@ -71,6 +71,7 @@ private slots: void on_vga1_valueChanged(int value); void on_vga2_valueChanged(int value); void on_xb200_currentIndexChanged(int index); + void on_fcPos_currentIndexChanged(int index); void updateHardware(); }; diff --git a/plugins/samplesource/bladerf/bladerfgui.ui b/plugins/samplesource/bladerf/bladerfgui.ui index 07bff271f..8dcbe2c85 100644 --- a/plugins/samplesource/bladerf/bladerfgui.ui +++ b/plugins/samplesource/bladerf/bladerfgui.ui @@ -7,7 +7,7 @@ 0 0 198 - 255 + 274 @@ -364,6 +364,54 @@ + + + + 3 + + + + + Fc pos + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + Inf + + + + + Sup + + + + + + + + + + Qt::Horizontal + + + diff --git a/plugins/samplesource/bladerf/bladerfinput.cpp b/plugins/samplesource/bladerf/bladerfinput.cpp index a783a1df7..f76868eef 100644 --- a/plugins/samplesource/bladerf/bladerfinput.cpp +++ b/plugins/samplesource/bladerf/bladerfinput.cpp @@ -34,6 +34,7 @@ BladerfInput::Settings::Settings() : m_samplerate(3072000), m_bandwidth(1500000), m_log2Decim(0), + m_fcPos(FC_POS_INFRA), m_xb200(false), m_xb200Path(BLADERF_XB200_MIX), m_xb200Filter(BLADERF_XB200_AUTO_1DB) @@ -48,6 +49,7 @@ void BladerfInput::Settings::resetToDefaults() m_samplerate = 3072000; m_bandwidth = 1500000; m_log2Decim = 0; + m_fcPos = FC_POS_INFRA; m_xb200 = false; m_xb200Path = BLADERF_XB200_MIX; m_xb200Filter = BLADERF_XB200_AUTO_1DB; @@ -65,6 +67,7 @@ QByteArray BladerfInput::Settings::serialize() const s.writeS32(7, (int) m_xb200Path); s.writeS32(8, (int) m_xb200Filter); s.writeS32(9, m_bandwidth); + s.writeS32(10, (int) m_fcPos); return s.final(); } @@ -90,6 +93,8 @@ bool BladerfInput::Settings::deserialize(const QByteArray& data) d.readS32(8, &intval); m_xb200Filter = (bladerf_xb200_filter) intval; d.readS32(9, &m_bandwidth, 0); + d.readS32(10, &intval, 0); + m_fcPos = (fcPos_t) intval; return true; } else { resetToDefaults(); @@ -332,19 +337,50 @@ bool BladerfInput::applySettings(const GeneralSettings& generalSettings, const S } } + if((m_settings.m_fcPos != settings.m_fcPos) || force) { + if(m_dev != NULL) { + m_settings.m_fcPos = settings.m_fcPos; + m_bladerfThread->setFcPos((int) settings.m_fcPos); + std::cerr << "BladerfInput: set fc pos (enum) to " << (int) m_settings.m_fcPos << std::endl; + } + } + m_generalSettings.m_centerFrequency = generalSettings.m_centerFrequency; if(m_dev != NULL) { - qint64 centerFrequency = m_generalSettings.m_centerFrequency + (m_settings.m_samplerate / 4); + qint64 centerFrequency = m_generalSettings.m_centerFrequency; + qint64 f_img = centerFrequency; + qint64 f_cut = centerFrequency + m_settings.m_bandwidth/2; - if (m_settings.m_log2Decim == 0) { // Little wooby-doop if no decimation + if (m_settings.m_log2Decim == 0) + { // Little wooby-doop if no decimation centerFrequency = m_generalSettings.m_centerFrequency; - } else { - centerFrequency = m_generalSettings.m_centerFrequency + (m_settings.m_samplerate / 4); + f_img = centerFrequency; + f_cut = centerFrequency + m_settings.m_bandwidth/2; + } + else + { + if (m_settings.m_fcPos == FC_POS_INFRA) { + centerFrequency = m_generalSettings.m_centerFrequency + (m_settings.m_samplerate / 4); + f_img = centerFrequency + m_settings.m_samplerate/2; + f_cut = centerFrequency + m_settings.m_bandwidth/2; + } else if (m_settings.m_fcPos == FC_POS_SUPRA) { + centerFrequency = m_generalSettings.m_centerFrequency - (m_settings.m_samplerate / 4); + f_img = centerFrequency - m_settings.m_samplerate/2; + f_cut = centerFrequency - m_settings.m_bandwidth/2; + } } if(bladerf_set_frequency( m_dev, BLADERF_MODULE_RX, centerFrequency ) != 0) { qDebug("bladerf_set_frequency(%lld) failed", m_generalSettings.m_centerFrequency); } + + std::cerr << "BladerfInput: center freq: " << m_generalSettings.m_centerFrequency << " Hz" + << " RF center freq: " << centerFrequency << " Hz" + << " sample rate / 2 : " << m_settings.m_samplerate/2 << "Hz" + << " BW: " << m_settings.m_bandwidth << "Hz" + << " img: " << f_img << "Hz" + << " cut: " << f_cut << "Hz" + << " img - cut: " << f_img - f_cut << std::endl; } return true; diff --git a/plugins/samplesource/bladerf/bladerfinput.h b/plugins/samplesource/bladerf/bladerfinput.h index bf3ab84fa..62b7a0d0b 100644 --- a/plugins/samplesource/bladerf/bladerfinput.h +++ b/plugins/samplesource/bladerf/bladerfinput.h @@ -25,6 +25,11 @@ class BladerfThread; class BladerfInput : public SampleSource { public: + typedef enum { + FC_POS_INFRA = 0, + FC_POS_SUPRA + } fcPos_t; + struct Settings { qint32 m_lnaGain; qint32 m_vga1; @@ -32,6 +37,7 @@ public: qint32 m_samplerate; qint32 m_bandwidth; quint32 m_log2Decim; + fcPos_t m_fcPos; bool m_xb200; bladerf_xb200_path m_xb200Path; bladerf_xb200_filter m_xb200Filter; diff --git a/plugins/samplesource/bladerf/bladerfthread.cpp b/plugins/samplesource/bladerf/bladerfthread.cpp index eab70f4fe..aa24bc0c8 100644 --- a/plugins/samplesource/bladerf/bladerfthread.cpp +++ b/plugins/samplesource/bladerf/bladerfthread.cpp @@ -28,7 +28,8 @@ BladerfThread::BladerfThread(struct bladerf* dev, SampleFifo* sampleFifo, QObjec m_convertBuffer(BLADERF_BLOCKSIZE), m_sampleFifo(sampleFifo), m_samplerate(3072000), - m_log2Decim(0) + m_log2Decim(0), + m_fcPos(0) { } @@ -62,6 +63,11 @@ void BladerfThread::setLog2Decimation(unsigned int log2_decim) m_log2Decim = log2_decim; } +void BladerfThread::setFcPos(int fcPos) +{ + m_fcPos = fcPos; +} + void BladerfThread::run() { int res; @@ -128,6 +134,23 @@ void BladerfThread::decimate2(SampleVector::iterator* it, const qint16* buf, qin } } +void BladerfThread::decimate2_sup(SampleVector::iterator* it, const qint16* buf, qint32 len) +{ + qint16 xreal, yimag; + for (int pos = 0; pos < len - 7; pos += 8) { + xreal = buf[pos+1] - buf[pos+2]; + yimag = - buf[pos+0] - buf[pos+3]; + Sample s( xreal << 3, yimag << 3 ); + **it = s; + (*it)++; + xreal = buf[pos+6] - buf[pos+5]; + yimag = buf[pos+4] + buf[pos+7]; + Sample t( xreal << 3, yimag << 3 ); + **it = t; + (*it)++; + } +} + void BladerfThread::decimate4(SampleVector::iterator* it, const qint16* buf, qint32 len) { qint16 xreal, yimag; @@ -140,6 +163,26 @@ void BladerfThread::decimate4(SampleVector::iterator* it, const qint16* buf, qin } } +void BladerfThread::decimate4_sup(SampleVector::iterator* it, const qint16* buf, qint32 len) +{ + // Sup (USB): + // x y x y x y x y / x -> 1,-2,-5,6 / y -> -0,-3,4,7 + // [ rotate: 1, 0, -2, 3, -5, -4, 6, -7] + // Inf (LSB): + // x y x y x y x y / x -> 0,-3,-4,7 / y -> 1,2,-5,-6 + // [ rotate: 0, 1, -3, 2, -4, -5, 7, -6] + qint16 xreal, yimag; + for (int pos = 0; pos < len - 7; pos += 8) { + xreal = buf[pos+1] - buf[pos+2] - buf[pos+5] + buf[pos+6]; + yimag = - buf[pos+0] - buf[pos+3] + buf[pos+4] + buf[pos+7]; + //xreal = buf[pos+0] - buf[pos+3] - buf[pos+4] + buf[pos+7]; + //yimag = buf[pos+1] + buf[pos+2] - buf[pos+5] - buf[pos+6]; + Sample s( xreal << 2, yimag << 2 ); // was shift 3 + **it = s; + (*it)++; + } +} + void BladerfThread::decimate8(SampleVector::iterator* it, const qint16* buf, qint32 len) { qint16 xreal, yimag; @@ -158,6 +201,24 @@ void BladerfThread::decimate8(SampleVector::iterator* it, const qint16* buf, qin } } +void BladerfThread::decimate8_sup(SampleVector::iterator* it, const qint16* buf, qint32 len) +{ + qint16 xreal, yimag; + for (int pos = 0; pos < len - 15; pos += 8) { + xreal = buf[pos+1] - buf[pos+2] - buf[pos+5] + buf[pos+6]; + yimag = - buf[pos+0] - buf[pos+3] + buf[pos+4] + buf[pos+7]; + Sample s1( xreal << 2, yimag << 2 ); // was shift 3 + pos += 8; + xreal = buf[pos+1] - buf[pos+2] - buf[pos+5] + buf[pos+6]; + yimag = - buf[pos+0] - buf[pos+3] + buf[pos+4] + buf[pos+7]; + Sample s2( xreal << 2, yimag << 2 ); // was shift 3 + + m_decimator2.myDecimate(&s1, &s2); + **it = s2; + (*it)++; + } +} + void BladerfThread::decimate16(SampleVector::iterator* it, const qint16* buf, qint32 len) { // Offset tuning: 4x downsample and rotate, then @@ -186,6 +247,34 @@ void BladerfThread::decimate16(SampleVector::iterator* it, const qint16* buf, qi } } +void BladerfThread::decimate16_sup(SampleVector::iterator* it, const qint16* buf, qint32 len) +{ + // Offset tuning: 4x downsample and rotate, then + // downsample 4x more. [ rotate: 1, 0, -2, 3, -5, -4, 6, -7] + qint16 xreal[4], yimag[4]; + + for (int pos = 0; pos < len - 31; ) { + for (int i = 0; i < 4; i++) { + xreal[i] = (buf[pos+1] - buf[pos+2] - buf[pos+5] + buf[pos+6]) << 2; // was shift 4 + yimag[i] = (buf[pos+4] + buf[pos+7] - buf[pos+0] - buf[pos+3]) << 2; // was shift 4 + pos += 8; + } + + Sample s1( xreal[0], yimag[0] ); + Sample s2( xreal[1], yimag[1] ); + Sample s3( xreal[2], yimag[2] ); + Sample s4( xreal[3], yimag[3] ); + + m_decimator2.myDecimate(&s1, &s2); + m_decimator2.myDecimate(&s3, &s4); + + m_decimator4.myDecimate(&s2, &s4); + + **it = s4; + (*it)++; + } +} + void BladerfThread::decimate32(SampleVector::iterator* it, const qint16* buf, qint32 len) { qint16 xreal[8], yimag[8]; @@ -221,34 +310,100 @@ void BladerfThread::decimate32(SampleVector::iterator* it, const qint16* buf, qi } } +void BladerfThread::decimate32_sup(SampleVector::iterator* it, const qint16* buf, qint32 len) +{ + qint16 xreal[8], yimag[8]; + + for (int pos = 0; pos < len - 63; ) { + for (int i = 0; i < 8; i++) { + xreal[i] = (buf[pos+1] - buf[pos+2] - buf[pos+5] + buf[pos+6]) << 2; + yimag[i] = (buf[pos+4] + buf[pos+7] - buf[pos+0] - buf[pos+3]) << 2; + pos += 8; + } + + Sample s1( xreal[0], yimag[0] ); + Sample s2( xreal[1], yimag[1] ); + Sample s3( xreal[2], yimag[2] ); + Sample s4( xreal[3], yimag[3] ); + Sample s5( xreal[4], yimag[4] ); + Sample s6( xreal[5], yimag[5] ); + Sample s7( xreal[6], yimag[6] ); + Sample s8( xreal[7], yimag[7] ); + + m_decimator2.myDecimate(&s1, &s2); + m_decimator2.myDecimate(&s3, &s4); + m_decimator2.myDecimate(&s5, &s6); + m_decimator2.myDecimate(&s7, &s8); + + m_decimator4.myDecimate(&s2, &s4); + m_decimator4.myDecimate(&s6, &s8); + + m_decimator8.myDecimate(&s4, &s8); + + **it = s8; + (*it)++; + } +} + // Decimate according to specified log2 (ex: log2=4 => decim=16) void BladerfThread::callback(const qint16* buf, qint32 len) { SampleVector::iterator it = m_convertBuffer.begin(); - switch (m_log2Decim) + if (m_log2Decim == 0) { - case 0: decimate1(&it, buf, len); - break; - case 1: - decimate2(&it, buf, len); - break; - case 2: - decimate4(&it, buf, len); - break; - case 3: - decimate8(&it, buf, len); - break; - case 4: - decimate16(&it, buf, len); - break; - case 5: - decimate32(&it, buf, len); - break; - default: - break; } + else + { + if (m_fcPos == 0) // Infra + { + switch (m_log2Decim) + { + case 1: + decimate2(&it, buf, len); + break; + case 2: + decimate4(&it, buf, len); + break; + case 3: + decimate8(&it, buf, len); + break; + case 4: + decimate16(&it, buf, len); + break; + case 5: + decimate32(&it, buf, len); + break; + default: + break; + } + } + else if (m_fcPos == 1) // Supra + { + switch (m_log2Decim) + { + case 1: + decimate2_sup(&it, buf, len); + break; + case 2: + decimate4_sup(&it, buf, len); + break; + case 3: + decimate8_sup(&it, buf, len); + break; + case 4: + decimate16_sup(&it, buf, len); + break; + case 5: + decimate32_sup(&it, buf, len); + break; + default: + break; + } + } + } + m_sampleFifo->write(m_convertBuffer.begin(), it); } diff --git a/plugins/samplesource/bladerf/bladerfthread.h b/plugins/samplesource/bladerf/bladerfthread.h index d5493d459..aa0b9c77c 100644 --- a/plugins/samplesource/bladerf/bladerfthread.h +++ b/plugins/samplesource/bladerf/bladerfthread.h @@ -37,6 +37,7 @@ public: void stopWork(); void setSamplerate(int samplerate); void setLog2Decimation(unsigned int log2_decim); + void setFcPos(int fcPos); private: QMutex m_startWaitMutex; @@ -50,6 +51,7 @@ private: int m_samplerate; unsigned int m_log2Decim; + int m_fcPos; IntHalfbandFilter m_decimator2; // 1st stages IntHalfbandFilter m_decimator4; // 2nd stages @@ -59,10 +61,15 @@ private: void decimate1(SampleVector::iterator* it, const qint16* buf, qint32 len); void decimate2_u(SampleVector::iterator* it, const quint16* buf, qint32 len); void decimate2(SampleVector::iterator* it, const qint16* buf, qint32 len); + void decimate2_sup(SampleVector::iterator* it, const qint16* buf, qint32 len); void decimate4(SampleVector::iterator* it, const qint16* buf, qint32 len); + void decimate4_sup(SampleVector::iterator* it, const qint16* buf, qint32 len); void decimate8(SampleVector::iterator* it, const qint16* buf, qint32 len); + void decimate8_sup(SampleVector::iterator* it, const qint16* buf, qint32 len); void decimate16(SampleVector::iterator* it, const qint16* buf, qint32 len); + void decimate16_sup(SampleVector::iterator* it, const qint16* buf, qint32 len); void decimate32(SampleVector::iterator* it, const qint16* buf, qint32 len); + void decimate32_sup(SampleVector::iterator* it, const qint16* buf, qint32 len); void callback(const qint16* buf, qint32 len); };