Pau Espin Pedrol has submitted this change and it was merged. ( 
https://gerrit.osmocom.org/13809 )

Change subject: cosmetic: uhd: Move smpl_buf out of UHDDevice, move UHDDevice 
class definition to .h
......................................................................

cosmetic: uhd: Move smpl_buf out of UHDDevice, move UHDDevice class definition 
to .h

* move class definition to .h file, like we do for other devices.
* move smpl_buf class to a different file inside uhd/.
* Preparation work to have smpl_buf being used in a generic way for
devices other than UHD (LMS).

Change-Id: Ib4594320da9bb7f6e9f52e7d70d11ecd11106aae
---
M Transceiver52M/device/uhd/Makefile.am
M Transceiver52M/device/uhd/UHDDevice.cpp
A Transceiver52M/device/uhd/UHDDevice.h
A Transceiver52M/device/uhd/smpl_buf.cpp
A Transceiver52M/device/uhd/smpl_buf.h
5 files changed, 455 insertions(+), 362 deletions(-)

Approvals:
  Jenkins Builder: Verified
  Harald Welte: Looks good to me, approved



diff --git a/Transceiver52M/device/uhd/Makefile.am 
b/Transceiver52M/device/uhd/Makefile.am
index bb34d2f..4fcc0d7 100644
--- a/Transceiver52M/device/uhd/Makefile.am
+++ b/Transceiver52M/device/uhd/Makefile.am
@@ -3,6 +3,8 @@
 AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) -I${srcdir}/..
 AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) 
$(LIBOSMOVTY_CFLAGS) $(UHD_CFLAGS)

+noinst_HEADERS = UHDDevice.h smpl_buf.h
+
 noinst_LTLIBRARIES = libdevice.la
 
-libdevice_la_SOURCES = UHDDevice.cpp
+libdevice_la_SOURCES = UHDDevice.cpp smpl_buf.cpp
diff --git a/Transceiver52M/device/uhd/UHDDevice.cpp 
b/Transceiver52M/device/uhd/UHDDevice.cpp
index 46284e5..67b7416 100644
--- a/Transceiver52M/device/uhd/UHDDevice.cpp
+++ b/Transceiver52M/device/uhd/UHDDevice.cpp
@@ -23,11 +23,9 @@

 #include <map>
 #include "radioDevice.h"
+#include "UHDDevice.h"
 #include "Threads.h"
 #include "Logger.h"
-#include <uhd/version.hpp>
-#include <uhd/property_tree.hpp>
-#include <uhd/usrp/multi_usrp.hpp>

 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -58,20 +56,6 @@
  */
 #define UMTRX_VGA1_DEF   -18
 
-enum uhd_dev_type {
-       USRP1,
-       USRP2,
-       B100,
-       B200,
-       B210,
-       B2XX_MCBTS,
-       E1XX,
-       E3XX,
-       X3XX,
-       UMTRX,
-       LIMESDR,
-};
-
 /*
  * USRP version dependent device timings
  */
@@ -136,190 +120,6 @@
        { std::make_tuple(B2XX_MCBTS, 4, 4), { 1, 51.2e6, MCBTS_SPACING*4, 
B2XX_TIMING_MCBTS, "B200/B210 4 SPS Multi-ARFCN" } },
 };

-/*
-    Sample Buffer - Allows reading and writing of timed samples using osmo-trx
-                    or UHD style timestamps. Time conversions are handled
-                    internally or accessable through the static convert calls.
-*/
-class smpl_buf {
-public:
-       /** Sample buffer constructor
-           @param len number of 32-bit samples the buffer should hold
-           @param rate sample clockrate
-           @param timestamp
-       */
-       smpl_buf(size_t len, double rate);
-       ~smpl_buf();
-
-       /** Query number of samples available for reading
-           @param timestamp time of first sample
-           @return number of available samples or error
-       */
-       ssize_t avail_smpls(TIMESTAMP timestamp) const;
-       ssize_t avail_smpls(uhd::time_spec_t timestamp) const;
-
-       /** Read and write
-           @param buf pointer to buffer
-           @param len number of samples desired to read or write
-           @param timestamp time of first stample
-           @return number of actual samples read or written or error
-       */
-       ssize_t read(void *buf, size_t len, TIMESTAMP timestamp);
-       ssize_t read(void *buf, size_t len, uhd::time_spec_t timestamp);
-       ssize_t write(void *buf, size_t len, TIMESTAMP timestamp);
-       ssize_t write(void *buf, size_t len, uhd::time_spec_t timestamp);
-
-       /** Buffer status string
-           @return a formatted string describing internal buffer state
-       */
-       std::string str_status(size_t ts) const;
-
-       /** Formatted error string
-           @param code an error code
-           @return a formatted error string
-       */
-       static std::string str_code(ssize_t code);
-
-       enum err_code {
-               ERROR_TIMESTAMP = -1,
-               ERROR_READ = -2,
-               ERROR_WRITE = -3,
-               ERROR_OVERFLOW = -4
-       };
-
-private:
-       uint32_t *data;
-       size_t buf_len;
-
-       double clk_rt;
-
-       TIMESTAMP time_start;
-       TIMESTAMP time_end;
-
-       size_t data_start;
-       size_t data_end;
-};
-
-/*
-    uhd_device - UHD implementation of the Device interface. Timestamped 
samples
-                are sent to and received from the device. An intermediate 
buffer
-                on the receive side collects and aligns packets of samples.
-                Events and errors such as underruns are reported asynchronously
-                by the device and received in a separate thread.
-*/
-class uhd_device : public RadioDevice {
-public:
-       uhd_device(size_t tx_sps, size_t rx_sps, InterfaceType type,
-                  size_t chans, double offset,
-                  const std::vector<std::string>& tx_paths,
-                  const std::vector<std::string>& rx_paths);
-       ~uhd_device();
-
-       int open(const std::string &args, int ref, bool swap_channels);
-       bool start();
-       bool stop();
-       bool restart();
-       void setPriority(float prio);
-       enum TxWindowType getWindowType() { return tx_window; }
-
-       int readSamples(std::vector<short *> &bufs, int len, bool *overrun,
-                       TIMESTAMP timestamp, bool *underrun, unsigned *RSSI);
-
-       int writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
-                        TIMESTAMP timestamp, bool isControl);
-
-       bool updateAlignment(TIMESTAMP timestamp);
-
-       bool setTxFreq(double wFreq, size_t chan);
-       bool setRxFreq(double wFreq, size_t chan);
-
-       TIMESTAMP initialWriteTimestamp();
-       TIMESTAMP initialReadTimestamp();
-
-       double fullScaleInputValue();
-       double fullScaleOutputValue();
-
-       double setRxGain(double db, size_t chan);
-       double getRxGain(size_t chan);
-       double maxRxGain(void) { return rx_gain_max; }
-       double minRxGain(void) { return rx_gain_min; }
-
-       double setTxGain(double db, size_t chan);
-       double maxTxGain(void) { return tx_gain_max; }
-       double minTxGain(void) { return tx_gain_min; }
-
-       double getTxFreq(size_t chan);
-       double getRxFreq(size_t chan);
-       double getRxFreq();
-
-       bool setRxAntenna(const std::string &ant, size_t chan);
-       std::string getRxAntenna(size_t chan);
-       bool setTxAntenna(const std::string &ant, size_t chan);
-       std::string getTxAntenna(size_t chan);
-
-       bool requiresRadioAlign();
-
-       GSM::Time minLatency();
-
-       inline double getSampleRate() { return tx_rate; }
-       inline double numberRead() { return rx_pkt_cnt; }
-       inline double numberWritten() { return 0; }
-
-       /** Receive and process asynchronous message
-           @return true if message received or false on timeout or error
-       */
-       bool recv_async_msg();
-
-       enum err_code {
-               ERROR_TIMING = -1,
-               ERROR_TIMEOUT = -2,
-               ERROR_UNRECOVERABLE = -3,
-               ERROR_UNHANDLED = -4,
-       };
-
-private:
-       uhd::usrp::multi_usrp::sptr usrp_dev;
-       uhd::tx_streamer::sptr tx_stream;
-       uhd::rx_streamer::sptr rx_stream;
-       enum TxWindowType tx_window;
-       enum uhd_dev_type dev_type;
-
-       double tx_rate, rx_rate;
-
-       double tx_gain_min, tx_gain_max;
-       double rx_gain_min, rx_gain_max;
-
-       std::vector<double> tx_gains, rx_gains;
-       std::vector<double> tx_freqs, rx_freqs;
-       size_t tx_spp, rx_spp;
-
-       bool started;
-       bool aligned;
-
-       size_t rx_pkt_cnt;
-       size_t drop_cnt;
-       uhd::time_spec_t prev_ts;
-
-       TIMESTAMP ts_initial, ts_offset;
-       std::vector<smpl_buf *> rx_buffers;
-
-       void init_gains();
-       void set_channels(bool swap);
-       void set_rates();
-       bool parse_dev_type();
-       bool flush_recv(size_t num_pkts);
-       int check_rx_md_err(uhd::rx_metadata_t &md, ssize_t num_smpls);
-
-       std::string str_code(uhd::rx_metadata_t metadata);
-       std::string str_code(uhd::async_metadata_t metadata);
-
-       uhd::tune_request_t select_freq(double wFreq, size_t chan, bool tx);
-       bool set_freq(double freq, size_t chan, bool tx);
-
-       Thread *async_event_thrd;
-       Mutex tune_lock;
-};
-
 void *async_event_loop(uhd_device *dev)
 {
        set_selfthread_name("UHDAsyncEvent");
@@ -1386,166 +1186,6 @@
        return ost.str();
 }

-smpl_buf::smpl_buf(size_t len, double rate)
-       : buf_len(len), clk_rt(rate),
-         time_start(0), time_end(0), data_start(0), data_end(0)
-{
-       data = new uint32_t[len];
-}
-
-smpl_buf::~smpl_buf()
-{
-       delete[] data;
-}
-
-ssize_t smpl_buf::avail_smpls(TIMESTAMP timestamp) const
-{
-       if (timestamp < time_start)
-               return ERROR_TIMESTAMP;
-       else if (timestamp >= time_end)
-               return 0;
-       else
-               return time_end - timestamp;
-}
-
-ssize_t smpl_buf::avail_smpls(uhd::time_spec_t timespec) const
-{
-       return avail_smpls(timespec.to_ticks(clk_rt));
-}
-
-ssize_t smpl_buf::read(void *buf, size_t len, TIMESTAMP timestamp)
-{
-       int type_sz = 2 * sizeof(short);
-
-       // Check for valid read
-       if (timestamp < time_start)
-               return ERROR_TIMESTAMP;
-       if (timestamp >= time_end)
-               return 0;
-       if (len >= buf_len)
-               return ERROR_READ;
-
-       // How many samples should be copied
-       size_t num_smpls = time_end - timestamp;
-       if (num_smpls > len)
-               num_smpls = len;
-
-       // Starting index
-       size_t read_start = (data_start + (timestamp - time_start)) % buf_len;
-
-       // Read it
-       if (read_start + num_smpls < buf_len) {
-               size_t numBytes = len * type_sz;
-               memcpy(buf, data + read_start, numBytes);
-       } else {
-               size_t first_cp = (buf_len - read_start) * type_sz;
-               size_t second_cp = len * type_sz - first_cp;
-
-               memcpy(buf, data + read_start, first_cp);
-               memcpy((char*) buf + first_cp, data, second_cp);
-       }
-
-       data_start = (read_start + len) % buf_len;
-       time_start = timestamp + len;
-
-       if (time_start > time_end)
-               return ERROR_READ;
-       else
-               return num_smpls;
-}
-
-ssize_t smpl_buf::read(void *buf, size_t len, uhd::time_spec_t ts)
-{
-       return read(buf, len, ts.to_ticks(clk_rt));
-}
-
-ssize_t smpl_buf::write(void *buf, size_t len, TIMESTAMP timestamp)
-{
-       int type_sz = 2 * sizeof(short);
-
-       // Check for valid write
-       if ((len == 0) || (len >= buf_len))
-               return ERROR_WRITE;
-       if ((timestamp + len) <= time_end)
-               return ERROR_TIMESTAMP;
-
-       if (timestamp < time_end) {
-               LOGC(DDEV, ERR) << "Overwriting old buffer data: 
timestamp="<<timestamp<<" time_end="<<time_end;
-               uhd::time_spec_t ts = uhd::time_spec_t::from_ticks(timestamp, 
clk_rt);
-               LOGC(DDEV, DEBUG) << "Requested timestamp = " << timestamp << " 
(real_sec=" << std::fixed << ts.get_real_secs() << " = " << ts.to_ticks(clk_rt) 
<< ") rate=" << clk_rt;
-               // Do not return error here, because it's a rounding error and 
is not fatal
-       }
-       if (timestamp > time_end && time_end != 0) {
-               LOGC(DDEV, ERR) << "Skipping buffer data: 
timestamp="<<timestamp<<" time_end="<<time_end;
-               uhd::time_spec_t ts = uhd::time_spec_t::from_ticks(timestamp, 
clk_rt);
-               LOGC(DDEV, DEBUG) << "Requested timestamp = " << timestamp << " 
(real_sec=" << std::fixed << ts.get_real_secs() << " = " << ts.to_ticks(clk_rt) 
<< ") rate=" << clk_rt;
-               // Do not return error here, because it's a rounding error and 
is not fatal
-       }
-
-       // Starting index
-       size_t write_start = (data_start + (timestamp - time_start)) % buf_len;
-
-       // Write it
-       if ((write_start + len) < buf_len) {
-               size_t numBytes = len * type_sz;
-               memcpy(data + write_start, buf, numBytes);
-       } else {
-               size_t first_cp = (buf_len - write_start) * type_sz;
-               size_t second_cp = len * type_sz - first_cp;
-
-               memcpy(data + write_start, buf, first_cp);
-               memcpy(data, (char*) buf + first_cp, second_cp);
-       }
-
-       data_end = (write_start + len) % buf_len;
-       time_end = timestamp + len;
-
-       if (!data_start)
-               data_start = write_start;
-
-       if (((write_start + len) > buf_len) && (data_end > data_start))
-               return ERROR_OVERFLOW;
-       else if (time_end <= time_start)
-               return ERROR_WRITE;
-       else
-               return len;
-}
-
-ssize_t smpl_buf::write(void *buf, size_t len, uhd::time_spec_t ts)
-{
-       return write(buf, len, ts.to_ticks(clk_rt));
-}
-
-std::string smpl_buf::str_status(size_t ts) const
-{
-       std::ostringstream ost("Sample buffer: ");
-
-       ost << "timestamp = " << ts;
-       ost << ", length = " << buf_len;
-       ost << ", time_start = " << time_start;
-       ost << ", time_end = " << time_end;
-       ost << ", data_start = " << data_start;
-       ost << ", data_end = " << data_end;
-
-       return ost.str();
-}
-
-std::string smpl_buf::str_code(ssize_t code)
-{
-       switch (code) {
-       case ERROR_TIMESTAMP:
-               return "Sample buffer: Requested timestamp is not valid";
-       case ERROR_READ:
-               return "Sample buffer: Read error";
-       case ERROR_WRITE:
-               return "Sample buffer: Write error";
-       case ERROR_OVERFLOW:
-               return "Sample buffer: Overrun";
-       default:
-               return "Sample buffer: Unknown error";
-       }
-}
-
 RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps,
                               InterfaceType iface, size_t chans, double 
lo_offset,
                               const std::vector<std::string>& tx_paths,
diff --git a/Transceiver52M/device/uhd/UHDDevice.h 
b/Transceiver52M/device/uhd/UHDDevice.h
new file mode 100644
index 0000000..f5d0b33
--- /dev/null
+++ b/Transceiver52M/device/uhd/UHDDevice.h
@@ -0,0 +1,171 @@
+/*
+ * Device support for Ettus Research UHD driver
+ *
+ * Copyright 2010,2011 Free Software Foundation, Inc.
+ * Copyright (C) 2015 Ettus Research LLC
+ * Copyright 2019 sysmocom - s.f.m.c. GmbH <[email protected]>
+ *
+ * Author: Tom Tsou <[email protected]>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * See the COPYING file in the main directory for details.
+ */
+
+#pragma once
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "radioDevice.h"
+#include "smpl_buf.h"
+
+#include <uhd/version.hpp>
+#include <uhd/property_tree.hpp>
+#include <uhd/usrp/multi_usrp.hpp>
+
+
+enum uhd_dev_type {
+       USRP1,
+       USRP2,
+       B100,
+       B200,
+       B210,
+       B2XX_MCBTS,
+       E1XX,
+       E3XX,
+       X3XX,
+       UMTRX,
+       LIMESDR,
+};
+
+/*
+    uhd_device - UHD implementation of the Device interface. Timestamped 
samples
+                are sent to and received from the device. An intermediate 
buffer
+                on the receive side collects and aligns packets of samples.
+                Events and errors such as underruns are reported asynchronously
+                by the device and received in a separate thread.
+*/
+class uhd_device : public RadioDevice {
+public:
+       uhd_device(size_t tx_sps, size_t rx_sps, InterfaceType type,
+                  size_t chans, double offset,
+                  const std::vector<std::string>& tx_paths,
+                  const std::vector<std::string>& rx_paths);
+       ~uhd_device();
+
+       int open(const std::string &args, int ref, bool swap_channels);
+       bool start();
+       bool stop();
+       bool restart();
+       void setPriority(float prio);
+       enum TxWindowType getWindowType() { return tx_window; }
+
+       int readSamples(std::vector<short *> &bufs, int len, bool *overrun,
+                       TIMESTAMP timestamp, bool *underrun, unsigned *RSSI);
+
+       int writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
+                        TIMESTAMP timestamp, bool isControl);
+
+       bool updateAlignment(TIMESTAMP timestamp);
+
+       bool setTxFreq(double wFreq, size_t chan);
+       bool setRxFreq(double wFreq, size_t chan);
+
+       TIMESTAMP initialWriteTimestamp();
+       TIMESTAMP initialReadTimestamp();
+
+       double fullScaleInputValue();
+       double fullScaleOutputValue();
+
+       double setRxGain(double db, size_t chan);
+       double getRxGain(size_t chan);
+       double maxRxGain(void) { return rx_gain_max; }
+       double minRxGain(void) { return rx_gain_min; }
+
+       double setTxGain(double db, size_t chan);
+       double maxTxGain(void) { return tx_gain_max; }
+       double minTxGain(void) { return tx_gain_min; }
+
+       double getTxFreq(size_t chan);
+       double getRxFreq(size_t chan);
+       double getRxFreq();
+
+       bool setRxAntenna(const std::string &ant, size_t chan);
+       std::string getRxAntenna(size_t chan);
+       bool setTxAntenna(const std::string &ant, size_t chan);
+       std::string getTxAntenna(size_t chan);
+
+       bool requiresRadioAlign();
+
+       GSM::Time minLatency();
+
+       inline double getSampleRate() { return tx_rate; }
+       inline double numberRead() { return rx_pkt_cnt; }
+       inline double numberWritten() { return 0; }
+
+       /** Receive and process asynchronous message
+           @return true if message received or false on timeout or error
+       */
+       bool recv_async_msg();
+
+       enum err_code {
+               ERROR_TIMING = -1,
+               ERROR_TIMEOUT = -2,
+               ERROR_UNRECOVERABLE = -3,
+               ERROR_UNHANDLED = -4,
+       };
+
+private:
+       uhd::usrp::multi_usrp::sptr usrp_dev;
+       uhd::tx_streamer::sptr tx_stream;
+       uhd::rx_streamer::sptr rx_stream;
+       enum TxWindowType tx_window;
+       enum uhd_dev_type dev_type;
+
+       double tx_rate, rx_rate;
+
+       double tx_gain_min, tx_gain_max;
+       double rx_gain_min, rx_gain_max;
+
+       std::vector<double> tx_gains, rx_gains;
+       std::vector<double> tx_freqs, rx_freqs;
+       size_t tx_spp, rx_spp;
+
+       bool started;
+       bool aligned;
+
+       size_t rx_pkt_cnt;
+       size_t drop_cnt;
+       uhd::time_spec_t prev_ts;
+
+       TIMESTAMP ts_initial, ts_offset;
+       std::vector<smpl_buf *> rx_buffers;
+
+       void init_gains();
+       void set_channels(bool swap);
+       void set_rates();
+       bool parse_dev_type();
+       bool flush_recv(size_t num_pkts);
+       int check_rx_md_err(uhd::rx_metadata_t &md, ssize_t num_smpls);
+
+       std::string str_code(uhd::rx_metadata_t metadata);
+       std::string str_code(uhd::async_metadata_t metadata);
+
+       uhd::tune_request_t select_freq(double wFreq, size_t chan, bool tx);
+       bool set_freq(double freq, size_t chan, bool tx);
+
+       Thread *async_event_thrd;
+       Mutex tune_lock;
+};
diff --git a/Transceiver52M/device/uhd/smpl_buf.cpp 
b/Transceiver52M/device/uhd/smpl_buf.cpp
new file mode 100644
index 0000000..d8bdbc4
--- /dev/null
+++ b/Transceiver52M/device/uhd/smpl_buf.cpp
@@ -0,0 +1,186 @@
+/*
+ * Sample Buffer - Allows reading and writing of timed samples
+ *
+ * Copyright 2010,2011 Free Software Foundation, Inc.
+ * Copyright (C) 2015 Ettus Research LLC
+ * Copyright 2019 sysmocom - s.f.m.c. GmbH <[email protected]>
+ *
+ * Author: Tom Tsou <[email protected]>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * See the COPYING file in the main directory for details.
+ */
+
+#include "smpl_buf.h"
+#include <inttypes.h>
+
+smpl_buf::smpl_buf(size_t len, double rate)
+       : buf_len(len), clk_rt(rate),
+         time_start(0), time_end(0), data_start(0), data_end(0)
+{
+       data = new uint32_t[len];
+}
+
+smpl_buf::~smpl_buf()
+{
+       delete[] data;
+}
+
+ssize_t smpl_buf::avail_smpls(TIMESTAMP timestamp) const
+{
+       if (timestamp < time_start)
+               return ERROR_TIMESTAMP;
+       else if (timestamp >= time_end)
+               return 0;
+       else
+               return time_end - timestamp;
+}
+
+ssize_t smpl_buf::avail_smpls(uhd::time_spec_t timespec) const
+{
+       return avail_smpls(timespec.to_ticks(clk_rt));
+}
+
+ssize_t smpl_buf::read(void *buf, size_t len, TIMESTAMP timestamp)
+{
+       int type_sz = 2 * sizeof(short);
+
+       // Check for valid read
+       if (timestamp < time_start)
+               return ERROR_TIMESTAMP;
+       if (timestamp >= time_end)
+               return 0;
+       if (len >= buf_len)
+               return ERROR_READ;
+
+       // How many samples should be copied
+       size_t num_smpls = time_end - timestamp;
+       if (num_smpls > len)
+               num_smpls = len;
+
+       // Starting index
+       size_t read_start = (data_start + (timestamp - time_start)) % buf_len;
+
+       // Read it
+       if (read_start + num_smpls < buf_len) {
+               size_t numBytes = len * type_sz;
+               memcpy(buf, data + read_start, numBytes);
+       } else {
+               size_t first_cp = (buf_len - read_start) * type_sz;
+               size_t second_cp = len * type_sz - first_cp;
+
+               memcpy(buf, data + read_start, first_cp);
+               memcpy((char*) buf + first_cp, data, second_cp);
+       }
+
+       data_start = (read_start + len) % buf_len;
+       time_start = timestamp + len;
+
+       if (time_start > time_end)
+               return ERROR_READ;
+       else
+               return num_smpls;
+}
+
+ssize_t smpl_buf::read(void *buf, size_t len, uhd::time_spec_t ts)
+{
+       return read(buf, len, ts.to_ticks(clk_rt));
+}
+
+ssize_t smpl_buf::write(void *buf, size_t len, TIMESTAMP timestamp)
+{
+       int type_sz = 2 * sizeof(short);
+
+       // Check for valid write
+       if ((len == 0) || (len >= buf_len))
+               return ERROR_WRITE;
+       if ((timestamp + len) <= time_end)
+               return ERROR_TIMESTAMP;
+
+       if (timestamp < time_end) {
+               LOGC(DDEV, ERR) << "Overwriting old buffer data: 
timestamp="<<timestamp<<" time_end="<<time_end;
+               uhd::time_spec_t ts = uhd::time_spec_t::from_ticks(timestamp, 
clk_rt);
+               LOGC(DDEV, DEBUG) << "Requested timestamp = " << timestamp << " 
(real_sec=" << std::fixed << ts.get_real_secs() << " = " << ts.to_ticks(clk_rt) 
<< ") rate=" << clk_rt;
+               // Do not return error here, because it's a rounding error and 
is not fatal
+       }
+       if (timestamp > time_end && time_end != 0) {
+               LOGC(DDEV, ERR) << "Skipping buffer data: 
timestamp="<<timestamp<<" time_end="<<time_end;
+               uhd::time_spec_t ts = uhd::time_spec_t::from_ticks(timestamp, 
clk_rt);
+               LOGC(DDEV, DEBUG) << "Requested timestamp = " << timestamp << " 
(real_sec=" << std::fixed << ts.get_real_secs() << " = " << ts.to_ticks(clk_rt) 
<< ") rate=" << clk_rt;
+               // Do not return error here, because it's a rounding error and 
is not fatal
+       }
+
+       // Starting index
+       size_t write_start = (data_start + (timestamp - time_start)) % buf_len;
+
+       // Write it
+       if ((write_start + len) < buf_len) {
+               size_t numBytes = len * type_sz;
+               memcpy(data + write_start, buf, numBytes);
+       } else {
+               size_t first_cp = (buf_len - write_start) * type_sz;
+               size_t second_cp = len * type_sz - first_cp;
+
+               memcpy(data + write_start, buf, first_cp);
+               memcpy(data, (char*) buf + first_cp, second_cp);
+       }
+
+       data_end = (write_start + len) % buf_len;
+       time_end = timestamp + len;
+
+       if (!data_start)
+               data_start = write_start;
+
+       if (((write_start + len) > buf_len) && (data_end > data_start))
+               return ERROR_OVERFLOW;
+       else if (time_end <= time_start)
+               return ERROR_WRITE;
+       else
+               return len;
+}
+
+ssize_t smpl_buf::write(void *buf, size_t len, uhd::time_spec_t ts)
+{
+       return write(buf, len, ts.to_ticks(clk_rt));
+}
+
+std::string smpl_buf::str_status(size_t ts) const
+{
+       std::ostringstream ost("Sample buffer: ");
+
+       ost << "timestamp = " << ts;
+       ost << ", length = " << buf_len;
+       ost << ", time_start = " << time_start;
+       ost << ", time_end = " << time_end;
+       ost << ", data_start = " << data_start;
+       ost << ", data_end = " << data_end;
+
+       return ost.str();
+}
+
+std::string smpl_buf::str_code(ssize_t code)
+{
+       switch (code) {
+       case ERROR_TIMESTAMP:
+               return "Sample buffer: Requested timestamp is not valid";
+       case ERROR_READ:
+               return "Sample buffer: Read error";
+       case ERROR_WRITE:
+               return "Sample buffer: Write error";
+       case ERROR_OVERFLOW:
+               return "Sample buffer: Overrun";
+       default:
+               return "Sample buffer: Unknown error";
+       }
+}
diff --git a/Transceiver52M/device/uhd/smpl_buf.h 
b/Transceiver52M/device/uhd/smpl_buf.h
new file mode 100644
index 0000000..6af97c2
--- /dev/null
+++ b/Transceiver52M/device/uhd/smpl_buf.h
@@ -0,0 +1,94 @@
+/*
+ * Sample Buffer - Allows reading and writing of timed samples
+ *
+ * Copyright 2010,2011 Free Software Foundation, Inc.
+ * Copyright (C) 2015 Ettus Research LLC
+ * Copyright 2019 sysmocom - s.f.m.c. GmbH <[email protected]>
+ *
+ * Author: Tom Tsou <[email protected]>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * See the COPYING file in the main directory for details.
+ */
+
+#pragma once
+
+#include <unistd.h>
+#include <uhd/types/time_spec.hpp>
+
+#include "radioDevice.h"
+
+/*
+    Sample Buffer - Allows reading and writing of timed samples using osmo-trx
+                    or UHD style timestamps. Time conversions are handled
+                    internally or accessable through the static convert calls.
+*/
+class smpl_buf {
+public:
+       /** Sample buffer constructor
+           @param len number of 32-bit samples the buffer should hold
+           @param rate sample clockrate
+           @param timestamp
+       */
+       smpl_buf(size_t len, double rate);
+       ~smpl_buf();
+
+       /** Query number of samples available for reading
+           @param timestamp time of first sample
+           @return number of available samples or error
+       */
+       ssize_t avail_smpls(TIMESTAMP timestamp) const;
+       ssize_t avail_smpls(uhd::time_spec_t timestamp) const;
+
+       /** Read and write
+           @param buf pointer to buffer
+           @param len number of samples desired to read or write
+           @param timestamp time of first stample
+           @return number of actual samples read or written or error
+       */
+       ssize_t read(void *buf, size_t len, TIMESTAMP timestamp);
+       ssize_t read(void *buf, size_t len, uhd::time_spec_t timestamp);
+       ssize_t write(void *buf, size_t len, TIMESTAMP timestamp);
+       ssize_t write(void *buf, size_t len, uhd::time_spec_t timestamp);
+
+       /** Buffer status string
+           @return a formatted string describing internal buffer state
+       */
+       std::string str_status(size_t ts) const;
+
+       /** Formatted error string
+           @param code an error code
+           @return a formatted error string
+       */
+       static std::string str_code(ssize_t code);
+
+       enum err_code {
+               ERROR_TIMESTAMP = -1,
+               ERROR_READ = -2,
+               ERROR_WRITE = -3,
+               ERROR_OVERFLOW = -4
+       };
+
+private:
+       uint32_t *data;
+       size_t buf_len;
+
+       double clk_rt;
+
+       TIMESTAMP time_start;
+       TIMESTAMP time_end;
+
+       size_t data_start;
+       size_t data_end;
+};

--
To view, visit https://gerrit.osmocom.org/13809
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-trx
Gerrit-Branch: master
Gerrit-MessageType: merged
Gerrit-Change-Id: Ib4594320da9bb7f6e9f52e7d70d11ecd11106aae
Gerrit-Change-Number: 13809
Gerrit-PatchSet: 2
Gerrit-Owner: Pau Espin Pedrol <[email protected]>
Gerrit-Reviewer: Harald Welte <[email protected]>
Gerrit-Reviewer: Jenkins Builder (1000002)
Gerrit-Reviewer: Pau Espin Pedrol <[email protected]>
Gerrit-Reviewer: tnt <[email protected]>
Gerrit-CC: Vadim Yanitskiy <[email protected]>

Reply via email to