1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2026-01-07 08:48:47 -05:00

LimeSDR MIMO: corrections and actual implementation

This commit is contained in:
f4exb 2020-04-27 09:21:52 +02:00
parent e62af95d46
commit 1816ab82bf
12 changed files with 200 additions and 185 deletions

View File

@ -4,6 +4,10 @@ if(ENABLE_BLADERF AND LIBBLADERF_FOUND)
add_subdirectory(bladerf2mimo)
endif()
if(ENABLE_LIMESUITE AND LIMESUITE_FOUND)
add_subdirectory(limesdrmimo)
endif()
if(ENABLE_XTRX AND LIBXTRX_FOUND)
add_subdirectory(xtrxmimo)
endif()

View File

@ -58,6 +58,8 @@ LimeSDRMIMO::LimeSDRMIMO(DeviceAPI *deviceAPI) :
m_txChannelEnabled[channel] = false;
m_rxStreamStarted[channel] = false;
m_txStreamStarted[channel] = false;
m_rxStreams[channel].handle = 0;
m_txStreams[channel].handle = 0;
}
m_open = openDevice();
@ -163,8 +165,8 @@ bool LimeSDRMIMO::setupRxStream(unsigned int channel)
}
// set up the stream
m_rxStreams[channel].channel = channel; // channel number
m_rxStreams[channel].fifoSize = 1024 * 1024; // fifo size in samples (SR / 10 take ~5MS/s)
m_rxStreams[channel].channel = channel | LMS_ALIGN_CH_PHASE; // channel number
m_rxStreams[channel].fifoSize = 10 * 1024 * 1024; // fifo size in samples (SR / 10 take ~5MS/s)
m_rxStreams[channel].throughputVsLatency = 0.5; // optimize for min latency
m_rxStreams[channel].isTx = false; // RX channel
m_rxStreams[channel].dataFmt = lms_stream_t::LMS_FMT_I12; // 12-bit integers
@ -202,7 +204,7 @@ bool LimeSDRMIMO::setupTxStream(unsigned int channel)
}
// set up the stream
m_txStreams[channel].channel = channel; // channel number
m_txStreams[channel].channel = channel | LMS_ALIGN_CH_PHASE; // channel number
m_txStreams[channel].fifoSize = 1024 * 1024; // fifo size in samples (SR / 10 take ~5MS/s)
m_txStreams[channel].throughputVsLatency = 0.5; // optimize for min latency
m_txStreams[channel].isTx = true; // TX channel
@ -546,6 +548,87 @@ bool LimeSDRMIMO::handleMessage(const Message& message)
return true;
}
else if (MsgGetStreamInfo::match(message))
{
MsgGetStreamInfo& cmd = (MsgGetStreamInfo&) message;
lms_stream_status_t status;
lms_stream_t *stream;
if (cmd.getRxElseTx() && (cmd.getChannel() == 0) && m_rxStreams[0].handle) {
stream = &m_rxStreams[0];
} else if (cmd.getRxElseTx() && (cmd.getChannel() == 1) && m_rxStreams[1].handle) {
stream = &m_rxStreams[1];
} else if (!cmd.getRxElseTx() && (cmd.getChannel() == 0) && m_txStreams[0].handle) {
stream = &m_txStreams[0];
} else if (!cmd.getRxElseTx() && (cmd.getChannel() == 1) && m_txStreams[1].handle) {
stream = &m_txStreams[1];
} else {
stream = nullptr;
}
if (stream && (LMS_GetStreamStatus(stream, &status) == 0))
{
if (getMessageQueueToGUI())
{
MsgReportStreamInfo *report = MsgReportStreamInfo::create(
true, // Success
status.active,
status.fifoFilledCount,
status.fifoSize,
status.underrun,
status.overrun,
status.droppedPackets,
status.linkRate,
status.timestamp);
getMessageQueueToGUI()->push(report);
}
}
else
{
if (m_deviceAPI->getSamplingDeviceGUIMessageQueue())
{
MsgReportStreamInfo *report = MsgReportStreamInfo::create(
false, // Success
false, // status.active,
0, // status.fifoFilledCount,
16384, // status.fifoSize,
0, // status.underrun,
0, // status.overrun,
0, // status.droppedPackets,
0, // status.linkRate,
0); // status.timestamp);
m_deviceAPI->getSamplingDeviceGUIMessageQueue()->push(report);
}
}
return true;
}
else if (MsgGetDeviceInfo::match(message))
{
double temp = 0.0;
uint8_t gpioPins = 0;
if (m_deviceParams->getDevice() && (LMS_GetChipTemperature(m_deviceParams->getDevice(), 0, &temp) != 0)) {
qDebug("LimeSDRMIMO::handleMessage: MsgGetDeviceInfo: cannot get temperature");
}
if ((m_deviceParams->m_type != DeviceLimeSDRParams::LimeMini)
&& (m_deviceParams->m_type != DeviceLimeSDRParams::LimeUndefined))
{
if (m_deviceParams->getDevice() && (LMS_GPIORead(m_deviceParams->getDevice(), &gpioPins, 1) != 0)) {
qDebug("LimeSDRMIMO::handleMessage: MsgGetDeviceInfo: cannot get GPIO pins values");
}
}
// send to oneself
if (getMessageQueueToGUI())
{
DeviceLimeSDRShared::MsgReportDeviceInfo *report = DeviceLimeSDRShared::MsgReportDeviceInfo::create(temp, gpioPins);
getMessageQueueToGUI()->push(report);
}
return true;
}
else
{
return false;
@ -571,7 +654,6 @@ bool LimeSDRMIMO::applySettings(const LimeSDRMIMOSettings& settings, bool force)
qDebug() << "LimeSDRMIMO::applySettings: common:"
<< " m_devSampleRate: " << settings.m_devSampleRate
<< " m_LOppmTenths: " << settings.m_LOppmTenths
<< " m_gpioDir: " << settings.m_gpioDir
<< " m_gpioPins: " << settings.m_gpioPins
<< " m_extClock: " << settings.m_extClock

View File

@ -67,14 +67,22 @@ public:
MESSAGE_CLASS_DECLARATION
public:
static MsgGetStreamInfo* create()
bool getRxElseTx() const { return m_rxElseTx; }
uint32_t getChannel() const { return m_channel; }
static MsgGetStreamInfo* create(bool rxElseTx, uint32_t channel)
{
return new MsgGetStreamInfo();
return new MsgGetStreamInfo(rxElseTx, channel);
}
private:
MsgGetStreamInfo() :
Message()
bool m_rxElseTx;
uint32_t m_channel;
MsgGetStreamInfo(bool rxElseTx, uint32_t channel) :
Message(),
m_rxElseTx(rxElseTx),
m_channel(channel)
{ }
};

View File

@ -276,6 +276,9 @@ bool LimeSDRMIMOGUI::handleMessage(const Message& message)
void LimeSDRMIMOGUI::displaySettings()
{
updateFrequencyLimits();
updateLPFLimits();
if (m_rxElseTx)
{
ui->antenna->blockSignals(true);
@ -391,7 +394,7 @@ void LimeSDRMIMOGUI::displaySettings()
ui->lpFIREnable->setChecked(m_settings.m_lpfFIREnableTx0);
ui->lpFIR->setValue(m_settings.m_lpfFIRBWTx0 / 1000);
ui->gain->setValue(m_settings.m_gainTx0);
ui->gainText->setText(tr("%1dB").arg(m_settings.m_gainTx0));
ui->gainText->setText(tr("%1").arg(m_settings.m_gainTx0));
ui->antenna->setCurrentIndex((int) m_settings.m_antennaPathTx0);
}
else if (m_streamIndex == 1)
@ -400,7 +403,7 @@ void LimeSDRMIMOGUI::displaySettings()
ui->lpFIREnable->setChecked(m_settings.m_lpfFIREnableTx1);
ui->lpFIR->setValue(m_settings.m_lpfFIRBWTx1 / 1000);
ui->gain->setValue(m_settings.m_gainTx1);
ui->gainText->setText(tr("%1dB").arg(m_settings.m_gainTx1));
ui->gainText->setText(tr("%1").arg(m_settings.m_gainTx1));
ui->antenna->setCurrentIndex((int) m_settings.m_antennaPathTx1);
}
}
@ -713,7 +716,7 @@ void LimeSDRMIMOGUI::updateStatus()
}
else
{
LimeSDRMIMO::MsgGetStreamInfo* message = LimeSDRMIMO::MsgGetStreamInfo::create();
LimeSDRMIMO::MsgGetStreamInfo* message = LimeSDRMIMO::MsgGetStreamInfo::create(m_rxElseTx, m_streamIndex);
m_limeSDRMIMO->getInputMessageQueue()->push(message);
m_statusCounter = 0;
}
@ -724,12 +727,8 @@ void LimeSDRMIMOGUI::updateStatus()
}
else
{
if (m_deviceUISet->m_deviceAPI->isBuddyLeader())
{
LimeSDRMIMO::MsgGetDeviceInfo* message = LimeSDRMIMO::MsgGetDeviceInfo::create();
m_limeSDRMIMO->getInputMessageQueue()->push(message);
}
LimeSDRMIMO::MsgGetDeviceInfo* message = LimeSDRMIMO::MsgGetDeviceInfo::create();
m_limeSDRMIMO->getInputMessageQueue()->push(message);
m_deviceStatusCounter = 0;
}
}
@ -754,6 +753,7 @@ void LimeSDRMIMOGUI::on_spectrumSide_currentIndexChanged(int index)
m_deviceUISet->m_deviceAPI->setSpectrumSinkInput(m_spectrumRxElseTx, m_spectrumStreamIndex);
m_deviceUISet->setSpectrumScalingFactor(m_spectrumRxElseTx ? SDR_RX_SCALEF : SDR_TX_SCALEF);
updateSampleRateAndFrequency();
updateLPFLimits();
}
void LimeSDRMIMOGUI::on_spectrumIndex_currentIndexChanged(int index)
@ -797,21 +797,14 @@ void LimeSDRMIMOGUI::on_record_toggled(bool checked)
void LimeSDRMIMOGUI::on_centerFrequency_changed(quint64 value)
{
if (m_rxElseTx) {
m_settings.m_rxCenterFrequency = value * 1000;
setRxCenterFrequencySetting(value);
} else {
m_settings.m_txCenterFrequency = value * 1000;
setTxCenterFrequencySetting(value);
}
sendSettings();
}
void LimeSDRMIMOGUI::on_LOppm_valueChanged(int value)
{
ui->LOppmText->setText(QString("%1").arg(QString::number(value/10.0, 'f', 1)));
m_settings.m_LOppmTenths = value;
sendSettings();
}
void LimeSDRMIMOGUI::on_ncoEnable_toggled(bool checked)
{
if (m_rxElseTx)

View File

@ -114,7 +114,6 @@ private slots:
void on_startStopTx_toggled(bool checked);
void on_record_toggled(bool checked);
void on_centerFrequency_changed(quint64 value);
void on_LOppm_valueChanged(int value);
void on_ncoEnable_toggled(bool checked);
void on_ncoFrequency_changed(qint64 value);
void on_dcOffset_toggled(bool checked);

View File

@ -394,52 +394,6 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="LOppm_layout">
<item>
<widget class="QLabel" name="LOppmLabel">
<property name="text">
<string>LO ppm</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="LOppm">
<property name="toolTip">
<string>Local Oscillator ppm correction</string>
</property>
<property name="minimum">
<number>-20</number>
</property>
<property name="maximum">
<number>20</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="LOppmText">
<property name="minimumSize">
<size>
<width>26</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>-0.0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="topMargin">
@ -925,7 +879,7 @@
</size>
</property>
<property name="toolTip">
<string>Automatic global gain (dB)</string>
<string>Automatic global gain</string>
</property>
<property name="maximum">
<number>70</number>
@ -953,7 +907,7 @@
</size>
</property>
<property name="toolTip">
<string>Automatic global gain</string>
<string>Automatic global gain (dB)</string>
</property>
<property name="text">
<string>20</string>

View File

@ -31,7 +31,7 @@
const PluginDescriptor LimeSDRMIMOPlugin::m_pluginDescriptor = {
QString("LimeSDR"),
QString("LimeSDR MIMO"),
QString("5.4.0"),
QString("5.5.0"),
QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"),
true,

View File

@ -26,8 +26,7 @@ LimeSDRMIMOSettings::LimeSDRMIMOSettings()
void LimeSDRMIMOSettings::resetToDefaults()
{
m_devSampleRate = 5000000;
m_LOppmTenths = 0;
m_devSampleRate = 3200000;
m_gpioDir = 0;
m_gpioPins = 0;
m_extClock = false;
@ -94,7 +93,6 @@ QByteArray LimeSDRMIMOSettings::serialize() const
SimpleSerializer s(1);
s.writeS32(1, m_devSampleRate);
s.writeS32(2, m_LOppmTenths);
s.writeU32(3, m_gpioDir);
s.writeU32(4, m_gpioPins);
s.writeBool(5, m_extClock);
@ -174,7 +172,6 @@ bool LimeSDRMIMOSettings::deserialize(const QByteArray& data)
uint32_t uintval;
d.readS32(1, &m_devSampleRate, 5000000);
d.readS32(2, &m_LOppmTenths, 0);
d.readU32(3, &uintval, 0);
m_gpioDir = uintval & 0xFF;
d.readU32(4, &uintval, 0);

View File

@ -53,7 +53,6 @@ struct LimeSDRMIMOSettings
// General
qint32 m_devSampleRate;
qint32 m_LOppmTenths;
uint8_t m_gpioDir; //!< GPIO pin direction LSB first; 0 input, 1 output
uint8_t m_gpioPins; //!< GPIO pins to write; LSB first
bool m_extClock; //!< True if external clock source

View File

@ -51,35 +51,35 @@ void LimeSDRMIThread::startWork()
return; // return if running already
}
if (m_stream0)
int ret[2];
ret[0] = LMS_StartStream(m_stream0);
ret[1] = LMS_StartStream(m_stream1);
if (ret[0] < 0)
{
if (LMS_StartStream(m_stream0) < 0)
{
qCritical("LimeSDRMIThread::startWork: could not start stream 0");
return;
}
else
{
usleep(50000);
qDebug("LimeSDRMIThread::startWork: stream 0 started");
}
qCritical("LimeSDRMIThread::startWork: could not start stream 0");
return;
}
else
{
qDebug("LimeSDRMIThread::startWork: stream 0 started");
}
if (m_stream1)
{
if (LMS_StartStream(m_stream1) < 0)
if (ret[1] < 0)
{
qCritical("LimeSDRMIThread::startWork: could not start stream 1");
LMS_StopStream(m_stream0);
return;
}
else
{
usleep(50000);
qDebug("LimeSDRMIThread::startWork: stream 1 started");
qDebug("LimeSDRMIThread::startWork: stream 0 started");
}
}
usleep(50000);
m_startWaitMutex.lock();
start();
@ -98,32 +98,27 @@ void LimeSDRMIThread::stopWork()
m_running = false;
wait();
int ret[2];
if (m_stream0)
{
if (LMS_StopStream(m_stream0) < 0)
{
qCritical("LimeSDRInputThread::stopWork: could not stop stream 0");
}
else
{
usleep(50000);
qDebug("LimeSDRInputThread::stopWork: stream 0 stopped");
}
ret[0] = LMS_StopStream(m_stream0);
ret[1] = LMS_StopStream(m_stream1);
if (ret[0] < 0) {
qCritical("LimeSDRInputThread::stopWork: could not stop stream 0");
} else {
qDebug("LimeSDRInputThread::stopWork: stream 0 stopped");
}
if (m_stream1)
{
if (LMS_StopStream(m_stream1) < 0)
{
if (ret[1] < 0) {
qCritical("LimeSDRInputThread::stopWork: could not stop stream 1");
}
else
{
usleep(50000);
} else {
qDebug("LimeSDRInputThread::stopWork: stream 1 stopped");
}
}
usleep(50000);
}
void LimeSDRMIThread::setLog2Decimation(unsigned int log2_decim)
@ -138,57 +133,47 @@ unsigned int LimeSDRMIThread::getLog2Decimation() const
void LimeSDRMIThread::run()
{
int res;
lms_stream_meta_t metadata; //Use metadata for additional control over sample receive function behaviour
lms_stream_meta_t metadata; //Use metadata for additional control over sample receive function behaviour
metadata.flushPartialPacket = false; //Do not discard data remainder when read size differs from packet size
metadata.waitForTimestamp = false; //Do not wait for specific timestamps
int lengths[2];
int res[2];
m_running = true;
m_startWaiter.wakeAll();
while (m_running)
while (m_running && m_stream0)
{
if (m_stream0)
{
res = LMS_RecvStream(m_stream0, (void *) m_buf[0], DeviceLimeSDR::blockSize, &metadata, 1000);
res[0] = LMS_RecvStream(m_stream0, (void *) m_buf0, DeviceLimeSDR::blockSize, &metadata, 1000);
if (res < 0)
{
qCritical("LimeSDRMIThread::run read stream 0 error: %s", strerror(errno));
break;
}
lengths[0] = channelCallback(m_buf[0], 2*res, 0);
}
else
if (res[0] < 0)
{
std::fill(m_convertBuffer[0].begin(), m_convertBuffer[0].end(), Sample{0,0});
lengths[0] = m_convertBuffer[0].size() / (1<<m_log2Decim);
qCritical("LimeSDRMIThread::run read stream 0 error: %s", strerror(errno));
break;
}
if (m_stream1)
{
res = LMS_RecvStream(m_stream1, (void *) m_buf[1], DeviceLimeSDR::blockSize, &metadata, 1000);
res[1] = LMS_RecvStream(m_stream1, (void *) m_buf1, DeviceLimeSDR::blockSize, &metadata, 1000);
if (res < 0)
if (res[1] < 0)
{
qCritical("LimeSDRMIThread::run read stream 1 error: %s", strerror(errno));
break;
}
lengths[1] = channelCallback(m_buf[1], 2*res, 1);
}
else
{
std::fill(m_convertBuffer[1].begin(), m_convertBuffer[1].end(), Sample{0,0});
lengths[1] = m_convertBuffer[1].size() / (1<<m_log2Decim);
std::fill(m_buf1, m_buf1 + 2*DeviceLimeSDR::blockSize, 0);
res[1] = DeviceLimeSDR::blockSize;
}
lengths[0] = channelCallback(m_buf0, 2*res[0], 0);
lengths[1] = channelCallback(m_buf1, 2*res[1], 1);
if (lengths[0] == lengths[1])
{
qDebug("LimeSDRMIThread::run: writeSync %d samples", lengths[0]);
//qDebug("LimeSDRMIThread::run: writeSync %d samples", lengths[0]);
m_sampleFifo->writeSync(m_vBegin, lengths[0]);
}
else

View File

@ -54,7 +54,8 @@ private:
lms_stream_t* m_stream0;
lms_stream_t* m_stream1;
qint16 m_buf[2][2*DeviceLimeSDR::blockSize];
qint16 m_buf0[2*DeviceLimeSDR::blockSize];
qint16 m_buf1[2*DeviceLimeSDR::blockSize];
SampleVector m_convertBuffer[2];
std::vector<SampleVector::const_iterator> m_vBegin;
SampleMIFifo* m_sampleFifo;

View File

@ -48,23 +48,24 @@ void LimeSDRMOThread::startWork()
return; // return if running already
}
if (m_stream0)
int ret[2];
ret[0] = LMS_StartStream(m_stream0);
ret[1] = LMS_StartStream(m_stream1);
if (ret[0] < 0)
{
if (LMS_StartStream(m_stream0) < 0)
{
qCritical("LimeSDROutputThread::startWork: could not start stream 0");
return;
}
else
{
usleep(50000);
qDebug("LimeSDROutputThread::startWork: stream 0 started");
}
qCritical("LimeSDROutputThread::startWork: could not start stream 0");
return;
}
else
{
qDebug("LimeSDROutputThread::startWork: stream 0 started");
}
if (m_stream1)
{
if (LMS_StartStream(m_stream1) < 0)
if (ret[1] < 0)
{
qCritical("LimeSDROutputThread::startWork: could not start stream 1");
LMS_StopStream(m_stream0);
@ -72,11 +73,11 @@ void LimeSDRMOThread::startWork()
}
else
{
usleep(50000);
qDebug("LimeSDROutputThread::startWork: stream 1 started");
}
}
usleep(50000);
m_startWaitMutex.lock();
start();
@ -95,32 +96,29 @@ void LimeSDRMOThread::stopWork()
m_running = false;
wait();
int ret[2];
if (m_stream0)
ret[0] = LMS_StopStream(m_stream0);
ret[1] = LMS_StopStream(m_stream1);
if (ret[0] < 0)
{
if (LMS_StopStream(m_stream0) < 0)
{
qCritical("LimeSDROutputThread::stopWork: could not stop stream 0");
}
else
{
usleep(50000);
qDebug("LimeSDROutputThread::stopWork: stream 0 stopped");
}
qCritical("LimeSDROutputThread::stopWork: could not stop stream 0");
} else {
qDebug("LimeSDROutputThread::stopWork: stream 0 stopped");
}
if (m_stream1)
{
if (LMS_StopStream(m_stream1) < 0)
if (ret[1] < 0)
{
qCritical("LimeSDROutputThread::stopWork: could not stop stream 1");
}
else
{
usleep(50000);
} else {
qDebug("LimeSDROutputThread::stopWork: stream 1 stopped");
}
}
usleep(50000);
}
void LimeSDRMOThread::setLog2Interpolation(unsigned int log2Interp)
@ -136,47 +134,42 @@ unsigned int LimeSDRMOThread::getLog2Interpolation() const
void LimeSDRMOThread::run()
{
int res;
lms_stream_meta_t metadata; //Use metadata for additional control over sample receive function behaviour
metadata.flushPartialPacket = false; //Do not discard data remainder when read size differs from packet size
metadata.waitForTimestamp = false; //Do not wait for specific timestamps
m_running = true;
m_startWaiter.wakeAll();
int res[2];
while (m_running)
{
callback(m_buf, DeviceLimeSDR::blockSize);
res[0] = LMS_SendStream(m_stream0, (void *) &m_buf[0], DeviceLimeSDR::blockSize, &metadata, 1000000);
if (m_stream0)
if (res[0] < 0)
{
res = LMS_SendStream(m_stream0, (void *) &m_buf[0], DeviceLimeSDR::blockSize, &metadata, 1000000);
if (res < 0)
{
qCritical("LimeSDROutputThread::run stream 0 write error: %s", strerror(errno));
break;
}
else if (res != DeviceLimeSDR::blockSize)
{
qDebug("LimeSDROutputThread::run stream 0 written %d/%d samples", res, DeviceLimeSDR::blockSize);
}
qCritical("LimeSDROutputThread::run stream 0 write error: %s", strerror(errno));
break;
}
else if (res[0] != DeviceLimeSDR::blockSize)
{
qDebug("LimeSDROutputThread::run stream 0 written %d/%u samples", res[0], DeviceLimeSDR::blockSize);
}
if (m_stream1)
{
res = LMS_SendStream(m_stream1, (void *) &m_buf[2*DeviceLimeSDR::blockSize], DeviceLimeSDR::blockSize, &metadata, 1000000);
res[1] = LMS_SendStream(m_stream1, (void *) &m_buf[2*DeviceLimeSDR::blockSize], DeviceLimeSDR::blockSize, &metadata, 1000000);
if (res < 0)
if (res[1] < 0)
{
qCritical("LimeSDROutputThread::run stream 1 write error: %s", strerror(errno));
break;
}
else if (res != DeviceLimeSDR::blockSize)
else if (res[1] != DeviceLimeSDR::blockSize)
{
qDebug("LimeSDROutputThread::run stream 1 written %d/%d samples", res, DeviceLimeSDR::blockSize);
qDebug("LimeSDROutputThread::run stream 1 written %d/%u samples", res[1], DeviceLimeSDR::blockSize);
}
}
}