Change in osmo-trx[master]: cosmetic: uhd: Move smpl_buf out of UHDDevice, move UHDDevice class d...

Pau Espin Pedrol gerrit-no-reply at lists.osmocom.org
Mon Apr 29 15:25:43 UTC 2019


Pau Espin Pedrol has uploaded this change for review. ( 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, 418 insertions(+), 362 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-trx refs/changes/09/13809/1

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..93a9660
--- /dev/null
+++ b/Transceiver52M/device/uhd/UHDDevice.h
@@ -0,0 +1,164 @@
+/*
+* Copyright 2019 sysmocom - s.f.m.c. GmbH
+*
+* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
+*
+* This use of this software may be subject to additional restrictions.
+* See the LEGAL file in the main directory for details.
+
+    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.
+
+*/
+
+#ifndef _UHD_DEVICE_H_
+#define _UHD_DEVICE_H_
+
+#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;
+};
+
+#endif // _UHD_DEVICE_H_
diff --git a/Transceiver52M/device/uhd/smpl_buf.cpp b/Transceiver52M/device/uhd/smpl_buf.cpp
new file mode 100644
index 0000000..f1a6a89
--- /dev/null
+++ b/Transceiver52M/device/uhd/smpl_buf.cpp
@@ -0,0 +1,162 @@
+#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..2c1e435
--- /dev/null
+++ b/Transceiver52M/device/uhd/smpl_buf.h
@@ -0,0 +1,88 @@
+/*
+* Copyright 2019 sysmocom - s.f.m.c. GmbH
+*
+* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
+*
+* This use of this software may be subject to additional restrictions.
+* See the LEGAL file in the main directory for details.
+
+    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.
+
+*/
+
+#ifndef _SAMPLE_BUF_H_
+#define _SAMPLE_BUF_H_
+
+#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;
+};
+
+
+#endif // _SAMPLE_BUF_H_

-- 
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: newchange
Gerrit-Change-Id: Ib4594320da9bb7f6e9f52e7d70d11ecd11106aae
Gerrit-Change-Number: 13809
Gerrit-PatchSet: 1
Gerrit-Owner: Pau Espin Pedrol <pespin at sysmocom.de>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20190429/22c46db7/attachment.html>


More information about the gerrit-log mailing list