<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, ×tamp_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, ×tamp_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>