<p>Harald Welte <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/13872">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  Harald Welte: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">lms: Use smpl_buf to recover from timestamp jumps<br><br>Also take the chance to make sure we handle properly short reads (keep<br>reading again).<br><br>Both scenarios can be tested by running osmo-trx-lms and then using<br>on a terminal:<br>sudo kill -STOP `pidof osmo-trx-lms`; sleep 0.5; sudo kill -CONT `pidof osmo-trx-lms`<br><br>Fixes: OS#3339<br>Change-Id: Idfc4e69acc30afb11440b6b9cbdcfa09ff920265<br>---<br>M Transceiver52M/device/lms/LMSDevice.cpp<br>M Transceiver52M/device/lms/LMSDevice.h<br>M Transceiver52M/device/lms/Makefile.am<br>3 files changed, 70 insertions(+), 16 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/Transceiver52M/device/lms/LMSDevice.cpp b/Transceiver52M/device/lms/LMSDevice.cpp</span><br><span>index 75efa1e..c320540 100644</span><br><span>--- a/Transceiver52M/device/lms/LMSDevice.cpp</span><br><span>+++ b/Transceiver52M/device/lms/LMSDevice.cpp</span><br><span>@@ -40,6 +40,7 @@</span><br><span> #define GSM_CARRIER_BW 270000.0 /* 270kHz */</span><br><span> #define LMS_MIN_BW_SUPPORTED 2.5e6 /* 2.5mHz, minimum supported by LMS */</span><br><span> #define LMS_CALIBRATE_BW_HZ OSMO_MAX(GSM_CARRIER_BW, LMS_MIN_BW_SUPPORTED)</span><br><span style="color: hsl(120, 100%, 40%);">+#define SAMPLE_BUF_SZ    (1 << 20) /* Size of Rx timestamp based Ring buffer, in bytes */</span><br><span> </span><br><span> LMSDevice::LMSDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chans, double lo_offset,</span><br><span>                 const std::vector<std::string>& tx_paths,</span><br><span>@@ -56,6 +57,8 @@</span><br><span>         m_last_rx_overruns.resize(chans, 0);</span><br><span>         m_last_rx_dropped.resize(chans, 0);</span><br><span>  m_last_tx_underruns.resize(chans, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       rx_buffers.resize(chans);</span><br><span> }</span><br><span> </span><br><span> LMSDevice::~LMSDevice()</span><br><span>@@ -71,6 +74,9 @@</span><br><span>            LMS_Close(m_lms_dev);</span><br><span>                m_lms_dev = NULL;</span><br><span>    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (size_t i = 0; i < rx_buffers.size(); i++)</span><br><span style="color: hsl(120, 100%, 40%);">+             delete rx_buffers[i];</span><br><span> }</span><br><span> </span><br><span> static void lms_log_callback(int lvl, const char *msg)</span><br><span>@@ -238,6 +244,10 @@</span><br><span>              goto out_close;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Set up per-channel Rx timestamp based Ring buffers */</span><br><span style="color: hsl(120, 100%, 40%);">+      for (size_t i = 0; i < rx_buffers.size(); i++)</span><br><span style="color: hsl(120, 100%, 40%);">+             rx_buffers[i] = new smpl_buf(SAMPLE_BUF_SZ / sizeof(uint32_t));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    started = false;</span><br><span> </span><br><span>         return NORMAL;</span><br><span>@@ -600,7 +610,9 @@</span><br><span> int LMSDevice::readSamples(std::vector < short *>&bufs, int len, bool * overrun,</span><br><span>                      TIMESTAMP timestamp, bool * underrun, unsigned *RSSI)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc, num_smpls, expect_smpls;</span><br><span style="color: hsl(120, 100%, 40%);">+      ssize_t avail_smpls;</span><br><span style="color: hsl(120, 100%, 40%);">+  TIMESTAMP expect_timestamp;</span><br><span>  unsigned int i;</span><br><span>      lms_stream_meta_t rx_metadata = {};</span><br><span>  rx_metadata.flushPartialPacket = false;</span><br><span>@@ -614,24 +626,62 @@</span><br><span> </span><br><span>  *overrun = false;</span><br><span>    *underrun = false;</span><br><span style="color: hsl(0, 100%, 40%);">-      for (i = 0; i<chans; i++) {</span><br><span style="color: hsl(0, 100%, 40%);">-          thread_enable_cancel(false);</span><br><span style="color: hsl(0, 100%, 40%);">-            rc = LMS_RecvStream(&m_lms_stream_rx[i], bufs[i], len, &rx_metadata, 100);</span><br><span style="color: hsl(0, 100%, 40%);">-              update_stream_stats(i, underrun, overrun);</span><br><span style="color: hsl(0, 100%, 40%);">-              if (rc != len) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        LOGCHAN(i, DDEV, ERROR) << "LMS: Device receive timed out (" << rc << " vs exp " << len << ").";</span><br><span style="color: hsl(0, 100%, 40%);">-                    thread_enable_cancel(true);</span><br><span style="color: hsl(0, 100%, 40%);">-                     return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-              }</span><br><span style="color: hsl(0, 100%, 40%);">-               if (timestamp != (TIMESTAMP)rx_metadata.timestamp)</span><br><span style="color: hsl(0, 100%, 40%);">-                      LOGCHAN(i, DDEV, ERROR) << "recv buffer of len " << rc << " expect " << std::hex << timestamp << " got " << std::hex << (TIMESTAMP)rx_metadata.timestamp << " (" << std::hex << rx_metadata.timestamp <<") diff=" << rx_metadata.timestamp - timestamp;</span><br><span style="color: hsl(0, 100%, 40%);">-         thread_enable_cancel(true);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Check that timestamp is valid */</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = rx_buffers[0]->avail_smpls(timestamp);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGC(DDEV, ERROR) << rx_buffers[0]->str_code(rc);</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGC(DDEV, ERROR) << rx_buffers[0]->str_status(timestamp);</span><br><span style="color: hsl(120, 100%, 40%);">+           return 0;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (((TIMESTAMP) rx_metadata.timestamp) < timestamp)</span><br><span style="color: hsl(0, 100%, 40%);">-         rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+       for (i = 0; i<chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                /* Receive samples from HW until we have enough */</span><br><span style="color: hsl(120, 100%, 40%);">+            while ((avail_smpls = rx_buffers[i]->avail_smpls(timestamp)) < len) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   thread_enable_cancel(false);</span><br><span style="color: hsl(120, 100%, 40%);">+                  num_smpls = LMS_RecvStream(&m_lms_stream_rx[i], bufs[i], len - avail_smpls, &rx_metadata, 100);</span><br><span style="color: hsl(120, 100%, 40%);">+                       update_stream_stats(i, underrun, overrun);</span><br><span style="color: hsl(120, 100%, 40%);">+                    thread_enable_cancel(true);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (num_smpls <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              LOGCHAN(i, DDEV, ERROR) << "Device receive timed out (" << rc << " vs exp " << len << ").";</span><br><span style="color: hsl(120, 100%, 40%);">+                               return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+                    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+                    LOGCHAN(i, DDEV, DEBUG) "Received timestamp = " << (TIMESTAMP)rx_metadata.timestamp << " (" << num_smpls << ")";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                      expect_smpls = len - avail_smpls;</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (expect_smpls != num_smpls)</span><br><span style="color: hsl(120, 100%, 40%);">+                                LOGCHAN(i, DDEV, NOTICE) << "Unexpected recv buffer len: expect "</span><br><span style="color: hsl(120, 100%, 40%);">+                                                      << expect_smpls << " got " << num_smpls</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   << ", diff=" << expect_smpls - num_smpls;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                    expect_timestamp = timestamp + avail_smpls;</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (expect_timestamp != (TIMESTAMP)rx_metadata.timestamp)</span><br><span style="color: hsl(120, 100%, 40%);">+                             LOGCHAN(i, DDEV, ERROR) << "Unexpected recv buffer timestamp: expect "</span><br><span style="color: hsl(120, 100%, 40%);">+                                                        << expect_timestamp << " got " << (TIMESTAMP)rx_metadata.timestamp</span><br><span style="color: hsl(120, 100%, 40%);">+                                                        << ", diff=" << rx_metadata.timestamp - expect_timestamp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                     rc = rx_buffers[i]->write(bufs[i], num_smpls, (TIMESTAMP)rx_metadata.timestamp);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              LOGCHAN(i, DDEV, ERROR) << rx_buffers[i]->str_code(rc);</span><br><span style="color: hsl(120, 100%, 40%);">+                              LOGCHAN(i, DDEV, ERROR) << rx_buffers[i]->str_status(timestamp);</span><br><span style="color: hsl(120, 100%, 40%);">+                             if (rc != smpl_buf::ERROR_OVERFLOW)</span><br><span style="color: hsl(120, 100%, 40%);">+                                   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* We have enough samples */</span><br><span style="color: hsl(120, 100%, 40%);">+  for (size_t i = 0; i < rx_buffers.size(); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = rx_buffers[i]->read(bufs[i], len, timestamp);</span><br><span style="color: hsl(120, 100%, 40%);">+         if ((rc < 0) || (rc != len)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     LOGC(DDEV, ERROR) << rx_buffers[i]->str_code(rc);</span><br><span style="color: hsl(120, 100%, 40%);">+                    LOGC(DDEV, ERROR) << rx_buffers[i]->str_status(timestamp);</span><br><span style="color: hsl(120, 100%, 40%);">+                   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return len;</span><br><span> }</span><br><span> </span><br><span> int LMSDevice::writeSamples(std::vector < short *>&bufs, int len,</span><br><span>diff --git a/Transceiver52M/device/lms/LMSDevice.h b/Transceiver52M/device/lms/LMSDevice.h</span><br><span>index b0ff03b..2828578 100644</span><br><span>--- a/Transceiver52M/device/lms/LMSDevice.h</span><br><span>+++ b/Transceiver52M/device/lms/LMSDevice.h</span><br><span>@@ -20,6 +20,7 @@</span><br><span> #endif</span><br><span> </span><br><span> #include "radioDevice.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "smpl_buf.h"</span><br><span> </span><br><span> #include <sys/time.h></span><br><span> #include <math.h></span><br><span>@@ -53,6 +54,8 @@</span><br><span>      std::vector<uint32_t> m_last_rx_dropped;</span><br><span>       std::vector<uint32_t> m_last_tx_underruns;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+  std::vector<smpl_buf *> rx_buffers;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  double actualSampleRate;        ///< the actual USRP sampling rate</span><br><span> </span><br><span>    bool started;           ///< flag indicates LMS has started</span><br><span>diff --git a/Transceiver52M/device/lms/Makefile.am b/Transceiver52M/device/lms/Makefile.am</span><br><span>index 682cf26..77fd0e9 100644</span><br><span>--- a/Transceiver52M/device/lms/Makefile.am</span><br><span>+++ b/Transceiver52M/device/lms/Makefile.am</span><br><span>@@ -8,3 +8,4 @@</span><br><span> noinst_LTLIBRARIES = libdevice.la</span><br><span> </span><br><span> libdevice_la_SOURCES = LMSDevice.cpp</span><br><span style="color: hsl(120, 100%, 40%);">+libdevice_la_LIBADD = $(top_builddir)/Transceiver52M/device/common/libdevice_common.la</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/13872">change 13872</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/13872"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-trx </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: Idfc4e69acc30afb11440b6b9cbdcfa09ff920265 </div>
<div style="display:none"> Gerrit-Change-Number: 13872 </div>
<div style="display:none"> Gerrit-PatchSet: 4 </div>
<div style="display:none"> Gerrit-Owner: Pau Espin Pedrol <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder (1000002) </div>
<div style="display:none"> Gerrit-Reviewer: Pau Espin Pedrol <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: tnt <tnt@246tNt.com> </div>