summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2019-02-27 11:37:53 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2019-02-27 11:37:53 +0100
commit705ae30e5f7cc2525627f338beef8c90a8678c2f (patch)
treed119190bf5eba0e70eea2fecc8fd005ec2fa9cb5
parent6db4e5b3ad28973601b8e7426a4cffa01322b9a2 (diff)
downloaddabmod-705ae30e5f7cc2525627f338beef8c90a8678c2f.tar.gz
dabmod-705ae30e5f7cc2525627f338beef8c90a8678c2f.tar.bz2
dabmod-705ae30e5f7cc2525627f338beef8c90a8678c2f.zip
Refactor Lime output
* master_clock_rate sets CGEN clock, not sample rate * set sample rate accordingly * support only interpolate 1 and 2 * add frequency, txgain and temperature to RC * improve error handling * fix signedness of LMS_SendStream() return value
-rw-r--r--doc/example.ini19
-rw-r--r--src/output/Lime.cpp389
-rw-r--r--src/output/Lime.h14
3 files changed, 223 insertions, 199 deletions
diff --git a/doc/example.ini b/doc/example.ini
index b94825c..5dd2846 100644
--- a/doc/example.ini
+++ b/doc/example.ini
@@ -154,7 +154,7 @@ enabled=0
polycoeffile=polyCoefs
[output]
-; choose output: possible values: uhd, file, zmq, soapysdr
+; choose output: possible values: uhd, file, zmq, soapysdr, limesdr
output=uhd
[fileoutput]
@@ -306,6 +306,23 @@ channel=13C
; Set to 0 to disable
;dpd_port=50055
+[limeoutput]
+; Lime output directly runs against the LMS device driver. It does not support SFN nor predistortion.
+device=
+;master_clock_rate=
+
+; txgain range: 0 .. 100
+txgain=20
+tx_antenna=BAND1
+;lo_offset=2048000
+;frequency=234208000
+channel=13C
+
+; The LimeSDR contains a FIR filter in FPGA that can be used to filter the IQ signal.
+; This is useful because it allows us to upsample in a very cheap way in software instead
+; of using the FFT-based resampler.
+upsample=1
+
; Used for running single-frequency networks
[delaymanagement]
; Enable handling of timestamps for SFN
diff --git a/src/output/Lime.cpp b/src/output/Lime.cpp
index 219b97a..7aa7d67 100644
--- a/src/output/Lime.cpp
+++ b/src/output/Lime.cpp
@@ -5,7 +5,11 @@
Copyright (C) 2018
Evariste F5OEO, evaristec@gmail.com
-
+ Copyright (C) 2019
+ Matthias P. Braendli, matthias.braendli@mpb.li
+
+ http://opendigitalradio.org
+
DESCRIPTION:
It is an output driver using the LimeSDR library.
*/
@@ -45,127 +49,190 @@ namespace Output
{
static constexpr size_t FRAMES_MAX_SIZE = 2;
+static constexpr size_t FRAME_LENGTH = 196608; // at native sample rate!
-Lime::Lime(SDRDeviceConfig &config) : SDRDevice(),
- m_conf(config)
+Lime::Lime(SDRDeviceConfig &config) : SDRDevice(), m_conf(config)
{
m_interpolate = m_conf.upsample;
etiLog.level(info) << "Lime:Creating the device with: " << m_conf.device;
- int device_count = LMS_GetDeviceList(NULL);
- if (device_count < 0)
- {
+
+ const int device_count = LMS_GetDeviceList(nullptr);
+ if (device_count < 0) {
etiLog.level(error) << "Error making LimeSDR device: " << LMS_GetLastErrorMessage();
- throw std::runtime_error("Cannot find LimeSDR output device");
+ throw runtime_error("Cannot find LimeSDR output device");
}
+
lms_info_str_t device_list[device_count];
- if (LMS_GetDeviceList(device_list) < 0)
- {
+ if (LMS_GetDeviceList(device_list) < 0) {
etiLog.level(error) << "Error making LimeSDR device: %s " << LMS_GetLastErrorMessage();
- throw std::runtime_error("Cannot find LimeSDR output device");
+ throw runtime_error("Cannot find LimeSDR output device");
}
- unsigned int device_i = 0; // If several cards, need to get device by configuration
- if (LMS_Open(&m_device, device_list[device_i], NULL) < 0)
- {
+
+ size_t device_i = 0; // If several cards, need to get device by configuration
+ if (LMS_Open(&m_device, device_list[device_i], nullptr) < 0) {
etiLog.level(error) << "Error making LimeSDR device: %s " << LMS_GetLastErrorMessage();
- throw std::runtime_error("Cannot open LimeSDR output device");
+ throw runtime_error("Cannot open LimeSDR output device");
}
- if (LMS_Reset(m_device) < 0)
- {
+
+ if (LMS_Reset(m_device) < 0) {
etiLog.level(error) << "Error making LimeSDR device: %s " << LMS_GetLastErrorMessage();
- throw std::runtime_error("Cannot reset LimeSDR output device");
+ throw runtime_error("Cannot reset LimeSDR output device");
}
- if (LMS_Init(m_device) < 0)
- {
+ if (LMS_Init(m_device) < 0) {
etiLog.level(error) << "Error making LimeSDR device: %s " << LMS_GetLastErrorMessage();
- throw std::runtime_error("Cannot init LimeSDR output device");
+ throw runtime_error("Cannot init LimeSDR output device");
}
- if (LMS_EnableChannel(m_device, LMS_CH_TX, m_channel, true) < 0)
- {
- etiLog.level(error) << "Error making LimeSDR device: %s " << LMS_GetLastErrorMessage();
- throw std::runtime_error("Cannot channel LimeSDR output device");
+ if (m_conf.masterClockRate != 0) {
+ if (LMS_SetClockFreq(m_device, LMS_CLOCK_CGEN, m_conf.masterClockRate) < 0) {
+ etiLog.level(error) << "Error making LimeSDR device: %s " << LMS_GetLastErrorMessage();
+ throw runtime_error("Cannot set master clock rate (CGEN) for LimeSDR output device");
+ }
+
+ float_type masterClockRate = 0;
+ if (LMS_GetClockFreq(m_device, LMS_CLOCK_CGEN, &masterClockRate) < 0) {
+ etiLog.level(error) << "Error reading CGEN clock LimeSDR device: %s " << LMS_GetLastErrorMessage();
+ }
+ else {
+ etiLog.level(info) << "LimeSDR master clock rate set to " << fixed << setprecision(4) <<
+ masterClockRate;
+ }
}
- if (LMS_SetSampleRate(m_device, m_conf.masterClockRate * m_interpolate, 0) < 0)
- {
+ if (LMS_EnableChannel(m_device, LMS_CH_TX, m_channel, true) < 0) {
etiLog.level(error) << "Error making LimeSDR device: %s " << LMS_GetLastErrorMessage();
- throw std::runtime_error("Cannot channel LimeSDR output device");
+ throw runtime_error("Cannot enable channel for LimeSDR output device");
}
- float_type host_sample_rate = 0.0;
- if (LMS_GetSampleRate(m_device, LMS_CH_TX, m_channel, &host_sample_rate, NULL) < 0)
- {
+ if (LMS_SetSampleRate(m_device, m_conf.sampleRate * m_interpolate, 0) < 0) {
etiLog.level(error) << "Error making LimeSDR device: %s " << LMS_GetLastErrorMessage();
- throw std::runtime_error("Cannot getsamplerate LimeSDR output device");
+ throw runtime_error("Cannot set sample rate for LimeSDR output device");
}
- etiLog.level(info) << "LimeSDR master clock rate set to " << std::fixed << std::setprecision(4) << host_sample_rate / 1000.0 << " kHz";
+ float_type host_sample_rate = 0.0;
- if (LMS_SetLOFrequency(m_device, LMS_CH_TX, m_channel, m_conf.frequency) < 0)
- {
+ if (LMS_GetSampleRate(m_device, LMS_CH_TX, m_channel, &host_sample_rate, NULL) < 0) {
etiLog.level(error) << "Error making LimeSDR device: %s " << LMS_GetLastErrorMessage();
- throw std::runtime_error("Cannot Frequency LimeSDR output device");
+ throw runtime_error("Cannot get samplerate for LimeSDR output device");
}
+ etiLog.level(info) << "LimeSDR sample rate set to " << fixed << setprecision(4) <<
+ host_sample_rate / 1000.0 << " kHz";
+
+ tune(m_conf.lo_offset, m_conf.frequency);
float_type cur_frequency = 0.0;
- if (LMS_GetLOFrequency(m_device, LMS_CH_TX, m_channel, &cur_frequency) < 0)
- {
+ if (LMS_GetLOFrequency(m_device, LMS_CH_TX, m_channel, &cur_frequency) < 0) {
etiLog.level(error) << "Error making LimeSDR device: %s " << LMS_GetLastErrorMessage();
- throw std::runtime_error("Cannot GetFrequency LimeSDR output device");
+ throw runtime_error("Cannot get frequency for LimeSDR output device");
}
- etiLog.level(info) << "LimeSDR:Actual frequency: " << std::fixed << std::setprecision(3) << cur_frequency / 1000.0 << " kHz.";
+ etiLog.level(info) << "LimeSDR:Actual frequency: " << fixed << setprecision(3) <<
+ cur_frequency / 1000.0 << " kHz.";
- if (LMS_SetNormalizedGain(m_device, LMS_CH_TX, m_channel, m_conf.txgain / 100.0) < 0) //value 0..100 -> Normalize
- {
+ if (LMS_SetNormalizedGain(m_device, LMS_CH_TX, m_channel, m_conf.txgain / 100.0) < 0) {
+ //value 0..100 -> Normalize
etiLog.level(error) << "Error making LimeSDR device: %s " << LMS_GetLastErrorMessage();
- throw std::runtime_error("Cannot Gain LimeSDR output device");
+ throw runtime_error("Cannot set TX gain for LimeSDR output device");
}
- if (LMS_SetAntenna(m_device, LMS_CH_TX, m_channel, LMS_PATH_TX2) < 0)
- {
+ if (LMS_SetAntenna(m_device, LMS_CH_TX, m_channel, LMS_PATH_TX2) < 0) {
etiLog.level(error) << "Error making LimeSDR device: %s " << LMS_GetLastErrorMessage();
- throw std::runtime_error("Cannot Antenna LimeSDR output device");
+ throw runtime_error("Cannot set antenna for LimeSDR output device");
}
double bandwidth_calibrating = 2.5e6; // Minimal bandwidth
- if (LMS_Calibrate(m_device, LMS_CH_TX, m_channel, bandwidth_calibrating, 0) < 0)
- {
+ if (LMS_Calibrate(m_device, LMS_CH_TX, m_channel, bandwidth_calibrating, 0) < 0) {
etiLog.level(error) << "Error making LimeSDR device: %s " << LMS_GetLastErrorMessage();
- throw std::runtime_error("Cannot Gain LimeSDR output device");
+ throw runtime_error("Cannot calibrate LimeSDR output device");
}
- switch (m_interpolate)
- {
- case 1:
- {
- static double coeff[] = {-0.0014080960536375642, 0.0010270054917782545, 0.0002103941806126386, -0.0023147952742874622, 0.004256128799170256, -0.0038850826676934958, -0.0006057845894247293, 0.008352266624569893, -0.014639420434832573, 0.01275692880153656, 0.0012119393795728683, -0.02339744009077549, 0.04088031128048897, -0.03649924695491791, -0.001745241112075746, 0.07178881019353867, -0.15494878590106964, 0.22244733572006226, 0.7530255913734436, 0.22244733572006226, -0.15494878590106964, 0.07178881019353867, -0.001745241112075746, -0.03649924695491791, 0.04088031128048897, -0.02339744009077549, 0.0012119393795728683, 0.01275692880153656, -0.014639420434832573, 0.008352266624569893, -0.0006057845894247293, -0.0038850826676934958, 0.004256128799170256, -0.0023147952742874622, 0.0002103941806126386, 0.0010270054917782545, -0.0014080960536375642};
- LMS_SetGFIRCoeff(m_device, LMS_CH_TX, m_channel, LMS_GFIR3, coeff, 37);
- LMS_SetGFIR(m_device, LMS_CH_TX, m_channel, LMS_GFIR3, true);
- }
- break;
- case 2:
- {
- static double coeff[] = {0.0007009872933849692, 0.0006160094635561109, -0.0003868100175168365, -0.0010892765130847692, -0.0003017585549969226, 0.0013388358056545258, 0.0014964848523959517, -0.000810395460575819, -0.0028437587898224592, -0.001026041223667562, 0.0033166243229061365, 0.004008698742836714, -0.0016114861937239766, -0.006794447544962168, -0.0029077117796987295, 0.0070640090852975845, 0.009203733876347542, -0.002605677582323551, -0.014204192906618118, -0.007088471669703722, 0.013578214682638645, 0.019509244710206985, -0.0035577849484980106, -0.028872046619653702, -0.016949573531746864, 0.02703845500946045, 0.045044951140880585, -0.00423968443647027, -0.07416801154613495, -0.05744718387722969, 0.09617383778095245, 0.30029231309890747, 0.39504382014274597, 0.30029231309890747, 0.09617383778095245, -0.05744718387722969, -0.07416801154613495, -0.00423968443647027, 0.045044951140880585, 0.02703845500946045, -0.016949573531746864, -0.028872046619653702, -0.0035577849484980106, 0.019509244710206985, 0.013578214682638645, -0.007088471669703722, -0.014204192906618118, -0.002605677582323551, 0.009203733876347542, 0.0070640090852975845, -0.0029077117796987295, -0.006794447544962168, -0.0016114861937239766, 0.004008698742836714, 0.0033166243229061365, -0.001026041223667562, -0.0028437587898224592, -0.000810395460575819, 0.0014964848523959517, 0.0013388358056545258, -0.0003017585549969226, -0.0010892765130847692, -0.0003868100175168365, 0.0006160094635561109, 0.0007009872933849692};
- LMS_SetGFIRCoeff(m_device, LMS_CH_TX, m_channel, LMS_GFIR3, coeff, 65);
- LMS_SetGFIR(m_device, LMS_CH_TX, m_channel, LMS_GFIR3, true);
+
+ switch (m_interpolate) {
+ case 1:
+ {
+ static double coeff[] = {
+ -0.0014080960536375642, 0.0010270054917782545,
+ 0.0002103941806126386, -0.0023147952742874622,
+ 0.004256128799170256, -0.0038850826676934958,
+ -0.0006057845894247293, 0.008352266624569893,
+ -0.014639420434832573, 0.01275692880153656,
+ 0.0012119393795728683, -0.02339744009077549,
+ 0.04088031128048897, -0.03649924695491791,
+ -0.001745241112075746, 0.07178881019353867,
+ -0.15494878590106964, 0.22244733572006226,
+ 0.7530255913734436, 0.22244733572006226,
+ -0.15494878590106964, 0.07178881019353867,
+ -0.001745241112075746, -0.03649924695491791,
+ 0.04088031128048897, -0.02339744009077549,
+ 0.0012119393795728683, 0.01275692880153656,
+ -0.014639420434832573, 0.008352266624569893,
+ -0.0006057845894247293, -0.0038850826676934958,
+ 0.004256128799170256, -0.0023147952742874622,
+ 0.0002103941806126386, 0.0010270054917782545,
+ -0.0014080960536375642};
+ LMS_SetGFIRCoeff(m_device, LMS_CH_TX, m_channel, LMS_GFIR3, coeff, 37);
+ LMS_SetGFIR(m_device, LMS_CH_TX, m_channel, LMS_GFIR3, true);
+ }
+ break;
+ case 2:
+ {
+ static double coeff[] = {0.0007009872933849692,
+ 0.0006160094635561109, -0.0003868100175168365,
+ -0.0010892765130847692, -0.0003017585549969226,
+ 0.0013388358056545258, 0.0014964848523959517,
+ -0.000810395460575819, -0.0028437587898224592,
+ -0.001026041223667562, 0.0033166243229061365,
+ 0.004008698742836714, -0.0016114861937239766,
+ -0.006794447544962168, -0.0029077117796987295,
+ 0.0070640090852975845, 0.009203733876347542,
+ -0.002605677582323551, -0.014204192906618118,
+ -0.007088471669703722, 0.013578214682638645,
+ 0.019509244710206985, -0.0035577849484980106,
+ -0.028872046619653702, -0.016949573531746864,
+ 0.02703845500946045, 0.045044951140880585,
+ -0.00423968443647027, -0.07416801154613495,
+ -0.05744718387722969, 0.09617383778095245,
+ 0.30029231309890747, 0.39504382014274597,
+ 0.30029231309890747, 0.09617383778095245,
+ -0.05744718387722969, -0.07416801154613495,
+ -0.00423968443647027, 0.045044951140880585,
+ 0.02703845500946045, -0.016949573531746864,
+ -0.028872046619653702, -0.0035577849484980106,
+ 0.019509244710206985, 0.013578214682638645,
+ -0.007088471669703722, -0.014204192906618118,
+ -0.002605677582323551, 0.009203733876347542,
+ 0.0070640090852975845, -0.0029077117796987295,
+ -0.006794447544962168, -0.0016114861937239766,
+ 0.004008698742836714, 0.0033166243229061365,
+ -0.001026041223667562, -0.0028437587898224592,
+ -0.000810395460575819, 0.0014964848523959517,
+ 0.0013388358056545258, -0.0003017585549969226,
+ -0.0010892765130847692, -0.0003868100175168365,
+ 0.0006160094635561109, 0.0007009872933849692};
+ LMS_SetGFIRCoeff(m_device, LMS_CH_TX, m_channel, LMS_GFIR3, coeff, 65);
+ LMS_SetGFIR(m_device, LMS_CH_TX, m_channel, LMS_GFIR3, true);
+ }
+ break;
+ default:
+ throw runtime_error("Unsupported interpolate: " + to_string(m_interpolate));
}
- break;
+
+ if (m_conf.sampleRate != 2048000) {
+ throw runtime_error("Lime output only supports native samplerate = 2048000");
+ /* The buffer_size calculation below does not take into account resampling */
}
-#define FRAME_LENGTH 196608
- // FRAME DURATION is 96ms
- unsigned int buffer_size = FRAME_LENGTH * m_interpolate * 10; // We take 10 Frame buffer size Fifo
- interpolatebuf = new complexf[FRAME_LENGTH * m_interpolate];
+
+ // Frame duration is 96ms
+ size_t buffer_size = FRAME_LENGTH * m_interpolate * 10; // We take 10 Frame buffer size Fifo
// Fifo seems to be round to multiple of SampleRate
m_tx_stream.channel = m_channel;
m_tx_stream.fifoSize = buffer_size;
m_tx_stream.throughputVsLatency = 1.0;
m_tx_stream.isTx = LMS_CH_TX;
m_tx_stream.dataFmt = lms_stream_t::LMS_FMT_F32;
- if (LMS_SetupStream(m_device, &m_tx_stream) < 0)
- {
+ if (LMS_SetupStream(m_device, &m_tx_stream) < 0) {
etiLog.level(error) << "Error making LimeSDR device: %s " << LMS_GetLastErrorMessage();
- throw std::runtime_error("Cannot Channel Activate LimeSDR output device");
+ throw runtime_error("Cannot setup TX stream for LimeSDR output device");
}
LMS_StartStream(&m_tx_stream);
LMS_SetGFIR(m_device, LMS_CH_TX, m_channel, LMS_GFIR3, true);
@@ -173,35 +240,22 @@ Lime::Lime(SDRDeviceConfig &config) : SDRDevice(),
Lime::~Lime()
{
-
- if (m_device != nullptr)
- {
-
- //if (m_tx_stream != nullptr)
- {
- LMS_StopStream(&m_tx_stream);
- LMS_DestroyStream(m_device, &m_tx_stream);
- }
- /*
- if (m_rx_stream != nullptr) {
- m_device->closeStream(m_rx_stream);
- }
- */
+ if (m_device != nullptr) {
+ LMS_StopStream(&m_tx_stream);
+ LMS_DestroyStream(m_device, &m_tx_stream);
LMS_EnableChannel(m_device, LMS_CH_TX, m_channel, false);
LMS_Close(m_device);
}
- if (interpolatebuf != nullptr)
- delete (interpolatebuf);
}
void Lime::tune(double lo_offset, double frequency)
{
- /* if (not m_device) throw runtime_error("Soapy device not set up");
+ if (not m_device)
+ throw runtime_error("Lime device not set up");
- SoapySDR::Kwargs offset_arg;
- offset_arg["OFFSET"] = to_string(lo_offset);
- m_device->setFrequency(SOAPY_SDR_TX, 0, m_conf.frequency, offset_arg);
- */
+ if (LMS_SetLOFrequency(m_device, LMS_CH_TX, m_channel, m_conf.frequency) < 0) {
+ etiLog.level(error) << "Error setting LimeSDR TX frequency: %s " << LMS_GetLastErrorMessage();
+ }
}
double Lime::get_tx_freq(void) const
@@ -209,8 +263,13 @@ double Lime::get_tx_freq(void) const
if (not m_device)
throw runtime_error("Lime device not set up");
- // TODO lo offset
- return 0; //m_device->getFrequency(SOAPY_SDR_TX, 0);
+ float_type cur_frequency = 0.0;
+
+ if (LMS_GetLOFrequency(m_device, LMS_CH_TX, m_channel, &cur_frequency) < 0) {
+ etiLog.level(error) << "Error getting LimeSDR TX frequency: %s " << LMS_GetLastErrorMessage();
+ }
+
+ return cur_frequency;
}
void Lime::set_txgain(double txgain)
@@ -218,14 +277,22 @@ void Lime::set_txgain(double txgain)
m_conf.txgain = txgain;
if (not m_device)
throw runtime_error("Lime device not set up");
- //m_device->setGain(SOAPY_SDR_TX, 0, m_conf.txgain);
+
+ if (LMS_SetNormalizedGain(m_device, LMS_CH_TX, m_channel, m_conf.txgain / 100.0) < 0) {
+ etiLog.level(error) << "Error setting LimeSDR TX gain: %s " << LMS_GetLastErrorMessage();
+ }
}
double Lime::get_txgain(void) const
{
if (not m_device)
throw runtime_error("Lime device not set up");
- return 0; //m_device->getGain(SOAPY_SDR_TX, 0);
+
+ float_type txgain = 0;
+ if (LMS_GetNormalizedGain(m_device, LMS_CH_TX, m_channel, &txgain) < 0) {
+ etiLog.level(error) << "Error getting LimeSDR TX gain: %s " << LMS_GetLastErrorMessage();
+ }
+ return txgain;
}
SDRDevice::RunStatistics Lime::get_run_statistics(void) const
@@ -240,26 +307,19 @@ SDRDevice::RunStatistics Lime::get_run_statistics(void) const
double Lime::get_real_secs(void) const
{
- /*if (m_device) {
- long long time_ns = m_device->getHardwareTime();
- return time_ns / 1e9;
- }
- else {
- return 0.0;
- }*/
+ // TODO
return 0.0;
}
void Lime::set_rxgain(double rxgain)
{
- /*m_device->setGain(SOAPY_SDR_RX, 0, m_conf.rxgain);
- m_conf.rxgain = m_device->getGain(SOAPY_SDR_RX, 0);
- */
+ // TODO
}
double Lime::get_rxgain(void) const
{
- return 0.0; //m_device->getGain(SOAPY_SDR_RX, 0);
+ // TODO
+ return 0.0;
}
size_t Lime::receive_frame(
@@ -268,39 +328,7 @@ size_t Lime::receive_frame(
struct frame_timestamp &ts,
double timeout_secs)
{
- /*int flags = 0;
- long long timeNs = ts.get_ns();
- const size_t numElems = num_samples;
-
- void *buffs[1];
- buffs[0] = buf;
-
- int ret = m_device->activateStream(m_rx_stream, flags, timeNs, numElems);
- if (ret != 0) {
- throw std::runtime_error(string("Soapy activate RX stream failed: ") +
- SoapySDR::errToStr(ret));
- }
- m_rx_stream_active = true;
-
- int n_read = m_device->readStream(
- m_rx_stream, buffs, num_samples, flags, timeNs);
-
- ret = m_device->deactivateStream(m_rx_stream);
- if (ret != 0) {
- throw std::runtime_error(string("Soapy deactivate RX stream failed: ") +
- SoapySDR::errToStr(ret));
- }
- m_rx_stream_active = false;
-
- if (n_read < 0) {
- throw std::runtime_error(string("Soapy failed to read from RX stream : ") +
- SoapySDR::errToStr(ret));
- }
-
- ts.set_ns(timeNs);
-
- return n_read;
- */
+ // TODO
return 0;
}
@@ -317,53 +345,38 @@ const char *Lime::device_name(void) const
double Lime::get_temperature(void) const
{
- // TODO Unimplemented
- // LimeSDR exports 'lms7_temp'
- return std::numeric_limits<double>::quiet_NaN();
+ if (not m_device)
+ throw runtime_error("Lime device not set up");
+
+ float_type temp = numeric_limits<float_type>::quiet_NaN();
+ if (LMS_GetChipTemperature(m_device, 0, &temp) < 0) {
+ etiLog.level(error) << "Error getting LimeSDR temperature: %s " << LMS_GetLastErrorMessage();
+ }
+ return temp;
}
void Lime::transmit_frame(const struct FrameData &frame)
{
-
if (not m_device)
throw runtime_error("Lime device not set up");
- /*if (not m_tx_stream_active)
- {
- unsigned int buffer_size = FRAME_LENGTH*m_interpolate*10; // We take 10 Frame buffer size Fifo
- // Fifo seems to be round to multiple of SampleRate
- m_tx_stream.channel = m_channel;
- m_tx_stream.fifoSize = buffer_size;
- m_tx_stream.throughputVsLatency = 0.8;
- m_tx_stream.isTx = LMS_CH_TX;
- m_tx_stream.dataFmt = lms_stream_t::LMS_FMT_F32;
-
- if ( LMS_SetupStream(m_device, &m_tx_stream) < 0 )
- {
- etiLog.level(error) << "Error making LimeSDR device: %s " << LMS_GetLastErrorMessage();
- throw std::runtime_error("Cannot Channel Activate LimeSDR output device");
- }
- //LMS_StartStream(&m_tx_stream);
- LMS_SetGFIR(m_device, LMS_CH_TX, m_channel, LMS_GFIR3, true);
- m_tx_stream_active = false;
- }*/
-
// The frame buffer contains bytes representing FC32 samples
const complexf *buf = reinterpret_cast<const complexf *>(frame.buf.data());
const size_t numSamples = frame.buf.size() / sizeof(complexf);
- if ((frame.buf.size() % sizeof(complexf)) != 0)
- {
- throw std::runtime_error("Lime: invalid buffer size");
+ if ((frame.buf.size() % sizeof(complexf)) != 0) {
+ throw runtime_error("Lime: invalid buffer size");
}
lms_stream_status_t LimeStatus;
LMS_GetStreamStatus(&m_tx_stream, &LimeStatus);
- overflows = LimeStatus.overrun;
- underflows = LimeStatus.underrun;
- late_packets = LimeStatus.droppedPackets;
+ overflows += LimeStatus.overrun;
+ underflows += LimeStatus.underrun;
+ late_packets += LimeStatus.droppedPackets;
+#if LIMEDEBUG
etiLog.level(info) << LimeStatus.fifoFilledCount << "/" << LimeStatus.fifoSize << ":" << numSamples << "Rate" << LimeStatus.linkRate / (2 * 2.0);
etiLog.level(info) << "overrun" << LimeStatus.overrun << "underun" << LimeStatus.underrun << "drop" << LimeStatus.droppedPackets;
+#endif
/* if(LimeStatus.fifoFilledCount>LimeStatus.fifoSize-2*FRAME_LENGTH*m_interpolate) // Drop if Fifo is just 2 frames before fullness
{
@@ -371,49 +384,43 @@ void Lime::transmit_frame(const struct FrameData &frame)
return;
}*/
- if (LimeStatus.fifoFilledCount < FRAME_LENGTH * 2 * m_interpolate) // Wait if Fifo is just 2 frames before fullness
- {
+ // Wait if Fifo is just 2 frames before fullness
+ if (LimeStatus.fifoFilledCount < FRAME_LENGTH * 2 * m_interpolate) {
etiLog.level(info) << "Fifo underflow : duplicate for filling garbage";
for (size_t i = 0; i < m_interpolate * 10; i++)
LMS_SendStream(&m_tx_stream, buf, numSamples, NULL, 1000);
}
+
/*
- if(LimeStatus.fifoFilledCount>=5*FRAME_LENGTH*m_interpolate) // Start if FIFO is half full
- {
-
- if(not m_tx_stream_active)
- {
+ if(LimeStatus.fifoFilledCount>=5*FRAME_LENGTH*m_interpolate) // Start if FIFO is half full {
+ if(not m_tx_stream_active) {
etiLog.level(info) << "Fifo OK : Normal running";
LMS_StartStream(&m_tx_stream);
m_tx_stream_active = true;
}
-
}
*/
- size_t num_sent = 0;
- if (m_interpolate == 1)
+ ssize_t num_sent = 0;
+ if (m_interpolate == 1) {
num_sent = LMS_SendStream(&m_tx_stream, buf, numSamples, NULL, 1000);
+ }
- if (m_interpolate > 1) // We upsample (1 0 0 0), low pass filter is done by FIR
- {
- for (size_t i = 0; i < numSamples; i++)
- {
+ if (m_interpolate > 1) { // We upsample (1 0 0 0), low pass filter is done by FIR
+ interpolatebuf.resize(m_interpolate * numSamples);
+ for (size_t i = 0; i < numSamples; i++) {
interpolatebuf[i * m_interpolate] = buf[i];
for (size_t j = 1; j < m_interpolate; j++)
interpolatebuf[i * m_interpolate + j] = complexf(0, 0);
}
- num_sent = LMS_SendStream(&m_tx_stream, interpolatebuf, numSamples * m_interpolate, NULL, 1000);
+ num_sent = LMS_SendStream(&m_tx_stream, interpolatebuf.data(), numSamples * m_interpolate, NULL, 1000);
}
- if (num_sent <= 0)
- {
- etiLog.level(info) << "Underflow" << num_sent;
- //throw std::runtime_error("Lime: Too Loonnnngg");
+ if (num_sent == 0) {
+ etiLog.level(info) << "Lime: zero samples sent" << num_sent;
}
- else
- {
- //etiLog.level(info) << "OK" << num_sent;
+ else if (num_sent == -1) {
+ etiLog.level(error) << "Error sending LimeSDR stream: %s " << LMS_GetLastErrorMessage();
}
num_frames_modulated++;
diff --git a/src/output/Lime.h b/src/output/Lime.h
index ab0a388..89f3b7e 100644
--- a/src/output/Lime.h
+++ b/src/output/Lime.h
@@ -5,7 +5,11 @@
Copyright (C) 2018
Evariste F5OEO, evaristec@gmail.com
-
+ Copyright (C) 2019
+ Matthias P. Braendli, matthias.braendli@mpb.li
+
+ http://opendigitalradio.org
+
DESCRIPTION:
It is an output driver using the LimeSDR library.
*/
@@ -32,7 +36,7 @@ DESCRIPTION:
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
-//#define HAVE_LIMESDR
+
#ifdef HAVE_LIMESDR
#include <string>
@@ -81,14 +85,10 @@ class Lime : public Output::SDRDevice
SDRDeviceConfig &m_conf;
lms_device_t *m_device = nullptr;
size_t m_channel = 0; // Should be set by config
- /*
- SoapySDR::Device *m_device = nullptr;
- SoapySDR::Stream *m_tx_stream = nullptr;
- */
lms_stream_t m_tx_stream;
bool m_tx_stream_active = false;
size_t m_interpolate = 1;
- complexf *interpolatebuf = nullptr;
+ std::vector<complexf> interpolatebuf;
size_t underflows = 0;
size_t overflows = 0;