kopia lustrzana https://github.com/f4exb/sdrangel
USRP driver improvements.
Set bit size to be 16 for interpolators and decimators. Match buffer size to UHD. Don't destroy TX stream, as there appears to be a bug when recreating it. Catch exception when checking for TX underflow. Increase RX FIFO size, to reduce overflows at high sample rates. Allow RX to continue streaming after receiving timeout.pull/670/head
rodzic
8b05670814
commit
209be94947
|
@ -33,8 +33,6 @@ public:
|
|||
/** Enumeration of USRP hardware devices */
|
||||
static void enumOriginDevices(const QString& hardwareId, PluginInterface::OriginDevices& originDevices);
|
||||
|
||||
/** Block size used for transferring IQ samples to and from the device. This perhaps needs tuning. */
|
||||
static const unsigned int blockSize = (1<<15);
|
||||
};
|
||||
|
||||
#endif /* DEVICES_USRP_DEVICEUSRP_H_ */
|
||||
|
|
|
@ -51,6 +51,7 @@ USRPOutput::USRPOutput(DeviceAPI *deviceAPI) :
|
|||
m_deviceAPI(deviceAPI),
|
||||
m_settings(),
|
||||
m_usrpOutputThread(nullptr),
|
||||
m_bufSamples(0),
|
||||
m_deviceDescription("USRPOutput"),
|
||||
m_running(false),
|
||||
m_channelAcquired(false)
|
||||
|
@ -288,6 +289,8 @@ bool USRPOutput::acquireChannel()
|
|||
suspendRxBuddies();
|
||||
suspendTxBuddies();
|
||||
|
||||
if (m_streamId == nullptr)
|
||||
{
|
||||
try
|
||||
{
|
||||
// set up the stream
|
||||
|
@ -300,11 +303,15 @@ bool USRPOutput::acquireChannel()
|
|||
stream_args.channels = channel_nums;
|
||||
|
||||
m_streamId = m_deviceShared.m_deviceParams->getDevice()->get_tx_stream(stream_args);
|
||||
|
||||
// Match our transmit buffer size to what UHD uses
|
||||
m_bufSamples = m_streamId->get_max_num_samps();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
qDebug() << "USRPOutput::acquireChannel: exception: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
resumeTxBuddies();
|
||||
resumeRxBuddies();
|
||||
|
@ -319,8 +326,14 @@ void USRPOutput::releaseChannel()
|
|||
suspendRxBuddies();
|
||||
suspendTxBuddies();
|
||||
|
||||
// destroy the stream - FIXME: Better way to do this?
|
||||
// FIXME: Currently we do not try to destroy the stream, as there seems to be
|
||||
// an issue when we re-acquire the stream, the output spectrum will not be correct
|
||||
// The transmitter output will be disabled when we stop sending data to it anyway
|
||||
if (false)
|
||||
{
|
||||
// destroy the stream
|
||||
m_streamId = nullptr;
|
||||
}
|
||||
|
||||
resumeTxBuddies();
|
||||
resumeRxBuddies();
|
||||
|
@ -346,9 +359,7 @@ bool USRPOutput::start()
|
|||
return false;
|
||||
}
|
||||
|
||||
// start / stop streaming is done in the thread.
|
||||
|
||||
m_usrpOutputThread = new USRPOutputThread(m_streamId, &m_sampleSourceFifo);
|
||||
m_usrpOutputThread = new USRPOutputThread(m_streamId, m_bufSamples, &m_sampleSourceFifo);
|
||||
qDebug("USRPOutput::start: thread created");
|
||||
|
||||
applySettings(m_settings, true);
|
||||
|
@ -563,7 +574,7 @@ bool USRPOutput::handleMessage(const Message& message)
|
|||
{
|
||||
if (m_deviceAPI->getSamplingDeviceGUIMessageQueue())
|
||||
{
|
||||
if (m_streamId != nullptr)
|
||||
if ((m_streamId != nullptr) && m_channelAcquired)
|
||||
{
|
||||
bool active;
|
||||
quint32 underflows;
|
||||
|
@ -1024,7 +1035,7 @@ void USRPOutput::webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response
|
|||
quint32 underflows = 0;
|
||||
quint32 droppedPackets = 0;
|
||||
|
||||
if (m_streamId != nullptr)
|
||||
if ((m_streamId != nullptr) && m_channelAcquired)
|
||||
{
|
||||
m_usrpOutputThread->getStreamStatus(active, underflows, droppedPackets);
|
||||
success = true;
|
||||
|
|
|
@ -226,6 +226,7 @@ private:
|
|||
DeviceUSRPShared m_deviceShared;
|
||||
bool m_channelAcquired;
|
||||
uhd::tx_streamer::sptr m_streamId;
|
||||
size_t m_bufSamples;
|
||||
QNetworkAccessManager *m_networkManager;
|
||||
QNetworkRequest m_networkRequest;
|
||||
|
||||
|
|
|
@ -26,19 +26,23 @@
|
|||
#include "usrpoutputthread.h"
|
||||
#include "usrpoutputsettings.h"
|
||||
|
||||
USRPOutputThread::USRPOutputThread(uhd::tx_streamer::sptr stream, SampleSourceFifo* sampleFifo, QObject* parent) :
|
||||
USRPOutputThread::USRPOutputThread(uhd::tx_streamer::sptr stream, size_t bufSamples, SampleSourceFifo* sampleFifo, QObject* parent) :
|
||||
QThread(parent),
|
||||
m_running(false),
|
||||
m_stream(stream),
|
||||
m_bufSamples(bufSamples),
|
||||
m_sampleFifo(sampleFifo),
|
||||
m_log2Interp(0)
|
||||
{
|
||||
std::fill(m_buf, m_buf + 2*DeviceUSRP::blockSize, 0);
|
||||
// *2 as samples are I+Q
|
||||
m_buf = new qint16[2*bufSamples];
|
||||
std::fill(m_buf, m_buf + 2*bufSamples, 0);
|
||||
}
|
||||
|
||||
USRPOutputThread::~USRPOutputThread()
|
||||
{
|
||||
stopWork();
|
||||
delete m_buf;
|
||||
}
|
||||
|
||||
void USRPOutputThread::startWork()
|
||||
|
@ -66,8 +70,15 @@ void USRPOutputThread::stopWork()
|
|||
m_running = false;
|
||||
wait();
|
||||
|
||||
try
|
||||
{
|
||||
// Get message indicating underflow, so it doesn't appear if we restart
|
||||
m_stream->recv_async_msg(md);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
qDebug() << "USRPOutputThread::stopWork: exception: " << e.what();
|
||||
}
|
||||
|
||||
qDebug("USRPOutputThread::stopWork: stream stopped");
|
||||
}
|
||||
|
@ -90,15 +101,15 @@ void USRPOutputThread::run()
|
|||
|
||||
while (m_running)
|
||||
{
|
||||
callback(m_buf, DeviceUSRP::blockSize);
|
||||
callback(m_buf, m_bufSamples);
|
||||
|
||||
try
|
||||
{
|
||||
const size_t samples_sent = m_stream->send(m_buf, DeviceUSRP::blockSize, md);
|
||||
const size_t samples_sent = m_stream->send(m_buf, m_bufSamples, md);
|
||||
m_packets++;
|
||||
if (samples_sent != DeviceUSRP::blockSize)
|
||||
if (samples_sent != m_bufSamples)
|
||||
{
|
||||
qDebug("USRPOutputThread::run written %ld/%d samples", samples_sent, DeviceUSRP::blockSize);
|
||||
qDebug("USRPOutputThread::run written %ld/%d samples", samples_sent, m_bufSamples);
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
|
|
|
@ -37,7 +37,7 @@ class USRPOutputThread : public QThread, public DeviceUSRPShared::ThreadInterfac
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
USRPOutputThread(uhd::tx_streamer::sptr stream, SampleSourceFifo* sampleFifo, QObject* parent = 0);
|
||||
USRPOutputThread(uhd::tx_streamer::sptr stream, size_t bufSamples, SampleSourceFifo* sampleFifo, QObject* parent = 0);
|
||||
~USRPOutputThread();
|
||||
|
||||
virtual void startWork();
|
||||
|
@ -57,7 +57,8 @@ private:
|
|||
quint32 m_droppedPackets;
|
||||
|
||||
uhd::tx_streamer::sptr m_stream;
|
||||
qint16 m_buf[2*DeviceUSRP::blockSize]; //must hold I+Q values of each sample hence 2xcomplex size
|
||||
qint16 *m_buf;
|
||||
size_t m_bufSamples;
|
||||
SampleSourceFifo* m_sampleFifo;
|
||||
|
||||
unsigned int m_log2Interp; // soft decimation
|
||||
|
|
|
@ -51,6 +51,7 @@ USRPInput::USRPInput(DeviceAPI *deviceAPI) :
|
|||
m_deviceAPI(deviceAPI),
|
||||
m_settings(),
|
||||
m_usrpInputThread(nullptr),
|
||||
m_bufSamples(0),
|
||||
m_deviceDescription("USRPInput"),
|
||||
m_running(false),
|
||||
m_channelAcquired(false)
|
||||
|
@ -91,7 +92,9 @@ void USRPInput::destroy()
|
|||
|
||||
bool USRPInput::openDevice()
|
||||
{
|
||||
if (!m_sampleFifo.setSize(96000 * 4))
|
||||
// B210 supports up to 50MSa/s, so a fairly large FIFO is probably a good idea
|
||||
// Should it be bigger still?
|
||||
if (!m_sampleFifo.setSize(2000000))
|
||||
{
|
||||
qCritical("USRPInput::openDevice: could not allocate SampleFifo");
|
||||
return false;
|
||||
|
@ -325,6 +328,9 @@ bool USRPInput::acquireChannel()
|
|||
stream_args.channels = channel_nums;
|
||||
|
||||
m_streamId = m_deviceShared.m_deviceParams->getDevice()->get_rx_stream(stream_args);
|
||||
|
||||
// Match our receive buffer size to what UHD uses
|
||||
m_bufSamples = m_streamId->get_max_num_samps();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
|
@ -375,7 +381,7 @@ bool USRPInput::start()
|
|||
|
||||
// start / stop streaming is done in the thread.
|
||||
|
||||
m_usrpInputThread = new USRPInputThread(m_streamId, &m_sampleFifo);
|
||||
m_usrpInputThread = new USRPInputThread(m_streamId, m_bufSamples, &m_sampleFifo);
|
||||
qDebug("USRPInput::start: thread created");
|
||||
|
||||
applySettings(m_settings, true);
|
||||
|
|
|
@ -227,6 +227,7 @@ private:
|
|||
DeviceUSRPShared m_deviceShared;
|
||||
bool m_channelAcquired;
|
||||
uhd::rx_streamer::sptr m_streamId;
|
||||
size_t m_bufSamples;
|
||||
QNetworkAccessManager *m_networkManager;
|
||||
QNetworkRequest m_networkRequest;
|
||||
|
||||
|
|
|
@ -26,20 +26,35 @@
|
|||
#include "usrpinputsettings.h"
|
||||
#include "usrpinputthread.h"
|
||||
|
||||
USRPInputThread::USRPInputThread(uhd::rx_streamer::sptr stream, SampleSinkFifo* sampleFifo, QObject* parent) :
|
||||
USRPInputThread::USRPInputThread(uhd::rx_streamer::sptr stream, size_t bufSamples, SampleSinkFifo* sampleFifo, QObject* parent) :
|
||||
QThread(parent),
|
||||
m_running(false),
|
||||
m_stream(stream),
|
||||
m_convertBuffer(DeviceUSRP::blockSize),
|
||||
m_bufSamples(bufSamples),
|
||||
m_convertBuffer(bufSamples),
|
||||
m_sampleFifo(sampleFifo),
|
||||
m_log2Decim(0)
|
||||
{
|
||||
std::fill(m_buf, m_buf + 2*DeviceUSRP::blockSize, 0);
|
||||
// *2 as samples are I+Q
|
||||
m_buf = new qint16[2*bufSamples];
|
||||
std::fill(m_buf, m_buf + 2*bufSamples, 0);
|
||||
}
|
||||
|
||||
USRPInputThread::~USRPInputThread()
|
||||
{
|
||||
stopWork();
|
||||
delete m_buf;
|
||||
}
|
||||
|
||||
void USRPInputThread::issueStreamCmd(bool start)
|
||||
{
|
||||
uhd::stream_cmd_t stream_cmd(start ? uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS : uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
|
||||
stream_cmd.num_samps = size_t(0);
|
||||
stream_cmd.stream_now = true;
|
||||
stream_cmd.time_spec = uhd::time_spec_t();
|
||||
|
||||
m_stream->issue_stream_cmd(stream_cmd);
|
||||
qDebug() << "USRPInputThread::issueStreamCmd " << (start ? "start" : "stop");
|
||||
}
|
||||
|
||||
void USRPInputThread::startWork()
|
||||
|
@ -48,12 +63,8 @@ void USRPInputThread::startWork()
|
|||
|
||||
try
|
||||
{
|
||||
uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
|
||||
stream_cmd.num_samps = size_t(0);
|
||||
stream_cmd.stream_now = true;
|
||||
stream_cmd.time_spec = uhd::time_spec_t();
|
||||
|
||||
m_stream->issue_stream_cmd(stream_cmd);
|
||||
// Start streaming
|
||||
issueStreamCmd(true);
|
||||
|
||||
// Reset stats
|
||||
m_packets = 0;
|
||||
|
@ -84,18 +95,20 @@ void USRPInputThread::stopWork()
|
|||
try
|
||||
{
|
||||
uhd::rx_metadata_t md;
|
||||
uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
|
||||
stream_cmd.stream_now = true;
|
||||
m_stream->issue_stream_cmd(stream_cmd);
|
||||
|
||||
// Stop streaming
|
||||
issueStreamCmd(false);
|
||||
|
||||
// Clear out any data left in the stream, otherwise we'll get an
|
||||
// exception 'recv buffer smaller than vrt packet offset' when restarting
|
||||
while (!md.end_of_burst)
|
||||
md.end_of_burst = false;
|
||||
md.error_code = uhd::rx_metadata_t::ERROR_CODE_NONE;
|
||||
while (!md.end_of_burst && (md.error_code != uhd::rx_metadata_t::ERROR_CODE_TIMEOUT))
|
||||
{
|
||||
try
|
||||
{
|
||||
//qDebug() << "USRPInputThread::stopWork: recing until end of burst";
|
||||
m_stream->recv(m_buf, DeviceUSRP::blockSize, md);
|
||||
md.reset();
|
||||
m_stream->recv(m_buf, m_bufSamples, md);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
|
@ -127,26 +140,38 @@ void USRPInputThread::run()
|
|||
{
|
||||
while (m_running)
|
||||
{
|
||||
const size_t samples_received = m_stream->recv(m_buf, DeviceUSRP::blockSize, md);
|
||||
md.reset();
|
||||
const size_t samples_received = m_stream->recv(m_buf, m_bufSamples, md);
|
||||
|
||||
m_packets++;
|
||||
if (samples_received != DeviceUSRP::blockSize)
|
||||
if (samples_received != m_bufSamples)
|
||||
{
|
||||
qDebug("USRPInputThread::run - received %ld/%d samples", samples_received, DeviceUSRP::blockSize);
|
||||
qDebug("USRPInputThread::run - received %ld/%d samples", samples_received, m_bufSamples);
|
||||
}
|
||||
if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT)
|
||||
{
|
||||
qDebug("USRPInputThread::run - timeout - ending thread");
|
||||
m_timeouts++;
|
||||
// It seems we can't recover after a timeout, so stop thread
|
||||
m_running = false;
|
||||
// Restart streaming
|
||||
issueStreamCmd(false);
|
||||
issueStreamCmd(true);
|
||||
qDebug("USRPInputThread::run - timeout - restarting");
|
||||
}
|
||||
else if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW)
|
||||
{
|
||||
qDebug("USRPInputThread::run - overflow");
|
||||
m_overflows++;
|
||||
}
|
||||
else if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_LATE_COMMAND)
|
||||
qDebug("USRPInputThread::run - late command error");
|
||||
else if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_BROKEN_CHAIN)
|
||||
qDebug("USRPInputThread::run - broken chain error");
|
||||
else if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_ALIGNMENT)
|
||||
qDebug("USRPInputThread::run - alignment error");
|
||||
else if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_BAD_PACKET)
|
||||
qDebug("USRPInputThread::run - bad packet error");
|
||||
|
||||
if (samples_received > 0)
|
||||
callbackIQ(m_buf, 2 * samples_received);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ class USRPInputThread : public QThread, public DeviceUSRPShared::ThreadInterface
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
USRPInputThread(uhd::rx_streamer::sptr stream, SampleSinkFifo* sampleFifo, QObject* parent = 0);
|
||||
USRPInputThread(uhd::rx_streamer::sptr stream, size_t bufSamples, SampleSinkFifo* sampleFifo, QObject* parent = 0);
|
||||
~USRPInputThread();
|
||||
|
||||
virtual void startWork();
|
||||
|
@ -45,6 +45,7 @@ public:
|
|||
virtual bool isRunning() { return m_running; }
|
||||
void setLog2Decimation(unsigned int log2_decim);
|
||||
void getStreamStatus(bool& active, quint32& overflows, quint32& m_timeouts);
|
||||
void issueStreamCmd(bool start);
|
||||
|
||||
private:
|
||||
QMutex m_startWaitMutex;
|
||||
|
@ -56,13 +57,14 @@ private:
|
|||
quint32 m_timeouts;
|
||||
|
||||
uhd::rx_streamer::sptr m_stream;
|
||||
qint16 m_buf[2*DeviceUSRP::blockSize]; //must hold I+Q values of each sample hence 2xcomplex size
|
||||
qint16 *m_buf;
|
||||
size_t m_bufSamples;
|
||||
SampleVector m_convertBuffer;
|
||||
SampleSinkFifo* m_sampleFifo;
|
||||
|
||||
unsigned int m_log2Decim; // soft decimation
|
||||
|
||||
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 12, true> m_decimatorsIQ;
|
||||
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 16, true> m_decimatorsIQ;
|
||||
|
||||
void run();
|
||||
void callbackIQ(const qint16* buf, qint32 len);
|
||||
|
|
Ładowanie…
Reference in New Issue