mirror of https://github.com/f4exb/sdrangel.git
BladeRF2 output: fixed SO mode
This commit is contained in:
parent
5566dc6a7e
commit
53ff8f32bf
|
@ -18,6 +18,10 @@
|
||||||
|
|
||||||
MESSAGE_CLASS_DEFINITION(DeviceBladeRF2Shared::MsgReportBuddyChange, Message)
|
MESSAGE_CLASS_DEFINITION(DeviceBladeRF2Shared::MsgReportBuddyChange, Message)
|
||||||
|
|
||||||
|
const float DeviceBladeRF2Shared::m_sampleFifoLengthInSeconds = 0.25;
|
||||||
|
const int DeviceBladeRF2Shared::m_sampleFifoMinSize = 75000; // 300 kS/s knee
|
||||||
|
const int DeviceBladeRF2Shared::m_sampleFifoMinSize32 = 150000; // Fixed for interpolation by 32
|
||||||
|
|
||||||
DeviceBladeRF2Shared::DeviceBladeRF2Shared() :
|
DeviceBladeRF2Shared::DeviceBladeRF2Shared() :
|
||||||
m_dev(0),
|
m_dev(0),
|
||||||
m_channel(-1),
|
m_channel(-1),
|
||||||
|
|
|
@ -79,6 +79,10 @@ public:
|
||||||
int m_channel; //!< allocated channel (-1 if none)
|
int m_channel; //!< allocated channel (-1 if none)
|
||||||
BladeRF2Input *m_source;
|
BladeRF2Input *m_source;
|
||||||
BladeRF2Output *m_sink;
|
BladeRF2Output *m_sink;
|
||||||
|
|
||||||
|
static const float m_sampleFifoLengthInSeconds;
|
||||||
|
static const int m_sampleFifoMinSize;
|
||||||
|
static const int m_sampleFifoMinSize32;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -645,6 +645,37 @@ bool BladeRF2Output::applySettings(const BladeRF2OutputSettings& settings, bool
|
||||||
struct bladerf *dev = m_deviceShared.m_dev->getDev();
|
struct bladerf *dev = m_deviceShared.m_dev->getDev();
|
||||||
int requestedChannel = m_deviceAPI->getItemIndex();
|
int requestedChannel = m_deviceAPI->getItemIndex();
|
||||||
|
|
||||||
|
if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || (m_settings.m_log2Interp != settings.m_log2Interp) || force)
|
||||||
|
{
|
||||||
|
BladeRF2OutputThread *bladeRF2OutputThread = findThread();
|
||||||
|
SampleSourceFifo *fifo = 0;
|
||||||
|
|
||||||
|
if (bladeRF2OutputThread)
|
||||||
|
{
|
||||||
|
fifo = bladeRF2OutputThread->getFifo(requestedChannel);
|
||||||
|
bladeRF2OutputThread->setFifo(requestedChannel, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fifoSize;
|
||||||
|
|
||||||
|
if (settings.m_log2Interp >= 5)
|
||||||
|
{
|
||||||
|
fifoSize = DeviceBladeRF2Shared::m_sampleFifoMinSize32;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fifoSize = std::max(
|
||||||
|
(int) ((settings.m_devSampleRate/(1<<settings.m_log2Interp)) * DeviceBladeRF2Shared::m_sampleFifoLengthInSeconds),
|
||||||
|
DeviceBladeRF2Shared::m_sampleFifoMinSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_sampleSourceFifo.resize(fifoSize);
|
||||||
|
|
||||||
|
if (fifo) {
|
||||||
|
bladeRF2OutputThread->setFifo(requestedChannel, &m_sampleSourceFifo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force)
|
if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force)
|
||||||
{
|
{
|
||||||
forwardChangeOwnDSP = true;
|
forwardChangeOwnDSP = true;
|
||||||
|
@ -663,7 +694,7 @@ bool BladeRF2Output::applySettings(const BladeRF2OutputSettings& settings, bool
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qDebug() << "BladeRF2Output::applySettings: bladerf_set_sample_rate(BLADERF_MODULE_RX) actual sample rate is " << actualSamplerate;
|
qDebug() << "BladeRF2Output::applySettings: bladerf_set_sample_rate: actual sample rate is " << actualSamplerate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -684,7 +715,7 @@ bool BladeRF2Output::applySettings(const BladeRF2OutputSettings& settings, bool
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qDebug() << "BladeRF2Output::applySettings: bladerf_set_bandwidth(BLADERF_MODULE_RX) actual bandwidth is " << actualBandwidth;
|
qDebug() << "BladeRF2Output::applySettings: bladerf_set_bandwidth: actual bandwidth is " << actualBandwidth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -736,25 +767,7 @@ bool BladeRF2Output::applySettings(const BladeRF2OutputSettings& settings, bool
|
||||||
m_deviceShared.m_dev->setBiasTeeTx(settings.m_biasTee);
|
m_deviceShared.m_dev->setBiasTeeTx(settings.m_biasTee);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m_settings.m_gainMode != settings.m_gainMode) || force)
|
if ((m_settings.m_globalGain != settings.m_globalGain) || force)
|
||||||
{
|
|
||||||
forwardChangeTxBuddies = true;
|
|
||||||
|
|
||||||
if (dev)
|
|
||||||
{
|
|
||||||
int status = bladerf_set_gain_mode(dev, BLADERF_CHANNEL_TX(requestedChannel), (bladerf_gain_mode) settings.m_gainMode);
|
|
||||||
|
|
||||||
if (status < 0) {
|
|
||||||
qWarning("BladeRF2Output::applySettings: bladerf_set_gain_mode(%d) failed: %s",
|
|
||||||
settings.m_gainMode, bladerf_strerror(status));
|
|
||||||
} else {
|
|
||||||
qDebug("BladeRF2Output::applySettings: bladerf_set_gain_mode(%d)", settings.m_gainMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((m_settings.m_globalGain != settings.m_globalGain)
|
|
||||||
|| ((m_settings.m_gainMode != settings.m_gainMode) && (settings.m_gainMode == BLADERF_GAIN_MANUAL)) || force)
|
|
||||||
{
|
{
|
||||||
forwardChangeTxBuddies = true;
|
forwardChangeTxBuddies = true;
|
||||||
|
|
||||||
|
@ -821,7 +834,6 @@ bool BladeRF2Output::applySettings(const BladeRF2OutputSettings& settings, bool
|
||||||
<< " m_log2Interp: " << m_settings.m_log2Interp
|
<< " m_log2Interp: " << m_settings.m_log2Interp
|
||||||
<< " m_devSampleRate: " << m_settings.m_devSampleRate
|
<< " m_devSampleRate: " << m_settings.m_devSampleRate
|
||||||
<< " m_globalGain: " << m_settings.m_globalGain
|
<< " m_globalGain: " << m_settings.m_globalGain
|
||||||
<< " m_gainMode: " << m_settings.m_gainMode
|
|
||||||
<< " m_biasTee: " << m_settings.m_biasTee;
|
<< " m_biasTee: " << m_settings.m_biasTee;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -860,9 +872,6 @@ int BladeRF2Output::webapiSettingsPutPatch(
|
||||||
if (deviceSettingsKeys.contains("biasTee")) {
|
if (deviceSettingsKeys.contains("biasTee")) {
|
||||||
settings.m_biasTee = response.getBladeRf2OutputSettings()->getBiasTee() != 0;
|
settings.m_biasTee = response.getBladeRf2OutputSettings()->getBiasTee() != 0;
|
||||||
}
|
}
|
||||||
if (deviceSettingsKeys.contains("gainMode")) {
|
|
||||||
settings.m_gainMode = response.getBladeRf2OutputSettings()->getGainMode();
|
|
||||||
}
|
|
||||||
if (deviceSettingsKeys.contains("globalGain")) {
|
if (deviceSettingsKeys.contains("globalGain")) {
|
||||||
settings.m_globalGain = response.getBladeRf2OutputSettings()->getGlobalGain();
|
settings.m_globalGain = response.getBladeRf2OutputSettings()->getGlobalGain();
|
||||||
}
|
}
|
||||||
|
@ -895,7 +904,6 @@ void BladeRF2Output::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings&
|
||||||
response.getBladeRf2OutputSettings()->setBandwidth(settings.m_bandwidth);
|
response.getBladeRf2OutputSettings()->setBandwidth(settings.m_bandwidth);
|
||||||
response.getBladeRf2OutputSettings()->setLog2Interp(settings.m_log2Interp);
|
response.getBladeRf2OutputSettings()->setLog2Interp(settings.m_log2Interp);
|
||||||
response.getBladeRf2OutputSettings()->setBiasTee(settings.m_biasTee ? 1 : 0);
|
response.getBladeRf2OutputSettings()->setBiasTee(settings.m_biasTee ? 1 : 0);
|
||||||
response.getBladeRf2OutputSettings()->setGainMode(settings.m_gainMode);
|
|
||||||
response.getBladeRf2OutputSettings()->setGlobalGain(settings.m_globalGain);
|
response.getBladeRf2OutputSettings()->setGlobalGain(settings.m_globalGain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,7 @@ void BladeRF2OutputSettings::resetToDefaults()
|
||||||
m_centerFrequency = 435000*1000;
|
m_centerFrequency = 435000*1000;
|
||||||
m_devSampleRate = 3072000;
|
m_devSampleRate = 3072000;
|
||||||
m_bandwidth = 1500000;
|
m_bandwidth = 1500000;
|
||||||
m_gainMode = 0;
|
m_globalGain = -3;
|
||||||
m_globalGain = -20;
|
|
||||||
m_biasTee = false;
|
m_biasTee = false;
|
||||||
m_log2Interp = 0;
|
m_log2Interp = 0;
|
||||||
}
|
}
|
||||||
|
@ -42,7 +41,6 @@ QByteArray BladeRF2OutputSettings::serialize() const
|
||||||
|
|
||||||
s.writeS32(1, m_devSampleRate);
|
s.writeS32(1, m_devSampleRate);
|
||||||
s.writeS32(2, m_bandwidth);
|
s.writeS32(2, m_bandwidth);
|
||||||
s.writeS32(3, m_gainMode);
|
|
||||||
s.writeS32(4, m_globalGain);
|
s.writeS32(4, m_globalGain);
|
||||||
s.writeBool(5, m_biasTee);
|
s.writeBool(5, m_biasTee);
|
||||||
s.writeU32(6, m_log2Interp);
|
s.writeU32(6, m_log2Interp);
|
||||||
|
@ -64,7 +62,6 @@ bool BladeRF2OutputSettings::deserialize(const QByteArray& data)
|
||||||
{
|
{
|
||||||
d.readS32(1, &m_devSampleRate);
|
d.readS32(1, &m_devSampleRate);
|
||||||
d.readS32(2, &m_bandwidth);
|
d.readS32(2, &m_bandwidth);
|
||||||
d.readS32(3, &m_gainMode);
|
|
||||||
d.readS32(4, &m_globalGain);
|
d.readS32(4, &m_globalGain);
|
||||||
d.readBool(5, &m_biasTee);
|
d.readBool(5, &m_biasTee);
|
||||||
d.readU32(6, &m_log2Interp);
|
d.readU32(6, &m_log2Interp);
|
||||||
|
|
|
@ -24,7 +24,6 @@ struct BladeRF2OutputSettings {
|
||||||
quint64 m_centerFrequency;
|
quint64 m_centerFrequency;
|
||||||
qint32 m_devSampleRate;
|
qint32 m_devSampleRate;
|
||||||
qint32 m_bandwidth;
|
qint32 m_bandwidth;
|
||||||
int m_gainMode;
|
|
||||||
int m_globalGain;
|
int m_globalGain;
|
||||||
bool m_biasTee;
|
bool m_biasTee;
|
||||||
quint32 m_log2Interp;
|
quint32 m_log2Interp;
|
||||||
|
|
|
@ -92,10 +92,10 @@ void BladeRF2OutputThread::run()
|
||||||
if (m_nbChannels > 1) {
|
if (m_nbChannels > 1) {
|
||||||
callbackMO(m_buf, DeviceBladeRF2::blockSize);
|
callbackMO(m_buf, DeviceBladeRF2::blockSize);
|
||||||
} else {
|
} else {
|
||||||
callbackSO(m_buf, 2*DeviceBladeRF2::blockSize);
|
callbackSO(m_buf, DeviceBladeRF2::blockSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = bladerf_sync_tx(m_dev, m_buf, DeviceBladeRF2::blockSize, NULL, 10000);
|
res = bladerf_sync_tx(m_dev, m_buf, DeviceBladeRF2::blockSize, 0, 10000);
|
||||||
|
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
{
|
{
|
||||||
|
@ -166,7 +166,7 @@ void BladeRF2OutputThread::callbackMO(qint16* buf, qint32 samplesPerChannel)
|
||||||
for (unsigned int channel = 0; channel < m_nbChannels; channel++)
|
for (unsigned int channel = 0; channel < m_nbChannels; channel++)
|
||||||
{
|
{
|
||||||
if (m_channels[channel].m_sampleFifo) {
|
if (m_channels[channel].m_sampleFifo) {
|
||||||
callbackSO(&buf[2*samplesPerChannel*channel], 2*samplesPerChannel, channel);
|
callbackSO(&buf[2*samplesPerChannel*channel], samplesPerChannel, channel);
|
||||||
} else {
|
} else {
|
||||||
std::fill(&buf[2*samplesPerChannel*channel], &buf[2*samplesPerChannel*channel]+2*samplesPerChannel, 0); // fill with zero samples
|
std::fill(&buf[2*samplesPerChannel*channel], &buf[2*samplesPerChannel*channel]+2*samplesPerChannel, 0); // fill with zero samples
|
||||||
}
|
}
|
||||||
|
@ -182,42 +182,57 @@ void BladeRF2OutputThread::callbackMO(qint16* buf, qint32 samplesPerChannel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpolate according to specified log2 (ex: log2=4 => decim=16)
|
// Interpolate according to specified log2 (ex: log2=4 => decim=16). len is a number of samples (not a number of I or Q)
|
||||||
void BladeRF2OutputThread::callbackSO(qint16* buf, qint32 len, unsigned int channel)
|
void BladeRF2OutputThread::callbackSO(qint16* buf, qint32 len, unsigned int channel)
|
||||||
{
|
{
|
||||||
SampleVector::iterator beginRead;
|
if (m_channels[channel].m_sampleFifo)
|
||||||
m_channels[channel].m_sampleFifo->readAdvance(beginRead, len/(1<<m_channels[channel].m_log2Interp));
|
|
||||||
beginRead -= len;
|
|
||||||
|
|
||||||
if (m_channels[channel].m_log2Interp == 0)
|
|
||||||
{
|
{
|
||||||
m_channels[channel].m_interpolators.interpolate1(&beginRead, buf, len*2);
|
float bal = m_channels[channel].m_sampleFifo->getRWBalance();
|
||||||
|
|
||||||
|
if (bal < -0.25) {
|
||||||
|
qDebug("BladeRF2OutputThread::callbackSO: read lags: %f", bal);
|
||||||
|
} else if (bal > 0.25) {
|
||||||
|
qDebug("BladeRF2OutputThread::callbackSO: read leads: %f", bal);
|
||||||
|
}
|
||||||
|
|
||||||
|
SampleVector::iterator beginRead;
|
||||||
|
m_channels[channel].m_sampleFifo->readAdvance(beginRead, len/(1<<m_channels[channel].m_log2Interp));
|
||||||
|
beginRead -= len;
|
||||||
|
|
||||||
|
if (m_channels[channel].m_log2Interp == 0)
|
||||||
|
{
|
||||||
|
m_channels[channel].m_interpolators.interpolate1(&beginRead, buf, len*2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (m_channels[channel].m_log2Interp)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
m_channels[channel].m_interpolators.interpolate2_cen(&beginRead, buf, len*2);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
m_channels[channel].m_interpolators.interpolate4_cen(&beginRead, buf, len*2);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
m_channels[channel].m_interpolators.interpolate8_cen(&beginRead, buf, len*2);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
m_channels[channel].m_interpolators.interpolate16_cen(&beginRead, buf, len*2);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
m_channels[channel].m_interpolators.interpolate32_cen(&beginRead, buf, len*2);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
m_channels[channel].m_interpolators.interpolate64_cen(&beginRead, buf, len*2);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch (m_channels[channel].m_log2Interp)
|
std::fill(buf, buf+2*len, 0);
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
m_channels[channel].m_interpolators.interpolate2_cen(&beginRead, buf, len*2);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
m_channels[channel].m_interpolators.interpolate4_cen(&beginRead, buf, len*2);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
m_channels[channel].m_interpolators.interpolate8_cen(&beginRead, buf, len*2);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
m_channels[channel].m_interpolators.interpolate16_cen(&beginRead, buf, len*2);
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
m_channels[channel].m_interpolators.interpolate32_cen(&beginRead, buf, len*2);
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
m_channels[channel].m_interpolators.interpolate64_cen(&beginRead, buf, len*2);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -735,7 +735,7 @@ bool BladeRF2Input::applySettings(const BladeRF2InputSettings& settings, bool fo
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qDebug() << "BladeRF2Input::applySettings: bladerf_set_sample_rate(BLADERF_MODULE_RX) actual sample rate is " << actualSamplerate;
|
qDebug() << "BladeRF2Input::applySettings: bladerf_set_sample_rate: actual sample rate is " << actualSamplerate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -756,7 +756,7 @@ bool BladeRF2Input::applySettings(const BladeRF2InputSettings& settings, bool fo
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qDebug() << "BladeRF2Input::applySettings: bladerf_set_bandwidth(BLADERF_MODULE_RX) actual bandwidth is " << actualBandwidth;
|
qDebug() << "BladeRF2Input::applySettings: bladerf_set_bandwidth: actual bandwidth is " << actualBandwidth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ public:
|
||||||
|
|
||||||
void write(const Sample& sample); //!< write directly - phase 1 + phase 2
|
void write(const Sample& sample); //!< write directly - phase 1 + phase 2
|
||||||
|
|
||||||
/** returns ratio of off center over buffer size with sign: negative real lags and positive read leads */
|
/** returns ratio of off center over buffer size with sign: negative read lags and positive read leads */
|
||||||
float getRWBalance() const
|
float getRWBalance() const
|
||||||
{
|
{
|
||||||
int delta;
|
int delta;
|
||||||
|
|
|
@ -51,8 +51,6 @@ BladeRF2OutputSettings:
|
||||||
type: integer
|
type: integer
|
||||||
bandwidth:
|
bandwidth:
|
||||||
type: integer
|
type: integer
|
||||||
gainMode:
|
|
||||||
type: integer
|
|
||||||
globalGain:
|
globalGain:
|
||||||
type: integer
|
type: integer
|
||||||
biasTee:
|
biasTee:
|
||||||
|
|
Loading…
Reference in New Issue