<p>Xavier Zu has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-trx/+/19548">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Added PCIeSDR support<br><br>Change-Id: I5b49b61d1c8f357e33acc066f44d6c7acfc3ba79<br>---<br>M Transceiver52M/Makefile.am<br>M Transceiver52M/device/Makefile.am<br>A Transceiver52M/device/pciesdr/Makefile.am<br>A Transceiver52M/device/pciesdr/PCIESDRDevice.cpp<br>A Transceiver52M/device/pciesdr/PCIESDRDevice.h<br>M configure.ac<br>A doc/examples/osmo-trx-pciesdr/osmo-trx-pciesdr.cfg<br>7 files changed, 897 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-trx refs/changes/48/19548/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/Transceiver52M/Makefile.am b/Transceiver52M/Makefile.am</span><br><span>index ade4e30..6d4dad2 100644</span><br><span>--- a/Transceiver52M/Makefile.am</span><br><span>+++ b/Transceiver52M/Makefile.am</span><br><span>@@ -104,3 +104,12 @@</span><br><span>    $(LMS_LIBS)</span><br><span> osmo_trx_lms_CPPFLAGS  = $(AM_CPPFLAGS) $(LMS_CFLAGS)</span><br><span> endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+if DEVICE_PCIESDR</span><br><span style="color: hsl(120, 100%, 40%);">+bin_PROGRAMS += osmo-trx-pciesdr</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_trx_pciesdr_SOURCES = osmo-trx.cpp</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_trx_pciesdr_LDADD = \</span><br><span style="color: hsl(120, 100%, 40%);">+        $(builddir)/device/pciesdr/libdevice.la \</span><br><span style="color: hsl(120, 100%, 40%);">+        $(COMMON_LDADD)</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_trx_pciesdr_CPPFLAGS  = $(AM_CPPFLAGS)</span><br><span style="color: hsl(120, 100%, 40%);">+endif</span><br><span>diff --git a/Transceiver52M/device/Makefile.am b/Transceiver52M/device/Makefile.am</span><br><span>index 369e877..36366e3 100644</span><br><span>--- a/Transceiver52M/device/Makefile.am</span><br><span>+++ b/Transceiver52M/device/Makefile.am</span><br><span>@@ -13,3 +13,7 @@</span><br><span> if DEVICE_LMS</span><br><span> SUBDIRS += lms</span><br><span> endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+if DEVICE_PCIESDR</span><br><span style="color: hsl(120, 100%, 40%);">+SUBDIRS += pciesdr</span><br><span style="color: hsl(120, 100%, 40%);">+endif</span><br><span>diff --git a/Transceiver52M/device/pciesdr/Makefile.am b/Transceiver52M/device/pciesdr/Makefile.am</span><br><span>new file mode 100644</span><br><span>index 0000000..6f7ad1b</span><br><span>--- /dev/null</span><br><span>+++ b/Transceiver52M/device/pciesdr/Makefile.am</span><br><span>@@ -0,0 +1,11 @@</span><br><span style="color: hsl(120, 100%, 40%);">+include $(top_srcdir)/Makefile.common</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) -I${srcdir}/../common</span><br><span style="color: hsl(120, 100%, 40%);">+AM_CXXFLAGS = -lpthread -lsdr $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+noinst_HEADERS = PCIESDRDevice.h</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+noinst_LTLIBRARIES = libdevice.la</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+libdevice_la_SOURCES = PCIESDRDevice.cpp</span><br><span style="color: hsl(120, 100%, 40%);">+libdevice_la_LIBADD = $(top_builddir)/Transceiver52M/device/common/libdevice_common.la</span><br><span>diff --git a/Transceiver52M/device/pciesdr/PCIESDRDevice.cpp b/Transceiver52M/device/pciesdr/PCIESDRDevice.cpp</span><br><span>new file mode 100644</span><br><span>index 0000000..8dd0b1d</span><br><span>--- /dev/null</span><br><span>+++ b/Transceiver52M/device/pciesdr/PCIESDRDevice.cpp</span><br><span>@@ -0,0 +1,642 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+* Copyright 2018 sysmocom - s.f.m.c. GmbH</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* SPDX-License-Identifier: AGPL-3.0+</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+     This program is free software: you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+  it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+   the Free Software Foundation, either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+     (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+       but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ GNU Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+      along with this program.  If not, see <http://www.gnu.org/licenses/>.</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%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdlib.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <map></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "trx_vty.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "Logger.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "Threads.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "PCIESDRDevice.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "Utils.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LIBSDR_HAS_MSDR_CONVERT</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#include "libsdr.h"</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%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#include "../../arch/common/convert.h"</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%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#include "osmo_signal.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></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%);">+#ifdef HAVE_CONFIG_H</span><br><span style="color: hsl(120, 100%, 40%);">+#include "config.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+using namespace std;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define PSAMPLES_NUM  4096</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Size of Rx / Tx timestamp based Ring buffer, in bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+#define SAMPLE_BUF_SZ (1 << 20)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* greatest common divisor */</span><br><span style="color: hsl(120, 100%, 40%);">+static long gcd(long a, long b)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (a == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+           return b;</span><br><span style="color: hsl(120, 100%, 40%);">+     else if (b == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+              return a;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (a < b)</span><br><span style="color: hsl(120, 100%, 40%);">+         return gcd(a, b % a);</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+          return gcd(b, a % b);</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%);">+PCIESDRDevice::PCIESDRDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chan_num, double lo_offset,</span><br><span style="color: hsl(120, 100%, 40%);">+                             const std::vector<std::string>& tx_paths,</span><br><span style="color: hsl(120, 100%, 40%);">+                           const std::vector<std::string>& rx_paths):</span><br><span style="color: hsl(120, 100%, 40%);">+     RadioDevice(tx_sps, rx_sps, iface, chan_num, lo_offset, tx_paths, rx_paths)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        LOGC(DDEV, INFO) << "creating PCIESDR device...";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* The parameter dma_buffer_len is significant for functionality of the Rx chain */</span><br><span style="color: hsl(120, 100%, 40%);">+   dma_buffer_count = 10;</span><br><span style="color: hsl(120, 100%, 40%);">+        dma_buffer_len = 1000;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      device = NULL;</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 style="color: hsl(120, 100%, 40%);">+</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 style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+PCIESDRDevice::~PCIESDRDevice()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    LOGC(DDEV, INFO) << "Closing PCIESDR device";</span><br><span style="color: hsl(120, 100%, 40%);">+ if (device) {</span><br><span style="color: hsl(120, 100%, 40%);">+         msdr_close(device);</span><br><span style="color: hsl(120, 100%, 40%);">+           device = NULL;</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%);">+   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 style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int parse_config(const char* line, const char* argument, int default_value)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     const char* arg_found = strstr(line, argument);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!arg_found)</span><br><span style="color: hsl(120, 100%, 40%);">+               return default_value;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       const char* qe_pos = strchr(arg_found, '=');</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!qe_pos)</span><br><span style="color: hsl(120, 100%, 40%);">+          return default_value;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       int res = strtol(qe_pos + 1, NULL, 10);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (res == 0 && errno)</span><br><span style="color: hsl(120, 100%, 40%);">+                return default_value;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return res;</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%);">+int PCIESDRDevice::open(const std::string &args, int ref, bool swap_channels)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        int lb_param = parse_config(args.c_str(), "loopback", 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   char pciesdr_name[500];</span><br><span style="color: hsl(120, 100%, 40%);">+       const char* lend = strchr(args.c_str(), ',');</span><br><span style="color: hsl(120, 100%, 40%);">+ int len = (lend) ? (lend - args.c_str()) : sizeof(pciesdr_name) - 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        LOGC(DDEV, INFO) << "Opening PCIESDR device..";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     strncpy(pciesdr_name, args.c_str(), len);</span><br><span style="color: hsl(120, 100%, 40%);">+     pciesdr_name[len] = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        started = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (lb_param) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGC(DDEV, ERROR) << "PCIESDR LOOPBACK mode is not supported!";</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGC(DDEV, INFO) << "pciesdr_name"  << pciesdr_name << "";</span><br><span style="color: hsl(120, 100%, 40%);">+      device = msdr_open(pciesdr_name);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (device == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGC(DDEV, ERROR) << "PCIESDR creating failed, device " << pciesdr_name << "";</span><br><span style="color: hsl(120, 100%, 40%);">+          return -1;</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%);">+   msdr_set_default_start_params(device, &StartParams);</span><br><span style="color: hsl(120, 100%, 40%);">+      /* RF interface */</span><br><span style="color: hsl(120, 100%, 40%);">+    StartParams.interface_type = SDR_INTERFACE_RF;</span><br><span style="color: hsl(120, 100%, 40%);">+        /* no time synchronisation */</span><br><span style="color: hsl(120, 100%, 40%);">+ StartParams.sync_source = SDR_SYNC_NONE;</span><br><span style="color: hsl(120, 100%, 40%);">+      /* sync on internal PPS */</span><br><span style="color: hsl(120, 100%, 40%);">+    //StartParams.sync_source = SDR_SYNC_INTERNAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* calculate sample rate using Euclidean algorithm */</span><br><span style="color: hsl(120, 100%, 40%);">+ double rate = (double)GSMRATE*tx_sps;</span><br><span style="color: hsl(120, 100%, 40%);">+ double integral = floor(rate);</span><br><span style="color: hsl(120, 100%, 40%);">+        double frac = rate - integral;</span><br><span style="color: hsl(120, 100%, 40%);">+        /* This is the accuracy */</span><br><span style="color: hsl(120, 100%, 40%);">+    const long precision = 1000000000;</span><br><span style="color: hsl(120, 100%, 40%);">+    long gcd_ = gcd(round(frac * precision), precision);</span><br><span style="color: hsl(120, 100%, 40%);">+  long denominator = precision / gcd_;</span><br><span style="color: hsl(120, 100%, 40%);">+  long numerator = round(frac * precision) / gcd_;</span><br><span style="color: hsl(120, 100%, 40%);">+      StartParams.sample_rate_num[0] = (int64_t)(integral * denominator + numerator);</span><br><span style="color: hsl(120, 100%, 40%);">+       StartParams.sample_rate_den[0] = (int64_t)denominator;</span><br><span style="color: hsl(120, 100%, 40%);">+        actualSampleRate = (double)StartParams.sample_rate_num[0] / (double)StartParams.sample_rate_den[0];</span><br><span style="color: hsl(120, 100%, 40%);">+   StartParams.rx_bandwidth[0] = actualSampleRate * 0.75;</span><br><span style="color: hsl(120, 100%, 40%);">+        StartParams.tx_bandwidth[0] = actualSampleRate * 0.75;</span><br><span style="color: hsl(120, 100%, 40%);">+        LOGC(DDEV, INFO) << "PCIESDR device txsps:" << tx_sps << " rxsps:" << rx_sps</span><br><span style="color: hsl(120, 100%, 40%);">+                       << " GSMRATE * tx_sps:" << (double)GSMRATE * tx_sps;</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGC(DDEV, INFO) << "PCIESDR sample_rate_num:" << StartParams.sample_rate_num[0]</span><br><span style="color: hsl(120, 100%, 40%);">+                         << " sample_rate_den:" << StartParams.sample_rate_den[0]</span><br><span style="color: hsl(120, 100%, 40%);">+                        << " BW:" << StartParams.rx_bandwidth[0];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (ref) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case REF_INTERNAL:</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGC(DDEV, INFO) << "Setting Internal clock reference";</span><br><span style="color: hsl(120, 100%, 40%);">+               /* internal clock, using PPS to correct it */</span><br><span style="color: hsl(120, 100%, 40%);">+         StartParams.clock_source = SDR_CLOCK_INTERNAL;</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGC(DDEV, ERROR) << "Invalid reference type";</span><br><span style="color: hsl(120, 100%, 40%);">+                goto out_close;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     /* complex float32 */</span><br><span style="color: hsl(120, 100%, 40%);">+ StartParams.rx_sample_fmt = SDR_SAMPLE_FMT_CF32;</span><br><span style="color: hsl(120, 100%, 40%);">+      StartParams.tx_sample_fmt = SDR_SAMPLE_FMT_CF32;</span><br><span style="color: hsl(120, 100%, 40%);">+      /* choose best format fitting the bandwidth */</span><br><span style="color: hsl(120, 100%, 40%);">+        StartParams.rx_sample_hw_fmt = SDR_SAMPLE_HW_FMT_AUTO;</span><br><span style="color: hsl(120, 100%, 40%);">+        StartParams.tx_sample_hw_fmt = SDR_SAMPLE_HW_FMT_AUTO;</span><br><span style="color: hsl(120, 100%, 40%);">+        StartParams.rx_channel_count = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+     StartParams.tx_channel_count = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+     StartParams.rx_freq[0] = 1550e6;</span><br><span style="color: hsl(120, 100%, 40%);">+      StartParams.tx_freq[0] = 1500e6;</span><br><span style="color: hsl(120, 100%, 40%);">+      StartParams.rx_gain[0] = 60;</span><br><span style="color: hsl(120, 100%, 40%);">+  StartParams.tx_gain[0] = 40;</span><br><span style="color: hsl(120, 100%, 40%);">+  StartParams.rx_antenna[0] = SDR_RX_ANTENNA_RX;</span><br><span style="color: hsl(120, 100%, 40%);">+        StartParams.rf_port_count = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+        StartParams.tx_port_channel_count[0] = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+     StartParams.rx_port_channel_count[0] = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+     /* if != 0, set a custom DMA buffer configuration. Otherwise the default is 150 buffers per 10 ms */</span><br><span style="color: hsl(120, 100%, 40%);">+  StartParams.dma_buffer_count = dma_buffer_count;</span><br><span style="color: hsl(120, 100%, 40%);">+      /* in samples */</span><br><span style="color: hsl(120, 100%, 40%);">+      StartParams.dma_buffer_len = dma_buffer_len;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* FIXME: estimate it properly */</span><br><span style="color: hsl(120, 100%, 40%);">+     /* PCIe radio should have this close to zero */</span><br><span style="color: hsl(120, 100%, 40%);">+       /* The MS can connect if the value is between -30 and +5 */</span><br><span style="color: hsl(120, 100%, 40%);">+   ts_offset = -16;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    started = false;</span><br><span style="color: hsl(120, 100%, 40%);">+      return NORMAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+out_close:</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGC(DDEV, FATAL) << "Error in PCIESDR open, closing";</span><br><span style="color: hsl(120, 100%, 40%);">+        msdr_close(device);</span><br><span style="color: hsl(120, 100%, 40%);">+   device = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return -1;</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%);">+bool PCIESDRDevice::start()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       SDRStats stats;</span><br><span style="color: hsl(120, 100%, 40%);">+       int res;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    LOGC(DDEV, INFO) << "starting PCIESDR...";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (started) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGC(DDEV, ERROR) << "Device already started";</span><br><span style="color: hsl(120, 100%, 40%);">+                return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGC(DDEV, INFO) << "starting PCIESDR..., sample rate:" << actualSampleRate;</span><br><span style="color: hsl(120, 100%, 40%);">+    res = msdr_start(device, &StartParams);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGC(DDEV, ERROR) << "msdr_start failed:"<< res;</span><br><span style="color: hsl(120, 100%, 40%);">+                return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     res = msdr_get_stats(device, &stats);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (res != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGC(DDEV, ERROR) << "PCIESDRDevice start: get_stats failed:" << res;</span><br><span style="color: hsl(120, 100%, 40%);">+   } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              tx_underflow = stats.tx_underflow_count;</span><br><span style="color: hsl(120, 100%, 40%);">+              rx_overflow  = stats.rx_overflow_count;</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%);">+   flush_recv();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       started = true;</span><br><span style="color: hsl(120, 100%, 40%);">+       return true;</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%);">+bool PCIESDRDevice::stop()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int res;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    LOGC(DDEV, INFO) << "PCIESDRDevice stop";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (started) {</span><br><span style="color: hsl(120, 100%, 40%);">+                res = msdr_stop(device);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    LOGC(DDEV, ERROR) << "PCIESDR stop failed res: " << res;</span><br><span style="color: hsl(120, 100%, 40%);">+                } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGC(DDEV, INFO) << "PCIESDR stopped";</span><br><span style="color: hsl(120, 100%, 40%);">+                        started = false;</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 true;</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%);">+double PCIESDRDevice::maxTxGain()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       return 90;</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%);">+double PCIESDRDevice::maxRxGain()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return 50;</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%);">+double PCIESDRDevice::minRxGain()</span><br><span style="color: hsl(120, 100%, 40%);">+{</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%);">+double PCIESDRDevice::getTxGain(size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       if (chan) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGC(DDEV, ERROR) << "Invalid channel " << chan;</span><br><span style="color: hsl(120, 100%, 40%);">+                return 0.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%);">+   return msdr_get_tx_gain(device, chan);</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%);">+double PCIESDRDevice::setTxGain(double dB, size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (chan) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGC(DDEV, ERROR) << "Invalid channel " << chan;</span><br><span style="color: hsl(120, 100%, 40%);">+                return 0.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%);">+   LOGC(DDEV, INFO) << "Setting TX gain to " << dB << " dB. device:" << device << " chan:" << chan;</span><br><span style="color: hsl(120, 100%, 40%);">+    StartParams.tx_gain[chan] = dB;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (started) {</span><br><span style="color: hsl(120, 100%, 40%);">+                res = msdr_set_tx_gain(device, chan, StartParams.tx_gain[chan]);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    LOGC(DDEV, INFO) << "Error setting TX gain res: " << res;</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 StartParams.tx_gain[chan];</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%);">+double PCIESDRDevice::setPowerAttenuation(int atten, size_t chan) {</span><br><span style="color: hsl(120, 100%, 40%);">+   double rfGain;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      rfGain = setTxGain(maxTxGain() - atten, chan);</span><br><span style="color: hsl(120, 100%, 40%);">+        return maxTxGain() - rfGain;</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%);">+double PCIESDRDevice::getPowerAttenuation(size_t chan) {</span><br><span style="color: hsl(120, 100%, 40%);">+   return maxTxGain() - getTxGain(chan);</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%);">+double PCIESDRDevice::setRxGain(double dB, size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (chan) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGC(DDEV, ERROR) << "Invalid channel " << chan;</span><br><span style="color: hsl(120, 100%, 40%);">+                return 0.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%);">+   LOGC(DDEV, INFO) << "Setting RX gain to " << dB << " dB.";</span><br><span style="color: hsl(120, 100%, 40%);">+      StartParams.rx_gain[chan] = dB;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (started) {</span><br><span style="color: hsl(120, 100%, 40%);">+                res = msdr_set_rx_gain(device, chan, dB);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    LOGC(DDEV, ERROR) << "Error setting RX gain res: " << res;</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 StartParams.rx_gain[chan];</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%);">+int PCIESDRDevice::getNominalTxPower(size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  /* TODO: return value based on some experimentally generated table depending on</span><br><span style="color: hsl(120, 100%, 40%);">+       * band/arfcn, which is known here thanks to TXTUNE</span><br><span style="color: hsl(120, 100%, 40%);">+    */</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%);">+bool PCIESDRDevice::flush_recv()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int chan = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        static sample_t samples[PSAMPLES_NUM];</span><br><span style="color: hsl(120, 100%, 40%);">+        static sample_t *psamples;</span><br><span style="color: hsl(120, 100%, 40%);">+    int64_t timestamp_tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+        int expect_smpls = sizeof(samples) / sizeof(samples[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+      int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGC(DDEV, INFO) << "PCIESDRDevice flush";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  psamples = &samples[0];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ while ((rc = msdr_read(device, &timestamp_tmp, (void**)&psamples, expect_smpls, chan, 100)) > 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (rc < (int)expect_smpls)</span><br><span style="color: hsl(120, 100%, 40%);">+                        break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       ts_initial = (TIMESTAMP)timestamp_tmp + rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGC(DDEV, INFO) << "Initial timestamp " << ts_initial << std::endl;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return true;</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%);">+/* NOTE: Assumes sequential reads */</span><br><span style="color: hsl(120, 100%, 40%);">+int PCIESDRDevice::readSamples(std::vector <short *> &bufs, int len, bool *overrun,</span><br><span style="color: hsl(120, 100%, 40%);">+                               TIMESTAMP timestamp, bool *underrun)</span><br><span style="color: hsl(120, 100%, 40%);">+{</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 style="color: hsl(120, 100%, 40%);">+   unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+       static sample_t samples[PSAMPLES_NUM];</span><br><span style="color: hsl(120, 100%, 40%);">+        static sample_t *psamples;</span><br><span style="color: hsl(120, 100%, 40%);">+    int64_t timestamp_tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef LIBSDR_HAS_MSDR_CONVERT</span><br><span style="color: hsl(120, 100%, 40%);">+       float powerScaling[] = {1, 1, 1, 1};</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!started)</span><br><span style="color: hsl(120, 100%, 40%);">+         return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (bufs.size() != chans) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGC(DDEV, ERROR) << "Invalid channel combination " << bufs.size();</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</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%);">+   if (len > (int)(sizeof(samples) / sizeof(*samples))) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGC(DDEV, ERROR) << "Sample buffer:" << (sizeof(samples) / sizeof(*samples))</span><br><span style="color: hsl(120, 100%, 40%);">+                             << " is smaller than len:" << len;</span><br><span style="color: hsl(120, 100%, 40%);">+            return -1;</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%);">+   *overrun = false;</span><br><span style="color: hsl(120, 100%, 40%);">+     *underrun = false;</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) << "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 style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</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%);">+                   expect_smpls = len - avail_smpls;</span><br><span style="color: hsl(120, 100%, 40%);">+                     expect_smpls = expect_smpls > (int)dma_buffer_len ? expect_smpls : (int)dma_buffer_len;</span><br><span style="color: hsl(120, 100%, 40%);">+                    expect_timestamp = timestamp + avail_smpls;</span><br><span style="color: hsl(120, 100%, 40%);">+                   timestamp_tmp = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                    psamples = &samples[0];</span><br><span style="color: hsl(120, 100%, 40%);">+                   num_smpls = msdr_read(device, &timestamp_tmp, (void**)&psamples, expect_smpls, i, 100);</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (num_smpls < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               LOGC(DDEV, ERROR) << "PCIESDR readSamples msdr_read failed num_smpls " << num_smpls</span><br><span style="color: hsl(120, 100%, 40%);">+                                        << " device: " << device</span><br><span style="color: hsl(120, 100%, 40%);">+                                        << " expect_smpls: " << expect_smpls</span><br><span style="color: hsl(120, 100%, 40%);">+                                    << ", expTs:" << expect_timestamp << " got " << timestamp_tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+                         LOGCHAN(i, DDEV, ERROR) << "Device receive timed out (" << rc</span><br><span style="color: hsl(120, 100%, 40%);">+                                      << " 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 style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   LOGCHAN(i, DDEV, DEBUG) << "Received timestamp = " << (TIMESTAMP)timestamp_tmp</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                     << " (" << num_smpls << ")";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef LIBSDR_HAS_MSDR_CONVERT</span><br><span style="color: hsl(120, 100%, 40%);">+                       msdr_convert_cf32_to_ci16(bufs[i], (float *)psamples, num_smpls);</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+                      convert_float_short(bufs[i], (float *)psamples, powerScaling[0], num_smpls * 2);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</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, DEBUG) << "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%);">+                                                        << ", expTs:" << expect_timestamp << " got " << timestamp_tmp;</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%);">+                   if (expect_timestamp != (TIMESTAMP)timestamp_tmp) {</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_tmp</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   << ", diff=" << timestamp_tmp - 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)timestamp_tmp);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (rc < 0) {</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%);">+</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%);">+                     LOGCHAN(i, DDEV, ERROR) << rx_buffers[i]->str_code(rc) << ". "</span><br><span style="color: hsl(120, 100%, 40%);">+                                               << rx_buffers[i]->str_status(timestamp)</span><br><span style="color: hsl(120, 100%, 40%);">+                                              << ", (len=" << len << ")";</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 style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int PCIESDRDevice::writeSamples(std::vector<short *> &bufs, int len,</span><br><span style="color: hsl(120, 100%, 40%);">+                                bool *underrun, unsigned long long timestamp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+       static sample_t samples[PSAMPLES_NUM];</span><br><span style="color: hsl(120, 100%, 40%);">+        static sample_t *psamples;</span><br><span style="color: hsl(120, 100%, 40%);">+    int64_t hw_time;</span><br><span style="color: hsl(120, 100%, 40%);">+      int64_t timestamp_tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+        SDRStats stats;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!started)</span><br><span style="color: hsl(120, 100%, 40%);">+         return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (bufs.size() != chans) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGC(DDEV, ERROR) << "Invalid channel combination " << bufs.size();</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</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%);">+   if (len > (int)(sizeof(samples) / sizeof(*samples))) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGC(DDEV, ERROR) << "Sample buffer:" << (sizeof(samples) / sizeof(*samples))</span><br><span style="color: hsl(120, 100%, 40%);">+                             << " is smaller than len:" << len;</span><br><span style="color: hsl(120, 100%, 40%);">+            return -1;</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%);">+   timestamp_tmp = timestamp - ts_offset; /* Shift Tx time by offset */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        *underrun = false;</span><br><span style="color: hsl(120, 100%, 40%);">+    i = 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%);">+              LOGCHAN(i, DDEV, DEBUG) << "send buffer of len " << len << " timestamp " << std::hex << timestamp_tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+              psamples = &samples[0];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef LIBSDR_HAS_MSDR_CONVERT</span><br><span style="color: hsl(120, 100%, 40%);">+         msdr_convert_ci16_to_cf32((float*)psamples, bufs[i], len);</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+             convert_short_float((float*)psamples, bufs[i], len * 2);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = msdr_write(device, timestamp_tmp, (const void**)&psamples, len, i, &hw_time);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (rc != len) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGC(DDEV, ALERT) << "PCIESDR writeSamples: Device send timed out rc:" << rc</span><br><span style="color: hsl(120, 100%, 40%);">+                                      << " timestamp" << timestamp_tmp << " len:" << len << " hwtime:" << hw_time;</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGCHAN(i, DDEV, ERROR) << "PCIESDR: Device Tx 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 style="color: hsl(120, 100%, 40%);">+             if (msdr_get_stats(device, &stats)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     LOGC(DDEV, ALERT) << "PCIESDR: get_stats failed:" << rc;</span><br><span style="color: hsl(120, 100%, 40%);">+                } else if (stats.tx_underflow_count > tx_underflow) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      tx_underflow = stats.tx_underflow_count;</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGC(DDEV, ALERT) << "tx_underflow_count:" << stats.tx_underflow_count</span><br><span style="color: hsl(120, 100%, 40%);">+                                    << " rx_overflow_count:" << stats.rx_overflow_count;</span><br><span style="color: hsl(120, 100%, 40%);">+                  *underrun = true;</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%);">+           if (timestamp_tmp - hw_time > (int64_t)actualSampleRate / 10)</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGC(DDEV, ALERT) << "PCIESDR: tx diff more ts_tmp:" << timestamp_tmp << " ts:" << timestamp</span><br><span style="color: hsl(120, 100%, 40%);">+                                        << " hwts:" << hw_time;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             if (hw_time > timestamp_tmp) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     LOGC(DDEV, ALERT) << "PCIESDR: tx underrun ts_tmp:" << timestamp_tmp << " ts:" << timestamp</span><br><span style="color: hsl(120, 100%, 40%);">+                                         << " hwts:" << hw_time;</span><br><span style="color: hsl(120, 100%, 40%);">+                       *underrun = true;</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 rc;</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%);">+bool PCIESDRDevice::setRxAntenna(const std::string & ant, size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return true;</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%);">+std::string PCIESDRDevice::getRxAntenna(size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return "";</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%);">+bool PCIESDRDevice::setTxAntenna(const std::string & ant, size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return true;</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%);">+std::string PCIESDRDevice::getTxAntenna(size_t chan )</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   return "";</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%);">+bool PCIESDRDevice::requiresRadioAlign()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return false;</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%);">+GSM::Time PCIESDRDevice::minLatency()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  return GSM::Time(6,7);</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%);">+bool PCIESDRDevice::updateAlignment(TIMESTAMP timestamp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      LOGC(DDEV, INFO) << "Update Alignment ";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return true;</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%);">+bool PCIESDRDevice::setTxFreq(double wFreq, size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        double actual = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGCHAN(chan, DDEV, NOTICE) << "PCIESDR setTxFreq";</span><br><span style="color: hsl(120, 100%, 40%);">+   if (chan) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGC(DDEV, ERROR) << "Invalid channel " << chan;</span><br><span style="color: hsl(120, 100%, 40%);">+                return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     actual = StartParams.tx_freq[chan];</span><br><span style="color: hsl(120, 100%, 40%);">+   StartParams.tx_freq[chan] = wFreq;</span><br><span style="color: hsl(120, 100%, 40%);">+    LOGC(DDEV, INFO) << "set TX: " << wFreq << std::endl</span><br><span style="color: hsl(120, 100%, 40%);">+                       << "    actual freq: " << actual << std::endl;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return true;</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%);">+bool PCIESDRDevice::setRxFreq(double wFreq, size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        double actual = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGCHAN(chan, DDEV, NOTICE) << "PCIESDR setRxFreq";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGC(DDEV, ERROR) << "Invalid channel " << chan;</span><br><span style="color: hsl(120, 100%, 40%);">+                return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     actual = StartParams.rx_freq[chan];</span><br><span style="color: hsl(120, 100%, 40%);">+   StartParams.rx_freq[chan] = wFreq;</span><br><span style="color: hsl(120, 100%, 40%);">+    LOGC(DDEV, INFO) << "set RX: " << wFreq << std::endl</span><br><span style="color: hsl(120, 100%, 40%);">+                       << "    actual freq: " << actual << std::endl;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return true;</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%);">+RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps,</span><br><span style="color: hsl(120, 100%, 40%);">+                              InterfaceType iface, size_t chans, double lo_offset,</span><br><span style="color: hsl(120, 100%, 40%);">+                          const std::vector < std::string > &tx_paths,</span><br><span style="color: hsl(120, 100%, 40%);">+                        const std::vector < std::string > &rx_paths)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      if (tx_sps != rx_sps) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGC(DDEV, ERROR) << "PCIESDR Requires tx_sps == rx_sps";</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (lo_offset != 0.0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGC(DDEV, ERROR) << "PCIESDR doesn't support lo_offset";</span><br><span style="color: hsl(120, 100%, 40%);">+         return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     return new PCIESDRDevice(tx_sps, rx_sps, iface, chans, lo_offset, tx_paths, rx_paths);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/Transceiver52M/device/pciesdr/PCIESDRDevice.h b/Transceiver52M/device/pciesdr/PCIESDRDevice.h</span><br><span>new file mode 100644</span><br><span>index 0000000..a811078</span><br><span>--- /dev/null</span><br><span>+++ b/Transceiver52M/device/pciesdr/PCIESDRDevice.h</span><br><span>@@ -0,0 +1,199 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+* Copyright 2018 sysmocom - s.f.m.c. GmbH</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* SPDX-License-Identifier: AGPL-3.0+</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* This software is distributed under multiple licenses; see the COPYING file in</span><br><span style="color: hsl(120, 100%, 40%);">+* the main directory for licensing information for this specific distribution.</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* This use of this software may be subject to additional restrictions.</span><br><span style="color: hsl(120, 100%, 40%);">+* See the LEGAL file in the main directory for details.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+    but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.</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%);">+#ifndef _PCIESDR_DEVICE_H_</span><br><span style="color: hsl(120, 100%, 40%);">+#define _PCIESDR_DEVICE_H_</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef HAVE_CONFIG_H</span><br><span style="color: hsl(120, 100%, 40%);">+#include "config.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "radioDevice.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "smpl_buf.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/time.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <math.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <limits.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string></span><br><span style="color: hsl(120, 100%, 40%);">+#include <iostream></span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#include "libsdr.h"</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%);">+#define PCIESDR_TX_AMPL  0.707</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/** A class to handle a PCIESDR supported device */</span><br><span style="color: hsl(120, 100%, 40%);">+class PCIESDRDevice:public RadioDevice {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+private:</span><br><span style="color: hsl(120, 100%, 40%);">+   MultiSDRState* device;</span><br><span style="color: hsl(120, 100%, 40%);">+        SDRStartParams StartParams;</span><br><span style="color: hsl(120, 100%, 40%);">+   typedef struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              float re;</span><br><span style="color: hsl(120, 100%, 40%);">+             float im;</span><br><span style="color: hsl(120, 100%, 40%);">+     } sample_t;</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int dma_buffer_count;</span><br><span style="color: hsl(120, 100%, 40%);">+        unsigned int dma_buffer_len;</span><br><span style="color: hsl(120, 100%, 40%);">+</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 style="color: hsl(120, 100%, 40%);">+   double actualSampleRate;        ///< the actual sampling rate</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    bool started;                   ///< flag indicates device has started</span><br><span style="color: hsl(120, 100%, 40%);">+     bool skipRx;                    ///< set if device is transmit-only.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     TIMESTAMP ts_initial, ts_offset;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    std::vector<double> tx_gains, rx_gains;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       bool flush_recv();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  int64_t tx_underflow;</span><br><span style="color: hsl(120, 100%, 40%);">+ int64_t rx_overflow;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /** sets the transmit chan gain, returns the gain setting **/</span><br><span style="color: hsl(120, 100%, 40%);">+ double setTxGain(double dB, size_t chan = 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /** get transmit gain */</span><br><span style="color: hsl(120, 100%, 40%);">+      double getTxGain(size_t chan = 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /** return maximum Tx Gain **/</span><br><span style="color: hsl(120, 100%, 40%);">+        double maxTxGain(void);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+public:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /** Object constructor */</span><br><span style="color: hsl(120, 100%, 40%);">+     PCIESDRDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chan_num, double lo_offset,</span><br><span style="color: hsl(120, 100%, 40%);">+           const std::vector<std::string>& tx_paths,</span><br><span style="color: hsl(120, 100%, 40%);">+           const std::vector<std::string>& rx_paths);</span><br><span style="color: hsl(120, 100%, 40%);">+  ~PCIESDRDevice();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /** Instantiate the PCIESDR */</span><br><span style="color: hsl(120, 100%, 40%);">+        int open(const std::string &args, int ref, bool swap_channels);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /** Start the PCIESDR */</span><br><span style="color: hsl(120, 100%, 40%);">+      bool start();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /** Stop the PCIESDR */</span><br><span style="color: hsl(120, 100%, 40%);">+       bool stop();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        enum TxWindowType getWindowType() {</span><br><span style="color: hsl(120, 100%, 40%);">+           return TX_WINDOW_LMS1;</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%);">+   Read samples from the PCIESDR.</span><br><span style="color: hsl(120, 100%, 40%);">+        @param buf preallocated buf to contain read result</span><br><span style="color: hsl(120, 100%, 40%);">+    @param len number of samples desired</span><br><span style="color: hsl(120, 100%, 40%);">+  @param overrun Set if read buffer has been overrun, e.g. data not being read fast enough</span><br><span style="color: hsl(120, 100%, 40%);">+      @param timestamp The timestamp of the first samples to be read</span><br><span style="color: hsl(120, 100%, 40%);">+        @param underrun Set if PCIESDR does not have data to transmit, e.g. data not being sent fast enough</span><br><span style="color: hsl(120, 100%, 40%);">+   @return The number of samples actually read</span><br><span style="color: hsl(120, 100%, 40%);">+   */</span><br><span style="color: hsl(120, 100%, 40%);">+    int readSamples(std::vector <short *> &buf, int len, bool *overrun,</span><br><span style="color: hsl(120, 100%, 40%);">+                 TIMESTAMP timestamp = 0xffffffff, bool *underrun = NULL);</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%);">+   Write samples to the PCIESDR.</span><br><span style="color: hsl(120, 100%, 40%);">+ @param buf Contains the data to be written.</span><br><span style="color: hsl(120, 100%, 40%);">+   @param len number of samples to write.</span><br><span style="color: hsl(120, 100%, 40%);">+        @param underrun Set if PCIESDR does not have data to transmit, e.g. data not being sent fast enough</span><br><span style="color: hsl(120, 100%, 40%);">+   @param timestamp The timestamp of the first sample of the data buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+        @return The number of samples actually written</span><br><span style="color: hsl(120, 100%, 40%);">+        */</span><br><span style="color: hsl(120, 100%, 40%);">+    int writeSamples(std::vector <short *> &bufs, int len, bool *underrun,</span><br><span style="color: hsl(120, 100%, 40%);">+                       TIMESTAMP timestamp = 0xffffffff);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /** Update the alignment between the read and write timestamps */</span><br><span style="color: hsl(120, 100%, 40%);">+     bool updateAlignment(TIMESTAMP timestamp);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /** Set the transmitter frequency */</span><br><span style="color: hsl(120, 100%, 40%);">+  bool setTxFreq(double wFreq, size_t chan = 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /** Set the receiver frequency */</span><br><span style="color: hsl(120, 100%, 40%);">+     bool setRxFreq(double wFreq, size_t chan = 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /** Returns the starting write Timestamp*/</span><br><span style="color: hsl(120, 100%, 40%);">+    TIMESTAMP initialWriteTimestamp(void) {</span><br><span style="color: hsl(120, 100%, 40%);">+               return ts_initial;</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%);">+   /** Returns the starting read Timestamp*/</span><br><span style="color: hsl(120, 100%, 40%);">+     TIMESTAMP initialReadTimestamp(void) {</span><br><span style="color: hsl(120, 100%, 40%);">+                return ts_initial;</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%);">+   /** returns the full-scale transmit amplitude **/</span><br><span style="color: hsl(120, 100%, 40%);">+     double fullScaleInputValue() {</span><br><span style="color: hsl(120, 100%, 40%);">+                return (double) SHRT_MAX * PCIESDR_TX_AMPL;</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%);">+   /** returns the full-scale receive amplitude **/</span><br><span style="color: hsl(120, 100%, 40%);">+      double fullScaleOutputValue() {</span><br><span style="color: hsl(120, 100%, 40%);">+               return (double) SHRT_MAX;</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%);">+   /** sets the receive chan gain, returns the gain setting **/</span><br><span style="color: hsl(120, 100%, 40%);">+  double setRxGain(double dB, size_t chan = 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /** get the current receive gain */</span><br><span style="color: hsl(120, 100%, 40%);">+   double getRxGain(size_t chan = 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return rx_gains[chan];</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 maximum Rx Gain **/</span><br><span style="color: hsl(120, 100%, 40%);">+        double maxRxGain(void);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /** return minimum Rx Gain **/</span><br><span style="color: hsl(120, 100%, 40%);">+        double minRxGain(void);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     double setPowerAttenuation(int atten, size_t chan);</span><br><span style="color: hsl(120, 100%, 40%);">+   double getPowerAttenuation(size_t chan = 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        int getNominalTxPower(size_t chan = 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /** sets the RX path to use, returns true if successful and false otherwise */</span><br><span style="color: hsl(120, 100%, 40%);">+        bool setRxAntenna(const std::string & ant, size_t chan = 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /** return the used RX path */</span><br><span style="color: hsl(120, 100%, 40%);">+        std::string getRxAntenna(size_t chan = 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /** sets the RX path to use, returns true if successful and false otherwise */</span><br><span style="color: hsl(120, 100%, 40%);">+        bool setTxAntenna(const std::string & ant, size_t chan = 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /** return the used RX path */</span><br><span style="color: hsl(120, 100%, 40%);">+        std::string getTxAntenna(size_t chan = 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /** return whether user drives synchronization of Tx/Rx of USRP */</span><br><span style="color: hsl(120, 100%, 40%);">+    bool requiresRadioAlign();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /** return whether user drives synchronization of Tx/Rx of USRP */</span><br><span style="color: hsl(120, 100%, 40%);">+    virtual GSM::Time minLatency();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /** Return internal status values */</span><br><span style="color: hsl(120, 100%, 40%);">+  inline double getTxFreq(size_t chan = 0) {</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%);">+     inline double getRxFreq(size_t chan = 0) {</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%);">+     inline double getSampleRate() {</span><br><span style="color: hsl(120, 100%, 40%);">+               return actualSampleRate;</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%);">+#endif // _PCIESDR_DEVICE_H_</span><br><span>diff --git a/configure.ac b/configure.ac</span><br><span>index 07d4bf4..f792bc5 100644</span><br><span>--- a/configure.ac</span><br><span>+++ b/configure.ac</span><br><span>@@ -140,6 +140,11 @@</span><br><span>         [enable LimeSuite based transceiver])</span><br><span> ])</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+AC_ARG_WITH(pciesdr, [</span><br><span style="color: hsl(120, 100%, 40%);">+    AS_HELP_STRING([--with-pciesdr],</span><br><span style="color: hsl(120, 100%, 40%);">+        [enable PCIeSDR (Amarisoft) based transceiver])</span><br><span style="color: hsl(120, 100%, 40%);">+])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> AC_ARG_WITH(singledb, [</span><br><span>     AS_HELP_STRING([--with-singledb],</span><br><span>         [enable single daughterboard use on USRP1])</span><br><span>@@ -179,6 +184,10 @@</span><br><span>     PKG_CHECK_MODULES(LMS, LimeSuite)</span><br><span> ])</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+AS_IF([test "x$with_pciesdr" = "xyes"], [</span><br><span style="color: hsl(120, 100%, 40%);">+    PKG_CHECK_MODULES(PCIESDR, libsdr)</span><br><span style="color: hsl(120, 100%, 40%);">+])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> AS_IF([test "x$with_uhd" != "xno"],[</span><br><span>     PKG_CHECK_MODULES(UHD, uhd >= 003.011,</span><br><span>         [AC_DEFINE(USE_UHD_3_11, 1, UHD version 3.11.0 or higher)],</span><br><span>@@ -241,6 +250,7 @@</span><br><span> AM_CONDITIONAL(DEVICE_UHD, [test "x$with_uhd" != "xno"])</span><br><span> AM_CONDITIONAL(DEVICE_USRP1, [test "x$with_usrp1" = "xyes"])</span><br><span> AM_CONDITIONAL(DEVICE_LMS, [test "x$with_lms" = "xyes"])</span><br><span style="color: hsl(120, 100%, 40%);">+AM_CONDITIONAL(DEVICE_PCIESDR, [test "x$with_pciesdr" = "xyes"])</span><br><span> AM_CONDITIONAL(ARCH_ARM, [test "x$with_neon" = "xyes" || test "x$with_neon_vfpv4" = "xyes"])</span><br><span> AM_CONDITIONAL(ARCH_ARM_A15, [test "x$with_neon_vfpv4" = "xyes"])</span><br><span> </span><br><span>@@ -325,6 +335,7 @@</span><br><span>     Transceiver52M/device/uhd/Makefile \</span><br><span>     Transceiver52M/device/usrp1/Makefile \</span><br><span>     Transceiver52M/device/lms/Makefile \</span><br><span style="color: hsl(120, 100%, 40%);">+    Transceiver52M/device/pciesdr/Makefile \</span><br><span>     tests/Makefile \</span><br><span>     tests/CommonLibs/Makefile \</span><br><span>     tests/Transceiver52M/Makefile \</span><br><span>diff --git a/doc/examples/osmo-trx-pciesdr/osmo-trx-pciesdr.cfg b/doc/examples/osmo-trx-pciesdr/osmo-trx-pciesdr.cfg</span><br><span>new file mode 100644</span><br><span>index 0000000..b74d50c</span><br><span>--- /dev/null</span><br><span>+++ b/doc/examples/osmo-trx-pciesdr/osmo-trx-pciesdr.cfg</span><br><span>@@ -0,0 +1,21 @@</span><br><span style="color: hsl(120, 100%, 40%);">+log stderr</span><br><span style="color: hsl(120, 100%, 40%);">+ logging filter all 1</span><br><span style="color: hsl(120, 100%, 40%);">+ logging color 1</span><br><span style="color: hsl(120, 100%, 40%);">+ logging print category 1</span><br><span style="color: hsl(120, 100%, 40%);">+ logging timestamp 1</span><br><span style="color: hsl(120, 100%, 40%);">+ logging print file basename</span><br><span style="color: hsl(120, 100%, 40%);">+ logging level set-all info</span><br><span style="color: hsl(120, 100%, 40%);">+!</span><br><span style="color: hsl(120, 100%, 40%);">+line vty</span><br><span style="color: hsl(120, 100%, 40%);">+ no login</span><br><span style="color: hsl(120, 100%, 40%);">+!</span><br><span style="color: hsl(120, 100%, 40%);">+trx</span><br><span style="color: hsl(120, 100%, 40%);">+ bind-ip 127.0.0.1</span><br><span style="color: hsl(120, 100%, 40%);">+ remote-ip 127.0.0.1</span><br><span style="color: hsl(120, 100%, 40%);">+ base-port 5700</span><br><span style="color: hsl(120, 100%, 40%);">+ egprs disable</span><br><span style="color: hsl(120, 100%, 40%);">+ dev-args dev0=/dev/sdr0</span><br><span style="color: hsl(120, 100%, 40%);">+ tx-sps 4</span><br><span style="color: hsl(120, 100%, 40%);">+ rx-sps 4</span><br><span style="color: hsl(120, 100%, 40%);">+ rt-prio 18</span><br><span style="color: hsl(120, 100%, 40%);">+ chan 0</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-trx/+/19548">change 19548</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/c/osmo-trx/+/19548"/><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-Change-Id: I5b49b61d1c8f357e33acc066f44d6c7acfc3ba79 </div>
<div style="display:none"> Gerrit-Change-Number: 19548 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Xavier Zu <xaver1zu@gmail.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>