mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-trx.git
				synced 2025-11-04 06:03:17 +00:00 
			
		
		
		
	Compare commits
	
		
			28 Commits
		
	
	
		
			0.4.0
			...
			laforge/li
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					35a067ea7c | ||
| 
						 | 
					9939ccd0de | ||
| 
						 | 
					9eda0229a3 | ||
| 
						 | 
					a1031f1c9b | ||
| 
						 | 
					66efb7c538 | ||
| 
						 | 
					4f3aedbfee | ||
| 
						 | 
					70621b7484 | ||
| 
						 | 
					1568f87014 | ||
| 
						 | 
					cace86ec0d | ||
| 
						 | 
					59437da099 | ||
| 
						 | 
					c9ea6e3e8c | ||
| 
						 | 
					4b00e736f0 | ||
| 
						 | 
					aeccb44c7a | ||
| 
						 | 
					09aa5a3e9f | ||
| 
						 | 
					1a090b698c | ||
| 
						 | 
					c01ddf5ff3 | ||
| 
						 | 
					380067eeea | ||
| 
						 | 
					6d000ba2f7 | ||
| 
						 | 
					2b764c33e5 | ||
| 
						 | 
					e0d2f507ea | ||
| 
						 | 
					7ca30375c9 | ||
| 
						 | 
					ce092147ac | ||
| 
						 | 
					6437192bf3 | ||
| 
						 | 
					cdbe1e7ce2 | ||
| 
						 | 
					4a5484c770 | ||
| 
						 | 
					01eea0aa42 | ||
| 
						 | 
					55df1e43e3 | ||
| 
						 | 
					e9424e241f | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -4,6 +4,7 @@
 | 
			
		||||
*.la
 | 
			
		||||
Transceiver52M/osmo-trx-uhd
 | 
			
		||||
Transceiver52M/osmo-trx-usrp1
 | 
			
		||||
Transceiver52M/osmo-trx-lms
 | 
			
		||||
 | 
			
		||||
# tests
 | 
			
		||||
tests/CommonLibs/BitVectorTest
 | 
			
		||||
 
 | 
			
		||||
@@ -53,6 +53,9 @@ extern "C" {
 | 
			
		||||
#define LOGC(category, level) \
 | 
			
		||||
	Log(category, LOGL_##level, __BASE_FILE__, __LINE__).get() <<  "[tid=" << pthread_self() << "] "
 | 
			
		||||
 | 
			
		||||
#define LOGLV(category, level) \
 | 
			
		||||
	Log(category, level, __BASE_FILE__, __LINE__).get() <<  "[tid=" << pthread_self() << "] "
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
	A C++ stream-based thread-safe logger.
 | 
			
		||||
	This object is NOT the global logger;
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,12 @@ static const struct log_info_cat default_categories[] = {
 | 
			
		||||
		.color = NULL,
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_NOTICE,
 | 
			
		||||
	},
 | 
			
		||||
	[DLMS] = {
 | 
			
		||||
		.name = "DLMS",
 | 
			
		||||
		.description = "LimeSuite category",
 | 
			
		||||
		.color = NULL,
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_NOTICE,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const struct log_info log_info = {
 | 
			
		||||
 
 | 
			
		||||
@@ -5,4 +5,5 @@ extern const struct log_info log_info;
 | 
			
		||||
/* Debug Areas of the code */
 | 
			
		||||
enum {
 | 
			
		||||
	DMAIN,
 | 
			
		||||
	DLMS,
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -503,7 +503,9 @@ static int trx_vty_go_parent(struct vty *vty)
 | 
			
		||||
		vty->index_sub = NULL;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		OSMO_ASSERT(0);
 | 
			
		||||
		vty->node = CONFIG_NODE;
 | 
			
		||||
		vty->index = NULL;
 | 
			
		||||
		vty->index_sub = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return vty->node;
 | 
			
		||||
 
 | 
			
		||||
@@ -99,3 +99,13 @@ osmo_trx_usrp1_LDADD = \
 | 
			
		||||
	$(USRP_LIBS)
 | 
			
		||||
osmo_trx_usrp1_CPPFLAGS  = $(AM_CPPFLAGS) $(USRP_CFLAGS)
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
if DEVICE_LMS
 | 
			
		||||
bin_PROGRAMS += osmo-trx-lms
 | 
			
		||||
osmo_trx_lms_SOURCES = osmo-trx.cpp
 | 
			
		||||
osmo_trx_lms_LDADD = \
 | 
			
		||||
	$(builddir)/device/lms/libdevice.la \
 | 
			
		||||
	$(COMMON_LDADD) \
 | 
			
		||||
	$(LMS_LIBS)
 | 
			
		||||
osmo_trx_lms_CPPFLAGS  = $(AM_CPPFLAGS) $(LMS_CFLAGS)
 | 
			
		||||
endif
 | 
			
		||||
 
 | 
			
		||||
@@ -11,3 +11,7 @@ endif
 | 
			
		||||
if DEVICE_UHD
 | 
			
		||||
SUBDIRS += uhd
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
if DEVICE_LMS
 | 
			
		||||
SUBDIRS += lms
 | 
			
		||||
endif
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										629
									
								
								Transceiver52M/device/lms/LMSDevice.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										629
									
								
								Transceiver52M/device/lms/LMSDevice.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,629 @@
 | 
			
		||||
/*
 | 
			
		||||
* Copyright 2018 sysmocom - s.f.m.c. GmbH
 | 
			
		||||
*
 | 
			
		||||
	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/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include "Logger.h"
 | 
			
		||||
#include "Threads.h"
 | 
			
		||||
#include "LMSDevice.h"
 | 
			
		||||
 | 
			
		||||
#include <lime/LimeSuite.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/utils.h>
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
constexpr double LMSDevice::masterClockRate;
 | 
			
		||||
 | 
			
		||||
#define MAX_ANTENNA_LIST_SIZE 10
 | 
			
		||||
#define LMS_SAMPLE_RATE GSMRATE*32
 | 
			
		||||
#define GSM_CARRIER_BW 270000.0 /* 270kHz */
 | 
			
		||||
#define LMS_MIN_BW_SUPPORTED 2.5e6 /* 2.5mHz, minimum supported by LMS */
 | 
			
		||||
#define LMS_CALIBRATE_BW_HZ OSMO_MAX(GSM_CARRIER_BW, LMS_MIN_BW_SUPPORTED)
 | 
			
		||||
 | 
			
		||||
LMSDevice::LMSDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chans, double lo_offset,
 | 
			
		||||
		     const std::vector<std::string>& tx_paths,
 | 
			
		||||
		     const std::vector<std::string>& rx_paths):
 | 
			
		||||
	RadioDevice(tx_sps, rx_sps, iface, chans, lo_offset, tx_paths, rx_paths),
 | 
			
		||||
	m_lms_dev(NULL)
 | 
			
		||||
{
 | 
			
		||||
	LOG(INFO) << "creating LMS device...";
 | 
			
		||||
 | 
			
		||||
	m_lms_stream_rx.resize(chans);
 | 
			
		||||
	m_lms_stream_tx.resize(chans);
 | 
			
		||||
 | 
			
		||||
	m_last_rx_underruns.resize(chans, 0);
 | 
			
		||||
	m_last_rx_overruns.resize(chans, 0);
 | 
			
		||||
	m_last_tx_underruns.resize(chans, 0);
 | 
			
		||||
	m_last_tx_overruns.resize(chans, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lms_log_callback(int lvl, const char *msg)
 | 
			
		||||
{
 | 
			
		||||
	/* map lime specific log levels */
 | 
			
		||||
	static const int lvl_map[5] = {
 | 
			
		||||
		[0] = LOGL_FATAL,
 | 
			
		||||
		[1] = LOGL_ERROR,
 | 
			
		||||
		[2] = LOGL_NOTICE,
 | 
			
		||||
		[3] = LOGL_INFO,
 | 
			
		||||
		[4] = LOGL_DEBUG,
 | 
			
		||||
	};
 | 
			
		||||
	/* protect against future higher log level values (lower importance) */
 | 
			
		||||
	if ((unsigned int) lvl >= ARRAY_SIZE(lvl_map))
 | 
			
		||||
		lvl = ARRAY_SIZE(lvl_map)-1;
 | 
			
		||||
 | 
			
		||||
	LOGLV(DLMS, lvl) << msg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void thread_enable_cancel(bool cancel)
 | 
			
		||||
{
 | 
			
		||||
	cancel ? pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) :
 | 
			
		||||
		 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void print_range(const char* name, lms_range_t *range)
 | 
			
		||||
{
 | 
			
		||||
	LOG(DEBUG) << name << ": Min=" << range->min << " Max=" << range->max
 | 
			
		||||
		   << " Step=" << range->step;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int LMSDevice::open(const std::string &args, int ref, bool swap_channels)
 | 
			
		||||
{
 | 
			
		||||
	//lms_info_str_t dev_str;
 | 
			
		||||
	lms_info_str_t* info_list;
 | 
			
		||||
	lms_range_t range_lpfbw_rx, range_lpfbw_tx, range_sr;
 | 
			
		||||
	float_type sr_host, sr_rf, lpfbw_rx, lpfbw_tx;
 | 
			
		||||
	uint16_t dac_val;
 | 
			
		||||
	unsigned int i, n;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	LOG(INFO) << "Opening LMS device..";
 | 
			
		||||
 | 
			
		||||
	LMS_RegisterLogHandler(&lms_log_callback);
 | 
			
		||||
 | 
			
		||||
	if ((n = LMS_GetDeviceList(NULL)) < 0)
 | 
			
		||||
		LOG(ERROR) << "LMS_GetDeviceList(NULL) failed";
 | 
			
		||||
	LOG(DEBUG) << "Devices found: " << n;
 | 
			
		||||
	if (n < 1)
 | 
			
		||||
	    return -1;
 | 
			
		||||
 | 
			
		||||
	info_list = new lms_info_str_t[n];
 | 
			
		||||
 | 
			
		||||
	if (LMS_GetDeviceList(info_list) < 0)
 | 
			
		||||
		LOG(ERROR) << "LMS_GetDeviceList(info_list) failed";
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < n; i++)
 | 
			
		||||
		LOG(DEBUG) << "Device [" << i << "]: " << info_list[i];
 | 
			
		||||
 | 
			
		||||
	rc = LMS_Open(&m_lms_dev, info_list[0], NULL);
 | 
			
		||||
	if (rc != 0) {
 | 
			
		||||
		LOG(ERROR) << "LMS_GetDeviceList() failed)";
 | 
			
		||||
		delete [] info_list;
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	delete [] info_list;
 | 
			
		||||
 | 
			
		||||
	LOG(INFO) << "Init LMS device";
 | 
			
		||||
	if (LMS_Init(m_lms_dev) != 0) {
 | 
			
		||||
		LOG(ERROR) << "LMS_Init() failed";
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (LMS_GetSampleRateRange(m_lms_dev, LMS_CH_RX, &range_sr))
 | 
			
		||||
		goto out_close;
 | 
			
		||||
	print_range("Sample Rate", &range_sr);
 | 
			
		||||
 | 
			
		||||
	LOG(DEBUG) << "Setting sample rate to " << GSMRATE*tx_sps << " " << tx_sps;
 | 
			
		||||
	if (LMS_SetSampleRate(m_lms_dev, GSMRATE*tx_sps, 32) < 0)
 | 
			
		||||
		goto out_close;
 | 
			
		||||
 | 
			
		||||
	if (LMS_GetSampleRate(m_lms_dev, LMS_CH_RX, 0, &sr_host, &sr_rf))
 | 
			
		||||
		goto out_close;
 | 
			
		||||
	LOG(DEBUG) << "Sample Rate: Host=" << sr_host << " RF=" << sr_rf;
 | 
			
		||||
 | 
			
		||||
	/* FIXME: make this device/model dependent, like UHDDevice:dev_param_map! */
 | 
			
		||||
	ts_offset = static_cast<TIMESTAMP>(8.9e-5 * GSMRATE * tx_sps); /* time * sample_rate */
 | 
			
		||||
 | 
			
		||||
	switch (ref) {
 | 
			
		||||
	case REF_INTERNAL:
 | 
			
		||||
		LOG(DEBUG) << "Setting Internal clock reference";
 | 
			
		||||
		/* Ugly API: Selecting clock source implicit by writing to VCTCXO DAC ?!? */
 | 
			
		||||
		if (LMS_VCTCXORead(m_lms_dev, &dac_val) < 0)
 | 
			
		||||
			goto out_close;
 | 
			
		||||
		LOG(DEBUG) << "Setting VCTCXO to " << dac_val;
 | 
			
		||||
		if (LMS_VCTCXOWrite(m_lms_dev, dac_val) < 0)
 | 
			
		||||
			goto out_close;
 | 
			
		||||
		break;
 | 
			
		||||
	case REF_EXTERNAL:
 | 
			
		||||
		LOG(DEBUG) << "Setting External clock reference to " << 10000000.0;
 | 
			
		||||
		/* Assume an external 10 MHz reference clock */
 | 
			
		||||
		if (LMS_SetClockFreq(m_lms_dev, LMS_CLOCK_EXTREF, 10000000.0) < 0)
 | 
			
		||||
			goto out_close;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOG(ALERT) << "Invalid reference type";
 | 
			
		||||
		goto out_close;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (LMS_GetLPFBWRange(m_lms_dev, LMS_CH_RX, &range_lpfbw_rx))
 | 
			
		||||
		goto out_close;
 | 
			
		||||
	print_range("LPFBWRange Rx", &range_lpfbw_rx);
 | 
			
		||||
	if (LMS_GetLPFBWRange(m_lms_dev, LMS_CH_RX, &range_lpfbw_tx))
 | 
			
		||||
		goto out_close;
 | 
			
		||||
	print_range("LPFBWRange Tx", &range_lpfbw_tx);
 | 
			
		||||
	lpfbw_rx = OSMO_MIN(OSMO_MAX(1.4001e6, range_lpfbw_rx.min), range_lpfbw_rx.max);
 | 
			
		||||
	lpfbw_tx = OSMO_MIN(OSMO_MAX(5.2e6, range_lpfbw_tx.min), range_lpfbw_tx.max);
 | 
			
		||||
 | 
			
		||||
	LOG(DEBUG) << "LPFBW: Rx=" << lpfbw_rx << " Tx=" << lpfbw_tx;
 | 
			
		||||
 | 
			
		||||
	if (!set_antennas()) {
 | 
			
		||||
		LOG(ALERT) << "LMS antenna setting failed";
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Perform Rx and Tx calibration */
 | 
			
		||||
	for (i=0; i<chans; i++) {
 | 
			
		||||
		LOG(INFO) << "Setting LPFBW chan " << i;
 | 
			
		||||
		if (LMS_SetLPFBW(m_lms_dev, LMS_CH_RX, i, lpfbw_rx) < 0)
 | 
			
		||||
			goto out_close;
 | 
			
		||||
		if (LMS_SetLPFBW(m_lms_dev, LMS_CH_TX, i, lpfbw_tx) < 0)
 | 
			
		||||
			goto out_close;
 | 
			
		||||
		LOG(INFO) << "Calibrating chan " << i;
 | 
			
		||||
		if (LMS_Calibrate(m_lms_dev, LMS_CH_RX, i, LMS_CALIBRATE_BW_HZ, 0) < 0)
 | 
			
		||||
			goto out_close;
 | 
			
		||||
		if (LMS_Calibrate(m_lms_dev, LMS_CH_TX, i, LMS_CALIBRATE_BW_HZ, 0) < 0)
 | 
			
		||||
			goto out_close;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	samplesRead = 0;
 | 
			
		||||
	samplesWritten = 0;
 | 
			
		||||
	started = false;
 | 
			
		||||
 | 
			
		||||
	return NORMAL;
 | 
			
		||||
 | 
			
		||||
out_close:
 | 
			
		||||
	LOG(ALERT) << "Error in LMS open, closing: " << LMS_GetLastErrorMessage();
 | 
			
		||||
	LMS_Close(m_lms_dev);
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool LMSDevice::start()
 | 
			
		||||
{
 | 
			
		||||
	LOG(INFO) << "starting LMS...";
 | 
			
		||||
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	/* configure the channels/streams */
 | 
			
		||||
	for (i=0; i<chans; i++) {
 | 
			
		||||
		if (LMS_EnableChannel(m_lms_dev, LMS_CH_RX, i, true) < 0)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		if (LMS_EnableChannel(m_lms_dev, LMS_CH_TX, i, true) < 0)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		// Set gains to midpoint
 | 
			
		||||
		setTxGain((minTxGain() + maxTxGain()) / 2, i);
 | 
			
		||||
		setRxGain((minRxGain() + maxRxGain()) / 2, i);
 | 
			
		||||
 | 
			
		||||
		m_lms_stream_rx[i] = {};
 | 
			
		||||
		m_lms_stream_rx[i].isTx = false;
 | 
			
		||||
		m_lms_stream_rx[i].channel = i;
 | 
			
		||||
		m_lms_stream_rx[i].fifoSize = 1024 * 1024;
 | 
			
		||||
		m_lms_stream_rx[i].throughputVsLatency = 0.3;
 | 
			
		||||
		m_lms_stream_rx[i].dataFmt = lms_stream_t::LMS_FMT_I16;
 | 
			
		||||
 | 
			
		||||
		m_lms_stream_tx[i] = {};
 | 
			
		||||
		m_lms_stream_tx[i].isTx = true;
 | 
			
		||||
		m_lms_stream_tx[i].channel = i;
 | 
			
		||||
		m_lms_stream_tx[i].fifoSize = 1024 * 1024;
 | 
			
		||||
		m_lms_stream_tx[i].throughputVsLatency = 0.3;
 | 
			
		||||
		m_lms_stream_tx[i].dataFmt = lms_stream_t::LMS_FMT_I16;
 | 
			
		||||
 | 
			
		||||
		if (LMS_SetupStream(m_lms_dev, &m_lms_stream_rx[i]) < 0)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		if (LMS_SetupStream(m_lms_dev, &m_lms_stream_tx[i]) < 0)
 | 
			
		||||
			return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* now start the streams in a second loop, as we can no longer call
 | 
			
		||||
	 * LMS_SetupStream() after LMS_StartStream() of the first stream */
 | 
			
		||||
	for (i = 0; i < chans; i++) {
 | 
			
		||||
		if (LMS_StartStream(&m_lms_stream_rx[i]) < 0)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		if (LMS_StartStream(&m_lms_stream_tx[i]) < 0)
 | 
			
		||||
			return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	flush_recv(10);
 | 
			
		||||
 | 
			
		||||
	started = true;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool LMSDevice::stop()
 | 
			
		||||
{
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	if (!started)
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	for (i=0; i<chans; i++) {
 | 
			
		||||
		LMS_StopStream(&m_lms_stream_tx[i]);
 | 
			
		||||
		LMS_StopStream(&m_lms_stream_rx[i]);
 | 
			
		||||
 | 
			
		||||
		LMS_EnableChannel(m_lms_dev, LMS_CH_RX, i, false);
 | 
			
		||||
		LMS_EnableChannel(m_lms_dev, LMS_CH_TX, i, false);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double LMSDevice::maxTxGain()
 | 
			
		||||
{
 | 
			
		||||
	return 73.0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double LMSDevice::minTxGain()
 | 
			
		||||
{
 | 
			
		||||
	return 0.0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double LMSDevice::maxRxGain()
 | 
			
		||||
{
 | 
			
		||||
	return 73.0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double LMSDevice::minRxGain()
 | 
			
		||||
{
 | 
			
		||||
	return 0.0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double LMSDevice::setTxGain(double dB, size_t chan)
 | 
			
		||||
{
 | 
			
		||||
	if (chan) {
 | 
			
		||||
		LOG(ALERT) << "Invalid channel " << chan;
 | 
			
		||||
		return 0.0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (dB > maxTxGain())
 | 
			
		||||
		dB = maxTxGain();
 | 
			
		||||
	if (dB < minTxGain())
 | 
			
		||||
		dB = minTxGain();
 | 
			
		||||
 | 
			
		||||
	LOG(NOTICE) << "Setting TX gain to " << dB << " dB.";
 | 
			
		||||
 | 
			
		||||
	if (LMS_SetGaindB(m_lms_dev, LMS_CH_TX, chan, dB) < 0)
 | 
			
		||||
		LOG(ERR) << "Error setting TX gain";
 | 
			
		||||
 | 
			
		||||
	return dB;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double LMSDevice::setRxGain(double dB, size_t chan)
 | 
			
		||||
{
 | 
			
		||||
	if (chan) {
 | 
			
		||||
		LOG(ALERT) << "Invalid channel " << chan;
 | 
			
		||||
		return 0.0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dB = 34.0;
 | 
			
		||||
 | 
			
		||||
	if (dB > maxRxGain())
 | 
			
		||||
		dB = maxRxGain();
 | 
			
		||||
	if (dB < minRxGain())
 | 
			
		||||
		dB = minRxGain();
 | 
			
		||||
 | 
			
		||||
	LOG(NOTICE) << "Setting RX gain to " << dB << " dB.";
 | 
			
		||||
 | 
			
		||||
	if (LMS_SetGaindB(m_lms_dev, LMS_CH_RX, chan, dB) < 0)
 | 
			
		||||
		LOG(ERR) << "Error setting RX gain";
 | 
			
		||||
 | 
			
		||||
	return dB;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int LMSDevice::get_ant_idx(const std::string & name, bool dir_tx, size_t chan)
 | 
			
		||||
{
 | 
			
		||||
	lms_name_t name_list[MAX_ANTENNA_LIST_SIZE]; /* large enough list for antenna names. */
 | 
			
		||||
	const char* c_name = name.c_str();
 | 
			
		||||
	int num_names;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	num_names = LMS_GetAntennaList(m_lms_dev, dir_tx, chan, name_list);
 | 
			
		||||
	for (i = 0; i < num_names; i++) {
 | 
			
		||||
		if (!strcmp(c_name, name_list[i]))
 | 
			
		||||
			return i;
 | 
			
		||||
	}
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool LMSDevice::flush_recv(size_t num_pkts)
 | 
			
		||||
{
 | 
			
		||||
	#define CHUNK 625
 | 
			
		||||
	int len = CHUNK * tx_sps;
 | 
			
		||||
	short *buffer = new short[len * 2];
 | 
			
		||||
	int rc;
 | 
			
		||||
	lms_stream_meta_t rx_metadata = {};
 | 
			
		||||
	rx_metadata.flushPartialPacket = false;
 | 
			
		||||
	rx_metadata.waitForTimestamp = false;
 | 
			
		||||
 | 
			
		||||
	ts_initial = 0;
 | 
			
		||||
 | 
			
		||||
	while (!ts_initial || (num_pkts-- > 0)) {
 | 
			
		||||
		rc = LMS_RecvStream(&m_lms_stream_rx[0], &buffer[0], len, &rx_metadata, 100);
 | 
			
		||||
		LOG(DEBUG) << "Flush: Recv buffer of len " << rc << " at " << std::hex << rx_metadata.timestamp;
 | 
			
		||||
		if (rc != len) {
 | 
			
		||||
			LOG(ALERT) << "LMS: Device receive timed out";
 | 
			
		||||
			delete[] buffer;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ts_initial = rx_metadata.timestamp + len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	LOG(INFO) << "Initial timestamp " << ts_initial << std::endl;
 | 
			
		||||
	delete[] buffer;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool LMSDevice::setRxAntenna(const std::string & ant, size_t chan)
 | 
			
		||||
{
 | 
			
		||||
	int idx;
 | 
			
		||||
 | 
			
		||||
	if (chan >= rx_paths.size()) {
 | 
			
		||||
		LOG(ALERT) << "Requested non-existent channel " << chan;
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	idx = get_ant_idx(ant, LMS_CH_RX, chan);
 | 
			
		||||
	if (idx < 0) {
 | 
			
		||||
		LOG(ALERT) << "Invalid Rx Antenna";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (LMS_SetAntenna(m_lms_dev, LMS_CH_RX, chan, idx) < 0) {
 | 
			
		||||
		LOG(ALERT) << "Unable to set Rx Antenna";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string LMSDevice::getRxAntenna(size_t chan)
 | 
			
		||||
{
 | 
			
		||||
	lms_name_t name_list[MAX_ANTENNA_LIST_SIZE]; /* large enough list for antenna names. */
 | 
			
		||||
	int idx;
 | 
			
		||||
 | 
			
		||||
	if (chan >= rx_paths.size()) {
 | 
			
		||||
		LOG(ALERT) << "Requested non-existent channel " << chan;
 | 
			
		||||
		return "";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	idx = LMS_GetAntenna(m_lms_dev, LMS_CH_RX, chan);
 | 
			
		||||
	if (idx < 0) {
 | 
			
		||||
		LOG(ALERT) << "Error getting Rx Antenna";
 | 
			
		||||
		return "";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (LMS_GetAntennaList(m_lms_dev, LMS_CH_RX, chan, name_list) < idx) {
 | 
			
		||||
		LOG(ALERT) << "Error getting Rx Antenna List";
 | 
			
		||||
		return "";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return name_list[idx];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool LMSDevice::setTxAntenna(const std::string & ant, size_t chan)
 | 
			
		||||
{
 | 
			
		||||
	int idx;
 | 
			
		||||
 | 
			
		||||
	if (chan >= tx_paths.size()) {
 | 
			
		||||
		LOG(ALERT) << "Requested non-existent channel " << chan;
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	idx = get_ant_idx(ant, LMS_CH_TX, chan);
 | 
			
		||||
	if (idx < 0) {
 | 
			
		||||
		LOG(ALERT) << "Invalid Rx Antenna";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (LMS_SetAntenna(m_lms_dev, LMS_CH_TX, chan, idx) < 0) {
 | 
			
		||||
		LOG(ALERT) << "Unable to set Rx Antenna";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string LMSDevice::getTxAntenna(size_t chan)
 | 
			
		||||
{
 | 
			
		||||
	lms_name_t name_list[MAX_ANTENNA_LIST_SIZE]; /* large enough list for antenna names. */
 | 
			
		||||
	int idx;
 | 
			
		||||
 | 
			
		||||
	if (chan >= tx_paths.size()) {
 | 
			
		||||
		LOG(ALERT) << "Requested non-existent channel " << chan;
 | 
			
		||||
		return "";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	idx = LMS_GetAntenna(m_lms_dev, LMS_CH_TX, chan);
 | 
			
		||||
	if (idx < 0) {
 | 
			
		||||
		LOG(ALERT) << "Error getting Tx Antenna";
 | 
			
		||||
		return "";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (LMS_GetAntennaList(m_lms_dev, LMS_CH_TX, chan, name_list) < idx) {
 | 
			
		||||
		LOG(ALERT) << "Error getting Tx Antenna List";
 | 
			
		||||
		return "";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return name_list[idx];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool LMSDevice::requiresRadioAlign()
 | 
			
		||||
{
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GSM::Time LMSDevice::minLatency() {
 | 
			
		||||
	/* Empirical data from a handful of
 | 
			
		||||
	relatively recent machines shows that the B100 will underrun when
 | 
			
		||||
	the transmit threshold is reduced to a time of 6 and a half frames,
 | 
			
		||||
	so we set a minimum 7 frame threshold. */
 | 
			
		||||
	return GSM::Time(6,7);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NOTE: Assumes sequential reads
 | 
			
		||||
int LMSDevice::readSamples(std::vector < short *>&bufs, int len, bool * overrun,
 | 
			
		||||
			   TIMESTAMP timestamp, bool * underrun, unsigned *RSSI)
 | 
			
		||||
{
 | 
			
		||||
	int rc = 0;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	lms_stream_status_t status;
 | 
			
		||||
	lms_stream_meta_t rx_metadata = {};
 | 
			
		||||
	rx_metadata.flushPartialPacket = false;
 | 
			
		||||
	rx_metadata.waitForTimestamp = false;
 | 
			
		||||
	rx_metadata.timestamp = 0;
 | 
			
		||||
 | 
			
		||||
	if (bufs.size() != chans) {
 | 
			
		||||
		LOG(ALERT) << "Invalid channel combination " << bufs.size();
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*overrun = false;
 | 
			
		||||
	*underrun = false;
 | 
			
		||||
	for (i = 0; i<chans; i++) {
 | 
			
		||||
		thread_enable_cancel(false);
 | 
			
		||||
		rc = LMS_RecvStream(&m_lms_stream_rx[i], bufs[i], len, &rx_metadata, 100);
 | 
			
		||||
		if (timestamp != (TIMESTAMP)rx_metadata.timestamp)
 | 
			
		||||
			LOG(ALERT) << "chan "<< i << " recv buffer of len " << rc << " expect " << std::hex << timestamp << " got " << std::hex << (TIMESTAMP)rx_metadata.timestamp << " (" << std::hex << rx_metadata.timestamp <<") diff=" << rx_metadata.timestamp - timestamp;
 | 
			
		||||
		if (rc != len) {
 | 
			
		||||
			LOG(ALERT) << "LMS: Device receive timed out";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (LMS_GetStreamStatus(&m_lms_stream_rx[i], &status) == 0) {
 | 
			
		||||
			if (status.underrun > m_last_rx_underruns[i])
 | 
			
		||||
				*underrun = true;
 | 
			
		||||
			m_last_rx_underruns[i] = status.underrun;
 | 
			
		||||
 | 
			
		||||
			if (status.overrun > m_last_rx_overruns[i])
 | 
			
		||||
				*overrun = true;
 | 
			
		||||
			m_last_rx_overruns[i] = status.overrun;
 | 
			
		||||
		}
 | 
			
		||||
		thread_enable_cancel(true);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	samplesRead += rc;
 | 
			
		||||
 | 
			
		||||
	if (((TIMESTAMP) rx_metadata.timestamp) < timestamp)
 | 
			
		||||
		rc = 0;
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int LMSDevice::writeSamples(std::vector < short *>&bufs, int len,
 | 
			
		||||
			    bool * underrun, unsigned long long timestamp,
 | 
			
		||||
			    bool isControl)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	lms_stream_status_t status;
 | 
			
		||||
	lms_stream_meta_t tx_metadata = {};
 | 
			
		||||
	tx_metadata.flushPartialPacket = false;
 | 
			
		||||
	tx_metadata.waitForTimestamp = true;
 | 
			
		||||
	tx_metadata.timestamp = timestamp - ts_offset;	/* Shift Tx time by offset */
 | 
			
		||||
 | 
			
		||||
	if (isControl) {
 | 
			
		||||
		LOG(ERR) << "Control packets not supported";
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (bufs.size() != chans) {
 | 
			
		||||
		LOG(ALERT) << "Invalid channel combination " << bufs.size();
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*underrun = false;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i<chans; i++) {
 | 
			
		||||
		LOG(DEBUG) << "chan "<< i << " send buffer of len " << len << " timestamp " << std::hex << tx_metadata.timestamp;
 | 
			
		||||
		thread_enable_cancel(false);
 | 
			
		||||
		rc = LMS_SendStream(&m_lms_stream_tx[i], bufs[i], len, &tx_metadata, 100);
 | 
			
		||||
		if (rc != len) {
 | 
			
		||||
			LOG(ALERT) << "LMS: Device send timed out";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (LMS_GetStreamStatus(&m_lms_stream_tx[i], &status) == 0) {
 | 
			
		||||
			if (status.underrun > m_last_tx_underruns[i])
 | 
			
		||||
				*underrun = true;
 | 
			
		||||
			m_last_tx_underruns[i] = status.underrun;
 | 
			
		||||
		}
 | 
			
		||||
		thread_enable_cancel(true);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	samplesWritten += rc;
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool LMSDevice::updateAlignment(TIMESTAMP timestamp)
 | 
			
		||||
{
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool LMSDevice::setTxFreq(double wFreq, size_t chan)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	if (chan) {
 | 
			
		||||
		LOG(ALERT) << "Invalid channel " << chan;
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (LMS_SetLOFrequency(m_lms_dev, LMS_CH_TX, chan, wFreq) < 0) {
 | 
			
		||||
		LOG(ALERT) << "set Tx: " << wFreq << " failed!";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool LMSDevice::setRxFreq(double wFreq, size_t chan)
 | 
			
		||||
{
 | 
			
		||||
	if (chan) {
 | 
			
		||||
		LOG(ALERT) << "Invalid channel " << chan;
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (LMS_SetLOFrequency(m_lms_dev, LMS_CH_RX, chan, wFreq) < 0) {
 | 
			
		||||
		LOG(ALERT) << "set Rx: " << wFreq << " failed!";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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,
 | 
			
		||||
			       const std::vector < std::string > &rx_paths)
 | 
			
		||||
{
 | 
			
		||||
	return new LMSDevice(tx_sps, rx_sps, iface, chans, lo_offset, tx_paths, rx_paths);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										202
									
								
								Transceiver52M/device/lms/LMSDevice.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								Transceiver52M/device/lms/LMSDevice.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,202 @@
 | 
			
		||||
/*
 | 
			
		||||
* Copyright 2018 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 _LMS_DEVICE_H_
 | 
			
		||||
#define _LMS_DEVICE_H_
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "radioDevice.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <lime/LimeSuite.h>
 | 
			
		||||
 | 
			
		||||
#define LIMESDR_TX_AMPL  0.3
 | 
			
		||||
 | 
			
		||||
/** A class to handle a LimeSuite supported device */
 | 
			
		||||
class LMSDevice:public RadioDevice {
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
	static constexpr double masterClockRate = 52.0e6;
 | 
			
		||||
 | 
			
		||||
	lms_device_t *m_lms_dev;
 | 
			
		||||
	std::vector<lms_stream_t> m_lms_stream_rx;
 | 
			
		||||
	std::vector<lms_stream_t> m_lms_stream_tx;
 | 
			
		||||
 | 
			
		||||
	std::vector<uint32_t> m_last_rx_underruns;
 | 
			
		||||
	std::vector<uint32_t> m_last_rx_overruns;
 | 
			
		||||
	std::vector<uint32_t> m_last_tx_underruns;
 | 
			
		||||
	std::vector<uint32_t> m_last_tx_overruns;
 | 
			
		||||
 | 
			
		||||
	double actualSampleRate;	///< the actual USRP sampling rate
 | 
			
		||||
 | 
			
		||||
	unsigned long long samplesRead;	///< number of samples read from LMS
 | 
			
		||||
	unsigned long long samplesWritten;	///< number of samples sent to LMS
 | 
			
		||||
 | 
			
		||||
	bool started;		///< flag indicates LMS has started
 | 
			
		||||
	bool skipRx;		///< set if LMS is transmit-only.
 | 
			
		||||
 | 
			
		||||
	TIMESTAMP ts_initial, ts_offset;
 | 
			
		||||
 | 
			
		||||
	double rxGain;
 | 
			
		||||
 | 
			
		||||
	int get_ant_idx(const std::string & name, bool dir_tx, size_t chan);
 | 
			
		||||
	bool flush_recv(size_t num_pkts);
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
	/** Object constructor */
 | 
			
		||||
	LMSDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chans, double lo_offset,
 | 
			
		||||
		  const std::vector<std::string>& tx_paths,
 | 
			
		||||
		  const std::vector<std::string>& rx_paths);
 | 
			
		||||
 | 
			
		||||
	/** Instantiate the LMS */
 | 
			
		||||
	int open(const std::string &args, int ref, bool swap_channels);
 | 
			
		||||
 | 
			
		||||
	/** Start the LMS */
 | 
			
		||||
	bool start();
 | 
			
		||||
 | 
			
		||||
	/** Stop the LMS */
 | 
			
		||||
	bool stop();
 | 
			
		||||
 | 
			
		||||
	/** Set priority not supported */
 | 
			
		||||
	void setPriority(float prio = 0.5) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	enum TxWindowType getWindowType() {
 | 
			
		||||
		return TX_WINDOW_LMS1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	Read samples from the LMS.
 | 
			
		||||
	@param buf preallocated buf to contain read result
 | 
			
		||||
	@param len number of samples desired
 | 
			
		||||
	@param overrun Set if read buffer has been overrun, e.g. data not being read fast enough
 | 
			
		||||
	@param timestamp The timestamp of the first samples to be read
 | 
			
		||||
	@param underrun Set if LMS does not have data to transmit, e.g. data not being sent fast enough
 | 
			
		||||
	@param RSSI The received signal strength of the read result
 | 
			
		||||
	@return The number of samples actually read
 | 
			
		||||
	*/
 | 
			
		||||
	int readSamples(std::vector < short *>&buf, int len, bool * overrun,
 | 
			
		||||
			TIMESTAMP timestamp = 0xffffffff, bool * underrun =
 | 
			
		||||
			NULL, unsigned *RSSI = NULL);
 | 
			
		||||
	/**
 | 
			
		||||
	Write samples to the LMS.
 | 
			
		||||
	@param buf Contains the data to be written.
 | 
			
		||||
	@param len number of samples to write.
 | 
			
		||||
	@param underrun Set if LMS does not have data to transmit, e.g. data not being sent fast enough
 | 
			
		||||
	@param timestamp The timestamp of the first sample of the data buffer.
 | 
			
		||||
	@param isControl Set if data is a control packet, e.g. a ping command
 | 
			
		||||
	@return The number of samples actually written
 | 
			
		||||
	*/
 | 
			
		||||
	int writeSamples(std::vector < short *>&bufs, int len, bool * underrun,
 | 
			
		||||
			 TIMESTAMP timestamp = 0xffffffff, bool isControl =
 | 
			
		||||
			 false);
 | 
			
		||||
 | 
			
		||||
	/** Update the alignment between the read and write timestamps */
 | 
			
		||||
	bool updateAlignment(TIMESTAMP timestamp);
 | 
			
		||||
 | 
			
		||||
	/** Set the transmitter frequency */
 | 
			
		||||
	bool setTxFreq(double wFreq, size_t chan = 0);
 | 
			
		||||
 | 
			
		||||
	/** Set the receiver frequency */
 | 
			
		||||
	bool setRxFreq(double wFreq, size_t chan = 0);
 | 
			
		||||
 | 
			
		||||
	/** Returns the starting write Timestamp*/
 | 
			
		||||
	TIMESTAMP initialWriteTimestamp(void) {
 | 
			
		||||
		return ts_initial;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Returns the starting read Timestamp*/
 | 
			
		||||
	TIMESTAMP initialReadTimestamp(void) {
 | 
			
		||||
		return ts_initial;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** returns the full-scale transmit amplitude **/
 | 
			
		||||
	double fullScaleInputValue() {
 | 
			
		||||
		return(double) SHRT_MAX * LIMESDR_TX_AMPL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** returns the full-scale receive amplitude **/
 | 
			
		||||
	double fullScaleOutputValue() {
 | 
			
		||||
		return (double) SHRT_MAX;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** sets the receive chan gain, returns the gain setting **/
 | 
			
		||||
	double setRxGain(double dB, size_t chan = 0);
 | 
			
		||||
 | 
			
		||||
	/** get the current receive gain */
 | 
			
		||||
	double getRxGain(size_t chan = 0) {
 | 
			
		||||
		return rxGain;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** return maximum Rx Gain **/
 | 
			
		||||
	double maxRxGain(void);
 | 
			
		||||
 | 
			
		||||
	/** return minimum Rx Gain **/
 | 
			
		||||
	double minRxGain(void);
 | 
			
		||||
 | 
			
		||||
	/** sets the transmit chan gain, returns the gain setting **/
 | 
			
		||||
	double setTxGain(double dB, size_t chan = 0);
 | 
			
		||||
 | 
			
		||||
	/** return maximum Tx Gain **/
 | 
			
		||||
	double maxTxGain(void);
 | 
			
		||||
 | 
			
		||||
	/** return minimum Rx Gain **/
 | 
			
		||||
	double minTxGain(void);
 | 
			
		||||
 | 
			
		||||
	/** sets the RX path to use, returns true if successful and false otherwise */
 | 
			
		||||
	bool setRxAntenna(const std::string & ant, size_t chan = 0);
 | 
			
		||||
 | 
			
		||||
	/* return the used RX path */
 | 
			
		||||
	std::string getRxAntenna(size_t chan = 0);
 | 
			
		||||
 | 
			
		||||
	/** sets the RX path to use, returns true if successful and false otherwise */
 | 
			
		||||
	bool setTxAntenna(const std::string & ant, size_t chan = 0);
 | 
			
		||||
 | 
			
		||||
	/* return the used RX path */
 | 
			
		||||
	std::string getTxAntenna(size_t chan = 0);
 | 
			
		||||
 | 
			
		||||
	/** return whether user drives synchronization of Tx/Rx of USRP */
 | 
			
		||||
        bool requiresRadioAlign();
 | 
			
		||||
 | 
			
		||||
        /** return whether user drives synchronization of Tx/Rx of USRP */
 | 
			
		||||
        virtual GSM::Time minLatency();
 | 
			
		||||
 | 
			
		||||
	/** Return internal status values */
 | 
			
		||||
	inline double getTxFreq(size_t chan = 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	inline double getRxFreq(size_t chan = 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	inline double getSampleRate() {
 | 
			
		||||
		return actualSampleRate;
 | 
			
		||||
	}
 | 
			
		||||
	inline double numberRead() {
 | 
			
		||||
		return samplesRead;
 | 
			
		||||
	}
 | 
			
		||||
	inline double numberWritten() {
 | 
			
		||||
		return samplesWritten;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // _LMS_DEVICE_H_
 | 
			
		||||
							
								
								
									
										10
									
								
								Transceiver52M/device/lms/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Transceiver52M/device/lms/Makefile.am
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
include $(top_srcdir)/Makefile.common
 | 
			
		||||
 | 
			
		||||
AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) -I${srcdir}/..
 | 
			
		||||
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LMS_CFLAGS)
 | 
			
		||||
 | 
			
		||||
noinst_HEADERS = LMSDevice.h
 | 
			
		||||
 | 
			
		||||
noinst_LTLIBRARIES = libdevice.la
 | 
			
		||||
 | 
			
		||||
libdevice_la_SOURCES = LMSDevice.cpp
 | 
			
		||||
@@ -19,6 +19,7 @@
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "GSMCommon.h"
 | 
			
		||||
#include "Logger.h"
 | 
			
		||||
 | 
			
		||||
extern "C" {
 | 
			
		||||
#include "config_defs.h"
 | 
			
		||||
@@ -39,7 +40,7 @@ class RadioDevice {
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
  /* Available transport bus types */
 | 
			
		||||
  enum TxWindowType { TX_WINDOW_USRP1, TX_WINDOW_FIXED };
 | 
			
		||||
  enum TxWindowType { TX_WINDOW_USRP1, TX_WINDOW_FIXED, TX_WINDOW_LMS1 };
 | 
			
		||||
 | 
			
		||||
  /* Radio interface types */
 | 
			
		||||
  enum InterfaceType {
 | 
			
		||||
@@ -57,6 +58,13 @@ class RadioDevice {
 | 
			
		||||
  /** Initialize the USRP */
 | 
			
		||||
  virtual int open(const std::string &args, int ref, bool swap_channels)=0;
 | 
			
		||||
 | 
			
		||||
  RadioDevice(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):
 | 
			
		||||
		tx_sps(tx_sps), rx_sps(rx_sps), iface(type), chans(chans), lo_offset(offset),
 | 
			
		||||
		tx_paths(tx_paths), rx_paths(rx_paths)
 | 
			
		||||
	{ }
 | 
			
		||||
 | 
			
		||||
  virtual ~RadioDevice() { }
 | 
			
		||||
 | 
			
		||||
  /** Start the USRP */
 | 
			
		||||
@@ -163,6 +171,39 @@ class RadioDevice {
 | 
			
		||||
  virtual double numberRead()=0;
 | 
			
		||||
  virtual double numberWritten()=0;
 | 
			
		||||
 | 
			
		||||
  protected:
 | 
			
		||||
  size_t tx_sps, rx_sps;
 | 
			
		||||
  InterfaceType iface;
 | 
			
		||||
  size_t chans;
 | 
			
		||||
  double lo_offset;
 | 
			
		||||
  std::vector<std::string> tx_paths, rx_paths;
 | 
			
		||||
  bool set_antennas() {
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < tx_paths.size(); i++) {
 | 
			
		||||
		if (tx_paths[i] == "")
 | 
			
		||||
			continue;
 | 
			
		||||
		LOG(DEBUG) << "Configuring channel " << i << " with antenna " << tx_paths[i];
 | 
			
		||||
		if (!setTxAntenna(tx_paths[i], i)) {
 | 
			
		||||
			LOG(ALERT) << "Failed configuring channel " << i << " with antenna " << tx_paths[i];
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < rx_paths.size(); i++) {
 | 
			
		||||
		if (rx_paths[i] == "")
 | 
			
		||||
			continue;
 | 
			
		||||
		LOG(DEBUG) << "Configuring channel " << i << " with antenna " << rx_paths[i];
 | 
			
		||||
		if (!setRxAntenna(rx_paths[i], i)) {
 | 
			
		||||
			LOG(ALERT) << "Failed configuring channel " << i << " with antenna " << rx_paths[i];
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	LOG(INFO) << "Antennas configured successfully";
 | 
			
		||||
	return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -282,16 +282,13 @@ private:
 | 
			
		||||
	enum TxWindowType tx_window;
 | 
			
		||||
	enum uhd_dev_type dev_type;
 | 
			
		||||
 | 
			
		||||
	size_t tx_sps, rx_sps, chans;
 | 
			
		||||
	double tx_rate, rx_rate;
 | 
			
		||||
 | 
			
		||||
	double tx_gain_min, tx_gain_max;
 | 
			
		||||
	double rx_gain_min, rx_gain_max;
 | 
			
		||||
	double offset;
 | 
			
		||||
 | 
			
		||||
	std::vector<double> tx_gains, rx_gains;
 | 
			
		||||
	std::vector<double> tx_freqs, rx_freqs;
 | 
			
		||||
	std::vector<std::string> tx_paths, rx_paths;
 | 
			
		||||
	size_t tx_spp, rx_spp;
 | 
			
		||||
 | 
			
		||||
	bool started;
 | 
			
		||||
@@ -307,7 +304,6 @@ private:
 | 
			
		||||
	void init_gains();
 | 
			
		||||
	void set_channels(bool swap);
 | 
			
		||||
	void set_rates();
 | 
			
		||||
	bool set_antennas();
 | 
			
		||||
	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);
 | 
			
		||||
@@ -319,7 +315,6 @@ private:
 | 
			
		||||
	bool set_freq(double freq, size_t chan, bool tx);
 | 
			
		||||
 | 
			
		||||
	Thread *async_event_thrd;
 | 
			
		||||
	InterfaceType iface;
 | 
			
		||||
	Mutex tune_lock;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -366,22 +361,16 @@ static void thread_enable_cancel(bool cancel)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uhd_device::uhd_device(size_t tx_sps, size_t rx_sps,
 | 
			
		||||
		       InterfaceType iface, size_t chans, double offset,
 | 
			
		||||
		       InterfaceType iface, size_t chans, double lo_offset,
 | 
			
		||||
		       const std::vector<std::string>& tx_paths,
 | 
			
		||||
		       const std::vector<std::string>& rx_paths)
 | 
			
		||||
	: tx_gain_min(0.0), tx_gain_max(0.0),
 | 
			
		||||
	: RadioDevice(tx_sps, rx_sps, iface, chans, lo_offset, tx_paths, rx_paths),
 | 
			
		||||
	  tx_gain_min(0.0), tx_gain_max(0.0),
 | 
			
		||||
	  rx_gain_min(0.0), rx_gain_max(0.0),
 | 
			
		||||
	  tx_spp(0), rx_spp(0),
 | 
			
		||||
	  started(false), aligned(false), rx_pkt_cnt(0), drop_cnt(0),
 | 
			
		||||
	  prev_ts(0,0), ts_initial(0), ts_offset(0), async_event_thrd(NULL)
 | 
			
		||||
{
 | 
			
		||||
	this->tx_sps = tx_sps;
 | 
			
		||||
	this->rx_sps = rx_sps;
 | 
			
		||||
	this->chans = chans;
 | 
			
		||||
	this->offset = offset;
 | 
			
		||||
	this->iface = iface;
 | 
			
		||||
	this->tx_paths = tx_paths;
 | 
			
		||||
	this->rx_paths = rx_paths;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uhd_device::~uhd_device()
 | 
			
		||||
@@ -458,33 +447,6 @@ void uhd_device::set_rates()
 | 
			
		||||
	LOG(INFO) << "Rates configured for " << desc.str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool uhd_device::set_antennas()
 | 
			
		||||
{
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < tx_paths.size(); i++) {
 | 
			
		||||
		if (tx_paths[i] == "")
 | 
			
		||||
			continue;
 | 
			
		||||
		LOG(DEBUG) << "Configuring channel " << i << " with antenna " << tx_paths[i];
 | 
			
		||||
		if (!setTxAntenna(tx_paths[i], i)) {
 | 
			
		||||
			LOG(ALERT) << "Failed configuring channel " << i << " with antenna " << tx_paths[i];
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < rx_paths.size(); i++) {
 | 
			
		||||
		if (rx_paths[i] == "")
 | 
			
		||||
			continue;
 | 
			
		||||
		LOG(DEBUG) << "Configuring channel " << i << " with antenna " << rx_paths[i];
 | 
			
		||||
		if (!setRxAntenna(rx_paths[i], i)) {
 | 
			
		||||
			LOG(ALERT) << "Failed configuring channel " << i << " with antenna " << rx_paths[i];
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	LOG(INFO) << "Antennas configured successfully";
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double uhd_device::setTxGain(double db, size_t chan)
 | 
			
		||||
{
 | 
			
		||||
	if (iface == MULTI_ARFCN)
 | 
			
		||||
@@ -732,8 +694,8 @@ int uhd_device::open(const std::string &args, int ref, bool swap_channels)
 | 
			
		||||
		}
 | 
			
		||||
	} else if (dev_type == LIMESDR) {
 | 
			
		||||
		for (size_t i = 0; i < chans; i++) {
 | 
			
		||||
			usrp_dev->set_tx_bandwidth(5e6, i);
 | 
			
		||||
			usrp_dev->set_rx_bandwidth(5e6, i);
 | 
			
		||||
			usrp_dev->set_tx_bandwidth(5.2e6, i);
 | 
			
		||||
			usrp_dev->set_rx_bandwidth(1.4001e6, i);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -1086,8 +1048,8 @@ uhd::tune_request_t uhd_device::select_freq(double freq, size_t chan, bool tx)
 | 
			
		||||
	uhd::tune_request_t treq(freq);
 | 
			
		||||
 | 
			
		||||
	if (dev_type == UMTRX) {
 | 
			
		||||
		if (offset != 0.0)
 | 
			
		||||
			return uhd::tune_request_t(freq, offset);
 | 
			
		||||
		if (lo_offset != 0.0)
 | 
			
		||||
			return uhd::tune_request_t(freq, lo_offset);
 | 
			
		||||
 | 
			
		||||
		// Don't use DSP tuning, because LMS6002D PLL steps are small enough.
 | 
			
		||||
		// We end up with DSP tuning just for 2-3Hz, which is meaningless and
 | 
			
		||||
@@ -1099,10 +1061,10 @@ uhd::tune_request_t uhd_device::select_freq(double freq, size_t chan, bool tx)
 | 
			
		||||
		treq.dsp_freq = 0.0;
 | 
			
		||||
		return treq;
 | 
			
		||||
	} else if (chans == 1) {
 | 
			
		||||
		if (offset == 0.0)
 | 
			
		||||
		if (lo_offset == 0.0)
 | 
			
		||||
			return treq;
 | 
			
		||||
 | 
			
		||||
		return uhd::tune_request_t(freq, offset);
 | 
			
		||||
		return uhd::tune_request_t(freq, lo_offset);
 | 
			
		||||
	} else if ((dev_type != B210) || (chans > 2) || (chan > 1)) {
 | 
			
		||||
		LOG(ALERT) << chans << " channels unsupported";
 | 
			
		||||
		return treq;
 | 
			
		||||
@@ -1585,9 +1547,9 @@ std::string smpl_buf::str_code(ssize_t code)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps,
 | 
			
		||||
			       InterfaceType iface, size_t chans, double offset,
 | 
			
		||||
			       InterfaceType iface, size_t chans, double lo_offset,
 | 
			
		||||
			       const std::vector<std::string>& tx_paths,
 | 
			
		||||
			       const std::vector<std::string>& rx_paths)
 | 
			
		||||
{
 | 
			
		||||
	return new uhd_device(tx_sps, rx_sps, iface, chans, offset, tx_paths, rx_paths);
 | 
			
		||||
	return new uhd_device(tx_sps, rx_sps, iface, chans, lo_offset, tx_paths, rx_paths);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -58,12 +58,15 @@ const dboardConfigType dboardConfig = TXA_RXB;
 | 
			
		||||
 | 
			
		||||
const double USRPDevice::masterClockRate = 52.0e6;
 | 
			
		||||
 | 
			
		||||
USRPDevice::USRPDevice(size_t sps)
 | 
			
		||||
USRPDevice::USRPDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface,
 | 
			
		||||
		       size_t chans, double lo_offset,
 | 
			
		||||
		       const std::vector<std::string>& tx_paths,
 | 
			
		||||
		       const std::vector<std::string>& rx_paths):
 | 
			
		||||
		RadioDevice(tx_sps, rx_sps, iface, chans, lo_offset, tx_paths, rx_paths)
 | 
			
		||||
{
 | 
			
		||||
  LOG(INFO) << "creating USRP device...";
 | 
			
		||||
 | 
			
		||||
  this->sps = sps;
 | 
			
		||||
  decimRate = (unsigned int) round(masterClockRate/((GSMRATE) * (double) sps));
 | 
			
		||||
  decimRate = (unsigned int) round(masterClockRate/((GSMRATE) * (double) tx_sps));
 | 
			
		||||
  actualSampleRate = masterClockRate/decimRate;
 | 
			
		||||
  rxGain = 0;
 | 
			
		||||
 | 
			
		||||
@@ -73,9 +76,9 @@ USRPDevice::USRPDevice(size_t sps)
 | 
			
		||||
   * split sample rate Tx/Rx - 4/1 sps we need to need to
 | 
			
		||||
   * compensate for advance rather than delay.
 | 
			
		||||
   */
 | 
			
		||||
  if (sps == 1)
 | 
			
		||||
  if (tx_sps == 1)
 | 
			
		||||
    pingOffset = 272;
 | 
			
		||||
  else if (sps == 4)
 | 
			
		||||
  else if (tx_sps == 4)
 | 
			
		||||
    pingOffset = 269 - 7500;
 | 
			
		||||
  else
 | 
			
		||||
    pingOffset = 0;
 | 
			
		||||
@@ -100,7 +103,7 @@ int USRPDevice::open(const std::string &, int, bool)
 | 
			
		||||
  if (!skipRx) {
 | 
			
		||||
  try {
 | 
			
		||||
    m_uRx = usrp_standard_rx_sptr(usrp_standard_rx::make(
 | 
			
		||||
                                        0, decimRate * sps, 1, -1,
 | 
			
		||||
                                        0, decimRate * tx_sps, 1, -1,
 | 
			
		||||
                                        usrp_standard_rx::FPGA_MODE_NORMAL,
 | 
			
		||||
                                        1024, 16 * 8, rbf));
 | 
			
		||||
    m_uRx->set_fpga_master_clock_freq(masterClockRate);
 | 
			
		||||
@@ -648,9 +651,9 @@ bool USRPDevice::setRxFreq(double wFreq) { return true;};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps,
 | 
			
		||||
			       InterfaceType iface, size_t chans, double offset,
 | 
			
		||||
			       InterfaceType iface, size_t chans, double lo_offset,
 | 
			
		||||
			       const std::vector<std::string>& tx_paths,
 | 
			
		||||
			       const std::vector<std::string>& rx_paths)
 | 
			
		||||
{
 | 
			
		||||
	return new USRPDevice(tx_sps);
 | 
			
		||||
	return new USRPDevice(tx_sps, rx_sps, iface, chans, lo_offset, tx_paths, rx_paths);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -48,7 +48,6 @@ private:
 | 
			
		||||
  usrp_subdev_spec rxSubdevSpec;
 | 
			
		||||
  usrp_subdev_spec txSubdevSpec;
 | 
			
		||||
 | 
			
		||||
  int sps;
 | 
			
		||||
  double actualSampleRate;	///< the actual USRP sampling rate
 | 
			
		||||
  unsigned int decimRate;	///< the USRP decimation rate
 | 
			
		||||
 | 
			
		||||
@@ -96,7 +95,9 @@ private:
 | 
			
		||||
 public:
 | 
			
		||||
 | 
			
		||||
  /** Object constructor */
 | 
			
		||||
  USRPDevice(size_t sps);
 | 
			
		||||
  USRPDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chans, double lo_offset,
 | 
			
		||||
		const std::vector<std::string>& tx_paths,
 | 
			
		||||
		const std::vector<std::string>& rx_paths);
 | 
			
		||||
 | 
			
		||||
  /** Instantiate the USRP */
 | 
			
		||||
  int open(const std::string &, int, bool);
 | 
			
		||||
@@ -203,8 +204,6 @@ private:
 | 
			
		||||
  inline double getSampleRate() { return actualSampleRate; }
 | 
			
		||||
  inline double numberRead() { return samplesRead; }
 | 
			
		||||
  inline double numberWritten() { return samplesWritten; }
 | 
			
		||||
 | 
			
		||||
  std::vector<std::string> tx_paths, rx_paths;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // _USRP_DEVICE_H_
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								configure.ac
									
									
									
									
									
								
							@@ -100,6 +100,11 @@ AC_ARG_WITH(usrp1, [
 | 
			
		||||
        [enable USRP1 gnuradio based transceiver])
 | 
			
		||||
])
 | 
			
		||||
 | 
			
		||||
AC_ARG_WITH(lms, [
 | 
			
		||||
    AS_HELP_STRING([--with-lms],
 | 
			
		||||
        [enable LimeSuite gnuradio based transceiver])
 | 
			
		||||
])
 | 
			
		||||
 | 
			
		||||
AC_ARG_WITH(singledb, [
 | 
			
		||||
    AS_HELP_STRING([--with-singledb],
 | 
			
		||||
        [enable single daughterboard use on USRP1])
 | 
			
		||||
@@ -133,6 +138,10 @@ AS_IF([test "x$with_usrp1" = "xyes"], [
 | 
			
		||||
    PKG_CHECK_MODULES(USRP, usrp >= 3.3)
 | 
			
		||||
])
 | 
			
		||||
 | 
			
		||||
AS_IF([test "x$with_lms" = "xyes"], [
 | 
			
		||||
    PKG_CHECK_MODULES(LMS, LimeSuite)
 | 
			
		||||
])
 | 
			
		||||
 | 
			
		||||
AS_IF([test "x$with_uhd" != "xno"],[
 | 
			
		||||
    PKG_CHECK_MODULES(UHD, uhd >= 003.011,
 | 
			
		||||
        [AC_DEFINE(USE_UHD_3_11, 1, UHD version 3.11.0 or higher)],
 | 
			
		||||
@@ -184,6 +193,7 @@ CHECK_BUILTIN_SUPPORT([__builtin_cpu_supports],
 | 
			
		||||
 | 
			
		||||
AM_CONDITIONAL(DEVICE_UHD, [test "x$with_uhd" != "xno"])
 | 
			
		||||
AM_CONDITIONAL(DEVICE_USRP1, [test "x$with_usrp1" = "xyes"])
 | 
			
		||||
AM_CONDITIONAL(DEVICE_LMS, [test "x$with_lms" = "xyes"])
 | 
			
		||||
AM_CONDITIONAL(ARCH_ARM, [test "x$with_neon" = "xyes" || test "x$with_neon_vfpv4" = "xyes"])
 | 
			
		||||
AM_CONDITIONAL(ARCH_ARM_A15, [test "x$with_neon_vfpv4" = "xyes"])
 | 
			
		||||
 | 
			
		||||
@@ -211,6 +221,7 @@ AC_CONFIG_FILES([\
 | 
			
		||||
    Transceiver52M/device/Makefile \
 | 
			
		||||
    Transceiver52M/device/uhd/Makefile \
 | 
			
		||||
    Transceiver52M/device/usrp1/Makefile \
 | 
			
		||||
    Transceiver52M/device/lms/Makefile \
 | 
			
		||||
    tests/Makefile \
 | 
			
		||||
    tests/CommonLibs/Makefile \
 | 
			
		||||
    tests/Transceiver52M/Makefile \
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								doc/examples/osmo-trx-umtrx.cfg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								doc/examples/osmo-trx-umtrx.cfg
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
log stderr
 | 
			
		||||
  logging filter all 1
 | 
			
		||||
  logging color 1
 | 
			
		||||
  logging print category 1
 | 
			
		||||
  logging timestamp 1
 | 
			
		||||
  logging level all info
 | 
			
		||||
!
 | 
			
		||||
line vty
 | 
			
		||||
 no login
 | 
			
		||||
!
 | 
			
		||||
trx
 | 
			
		||||
 bind-ip 127.0.0.1
 | 
			
		||||
 remote-ip 127.0.0.1
 | 
			
		||||
 base-port 5700
 | 
			
		||||
 dev-args addr=192.168.10.2,pa=NONE,pa_power_max_dbm=23,fifo_ctrl_window=0,status_port=12345
 | 
			
		||||
 egprs disable
 | 
			
		||||
 tx-sps 4
 | 
			
		||||
 rx-sps 4
 | 
			
		||||
 rssi-offset 38
 | 
			
		||||
 rt-prio 18
 | 
			
		||||
 chan 0
 | 
			
		||||
 chan 1
 | 
			
		||||
		Reference in New Issue
	
	Block a user