Compare commits

..

2 Commits

Author SHA1 Message Date
Sergey Kostanbaev
3e3507d09d Initial XTRX support
Change-Id: I1067dfef53aa2669cc7c189cccae10074c674390
2019-10-09 01:47:55 +03:00
Sergey Kostanbaev
bcd1e72558 CommonLibs: check HAVE_CONFIG_H before including it
Change-Id: Idb9e938e7794b67b1db23a31e106c8945f79cf24
2019-10-09 01:47:55 +03:00
61 changed files with 1157 additions and 761 deletions

View File

@@ -666,7 +666,7 @@ For more information on this, and how to apply and follow the GNU AGPL, see
=========================================================================
This marks the end of the AGPLv3 text. The following text is appended to the
same file for convenience but constituting a distinct document, not part of the
same file for convience but constituting a distinct document, not part of the
actual AGPL text and not part of an attempt to create a deriviative work based
on the AGPLv3 text.

View File

@@ -37,7 +37,7 @@ using namespace std;
/**
Apply a Galois polymonial to a binary sequence.
Apply a Galois polymonial to a binary seqeunce.
@param val The input sequence.
@param poly The polynomial.
@param order The order of the polynomial.

View File

@@ -47,7 +47,7 @@
// (pat) The elements in the queue are type T*, and
// the Fifo class implements the underlying queue.
// The default is class PointerFIFO, which does not place any restrictions on the type of T,
// and is implemented by allocating auxiliary structures for the queue,
// and is implemented by allocating auxilliary structures for the queue,
// or SingleLinkedList, which implements the queue using an internal pointer in type T,
// which must implement the functional interface of class SingleLinkListNode,
// namely: functions T*next() and void setNext(T*).

View File

@@ -4,7 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0+
*
* This software is distributed under multiple licenses; see the COPYING file in
* the main directory for licensing information for this specific distribution.
* the main directory for licensing information for this specific distribuion.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.

View File

@@ -48,11 +48,9 @@ Log::~Log()
int neednl = (mlen==0 || mStream.str()[mlen-1] != '\n');
const char *fmt = neednl ? "%s\n" : "%s";
/* print related function called inside a C++ destructor, use pthread_setcancelstate() APIs.
See osmo-trx commit 86be40b4eb762d5c12e8e3f7388ca9f254e77b36 for more information */
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state);
log_mutex_lock_canceldisable(&old_state);
LOGPSRC(mCategory, mPriority, filename, line, fmt, mStream.str().c_str());
pthread_setcancelstate(old_state, NULL);
log_mutex_unlock_canceldisable(old_state);
}
ostringstream& Log::get()

View File

@@ -58,9 +58,6 @@ extern "C" {
#define LOGLV(category, level) \
Log(category, level, __BASE_FILE__, __LINE__).get() << "[tid=" << pthread_self() << "] "
#define LOGSRC(category, level, file, line) \
Log(category, level, file, line).get() << "[tid=" << pthread_self() << "] "
#define LOGCHAN(chan, category, level) \
Log(category, LOGL_##level, __BASE_FILE__, __LINE__).get() << "[tid=" << pthread_self() << "][chan=" << chan << "] "

View File

@@ -186,7 +186,7 @@ class Thread {
}
}
/** Send cancellation to thread */
/** Send cancelation to thread */
void cancel() { pthread_cancel(mThread); }
};

View File

@@ -84,7 +84,7 @@ class Timeval {
uint32_t usec() const { return mTimespec.tv_nsec / 1000; }
uint32_t nsec() const { return mTimespec.tv_nsec; }
/** Return difference from other (other-self), in ms. */
/** Return differnce from other (other-self), in ms. */
long delta(const Timeval& other) const;
/** Elapsed time in ms. */

View File

@@ -36,7 +36,7 @@
#include <assert.h>
#include <stdlib.h>
// We can't use Logger.h in this file...
// We cant use Logger.h in this file...
extern int gVectorDebug;
#define BVDEBUG(msg) if (gVectorDebug) {std::cout << msg;}
@@ -232,7 +232,7 @@ template <class T> class Vector {
assert(mStart+span<=mEnd);
for (i = 0; i < span; i++, src++, dst++)
*dst = *src;
/*TODO if not non-trivially copiable type class, optimize:
/*TODO if not non-trivially copyable type class, optimize:
memcpy(dst,mStart,span*sizeof(T)); */
}

View File

@@ -21,17 +21,7 @@
* See the COPYING file in the main directory for details.
*/
#include "config.h"
/* If HAVE_GETTID, then "_GNU_SOURCE" may need to be defined to use gettid() */
#if HAVE_GETTID
#define _GNU_SOURCE
#endif
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#include "config.h"
#include <pthread.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
@@ -45,39 +35,21 @@ static const struct log_info_cat default_categories[] = {
.color = NULL,
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DTRXCLK] = {
.name = "DTRXCLK",
.description = "TRX Master Clock",
.color = NULL,
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DTRXCTRL] = {
.name = "DTRXCTRL",
.description = "TRX CTRL interface",
.color = "\033[1;33m",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DTRXDDL] = {
.name = "DTRXDDL",
.description = "TRX Data interface Downlink",
.color = NULL,
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DTRXDUL] = {
.name = "DTRXDUL",
.description = "TRX CTRL interface Uplink",
.color = NULL,
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DDEV] = {
.name = "DDEV",
.description = "Device/Driver specific code",
.color = NULL,
.enabled = 1, .loglevel = LOGL_INFO,
},
[DDEVDRV] = {
.name = "DDEVDRV",
.description = "Logging from external device driver library implementing lower level specifics",
[DLMS] = {
.name = "DLMS",
.description = "Logging from within LimeSuite itself",
.color = NULL,
.enabled = 1, .loglevel = LOGL_NOTICE,
},
@@ -88,14 +60,48 @@ const struct log_info log_info = {
.num_cat = ARRAY_SIZE(default_categories),
};
pid_t my_gettid(void)
{
#if HAVE_GETTID
return gettid();
#elif defined(LINUX) && defined(__NR_gettid)
return (pid_t) syscall(__NR_gettid);
#else
#pragma message ("use pid as tid")
return getpid();
#endif
pthread_mutex_t log_mutex;
bool log_mutex_init() {
int rc;
pthread_mutexattr_t attr;
if ((rc = pthread_mutexattr_init(&attr))) {
fprintf(stderr, "pthread_mutexattr_init() failed: %d\n", rc);
return false;
}
if ((rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))) {
fprintf(stderr, "pthread_mutexattr_settype() failed: %d\n", rc);
return false;
}
if ((rc = pthread_mutex_init(&log_mutex, &attr))) {
fprintf(stderr, "pthread_mutex_init() failed: %d\n", rc);
return false;
}
if ((rc = pthread_mutexattr_destroy(&attr))) {
fprintf(stderr, "pthread_mutexattr_destroy() failed: %d\n", rc);
return false;
}
return true;
/* FIXME: do we need to call pthread_mutex_destroy() during process exit? */
}
/* If called inside a C++ destructor, use log_mutex_(un)lock_canceldisable() APIs instead.
See osmo-trx commit 86be40b4eb762d5c12e8e3f7388ca9f254e77b36 for more information */
void log_mutex_lock() {
OSMO_ASSERT(!pthread_mutex_lock(&log_mutex));
}
void log_mutex_unlock() {
OSMO_ASSERT(!pthread_mutex_unlock(&log_mutex));
}
void log_mutex_lock_canceldisable(int *st) {
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, st);
log_mutex_lock();
}
void log_mutex_unlock_canceldisable(int st) {
log_mutex_unlock();
pthread_setcancelstate(st, NULL);
}

View File

@@ -1,7 +1,7 @@
#pragma once
#include <stdbool.h>
#include <sys/types.h>
#include <pthread.h>
#include <osmocom/core/logging.h>
@@ -10,20 +10,26 @@ extern const struct log_info log_info;
/* Debug Areas of the code */
enum {
DMAIN,
DTRXCLK,
DTRXCTRL,
DTRXDDL,
DTRXDUL,
DDEV,
DDEVDRV,
DLMS,
};
pid_t my_gettid(void);
bool log_mutex_init();
void log_mutex_lock();
void log_mutex_unlock();
void log_mutex_lock_canceldisable(int *st);
void log_mutex_unlock_canceldisable(int st);
#define CLOGC(category, level, fmt, args...) do { \
LOGP(category, level, "[tid=%ld] " fmt, (long int) my_gettid(), ##args); \
log_mutex_lock(); \
LOGP(category, level, "[tid=%lu] " fmt, pthread_self(), ##args); \
log_mutex_unlock(); \
} while(0)
#define CLOGCHAN(chan, category, level, fmt, args...) do { \
LOGP(category, level, "[tid=%ld][chan=%zu] " fmt, (long int) my_gettid(), chan, ##args); \
log_mutex_lock(); \
LOGP(category, level, "[tid=%lu][chan=%lu] " fmt, pthread_self(), chan, ##args); \
log_mutex_unlock(); \
} while(0)

View File

@@ -38,7 +38,7 @@
* That signal is processed here in device_sig_cb, where a copy of the "struct
* device_counters" structure is held and the main thread is instructed through
* a timerfd to update rate_ctr APIs against this copy. All this is done inside
* a mutex to avoid different race conditions (between Rx andTx threads, and
* a mutex to avoid different race conditons (between Rx andTx threads, and
* between Rx/Tx and main thread). For the same reason, callers of signal
* <SS_DEVICE,S_DEVICE_COUNTER_CHANGE> (device_sig_cb), that is Rx/Tx threads,
* must do so with PTHREAD_CANCEL_DISABLE, in order to avoid possible deadlocks

View File

@@ -32,42 +32,34 @@
#include <osmocom/core/rate_ctr.h>
#include <osmocom/vty/command.h>
#include <osmocom/vty/logging.h>
#include <osmocom/vty/vty.h>
#include <osmocom/vty/misc.h>
#include "trx_rate_ctr.h"
#include "trx_vty.h"
#include "../config.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
static struct trx_ctx* g_trx_ctx;
const struct value_string clock_ref_names[] = {
static const struct value_string clock_ref_names[] = {
{ REF_INTERNAL, "internal" },
{ REF_EXTERNAL, "external" },
{ REF_GPS, "gpsdo" },
{ 0, NULL }
};
const struct value_string filler_names[] = {
{ FILLER_DUMMY, "Dummy bursts (C0 only)" },
{ FILLER_ZERO, "Empty bursts" },
{ FILLER_NORM_RAND, "GMSK Normal Bursts with random payload" },
{ FILLER_EDGE_RAND, "8-PSK Normal Bursts with random payload" },
{ FILLER_ACCESS_RAND, "Access Bursts with random payload" },
static const struct value_string filler_names[] = {
{ FILLER_DUMMY, "Dummy bursts" },
{ FILLER_ZERO, "Disabled" },
{ FILLER_NORM_RAND, "Normal bursts with random payload" },
{ FILLER_EDGE_RAND, "EDGE bursts with random payload" },
{ FILLER_ACCESS_RAND, "Access bursts with random payload" },
{ 0, NULL }
};
static const struct value_string filler_types[] = {
{ FILLER_DUMMY, "dummy" },
{ FILLER_ZERO, "zero" },
{ FILLER_NORM_RAND, "random-nb-gmsk" },
{ FILLER_EDGE_RAND, "random-nb-8psk" },
{ FILLER_ACCESS_RAND, "random-ab" },
{ 0, NULL }
};
struct trx_ctx *trx_from_vty(struct vty *v)
{
/* It can't hurt to force callers to continue to pass the vty instance
@@ -183,10 +175,57 @@ DEFUN(cfg_rx_sps, cfg_rx_sps_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_test_rtsc, cfg_test_rtsc_cmd,
"test rtsc <0-7>",
"Set the Random Normal Burst test mode with TSC\n"
"TSC\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
if (trx->cfg.rach_delay_set) {
vty_out(vty, "rach-delay and rtsc options are mutual-exclusive%s",
VTY_NEWLINE);
return CMD_WARNING;
}
trx->cfg.rtsc_set = true;
trx->cfg.rtsc = atoi(argv[0]);
if (!trx->cfg.egprs) /* Don't override egprs which sets different filler */
trx->cfg.filler = FILLER_NORM_RAND;
return CMD_SUCCESS;
}
DEFUN(cfg_test_rach_delay, cfg_test_rach_delay_cmd,
"test rach-delay <0-68>",
"Set the Random Access Burst test mode with delay\n"
"RACH delay\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
if (trx->cfg.rtsc_set) {
vty_out(vty, "rach-delay and rtsc options are mutual-exclusive%s",
VTY_NEWLINE);
return CMD_WARNING;
}
if (trx->cfg.egprs) {
vty_out(vty, "rach-delay and egprs options are mutual-exclusive%s",
VTY_NEWLINE);
return CMD_WARNING;
}
trx->cfg.rach_delay_set = true;
trx->cfg.rach_delay = atoi(argv[0]);
trx->cfg.filler = FILLER_ACCESS_RAND;
return CMD_SUCCESS;
}
DEFUN(cfg_clock_ref, cfg_clock_ref_cmd,
"clock-ref (internal|external|gpsdo)",
"Set the Reference Clock\n"
"Enable internal reference (default)\n"
"Enable internal referece (default)\n"
"Enable external 10 MHz reference\n"
"Enable GPSDO reference\n")
{
@@ -269,6 +308,7 @@ DEFUN(cfg_egprs, cfg_egprs_cmd,
trx->cfg.egprs = false;
} else if (strcmp("enable", argv[0]) == 0) {
trx->cfg.egprs = true;
trx->cfg.filler = FILLER_EDGE_RAND;
} else {
return CMD_WARNING;
}
@@ -315,57 +355,14 @@ DEFUN(cfg_stack_size, cfg_stack_size_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_filler, cfg_filler_type_cmd,
"filler type (zero|dummy|random-nb-gmsk|random-nb-8psk|random-ab)",
"Filler burst settings\n"
"Filler burst type (default=zero)\n"
"Send an empty burst when there is nothing to send (default)\n"
"Send a dummy burst when there is nothing to send on C0 (TRX0) and empty burst on other channels."
" Use for OpenBTS compatibility only, don't use with OsmoBTS as it breaks encryption.\n"
"Send a GMSK modulated Normal Burst with random bits when there is nothing to send."
" Use for spectrum mask testing. Configure 'filler tsc' to set training sequence.\n"
"Send an 8-PSK modulated Normal Burst with random bits when there is nothing to send."
" Use for spectrum mask testing. Configure 'filler tsc' to set training sequence.\n"
"Send an Access Burst with random bits when there is nothing to send. Use for Rx/Tx alignment."
" Configure 'filler access-burst-delay' to introduce artificial delay.\n"
)
{
struct trx_ctx *trx = trx_from_vty(vty);
// trx->cfg.filler is unsigned, so we need an interim int var to detect errors
int type = get_string_value(filler_types, argv[0]);
if (type < 0) {
trx->cfg.filler = FILLER_ZERO;
return CMD_WARNING;
}
trx->cfg.filler = type;
return CMD_SUCCESS;
}
DEFUN(cfg_test_rtsc, cfg_filler_tsc_cmd,
"filler tsc <0-7>",
"Filler burst settings\n"
"Set the TSC for GMSK/8-PSK Normal Burst random fillers. Used only with 'random-nb-gmsk' and"
" 'random-nb-8psk' filler types. (default=0)\n"
"TSC\n")
DEFUN(cfg_filler, cfg_filler_cmd,
"filler dummy",
"Enable C0 filler table\n"
"Dummy method\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
trx->cfg.rtsc = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_test_rach_delay, cfg_filler_rach_delay_cmd,
"filler access-burst-delay <0-68>",
"Filler burst settings\n"
"Set the delay for Access Burst random fillers. Used only with 'random-ab' filler type. (default=0)\n"
"RACH delay in symbols\n")
{
struct trx_ctx *trx = trx_from_vty(vty);
trx->cfg.rach_delay = atoi(argv[0]);
trx->cfg.filler = FILLER_DUMMY;
return CMD_SUCCESS;
}
@@ -553,6 +550,10 @@ static int config_write_trx(struct vty *vty)
vty_out(vty, " tx-sps %u%s", trx->cfg.tx_sps, VTY_NEWLINE);
if (trx->cfg.rx_sps != DEFAULT_RX_SPS)
vty_out(vty, " rx-sps %u%s", trx->cfg.rx_sps, VTY_NEWLINE);
if (trx->cfg.rtsc_set)
vty_out(vty, " test rtsc %u%s", trx->cfg.rtsc, VTY_NEWLINE);
if (trx->cfg.rach_delay_set)
vty_out(vty, " test rach-delay %u%s", trx->cfg.rach_delay, VTY_NEWLINE);
if (trx->cfg.clock_ref != REF_INTERNAL)
vty_out(vty, " clock-ref %s%s", get_value_string(clock_ref_names, trx->cfg.clock_ref), VTY_NEWLINE);
vty_out(vty, " multi-arfcn %s%s", trx->cfg.multi_arfcn ? "enable" : "disable", VTY_NEWLINE);
@@ -565,12 +566,6 @@ static int config_write_trx(struct vty *vty)
vty_out(vty, " ext-rach %s%s", trx->cfg.ext_rach ? "enable" : "disable", VTY_NEWLINE);
if (trx->cfg.sched_rr != 0)
vty_out(vty, " rt-prio %u%s", trx->cfg.sched_rr, VTY_NEWLINE);
if (trx->cfg.filler != FILLER_ZERO)
vty_out(vty, " filler type %s%s", get_value_string(filler_types, trx->cfg.filler), VTY_NEWLINE);
if (trx->cfg.rtsc > 0)
vty_out(vty, " filler tsc %u%s", trx->cfg.rtsc, VTY_NEWLINE);
if (trx->cfg.rach_delay > 0)
vty_out(vty, " filler access-burst-delay %u%s", trx->cfg.rach_delay, VTY_NEWLINE);
if (trx->cfg.stack_size != 0)
vty_out(vty, " stack-size %u%s", trx->cfg.stack_size, VTY_NEWLINE);
trx_rate_ctr_threshold_write_config(vty, " ");
@@ -598,9 +593,11 @@ static void trx_dump_vty(struct vty *vty, struct trx_ctx *trx)
vty_out(vty, " Device args: %s%s", trx->cfg.dev_args, VTY_NEWLINE);
vty_out(vty, " Tx Samples-per-Symbol: %u%s", trx->cfg.tx_sps, VTY_NEWLINE);
vty_out(vty, " Rx Samples-per-Symbol: %u%s", trx->cfg.rx_sps, VTY_NEWLINE);
vty_out(vty, " Filler Burst Type: %s%s", get_value_string(filler_names, trx->cfg.filler), VTY_NEWLINE);
vty_out(vty, " Filler Burst TSC: %u%s", trx->cfg.rtsc, VTY_NEWLINE);
vty_out(vty, " Filler Burst RACH Delay: %u%s", trx->cfg.rach_delay, VTY_NEWLINE);
vty_out(vty, " Test Mode: TSC: %u (%s)%s", trx->cfg.rtsc,
trx->cfg.rtsc_set ? "Enabled" : "Disabled", VTY_NEWLINE);
vty_out(vty, " Test Mode: RACH Delay: %u (%s)%s", trx->cfg.rach_delay,
trx->cfg.rach_delay_set ? "Enabled" : "Disabled", VTY_NEWLINE);
vty_out(vty, " C0 Filler Table: %s%s", get_value_string(filler_names, trx->cfg.filler), VTY_NEWLINE);
vty_out(vty, " Clock Reference: %s%s", get_value_string(clock_ref_names, trx->cfg.clock_ref), VTY_NEWLINE);
vty_out(vty, " Multi-Carrier: %s%s", trx->cfg.multi_arfcn ? "Enabled" : "Disabled", VTY_NEWLINE);
vty_out(vty, " Tuning offset: %f%s", trx->cfg.offset, VTY_NEWLINE);
@@ -669,7 +666,6 @@ static int trx_vty_go_parent(struct vty *vty)
static const char trx_copyright[] =
"Copyright (C) 2007-2014 Free Software Foundation, Inc.\r\n"
"Copyright (C) 2013 Thomas Tsou <tom@tsou.cc>\r\n"
"Copyright (C) 2013-2019 Fairwaves, Inc.\r\n"
"Copyright (C) 2015 Ettus Research LLC\r\n"
"Copyright (C) 2017-2018 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>\r\n"
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
@@ -712,6 +708,8 @@ int trx_vty_init(struct trx_ctx* trx)
install_element(TRX_NODE, &cfg_dev_args_cmd);
install_element(TRX_NODE, &cfg_tx_sps_cmd);
install_element(TRX_NODE, &cfg_rx_sps_cmd);
install_element(TRX_NODE, &cfg_test_rtsc_cmd);
install_element(TRX_NODE, &cfg_test_rach_delay_cmd);
install_element(TRX_NODE, &cfg_clock_ref_cmd);
install_element(TRX_NODE, &cfg_multi_arfcn_cmd);
install_element(TRX_NODE, &cfg_offset_cmd);
@@ -720,9 +718,7 @@ int trx_vty_init(struct trx_ctx* trx)
install_element(TRX_NODE, &cfg_egprs_cmd);
install_element(TRX_NODE, &cfg_ext_rach_cmd);
install_element(TRX_NODE, &cfg_rt_prio_cmd);
install_element(TRX_NODE, &cfg_filler_type_cmd);
install_element(TRX_NODE, &cfg_filler_tsc_cmd);
install_element(TRX_NODE, &cfg_filler_rach_delay_cmd);
install_element(TRX_NODE, &cfg_filler_cmd);
install_element(TRX_NODE, &cfg_ctr_error_threshold_cmd);
install_element(TRX_NODE, &cfg_no_ctr_error_threshold_cmd);
install_element(TRX_NODE, &cfg_stack_size_cmd);
@@ -732,7 +728,5 @@ int trx_vty_init(struct trx_ctx* trx)
install_element(CHAN_NODE, &cfg_chan_rx_path_cmd);
install_element(CHAN_NODE, &cfg_chan_tx_path_cmd);
logging_vty_add_deprecated_subsys(g_trx_ctx, "lms");
return 0;
}

View File

@@ -5,8 +5,6 @@
#include "config_defs.h"
extern struct vty_app_info g_vty_info;
extern const struct value_string clock_ref_names[];
extern const struct value_string filler_names[];
/* Maximum number of physical RF channels */
#define TRX_CHAN_MAX 8
@@ -53,7 +51,9 @@ struct trx_ctx {
unsigned int tx_sps;
unsigned int rx_sps;
unsigned int rtsc;
bool rtsc_set;
unsigned int rach_delay;
bool rach_delay_set;
enum ReferenceType clock_ref;
enum FillerType filler;
bool multi_arfcn;

View File

@@ -98,7 +98,7 @@ bool Channelizer::rotate(const float *in, size_t len)
return true;
}
/* Setup channelizer parameters */
/* Setup channelizer paramaters */
Channelizer::Channelizer(size_t m, size_t blockLen, size_t hLen)
: ChannelizerBase(m, blockLen, hLen)
{

View File

@@ -225,7 +225,7 @@ bool ChannelizerBase::checkLen(size_t innerLen, size_t outerLen)
}
/*
* Setup channelizer parameters
* Setup channelizer paramaters
*/
ChannelizerBase::ChannelizerBase(size_t m, size_t blockLen, size_t hLen)
: subFilters(NULL), hInputs(NULL), hOutputs(NULL), hist(NULL),

View File

@@ -32,7 +32,7 @@ protected:
/* Buffer length validity checking */
bool checkLen(size_t innerLen, size_t outerLen);
public:
/* Initialize channelizer/synthesis filter internals */
/* Initilize channelizer/synthesis filter internals */
bool init();
};

View File

@@ -5,7 +5,7 @@ unlike the built-in complex<> templates, these inline most operations for speed
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribution.
* 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.

View File

@@ -104,3 +104,13 @@ osmo_trx_lms_LDADD = \
$(LMS_LIBS)
osmo_trx_lms_CPPFLAGS = $(AM_CPPFLAGS) $(LMS_CFLAGS)
endif
if DEVICE_XTRX
bin_PROGRAMS += osmo-trx-xtrx
osmo_trx_xtrx_SOURCES = osmo-trx.cpp
osmo_trx_xtrx_LDADD = \
$(builddir)/device/xtrx/libdevice.la \
$(COMMON_LDADD) \
$(XTRX_LIBS)
osmo_trx_xtrx_CPPFLAGS = $(AM_CPPFLAGS) $(XTRX_CFLAGS)
endif

View File

@@ -35,12 +35,12 @@ public:
Resampler(size_t p, size_t q, size_t filt_len = 16);
~Resampler();
/* Initialize resampler filterbank.
/* Initilize resampler filterbank.
* @param bw bandwidth factor on filter generation (pre-window)
* @return false on error, zero otherwise
*
* Automatic setting is to compute the filter to prevent aliasing with
* a Blackman-Harris window. Adjustment is made through a bandwidth
* a Blackman-Harris window. Adjustment is made through a bandwith
* factor to shift the cutoff and/or the constituent filter lengths.
* Calculation of specific rolloff factors or 3-dB cutoff points is
* left as an excersize for the reader.

View File

@@ -180,12 +180,12 @@ bool Transceiver::init(FillerType filler, size_t rtsc, unsigned rach_delay,
int d_srcport, d_dstport, c_srcport, c_dstport;
if (!mChans) {
LOG(FATAL) << "No channels assigned";
LOG(ALERT) << "No channels assigned";
return false;
}
if (!sigProcLibSetup()) {
LOG(FATAL) << "Failed to initialize signal processing library";
LOG(ALERT) << "Failed to initialize signal processing library";
return false;
}
@@ -285,7 +285,7 @@ bool Transceiver::start()
mLatencyUpdateTime = time;
if (!mRadioInterface->start()) {
LOG(FATAL) << "Device failed to start";
LOG(ALERT) << "Device failed to start";
return false;
}
@@ -371,12 +371,12 @@ void Transceiver::addRadioVector(size_t chan, BitVector &bits,
radioVector *radio_burst;
if (chan >= mTxPriorityQueues.size()) {
LOGCHAN(chan, DTRXDDL, FATAL) << "Invalid channel";
LOG(ALERT) << "Invalid channel " << chan;
return;
}
if (wTime.TN() > 7) {
LOGCHAN(chan, DTRXDDL, FATAL) << "Received burst with invalid slot " << wTime.TN();
LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
return;
}
@@ -419,7 +419,7 @@ void Transceiver::pushRadioVector(GSM::Time &nowTime)
state = &mStates[i];
while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
LOGCHAN(i, DTRXDDL, NOTICE) << "dumping STALE burst in TRX->SDR interface ("
LOGCHAN(i, DMAIN, NOTICE) << "dumping STALE burst in TRX->SDR interface ("
<< burst->getTime() <<" vs " << nowTime << "), retrans=" << state->mRetrans;
if (state->mRetrans)
updateFillerTable(i, burst);
@@ -606,7 +606,7 @@ int Transceiver::pullRadioVector(size_t chan, struct trx_ul_burst_ind *bi)
/* Blocking FIFO read */
radioVector *radio_burst = mReceiveFIFO[chan]->read();
if (!radio_burst) {
LOGCHAN(chan, DTRXDUL, ERROR) << "ReceiveFIFO->read() returned no burst";
LOGCHAN(chan, DMAIN, ERROR) << "ReceiveFIFO->read() returned no burst";
return -EIO;
}
@@ -651,7 +651,7 @@ int Transceiver::pullRadioVector(size_t chan, struct trx_ul_burst_ind *bi)
}
if (max_i < 0) {
LOGCHAN(chan, DTRXDUL, FATAL) << "Received empty burst";
LOG(ALERT) << "Received empty burst";
goto ret_idle;
}
@@ -678,9 +678,9 @@ int Transceiver::pullRadioVector(size_t chan, struct trx_ul_burst_ind *bi)
rc = detectAnyBurst(*burst, mTSC, BURST_THRESH, mSPSRx, type, max_toa, &ebp);
if (rc <= 0) {
if (rc == -SIGERR_CLIP)
LOGCHAN(chan, DTRXDUL, NOTICE) << "Clipping detected on received RACH or Normal Burst";
LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
else if (rc != SIGERR_NONE)
LOGCHAN(chan, DTRXDUL, NOTICE) << "Unhandled RACH or Normal Burst detection error";
LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
goto ret_idle;
}
@@ -760,7 +760,7 @@ bool Transceiver::driveControl(size_t chan)
/* Attempt to read from control socket */
msgLen = read(mCtrlSockets[chan], buffer, MAX_PACKET_LENGTH);
if (msgLen <= 0) {
LOGCHAN(chan, DTRXCTRL, NOTICE) << "mCtrlSockets read(" << mCtrlSockets[chan] << ") failed: " << msgLen;
LOGCHAN(chan, DTRXCTRL, WARNING) << "mCtrlSockets read(" << mCtrlSockets[chan] << ") failed: " << msgLen;
return false;
}
@@ -769,7 +769,7 @@ bool Transceiver::driveControl(size_t chan)
/* Verify a command signature */
if (strncmp(buffer, "CMD ", 4)) {
LOGCHAN(chan, DTRXCTRL, NOTICE) << "bogus message on control interface";
LOGC(DTRXCTRL, WARNING) << "bogus message on control interface";
return false;
}
@@ -794,7 +794,7 @@ bool Transceiver::driveControl(size_t chan)
unsigned ts = 0, ss = 0;
sscanf(params, "%u %u", &ts, &ss);
if (ts > 7 || ss > 7) {
sprintf(response, "RSP HANDOVER 1 %u %u", ts, ss);
sprintf(response, "RSP NOHANDOVER 1 %u %u", ts, ss);
} else {
mHandover[ts][ss] = true;
sprintf(response, "RSP HANDOVER 0 %u %u", ts, ss);
@@ -854,7 +854,7 @@ bool Transceiver::driveControl(size_t chan)
sscanf(params, "%d", &freqKhz);
mRxFreq = freqKhz * 1e3;
if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
LOGCHAN(chan, DTRXCTRL, FATAL) << "RX failed to tune";
LOGC(DTRXCTRL, ALERT) << "RX failed to tune";
sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
}
else
@@ -865,7 +865,7 @@ bool Transceiver::driveControl(size_t chan)
sscanf(params, "%d", &freqKhz);
mTxFreq = freqKhz * 1e3;
if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
LOGCHAN(chan, DTRXCTRL, FATAL) << "TX failed to tune";
LOGC(DTRXCTRL, ALERT) << "TX failed to tune";
sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
}
else
@@ -887,7 +887,7 @@ bool Transceiver::driveControl(size_t chan)
int timeslot;
sscanf(params, "%d %d", &timeslot, &corrCode);
if ((timeslot < 0) || (timeslot > 7)) {
LOGCHAN(chan, DTRXCTRL, NOTICE) << "bogus message on control interface";
LOGC(DTRXCTRL, WARNING) << "bogus message on control interface";
sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
return true;
}
@@ -909,21 +909,21 @@ bool Transceiver::driveControl(size_t chan)
sprintf(response, "RSP SETFORMAT %u %u", version_recv, version_recv);
}
} else if (match_cmd(command, "_SETBURSTTODISKMASK", &params)) {
// debug command! may change or disappear without notice
// debug command! may change or disapear without notice
// set a mask which bursts to dump to disk
int mask;
sscanf(params, "%d", &mask);
mWriteBurstToDiskMask = mask;
sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
} else {
LOGCHAN(chan, DTRXCTRL, NOTICE) << "bogus command " << command << " on control interface.";
LOGC(DTRXCTRL, WARNING) << "bogus command " << command << " on control interface.";
sprintf(response,"RSP ERR 1");
}
LOGCHAN(chan, DTRXCTRL, INFO) << "response is '" << response << "'";
msgLen = write(mCtrlSockets[chan], response, strlen(response) + 1);
if (msgLen <= 0) {
LOGCHAN(chan, DTRXCTRL, NOTICE) << "mCtrlSockets write(" << mCtrlSockets[chan] << ") failed: " << msgLen;
LOGCHAN(chan, DTRXCTRL, WARNING) << "mCtrlSockets write(" << mCtrlSockets[chan] << ") failed: " << msgLen;
return false;
}
return true;
@@ -940,7 +940,7 @@ bool Transceiver::driveTxPriorityQueue(size_t chan)
// check data socket
msgLen = read(mDataSockets[chan], buffer, sizeof(buffer));
if (msgLen <= 0) {
LOGCHAN(chan, DTRXDDL, NOTICE) << "mDataSockets read(" << mCtrlSockets[chan] << ") failed: " << msgLen;
LOGCHAN(chan, DTRXCTRL, WARNING) << "mDataSockets read(" << mCtrlSockets[chan] << ") failed: " << msgLen;
return false;
}
@@ -950,13 +950,13 @@ bool Transceiver::driveTxPriorityQueue(size_t chan)
break;
case sizeof(*dl) + EDGE_BURST_NBITS: /* EDGE burst */
if (mSPSTx != 4) {
LOGCHAN(chan, DTRXDDL, ERROR) << "EDGE burst received but SPS is set to " << mSPSTx;
LOG(ERR) << "EDGE burst received but SPS is set to " << mSPSTx;
return false;
}
burstLen = EDGE_BURST_NBITS;
break;
default:
LOGCHAN(chan, DTRXDDL, ERROR) << "badly formatted packet on GSM->TRX interface (len="<< msgLen << ")";
LOG(ERR) << "badly formatted packet on GSM->TRX interface (len="<< msgLen << ")";
return false;
}
@@ -972,12 +972,13 @@ bool Transceiver::driveTxPriorityQueue(size_t chan)
case 1:
break;
default:
LOGCHAN(chan, DTRXDDL, ERROR) << "Rx TRXD message with unknown header version " << unsigned(dl->common.version);
LOG(ERR) << "Rx TRXD message with unknown header version " << unsigned(dl->common.version);
return false;
}
LOGCHAN(chan, DTRXDDL, DEBUG) << "Rx TRXD message (hdr_ver=" << unsigned(dl->common.version)
<< "): fn=" << fn << ", tn=" << unsigned(dl->common.tn) << ", burst_len=" << burstLen;
LOG(DEBUG) << "Rx TRXD message (hdr_ver=" << unsigned(dl->common.version) << "): "
<< "fn=" << fn << ", tn=" << unsigned(dl->common.tn) << ", "
<< "burst_len=" << burstLen;
BitVector newBurst(burstLen);
BitVector::iterator itr = newBurst.begin();
@@ -1019,7 +1020,7 @@ void Transceiver::logRxBurst(size_t chan, const struct trx_ul_burst_ind *bi)
else os << "-";
}
LOGCHAN(chan, DTRXDUL, DEBUG) << std::fixed << std::right
LOGCHAN(chan, DMAIN, DEBUG) << std::fixed << std::right
<< " time: " << unsigned(bi->tn) << ":" << bi->fn
<< " RSSI: " << std::setw(5) << std::setprecision(1) << (bi->rssi - rssiOffset)
<< "dBFS/" << std::setw(6) << -bi->rssi << "dBm"
@@ -1037,7 +1038,7 @@ bool Transceiver::driveReceiveFIFO(size_t chan)
if ((rc = pullRadioVector(chan, &bi)) < 0) {
if (rc == -ENOENT) { /* timeslot off, continue processing */
LOGCHAN(chan, DTRXDUL, DEBUG) << unsigned(bi.tn) << ":" << bi.fn << " timeslot is off";
LOGCHAN(chan, DMAIN, DEBUG) << unsigned(bi.tn) << ":" << bi.fn << " timeslot is off";
return true;
}
return false; /* other errors: we want to stop the process */
@@ -1074,7 +1075,7 @@ void Transceiver::driveTxFIFO()
if (mOn) {
//radioClock->wait(); // wait until clock updates
LOGC(DTRXCLK, DEBUG) << "radio clock " << radioClock->get();
LOG(DEBUG) << "radio clock " << radioClock->get();
while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
// if underrun, then we're not providing bursts to radio/USRP fast
// enough. Need to increase latency by one GSM frame.
@@ -1083,9 +1084,8 @@ void Transceiver::driveTxFIFO()
// only update latency at the defined frame interval
if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
LOGC(DTRXCLK, INFO) << "new latency: " << mTransmitLatency << " (underrun "
<< radioClock->get() << " vs "
<< mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL) << ")";
LOG(INFO) << "new latency: " << mTransmitLatency << " (underrun "
<< radioClock->get() << " vs " << mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL) << ")";
mLatencyUpdateTime = radioClock->get();
}
}
@@ -1095,7 +1095,7 @@ void Transceiver::driveTxFIFO()
if (mTransmitLatency > mRadioInterface->minLatency()) {
if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
mTransmitLatency.decTN();
LOGC(DTRXCLK, INFO) << "reduced latency: " << mTransmitLatency;
LOG(INFO) << "reduced latency: " << mTransmitLatency;
mLatencyUpdateTime = radioClock->get();
}
}
@@ -1119,11 +1119,11 @@ bool Transceiver::writeClockInterface()
// FIXME -- This should be adaptive.
sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
LOGC(DTRXCLK, INFO) << "sending " << command;
LOG(INFO) << "ClockInterface: sending " << command;
msgLen = write(mClockSocket, command, strlen(command) + 1);
if (msgLen <= 0) {
LOGC(DTRXCLK, ERROR) << "mClockSocket write(" << mClockSocket << ") failed: " << msgLen;
LOG(ERROR) << "mClockSocket write(" << mClockSocket << ") failed: " << msgLen;
return false;
}
@@ -1144,7 +1144,7 @@ void *RxUpperLoopAdapter(TrxChanThParams *params)
while (1) {
if (!trx->driveReceiveFIFO(num)) {
LOGCHAN(num, DTRXDUL, FATAL) << "Something went wrong in thread " << thread_name << ", requesting stop";
LOGCHAN(num, DMAIN, FATAL) << "Something went wrong in thread " << thread_name << ", requesting stop";
osmo_signal_dispatch(SS_MAIN, S_MAIN_STOP_REQUIRED, NULL);
break;
}
@@ -1159,7 +1159,7 @@ void *RxLowerLoopAdapter(Transceiver *transceiver)
while (1) {
if (!transceiver->driveReceiveRadio()) {
LOGC(DTRXDUL, FATAL) << "Something went wrong in thread RxLower, requesting stop";
LOG(FATAL) << "Something went wrong in thread RxLower, requesting stop";
osmo_signal_dispatch(SS_MAIN, S_MAIN_STOP_REQUIRED, NULL);
break;
}
@@ -1214,7 +1214,7 @@ void *TxUpperLoopAdapter(TrxChanThParams *params)
while (1) {
if (!trx->driveTxPriorityQueue(num)) {
LOGCHAN(num, DTRXDDL, FATAL) << "Something went wrong in thread " << thread_name << ", requesting stop";
LOGCHAN(num, DMAIN, FATAL) << "Something went wrong in thread " << thread_name << ", requesting stop";
osmo_signal_dispatch(SS_MAIN, S_MAIN_STOP_REQUIRED, NULL);
break;
}

View File

@@ -216,7 +216,7 @@ private:
bool start();
void stop();
/** Protect destructor accessible stop call */
/** Protect destructor accessable stop call */
Mutex mLock;
protected:

View File

@@ -58,7 +58,7 @@ static void neon_conv_cmplx_4n(float *x, float *h, float *y, int h_len, int len)
}
#endif
/* API: Initialize convolve module */
/* API: Initalize convolve module */
void convolve_init(void)
{
/* Stub */

View File

@@ -103,7 +103,7 @@ void free_fft(struct fft_hdl *hdl)
}
/*! \brief Run multiple DFT operations with the initialized plan
* \param[in] hdl handle to an initialized fft struct
* \param[in] hdl handle to an intitialized fft struct
*
* Input and output buffers are configured with init_fft().
*/

View File

@@ -27,7 +27,7 @@
#include "config.h"
#endif
/* Architecture dependent function pointers */
/* Architecture dependant function pointers */
struct convert_cpu_context {
void (*convert_si16_ps_16n) (float *, const short *, int);
void (*convert_si16_ps) (float *, const short *, int);

View File

@@ -27,7 +27,7 @@
#include "config.h"
#endif
/* Architecture dependent function pointers */
/* Architecture dependant function pointers */
struct convolve_cpu_context {
void (*conv_cmplx_4n) (const float *, int, const float *, int, float *,
int, int, int);
@@ -66,7 +66,7 @@ int _base_convolve_complex(const float *x, int x_len,
int bounds_check(int x_len, int h_len, int y_len,
int start, int len);
/* API: Initialize convolve module */
/* API: Initalize convolve module */
void convolve_init(void)
{
c.conv_cmplx_4n = (void *)_base_convolve_complex;

View File

@@ -13,3 +13,7 @@ endif
if DEVICE_LMS
SUBDIRS += lms
endif
if DEVICE_XTRX
SUBDIRS += xtrx
endif

View File

@@ -1,7 +1,7 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribution.
* 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.
@@ -77,20 +77,23 @@ class RadioDevice {
@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 radio 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
*/
virtual int readSamples(std::vector<short *> &bufs, int len, bool *overrun,
TIMESTAMP timestamp = 0xffffffff, bool *underrun = 0) = 0;
TIMESTAMP timestamp = 0xffffffff, bool *underrun = 0,
unsigned *RSSI = 0) = 0;
/**
Write samples to the radio.
@param buf Contains the data to be written.
@param len number of samples to write.
@param underrun Set if radio 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
*/
virtual int writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
TIMESTAMP timestamp) = 0;
TIMESTAMP timestamp, bool isControl = false) = 0;
/** Update the alignment between the read and write timestamps */
virtual bool updateAlignment(TIMESTAMP timestamp)=0;

View File

@@ -154,7 +154,7 @@ std::string smpl_buf::str_status(TIMESTAMP timestamp) const
return ost.str();
}
std::string smpl_buf::str_code(int code)
std::string smpl_buf::str_code(ssize_t code)
{
switch (code) {
case ERROR_TIMESTAMP:
@@ -166,8 +166,6 @@ std::string smpl_buf::str_code(int code)
case ERROR_OVERFLOW:
return "Sample buffer: Overrun";
default:
std::stringstream ss;
ss << "Sample buffer: Unknown error " << code;
return ss.str();
return "Sample buffer: Unknown error";
}
}

View File

@@ -33,7 +33,7 @@
/*
Sample Buffer - Allows reading and writing of timed samples using osmo-trx
timestamps. Time conversions are handled
internally or accessible through the static convert calls.
internally or accessable through the static convert calls.
*/
class smpl_buf {
public:
@@ -68,7 +68,7 @@ public:
@param code an error code
@return a formatted error string
*/
static std::string str_code(int code);
static std::string str_code(ssize_t code);
enum err_code {
ERROR_TIMESTAMP = -1,

View File

@@ -20,10 +20,6 @@
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <map>
#include "trx_vty.h"
#include "Logger.h"
#include "Threads.h"
#include "LMSDevice.h"
@@ -43,74 +39,17 @@ extern "C" {
using namespace std;
#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)
#define SAMPLE_BUF_SZ (1 << 20) /* Size of Rx timestamp based Ring buffer, in bytes */
/* Device Name Prefixes as presented by LimeSuite API LMS_GetDeviceInfo(): */
#define LMS_DEV_SDR_USB_PREFIX_NAME "LimeSDR-USB"
#define LMS_DEV_SDR_MINI_PREFIX_NAME "LimeSDR-Mini"
#define LMS_DEV_NET_MICRO_PREFIX_NAME "LimeNET-Micro"
/* Device parameter descriptor */
struct dev_desc {
/* Does LimeSuite allow switching the clock source for this device?
* LimeSDR-Mini does not have switches but needs soldering to select
* external/internal clock. Any call to LMS_SetClockFreq() will fail.
*/
bool clock_src_switchable;
/* Does LimeSuite allow using REF_INTERNAL for this device?
* LimeNET-Micro does not like selecting internal clock
*/
bool clock_src_int_usable;
/* Device specific maximum tx levels selected by phasenoise measurements, in dB */
double max_tx_gain;
/* Sample rate coef (without having TX/RX samples per symbol into account) */
double rate;
/* Sample rate coef (without having TX/RX samples per symbol into account), if multi-arfcn is enabled */
double rate_multiarfcn;
/* Coefficient multiplied by TX sample rate in order to shift Tx time */
double ts_offset_coef;
/* Coefficient multiplied by TX sample rate in order to shift Tx time, if multi-arfcn is enabled */
double ts_offset_coef_multiarfcn;
/* Device Name Prefix as presented by LimeSuite API LMS_GetDeviceInfo() */
std::string name_prefix;
};
static const std::map<enum lms_dev_type, struct dev_desc> dev_param_map {
{ LMS_DEV_SDR_USB, { true, true, 73.0, GSMRATE, MCBTS_SPACING, 8.9e-5, 7.9e-5, LMS_DEV_SDR_USB_PREFIX_NAME } },
{ LMS_DEV_SDR_MINI, { false, true, 66.0, GSMRATE, MCBTS_SPACING, 8.9e-5, 8.2e-5, LMS_DEV_SDR_MINI_PREFIX_NAME } },
{ LMS_DEV_NET_MICRO, { true, false, 71.0, GSMRATE, MCBTS_SPACING, 8.9e-5, 7.9e-5, LMS_DEV_NET_MICRO_PREFIX_NAME } },
{ LMS_DEV_UNKNOWN, { true, true, 73.0, GSMRATE, MCBTS_SPACING, 8.9e-5, 7.9e-5, "UNKNOWN" } },
};
static enum lms_dev_type parse_dev_type(lms_device_t *m_lms_dev)
{
std::map<enum lms_dev_type, struct dev_desc>::const_iterator it = dev_param_map.begin();
const lms_dev_info_t* device_info = LMS_GetDeviceInfo(m_lms_dev);
while (it != dev_param_map.end())
{
enum lms_dev_type dev_type = it->first;
struct dev_desc desc = it->second;
if (strncmp(device_info->deviceName, desc.name_prefix.c_str(), desc.name_prefix.length()) == 0) {
LOGC(DDEV, INFO) << "Device identified as " << desc.name_prefix;
return dev_type;
}
it++;
}
return LMS_DEV_UNKNOWN;
}
LMSDevice::LMSDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chan_num, double lo_offset,
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, chan_num, lo_offset, tx_paths, rx_paths),
m_lms_dev(NULL), started(false), m_dev_type(LMS_DEV_UNKNOWN)
RadioDevice(tx_sps, rx_sps, iface, chans, lo_offset, tx_paths, rx_paths),
m_lms_dev(NULL)
{
LOGC(DDEV, INFO) << "creating LMS device...";
@@ -120,11 +59,6 @@ LMSDevice::LMSDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t c
tx_gains.resize(chans);
rx_buffers.resize(chans);
/* Set up per-channel Rx timestamp based Ring buffers */
for (size_t i = 0; i < rx_buffers.size(); i++)
rx_buffers[i] = new smpl_buf(SAMPLE_BUF_SZ / sizeof(uint32_t));
}
LMSDevice::~LMSDevice()
@@ -159,7 +93,7 @@ static void lms_log_callback(int lvl, const char *msg)
if ((unsigned int) lvl >= ARRAY_SIZE(lvl_map))
lvl = ARRAY_SIZE(lvl_map)-1;
LOGLV(DDEVDRV, lvl_map[lvl]) << msg;
LOGLV(DLMS, lvl_map[lvl]) << msg;
}
static void print_range(const char* name, lms_range_t *range)
@@ -176,7 +110,7 @@ static void print_range(const char* name, lms_range_t *range)
int info_list_find(lms_info_str_t* info_list, unsigned int count, const std::string &args)
{
unsigned int i, j;
std::vector<string> filters;
vector<string> filters;
filters = comma_delimited_to_vector(args.c_str());
@@ -200,11 +134,11 @@ int info_list_find(lms_info_str_t* info_list, unsigned int count, const std::str
int LMSDevice::open(const std::string &args, int ref, bool swap_channels)
{
lms_info_str_t* info_list;
const lms_dev_info_t* device_info;
lms_range_t range_sr;
float_type sr_host, sr_rf;
unsigned int i, n;
int rc, dev_id;
struct dev_desc dev_desc;
LOGC(DDEV, INFO) << "Opening LMS device..";
@@ -241,20 +175,19 @@ int LMSDevice::open(const std::string &args, int ref, bool swap_channels)
delete [] info_list;
m_dev_type = parse_dev_type(m_lms_dev);
dev_desc = dev_param_map.at(m_dev_type);
device_info = LMS_GetDeviceInfo(m_lms_dev);
if ((ref != REF_EXTERNAL) && (ref != REF_INTERNAL)){
LOGC(DDEV, ERROR) << "Invalid reference type";
goto out_close;
}
/* if reference clock is external, setup must happen _before_ calling LMS_Init */
/* if reference clock is external setup must happen _before_ calling LMS_Init */
/* FIXME make external reference frequency configurable */
if (ref == REF_EXTERNAL) {
LOGC(DDEV, INFO) << "Setting External clock reference to 10MHz";
/* FIXME: Assume an external 10 MHz reference clock. make
external reference frequency configurable */
if (!do_clock_src_freq(REF_EXTERNAL, 10000000.0))
/* Assume an external 10 MHz reference clock */
if (LMS_SetClockFreq(m_lms_dev, LMS_CLOCK_EXTREF, 10000000.0) < 0)
goto out_close;
}
@@ -264,13 +197,22 @@ int LMSDevice::open(const std::string &args, int ref, bool swap_channels)
goto out_close;
}
/* if reference clock is internal, setup must happen _after_ calling LMS_Init */
if (ref == REF_INTERNAL) {
LOGC(DDEV, INFO) << "Setting Internal clock reference";
/* Internal freq param is not used */
if (!do_clock_src_freq(REF_INTERNAL, 0))
goto out_close;
}
/* LimeSDR-Mini does not have switches but needs soldering to select external/internal clock */
/* LimeNET-Micro also does not like selecting internal clock*/
/* also set device specific maximum tx levels selected by phasenoise measurements*/
if (strncmp(device_info->deviceName,"LimeSDR-USB",11) == 0){
/* if reference clock is internal setup must happen _after_ calling LMS_Init */
/* according to lms using LMS_CLOCK_EXTREF with a frequency <= 0 is the correct way to set clock to internal reference*/
if (ref == REF_INTERNAL) {
LOGC(DDEV, INFO) << "Setting Internal clock reference";
if (LMS_SetClockFreq(m_lms_dev, LMS_CLOCK_EXTREF, -1) < 0)
goto out_close;
}
maxTxGainClamp = 73.0;
} else if (strncmp(device_info->deviceName,"LimeSDR-Mini",12) == 0)
maxTxGainClamp = 66.0;
else
maxTxGainClamp = 71.0; /* "LimeNET-Micro", etc FIXME pciE based LMS boards?*/
/* enable all used channels */
for (i=0; i<chans; i++) {
@@ -285,22 +227,16 @@ int LMSDevice::open(const std::string &args, int ref, bool swap_channels)
goto out_close;
print_range("Sample Rate", &range_sr);
if (iface == MULTI_ARFCN)
sr_host = dev_desc.rate_multiarfcn * tx_sps;
else
sr_host = dev_desc.rate * tx_sps;
LOGC(DDEV, INFO) << "Setting sample rate to " << sr_host << " " << tx_sps;
if (LMS_SetSampleRate(m_lms_dev, sr_host, 32) < 0)
LOGC(DDEV, INFO) << "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;
LOGC(DDEV, INFO) << "Sample Rate: Host=" << sr_host << " RF=" << sr_rf;
if (iface == MULTI_ARFCN)
ts_offset = static_cast<TIMESTAMP>(dev_desc.ts_offset_coef_multiarfcn * sr_host);
else
ts_offset = static_cast<TIMESTAMP>(dev_desc.ts_offset_coef * sr_host);
/* 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 */
/* configure antennas */
if (!set_antennas()) {
@@ -308,7 +244,13 @@ int LMSDevice::open(const std::string &args, int ref, bool swap_channels)
goto out_close;
}
return iface == MULTI_ARFCN ? MULTI_ARFCN : NORMAL;
/* Set up per-channel Rx timestamp based Ring buffers */
for (size_t i = 0; i < rx_buffers.size(); i++)
rx_buffers[i] = new smpl_buf(SAMPLE_BUF_SZ / sizeof(uint32_t));
started = false;
return NORMAL;
out_close:
LOGC(DDEV, FATAL) << "Error in LMS open, closing: " << LMS_GetLastErrorMessage();
@@ -402,43 +344,6 @@ bool LMSDevice::stop()
return true;
}
bool LMSDevice::do_clock_src_freq(enum ReferenceType ref, double freq)
{
struct dev_desc dev_desc = dev_param_map.at(m_dev_type);
size_t lms_clk_id;
switch (ref) {
case REF_EXTERNAL:
lms_clk_id = LMS_CLOCK_EXTREF;
break;
case REF_INTERNAL:
if (!dev_desc.clock_src_int_usable) {
LOGC(DDEV, ERROR) << "Device type " << dev_desc.name_prefix
<< " doesn't support internal reference clock";
return false;
}
/* According to lms using LMS_CLOCK_EXTREF with a
frequency <= 0 is the correct way to set clock to
internal reference */
lms_clk_id = LMS_CLOCK_EXTREF;
freq = -1;
break;
default:
LOGC(DDEV, ERROR) << "Invalid reference type " << get_value_string(clock_ref_names, ref);
return false;
}
if (dev_desc.clock_src_switchable) {
if (LMS_SetClockFreq(m_lms_dev, lms_clk_id, freq) < 0)
return false;
} else {
LOGC(DDEV, INFO) << "Device type " << dev_desc.name_prefix
<< " doesn't support switching clock source through SW";
}
return true;
}
/* do rx/tx calibration - depends on gain, freq and bw */
bool LMSDevice::do_calib(size_t chan)
{
@@ -480,7 +385,7 @@ bool LMSDevice::do_filters(size_t chan)
double LMSDevice::maxTxGain()
{
return dev_param_map.at(m_dev_type).max_tx_gain;
return maxTxGainClamp;
}
double LMSDevice::minTxGain()
@@ -719,7 +624,7 @@ void LMSDevice::update_stream_stats_rx(size_t chan, bool *overrun)
m_ctr[chan].rx_overruns += status.overrun;
/* Dropped packets in Rx are counted when gaps in Rx timestamps are
detected (likely because buffer overflow in hardware). Value count
detected (likely because buffer oveflow in hardware). Value count
since the last call to LMS_GetStreamStatus(stream). */
if (status.droppedPackets) {
changed = true;
@@ -739,7 +644,7 @@ void LMSDevice::update_stream_stats_rx(size_t chan, bool *overrun)
// NOTE: Assumes sequential reads
int LMSDevice::readSamples(std::vector < short *>&bufs, int len, bool * overrun,
TIMESTAMP timestamp, bool * underrun)
TIMESTAMP timestamp, bool * underrun, unsigned *RSSI)
{
int rc, num_smpls, expect_smpls;
ssize_t avail_smpls;
@@ -806,9 +711,8 @@ int LMSDevice::readSamples(std::vector < short *>&bufs, int len, bool * overrun,
for (size_t i = 0; i < rx_buffers.size(); i++) {
rc = rx_buffers[i]->read(bufs[i], len, timestamp);
if ((rc < 0) || (rc != len)) {
LOGCHAN(i, DDEV, ERROR) << rx_buffers[i]->str_code(rc) << ". "
<< rx_buffers[i]->str_status(timestamp)
<< ", (len=" << len << ")";
LOGC(DDEV, ERROR) << rx_buffers[i]->str_code(rc);
LOGC(DDEV, ERROR) << rx_buffers[i]->str_status(timestamp);
return 0;
}
}
@@ -858,7 +762,8 @@ void LMSDevice::update_stream_stats_tx(size_t chan, bool *underrun)
}
int LMSDevice::writeSamples(std::vector < short *>&bufs, int len,
bool * underrun, unsigned long long timestamp)
bool * underrun, unsigned long long timestamp,
bool isControl)
{
int rc = 0;
unsigned int i;
@@ -867,6 +772,11 @@ int LMSDevice::writeSamples(std::vector < short *>&bufs, int len,
tx_metadata.waitForTimestamp = true;
tx_metadata.timestamp = timestamp - ts_offset; /* Shift Tx time by offset */
if (isControl) {
LOGC(DDEV, ERROR) << "Control packets not supported";
return 0;
}
if (bufs.size() != chans) {
LOGC(DDEV, ERROR) << "Invalid channel combination " << bufs.size();
return -1;

View File

@@ -4,7 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0+
*
* This software is distributed under multiple licenses; see the COPYING file in
* the main directory for licensing information for this specific distribution.
* 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.
@@ -41,13 +41,6 @@
* A^2 = 1 */
#define LIMESDR_TX_AMPL 0.707
enum lms_dev_type {
LMS_DEV_SDR_USB, /* LimeSDR-USB */
LMS_DEV_SDR_MINI, /* LimeSDR-Mini */
LMS_DEV_NET_MICRO, /* LimeNet-micro */
LMS_DEV_UNKNOWN,
};
/** A class to handle a LimeSuite supported device */
class LMSDevice:public RadioDevice {
@@ -66,8 +59,7 @@ private:
TIMESTAMP ts_initial, ts_offset;
std::vector<double> tx_gains, rx_gains;
enum lms_dev_type m_dev_type;
double maxTxGainClamp;
bool do_calib(size_t chan);
bool do_filters(size_t chan);
@@ -76,12 +68,11 @@ private:
bool flush_recv(size_t num_pkts);
void update_stream_stats_rx(size_t chan, bool *overrun);
void update_stream_stats_tx(size_t chan, bool *underrun);
bool do_clock_src_freq(enum ReferenceType ref, double freq);
public:
/** Object constructor */
LMSDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chan_num, double lo_offset,
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);
~LMSDevice();
@@ -106,21 +97,24 @@ public:
@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);
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);
TIMESTAMP timestamp = 0xffffffff, bool isControl =
false);
/** Update the alignment between the read and write timestamps */
bool updateAlignment(TIMESTAMP timestamp);

View File

@@ -33,12 +33,11 @@
#include "config.h"
#endif
#ifdef USE_UHD_3_11
#include <uhd/utils/log_add.hpp>
#include <uhd/utils/thread.hpp>
#else
#ifndef USE_UHD_3_11
#include <uhd/utils/msg.hpp>
#include <uhd/utils/thread_priority.hpp>
#else
#include <uhd/utils/thread.hpp>
#endif
#define USRP_TX_AMPL 0.3
@@ -121,8 +120,6 @@ static const std::map<dev_key, dev_desc> dev_param_map {
{ std::make_tuple(UMTRX, 4, 4), { 2, 0.0, GSMRATE, 5.1503e-5, "UmTRX 4 SPS" } },
{ std::make_tuple(LIMESDR, 4, 4), { 1, GSMRATE*32, GSMRATE, 8.9e-5, "LimeSDR 4 SPS" } },
{ std::make_tuple(B2XX_MCBTS, 4, 4), { 1, 51.2e6, MCBTS_SPACING*4, B2XX_TIMING_MCBTS, "B200/B210 4 SPS Multi-ARFCN" } },
{ std::make_tuple(OCR01, 4, 1), { 2, 26e6, GSMRATE, B2XX_TIMING_4SPS, "OCR01 4/1 Tx/Rx SPS"} },
{ std::make_tuple(OCR01, 4, 4), { 2, 26e6, GSMRATE, B2XX_TIMING_4_4SPS, "OCR01 4/4 Tx/Rx SPS"} },
};
void *async_event_loop(uhd_device *dev)
@@ -137,52 +134,23 @@ void *async_event_loop(uhd_device *dev)
return NULL;
}
#ifdef USE_UHD_3_11
static void uhd_log_handler(const uhd::log::logging_info &info)
{
int level;
switch (info.verbosity)
{
case uhd::log::trace:
case uhd::log::debug:
level = LOGL_DEBUG;
break;
case uhd::log::info:
level = LOGL_INFO;
break;
case uhd::log::warning:
level = LOGL_NOTICE;
break;
case uhd::log::error:
level = LOGL_ERROR;
break;
case uhd::log::fatal:
level = LOGL_FATAL;
break;
default:
level = LOGL_NOTICE;
}
LOGSRC(DDEVDRV, level, info.file.c_str(), info.line) << "[" << info.component << "] " << info.message;
}
#else
#ifndef USE_UHD_3_11
/*
Catch and drop underrun 'U' and overrun 'O' messages from stdout
since we already report using the logging facility. Direct
everything else appropriately.
*/
static void uhd_msg_handler(uhd::msg::type_t type, const std::string &msg)
void uhd_msg_handler(uhd::msg::type_t type, const std::string &msg)
{
switch (type) {
case uhd::msg::status:
LOGC(DDEVDRV, INFO) << msg;
LOGC(DDEV, INFO) << msg;
break;
case uhd::msg::warning:
LOGC(DDEVDRV, NOTICE) << msg;
LOGC(DDEV, WARNING) << msg;
break;
case uhd::msg::error:
LOGC(DDEVDRV, ERROR) << msg;
LOGC(DDEV, ERROR) << msg;
break;
case uhd::msg::fastpath:
break;
@@ -191,10 +159,10 @@ static void uhd_msg_handler(uhd::msg::type_t type, const std::string &msg)
#endif
uhd_device::uhd_device(size_t tx_sps, size_t rx_sps,
InterfaceType iface, size_t chan_num, double lo_offset,
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, chan_num, lo_offset, tx_paths, rx_paths),
: 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),
@@ -370,7 +338,6 @@ bool uhd_device::parse_dev_type()
{ "USRP2", { USRP2, TX_WINDOW_FIXED } },
{ "UmTRX", { UMTRX, TX_WINDOW_FIXED } },
{ "LimeSDR", { LIMESDR, TX_WINDOW_FIXED } },
{ "OCR01", { OCR01, TX_WINDOW_USRP1 } },
};
// Compare UHD motherboard and device strings */
@@ -412,7 +379,7 @@ static bool uhd_e3xx_version_chk()
void uhd_device::set_channels(bool swap)
{
if (iface == MULTI_ARFCN) {
if (dev_type != B200 && dev_type != B210 && dev_type != OCR01)
if (dev_type != B200 && dev_type != B210)
throw std::invalid_argument("Device does not support MCBTS");
dev_type = B2XX_MCBTS;
}
@@ -424,7 +391,6 @@ void uhd_device::set_channels(bool swap)
switch (dev_type) {
case B210:
case E3XX:
case OCR01:
if (chans == 1)
subdev_string = swap ? "A:B" : "A:A";
else if (chans == 2)
@@ -452,16 +418,6 @@ int uhd_device::open(const std::string &args, int ref, bool swap_channels)
{
const char *refstr;
/* Register msg handler. Different APIs depending on UHD version */
#ifdef USE_UHD_3_11
uhd::log::add_logger("OsmoTRX", &uhd_log_handler);
uhd::log::set_log_level(uhd::log::debug);
uhd::log::set_console_level(uhd::log::off);
uhd::log::set_logger_level("OsmoTRX", uhd::log::debug);
#else
uhd::msg::register_handler(&uhd_msg_handler);
#endif
// Find UHD devices
uhd::device_addr_t addr(args);
uhd::device_addrs_t dev_addrs = uhd::device::find(addr);
@@ -570,7 +526,7 @@ int uhd_device::open(const std::string &args, int ref, bool swap_channels)
init_gains();
// Print configuration
LOGC(DDEV, INFO) << "Device configuration: " << usrp_dev->get_pp_string();
LOGC(DDEV, INFO) << "\n" << usrp_dev->get_pp_string();
if (iface == MULTI_ARFCN)
return MULTI_ARFCN;
@@ -586,7 +542,6 @@ int uhd_device::open(const std::string &args, int ref, bool swap_channels)
case E1XX:
case E3XX:
case LIMESDR:
case OCR01:
default:
break;
}
@@ -649,6 +604,10 @@ bool uhd_device::start()
return false;
}
#ifndef USE_UHD_3_11
// Register msg handler
uhd::msg::register_handler(&uhd_msg_handler);
#endif
// Start asynchronous event (underrun check) loop
async_event_thrd = new Thread();
async_event_thrd->start((void * (*)(void*))async_event_loop, (void*)this);
@@ -726,7 +685,7 @@ int uhd_device::check_rx_md_err(uhd::rx_metadata_t &md, ssize_t num_smpls)
}
int uhd_device::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
TIMESTAMP timestamp, bool *underrun)
TIMESTAMP timestamp, bool *underrun, unsigned *RSSI)
{
ssize_t rc;
uhd::time_spec_t ts;
@@ -783,7 +742,7 @@ int uhd_device::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
for (size_t i = 0; i < rx_buffers.size(); i++) {
rc = rx_buffers[i]->write((short *) &pkt_bufs[i].front(),
num_smpls,
ts.to_ticks(rx_rate));
metadata.time_spec.to_ticks(rx_rate));
// Continue on local overrun, exit on other errors
if ((rc < 0)) {
@@ -809,7 +768,7 @@ int uhd_device::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
}
int uhd_device::writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
unsigned long long timestamp)
unsigned long long timestamp,bool isControl)
{
uhd::tx_metadata_t metadata;
metadata.has_time_spec = true;
@@ -819,6 +778,12 @@ int uhd_device::writeSamples(std::vector<short *> &bufs, int len, bool *underrun
*underrun = false;
// No control packets
if (isControl) {
LOGC(DDEV, ERROR) << "Control packets not supported";
return 0;
}
if (bufs.size() != chans) {
LOGC(DDEV, ALERT) << "Invalid channel combination " << bufs.size();
return -1;
@@ -918,18 +883,15 @@ bool uhd_device::set_freq(double freq, size_t chan, bool tx)
std::vector<double> freqs;
uhd::tune_result_t tres;
uhd::tune_request_t treq = select_freq(freq, chan, tx);
std::string str_dir;
if (tx) {
tres = usrp_dev->set_tx_freq(treq, chan);
tx_freqs[chan] = usrp_dev->get_tx_freq(chan);
str_dir = "Tx";
} else {
tres = usrp_dev->set_rx_freq(treq, chan);
rx_freqs[chan] = usrp_dev->get_rx_freq(chan);
str_dir = "Rx";
}
LOGCHAN(chan, DDEV, INFO) << "set_freq(" << freq << ", " << str_dir << "): " << tres.to_pp_string() << std::endl;
LOGC(DDEV, INFO) << "\n" << tres.to_pp_string() << std::endl;
if ((chans == 1) || ((chans == 2) && dev_type == UMTRX))
return true;
@@ -949,7 +911,7 @@ bool uhd_device::set_freq(double freq, size_t chan, bool tx)
rx_freqs[!chan] = usrp_dev->get_rx_freq(!chan);
}
LOGCHAN(chan, DDEV, INFO) << "set_freq(" << freq << ", " << str_dir << "): " << tres.to_pp_string() << std::endl;
LOGC(DDEV, INFO) << "\n" << tres.to_pp_string() << std::endl;
}
return true;

View File

@@ -50,7 +50,6 @@ enum uhd_dev_type {
X3XX,
UMTRX,
LIMESDR,
OCR01,
};
/*
@@ -63,7 +62,7 @@ enum uhd_dev_type {
class uhd_device : public RadioDevice {
public:
uhd_device(size_t tx_sps, size_t rx_sps, InterfaceType type,
size_t chan_num, double offset,
size_t chans, double offset,
const std::vector<std::string>& tx_paths,
const std::vector<std::string>& rx_paths);
~uhd_device();
@@ -75,10 +74,10 @@ public:
enum TxWindowType getWindowType() { return tx_window; }
int readSamples(std::vector<short *> &bufs, int len, bool *overrun,
TIMESTAMP timestamp, bool *underrun);
TIMESTAMP timestamp, bool *underrun, unsigned *RSSI);
int writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
TIMESTAMP timestamp);
TIMESTAMP timestamp, bool isControl);
bool updateAlignment(TIMESTAMP timestamp);

View File

@@ -61,10 +61,10 @@ const dboardConfigType dboardConfig = TXA_RXB;
const double USRPDevice::masterClockRate = 52.0e6;
USRPDevice::USRPDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface,
size_t chan_num, double lo_offset,
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, chan_num, lo_offset, tx_paths, rx_paths)
RadioDevice(tx_sps, rx_sps, iface, chans, lo_offset, tx_paths, rx_paths)
{
LOGC(DDEV, INFO) << "creating USRP device...";
@@ -365,7 +365,7 @@ GSM::Time USRPDevice::minLatency() {
// NOTE: Assumes sequential reads
int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
TIMESTAMP timestamp, bool *underrun)
TIMESTAMP timestamp, bool *underrun, unsigned *RSSI)
{
#ifndef SWLOOPBACK
if (!m_uRx)
@@ -433,10 +433,8 @@ int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
*underrun = true;
LOGC(DDEV, DEBUG) << "UNDERRUN in TRX->USRP interface";
}
#if 0
/* FIXME: Do something with this ? */
unsigned RSSI = (word0 >> 21) & 0x3f;
#endif
if (RSSI) *RSSI = (word0 >> 21) & 0x3f;
if (!isAligned) continue;
unsigned cursorStart = pktTimestamp - timeStart + dataStart;
@@ -515,8 +513,9 @@ int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
#endif
}
int USRPDevice::writeSamplesControl(std::vector<short *> &bufs, int len,
bool *underrun, unsigned long long timestamp, bool isControl)
int USRPDevice::writeSamples(std::vector<short *> &bufs, int len,
bool *underrun, unsigned long long timestamp,
bool isControl)
{
writeLock.lock();
@@ -570,12 +569,6 @@ int USRPDevice::writeSamplesControl(std::vector<short *> &bufs, int len,
#endif
}
int USRPDevice::writeSamples(std::vector<short *> &bufs, int len,
bool *underrun, unsigned long long timestamp)
{
return writeSamplesControl(bufs, len, underrun, timestamp, false);
}
bool USRPDevice::updateAlignment(TIMESTAMP timestamp)
{
#ifndef SWLOOPBACK
@@ -585,7 +578,7 @@ bool USRPDevice::updateAlignment(TIMESTAMP timestamp)
bool tmpUnderrun;
std::vector<short *> buf(1, data);
if (writeSamplesControl(buf, 1, &tmpUnderrun, timestamp & 0x0ffffffffll, true)) {
if (writeSamples(buf, 1, &tmpUnderrun, timestamp & 0x0ffffffffll, true)) {
pingTimestamp = timestamp;
return true;
}

View File

@@ -4,7 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0+
*
* This software is distributed under multiple licenses; see the COPYING file in
* the main directory for licensing information for this specific distribution.
* 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.
@@ -82,9 +82,6 @@ private:
double rxGain;
double txGain;
int writeSamplesControl(std::vector<short *> &bufs, int len, bool *underrun,
TIMESTAMP timestamp = 0xffffffff, bool isControl = false);
#ifdef SWLOOPBACK
short loopbackBuffer[1000000];
int loopbackBufferSize;
@@ -98,7 +95,7 @@ private:
public:
/** Object constructor */
USRPDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chan_num, double lo_offset,
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);
@@ -120,20 +117,23 @@ private:
@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 USRP 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);
TIMESTAMP timestamp = 0xffffffff, bool *underrun = NULL,
unsigned *RSSI = NULL);
/**
Write samples to the USRP.
@param buf Contains the data to be written.
@param len number of samples to write.
@param underrun Set if USRP 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);
TIMESTAMP timestamp = 0xffffffff, bool isControl = false);
/** Update the alignment between the read and write timestamps */
bool updateAlignment(TIMESTAMP timestamp);

View File

@@ -0,0 +1,10 @@
include $(top_srcdir)/Makefile.common
AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) -I${srcdir}/../common
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)
noinst_HEADERS = XTRXDevice.h
noinst_LTLIBRARIES = libdevice.la
libdevice_la_SOURCES = XTRXDevice.cpp

View File

@@ -0,0 +1,456 @@
/*
* Copyright 2018 Sergey Kostanbaev <sergey.kostanbaev@fairwaves.co>
* Copyright 2019 Alexander Chemeris <alexander.chemeris@fairwaves.co>
*
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 "Threads.h"
#include "XTRXDevice.h"
#include <Logger.h>
#include <errno.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
using namespace std;
const double defaultRXBandwidth = 0.5e6;
const double defaultTXBandwidth = 1.5e6;
static int time_tx_corr = 60;
XTRXDevice::XTRXDevice(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 XTRX device:"
<< " RXSPS: " << rx_sps
<< " TXSPS: " << tx_sps
<< " chans: " << chans
<< " lo_off: " << lo_offset
<< " rx_path(0): " << (rx_paths.size() ? rx_paths[0] : "<>")
<< " tx_path(0): " << (tx_paths.size() ? tx_paths[0] : "<>");
txsps = tx_sps;
rxsps = rx_sps;
rxGain = 0;
txGain = 0;
loopback = false;
device = NULL;
}
static int parse_config(const char* line, const char* argument, int default_value)
{
const char* arg_found = strstr(line, argument);
if (!arg_found)
return default_value;
const char* qe_pos = strchr(arg_found, '=');
if (!qe_pos)
return default_value;
int res = strtol(qe_pos + 1, NULL, 10);
if (res == 0 && errno) {
return default_value;
}
return res;
}
int XTRXDevice::open(const std::string &args, int ref, bool swap_channels)
{
LOG(INFO) << "opening XTRX device '" << args << "'..";
int loglevel = parse_config(args.c_str(), "loglevel", 3);
int lb_param = parse_config(args.c_str(), "loopback", 0);
time_tx_corr = parse_config(args.c_str(), "tcorr", time_tx_corr);
int fref = parse_config(args.c_str(), "refclk", 26000000);
int rxdec = parse_config(args.c_str(), "rxdec", 0);
char xtrx_name[500];
const char* lend = strchr(args.c_str(), ',');
int len = (lend) ? (lend - args.c_str()) : sizeof(xtrx_name) - 1;
strncpy(xtrx_name, args.c_str(), len);
xtrx_name[len] = 0;
if ((txsps % 2) || (rxsps % 2)) {
LOG(ALERT) << "XTRX TxSPS/RxSPS must be even!";
return -1;
}
if (lb_param) {
LOG(ALERT) << "XTRX LOOPBACK mode is set!";
loopback = true;
}
int res = xtrx_open(xtrx_name, loglevel, &device);
if (res) {
LOG(ALERT) << "XTRX creating failed, device " << xtrx_name << " code " << res;
return -1;
}
double actualMasterClock = 0;
if (fref > 0) {
xtrx_set_ref_clk(device, fref, XTRX_CLKSRC_INT);
}
res = xtrx_set_samplerate(device,
GSMRATE * (double) std::min(txsps, rxsps) * 32 * 4 * ((rxdec) ? 2 : 1),
GSMRATE * (double) rxsps,
GSMRATE * (double) txsps,
(rxdec) ? XTRX_SAMPLERATE_FORCE_RX_DECIM : 0,
&actualMasterClock,
&actualRXSampleRate,
&actualTXSampleRate);
if (res) {
LOG(ALERT) << "XTRX failed to set samplerate RX: " << GSMRATE * (double) rxsps
<< " TX: " << GSMRATE * (double) txsps
<< " res: " << res;
return -1;
} else {
LOG(INFO) << "XTRX set samplerate Master: " << actualMasterClock
<< " RX: " << actualRXSampleRate
<< " TX: " << actualTXSampleRate;
}
double bw;
double actualbw;
actualbw = 0;
bw = defaultRXBandwidth;
res = xtrx_tune_rx_bandwidth(device, XTRX_CH_AB, bw, &actualbw);
if (res) {
LOG(ALERT) << "XTRX failed to set RX bandwidth: " << bw
<< " res: " << res;
} else {
LOG(INFO) << "XTRX set RX bandwidth: " << actualbw;
}
actualbw = 0;
bw = defaultTXBandwidth;
res = xtrx_tune_tx_bandwidth(device, XTRX_CH_AB, bw, &actualbw);
if (res) {
LOG(ALERT) << "XTRX failed to set TX bandwidth: " << bw
<< " res: " << res;
} else {
LOG(INFO) << "XTRX set TX bandwidth: " << actualbw;
}
samplesRead = 0;
samplesWritten = 0;
started = false;
return NORMAL;
}
XTRXDevice::~XTRXDevice()
{
if (device) {
xtrx_close(device);
}
}
bool XTRXDevice::start()
{
LOG(INFO) << "starting XTRX...";
if (started) {
return false;
}
dataStart = 0;
dataEnd = 0;
timeStart = 0;
timeEnd = 0;
timeRx = initialReadTimestamp();
timestampOffset = 0;
latestWriteTimestamp = 0;
lastPktTimestamp = 0;
hi32Timestamp = 0;
isAligned = false;
xtrx_stop(device, XTRX_TX);
xtrx_stop(device, XTRX_RX);
xtrx_set_antenna(device, XTRX_TX_AUTO);
xtrx_set_antenna(device, XTRX_RX_AUTO);
xtrx_run_params_t params;
params.dir = XTRX_TRX;
params.nflags = (loopback) ? XTRX_RUN_DIGLOOPBACK : 0;
params.rx.chs = XTRX_CH_AB;
params.rx.flags = XTRX_RSP_SISO_MODE;
params.rx.hfmt = XTRX_IQ_INT16;
params.rx.wfmt = XTRX_WF_16;
params.rx.paketsize = 625 * rxsps;
params.tx.chs = XTRX_CH_AB;
params.tx.flags = XTRX_RSP_SISO_MODE;
params.tx.hfmt = XTRX_IQ_INT16;
params.tx.wfmt = XTRX_WF_16;
params.tx.paketsize = 625 * txsps;
if (loopback) {
params.tx.flags |= XTRX_RSP_SWAP_AB | XTRX_RSP_SWAP_IQ;
}
params.tx_repeat_buf = NULL;
params.rx_stream_start = initialReadTimestamp();
int res = xtrx_run_ex(device, &params);
if (res) {
LOG(ALERT) << "XTRX start failed res: " << res;
} else {
LOG(INFO) << "XTRX started";
started = true;
}
return started;
}
bool XTRXDevice::stop()
{
if (started) {
int res = xtrx_stop(device, XTRX_TRX);
if (res) {
LOG(ALERT) << "XTRX stop failed res: " << res;
} else {
LOG(INFO) << "XTRX stopped";
started = false;
}
}
return !started;
}
TIMESTAMP XTRXDevice::initialWriteTimestamp()
{
if (/*(iface == MULTI_ARFCN) || */(rxsps == txsps))
return initialReadTimestamp();
else
return initialReadTimestamp() * txsps;
}
double XTRXDevice::maxTxGain()
{
return 30;
}
double XTRXDevice::minTxGain()
{
return 0;
}
double XTRXDevice::maxRxGain()
{
return 30;
}
double XTRXDevice::minRxGain()
{
return 0;
}
double XTRXDevice::setTxGain(double dB, size_t chan)
{
if (chan) {
LOG(ALERT) << "Invalid channel " << chan;
return 0.0;
}
LOG(NOTICE) << "Setting TX gain to " << dB << " dB.";
int res = xtrx_set_gain(device, XTRX_CH_AB, XTRX_TX_PAD_GAIN, dB - 30, &txGain);
if (res) {
LOG(ERR) << "Error setting TX gain res: " << res;
} else {
LOG(NOTICE) << "Actual TX gain: " << txGain << " dB.";
}
return txGain;
}
double XTRXDevice::setRxGain(double dB, size_t chan)
{
if (chan) {
LOG(ALERT) << "Invalid channel " << chan;
return 0.0;
}
LOG(NOTICE) << "Setting RX gain to " << dB << " dB.";
int res = xtrx_set_gain(device, XTRX_CH_AB, XTRX_RX_LNA_GAIN, dB, &rxGain);
if (res) {
LOG(ERR) << "Error setting RX gain res: " << res;
} else {
LOG(NOTICE) << "Actual RX gain: " << rxGain << " dB.";
}
return rxGain;
}
// NOTE: Assumes sequential reads
int XTRXDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
TIMESTAMP timestamp, bool *underrun, unsigned *RSSI)
{
if (!started)
return -1;
struct xtrx_recv_ex_info ri;
ri.samples = len;
ri.buffer_count = bufs.size();
ri.buffers = (void* const*)&bufs[0];
ri.flags = 0;
int res = xtrx_recv_sync_ex(device, &ri);
if (res) {
LOG(ALERT) << "xtrx_recv_sync failed res " << res << " current TS " << timeRx << " req TS" << timestamp;
return -1;
}
timeRx += len;
// TODO get rid of it!
int i;
for (i = 0; i < len * 2; i++)
bufs[0][i] <<= 4;
if (underrun)
*underrun = (ri.out_events & RCVEX_EVENT_FILLED_ZERO);
return len;
}
int XTRXDevice::writeSamples(std::vector<short *> &bufs, int len,
bool *underrun, unsigned long long timestamp,
bool isControl)
{
if (!started)
return 0;
xtrx_send_ex_info_t nfo;
nfo.buffers = (const void* const*)&bufs[0];
nfo.buffer_count = bufs.size();
nfo.flags = XTRX_TX_DONT_BUFFER;
nfo.samples = len;
nfo.ts = timestamp - time_tx_corr;
int res = xtrx_send_sync_ex(device, &nfo);
if (res != 0) {
LOG(ALERT) << "xtrx_send_sync_ex returned " << res << " len=" << len << " ts=" << timestamp;
return 0;
}
if (*underrun) {
*underrun = (nfo.out_flags & XTRX_TX_DISCARDED_TO);
}
return len;
}
bool XTRXDevice::setRxAntenna(const std::string & ant, size_t chan)
{
LOG(ALERT) << "CH" << chan << ": RX ANTENNA: " << ant.c_str() << " (SETTING RX ANTENNA IS NOT IMPLEMENTED)";
return true;
}
std::string XTRXDevice::getRxAntenna(size_t chan)
{
return "";
}
bool XTRXDevice::setTxAntenna(const std::string & ant, size_t chan)
{
LOG(ALERT) << "CH" << chan << ": TX ANTENNA: " << ant.c_str() << " (SETTING TX ANTENNA IS NOT IMPLEMENTED)";
return true;
}
std::string XTRXDevice::getTxAntenna(size_t chan )
{
return "";
}
bool XTRXDevice::requiresRadioAlign()
{
return false;
}
GSM::Time XTRXDevice::minLatency()
{
return GSM::Time(6,7);
}
bool XTRXDevice::updateAlignment(TIMESTAMP timestamp)
{
LOG(ALERT) << "Update Aligment " << timestamp;
return true;
}
bool XTRXDevice::setTxFreq(double wFreq, size_t chan)
{
int res;
double actual = 0;
if (chan) {
LOG(ALERT) << "Invalid channel " << chan;
return false;
}
if ((res = xtrx_tune(device, XTRX_TUNE_TX_FDD, wFreq, &actual)) == 0) {
LOG(INFO) << "set RX: " << wFreq << std::endl
<< " actual freq: " << actual << std::endl;
return true;
}
else {
LOG(ALERT) << "set RX: " << wFreq << "failed (code: " << res << ")" << std::endl;
return false;
}
}
bool XTRXDevice::setRxFreq(double wFreq, size_t chan)
{
int res;
double actual = 0;
if (chan) {
LOG(ALERT) << "Invalid channel " << chan;
return false;
}
if ((res = xtrx_tune(device, XTRX_TUNE_RX_FDD, wFreq, &actual)) == 0) {
LOG(INFO) << "set RX: " << wFreq << std::endl
<< " actual freq: " << actual << std::endl;
return true;
}
else {
LOG(ALERT) << "set RX: " << wFreq << "failed (code: " << res << ")" << std::endl;
return false;
}
}
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 XTRXDevice(tx_sps, rx_sps, iface, chans, lo_offset, tx_paths, rx_paths);
}

View File

@@ -0,0 +1,180 @@
#ifndef _XTRX_DEVICE_H_
#define _XTRX_DEVICE_H_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "radioDevice.h"
#include <stdint.h>
#include <sys/time.h>
#include <string>
#include <iostream>
#include "Threads.h"
#include <xtrx_api.h>
class XTRXDevice: public RadioDevice {
private:
int txsps;
int rxsps;
double actualTXSampleRate; ///< the actual XTRX sampling rate
double actualRXSampleRate; ///< the actual XTRX sampling rate
//unsigned int decimRate; ///< the XTRX decimation rate
//unsigned int interRate; ///< the XTRX decimation rate
unsigned long long samplesRead; ///< number of samples read from XTRX
unsigned long long samplesWritten; ///< number of samples sent to XTRX
bool started; ///< flag indicates XTRX has started
short *data;
unsigned long dataStart;
unsigned long dataEnd;
TIMESTAMP timeStart;
TIMESTAMP timeEnd;
TIMESTAMP timeRx;
bool isAligned;
Mutex writeLock;
short *currData; ///< internal data buffer when reading from XTRX
TIMESTAMP currTimestamp; ///< timestamp of internal data buffer
unsigned currLen; ///< size of internal data buffer
TIMESTAMP timestampOffset; ///< timestamp offset b/w Tx and Rx blocks
TIMESTAMP latestWriteTimestamp; ///< timestamp of most recent ping command
TIMESTAMP pingTimestamp; ///< timestamp of most recent ping response
unsigned long hi32Timestamp;
unsigned long lastPktTimestamp;
double rxGain;
double txGain;
bool loopback;
xtrx_dev* device;
public:
/** Object constructor */
XTRXDevice(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);
~XTRXDevice();
/** Instantiate the XTRX */
int open(const std::string &args, int ref, bool swap_channels);
/** Start the XTRX */
bool start();
/** Stop the XTRX */
bool stop();
/** Set priority not supported */
void setPriority(float prio = 0.5) { }
enum TxWindowType getWindowType() { return TX_WINDOW_FIXED; }
/**
Read samples from the XTRX.
@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 XTRX 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 XTRX.
@param buf Contains the data to be written.
@param len number of samples to write.
@param underrun Set if XTRX 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);
/** Returns the starting read Timestamp*/
TIMESTAMP initialReadTimestamp(void) { return 20000;}
/** returns the full-scale transmit amplitude **/
double fullScaleInputValue() {return (double) 32767*0.7;}
/** returns the full-scale receive amplitude **/
double fullScaleOutputValue() {return (double) 32767;}
/** 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);
/** gets the current transmit gain **/
double getTxGain(size_t chan = 0) { return txGain; }
/** 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 actualTXSampleRate; }
inline double numberRead() { return samplesRead; }
inline double numberWritten() { return samplesWritten; }
};
#endif // _XTRX_DEVICE_H_

View File

@@ -334,12 +334,14 @@ static void handle_options(int argc, char **argv, struct trx_ctx* trx)
break;
case 'r':
print_deprecated(option);
trx->cfg.rtsc_set = true;
trx->cfg.rtsc = atoi(optarg);
if (!trx->cfg.egprs) /* Don't override egprs which sets different filler */
trx->cfg.filler = FILLER_NORM_RAND;
break;
case 'A':
print_deprecated(option);
trx->cfg.rach_delay_set = true;
trx->cfg.rach_delay = atoi(optarg);
trx->cfg.filler = FILLER_ACCESS_RAND;
break;
@@ -381,11 +383,6 @@ static void handle_options(int argc, char **argv, struct trx_ctx* trx)
}
}
if (argc > optind) {
LOG(ERROR) << "Unsupported positional arguments on command line";
goto bad_config;
}
/* Cmd line option specific validation & setup */
if (trx->cfg.num_chans > TRX_CHAN_MAX) {
@@ -462,9 +459,7 @@ static void print_config(struct trx_ctx *trx)
ost << " EDGE support............ " << trx->cfg.egprs << std::endl;
ost << " Extended RACH support... " << trx->cfg.ext_rach << std::endl;
ost << " Reference............... " << trx->cfg.clock_ref << std::endl;
ost << " Filler Burst Type....... " << get_value_string(filler_names, trx->cfg.filler) << std::endl;
ost << " Filler Burst TSC........ " << trx->cfg.rtsc << std::endl;
ost << " Filler Burst RACH Delay. " << trx->cfg.rach_delay << std::endl;
ost << " C0 Filler Table......... " << trx->cfg.filler << std::endl;
ost << " Multi-Carrier........... " << trx->cfg.multi_arfcn << std::endl;
ost << " Tuning offset........... " << trx->cfg.offset << std::endl;
ost << " RSSI to dBm offset...... " << trx->cfg.rssi_offset << std::endl;
@@ -581,17 +576,20 @@ int main(int argc, char *argv[])
printf("Built without atomic operation support. Using Mutex, it may affect performance!\n");
#endif
if (!log_mutex_init()) {
fprintf(stderr, "Failed to initialize log mutex!\n");
exit(2);
}
convolve_init();
convert_init();
osmo_init_logging2(tall_trx_ctx, &log_info);
log_enable_multithread();
osmo_stats_init(tall_trx_ctx);
vty_init(&g_vty_info);
logging_vty_add_cmds();
ctrl_vty_init(tall_trx_ctx);
trx_vty_init(g_trx_ctx);
logging_vty_add_cmds();
osmo_talloc_vty_add_cmds();
osmo_stats_vty_add_cmds();

View File

@@ -72,7 +72,7 @@ bool trxd_send_burst_ind_v0(size_t chan, int fd, const struct trx_ul_burst_ind *
if(bi->idle)
return true;
/* +2: Historically (OpenBTS times), two extra non-used bytes are sent appended to each burst */
/* +2: Historically (OpenBTS times), two extra non-used bytes are sent appeneded to each burst */
char buf[sizeof(struct trxd_hdr_v0) + bi->nbits + 2];
struct trxd_hdr_v0* pkt = (struct trxd_hdr_v0*)buf;

View File

@@ -1,7 +1,7 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribution.
* 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.
@@ -79,7 +79,7 @@ public:
bool start();
bool stop();
/** initialization */
/** intialization */
virtual bool init(int type);
virtual void close();
@@ -156,24 +156,16 @@ public:
void close();
};
struct freq_cfg_state {
bool set;
double freq_hz;
};
class RadioInterfaceMulti : public RadioInterface {
private:
bool pushBuffer();
int pullBuffer();
bool verify_arfcn_consistency(double freq, size_t chan, bool tx);
virtual double setTxGain(double dB, size_t chan);
signalVector *outerSendBuffer;
signalVector *outerRecvBuffer;
std::vector<signalVector *> history;
std::vector<bool> active;
std::vector<struct freq_cfg_state> rx_freq_state;
std::vector<struct freq_cfg_state> tx_freq_state;
Resampler *dnsampler;
Resampler *upsampler;

View File

@@ -73,8 +73,6 @@ void RadioInterfaceMulti::close()
powerScaling.resize(0);
history.resize(0);
active.resize(0);
rx_freq_state.resize(0);
tx_freq_state.resize(0);
RadioInterface::close();
}
@@ -150,8 +148,6 @@ bool RadioInterfaceMulti::init(int type)
mReceiveFIFO.resize(mChans);
powerScaling.resize(mChans);
history.resize(mChans);
rx_freq_state.resize(mChans);
tx_freq_state.resize(mChans);
active.resize(MCHANS, false);
inchunk = RESAMP_INRATE * 4;
@@ -366,67 +362,42 @@ static bool fltcmp(double a, double b)
return fabs(a - b) < FREQ_DELTA_LIMIT ? true : false;
}
bool RadioInterfaceMulti::verify_arfcn_consistency(double freq, size_t chan, bool tx)
{
double freq_i;
std::string str_dir = tx ? "Tx" : "Rx";
std::vector<struct freq_cfg_state> &v = tx ? tx_freq_state : rx_freq_state;
for (size_t i = 0; i < mChans; i++) {
if (i == chan)
continue;
if (!v[i].set)
continue;
freq_i = v[i].freq_hz + (double) ((int)chan - (int)i) * MCBTS_SPACING;
if (!fltcmp(freq, freq_i)) {
LOGCHAN(chan, DMAIN, ERROR)
<< "Setting " << str_dir << " frequency " << freq
<< " is incompatible: already configured channel "
<< i << " uses frequency " << v[i].freq_hz
<< " (expected " << freq_i << ")";
return false;
}
}
v[chan].set = true;
v[chan].freq_hz = freq;
return true;
}
bool RadioInterfaceMulti::tuneTx(double freq, size_t chan)
{
double shift;
if (chan >= mChans)
return false;
if (chan >= mChans)
return false;
double shift = (double) getFreqShift(mChans);
if (!verify_arfcn_consistency(freq, chan, true))
return false;
if (!chan)
return mDevice->setTxFreq(freq + shift * MCBTS_SPACING);
if (chan == 0) {
shift = (double) getFreqShift(mChans);
return mDevice->setTxFreq(freq + shift * MCBTS_SPACING);
}
double center = mDevice->getTxFreq();
if (!fltcmp(freq, center + (double) (chan - shift) * MCBTS_SPACING)) {
LOG(NOTICE) << "Channel " << chan << " RF Tx frequency offset is "
<< freq / 1e6 << " MHz";
}
return true;
return true;
}
bool RadioInterfaceMulti::tuneRx(double freq, size_t chan)
{
double shift;
if (chan >= mChans)
return false;
if (chan >= mChans)
return false;
double shift = (double) getFreqShift(mChans);
if (!verify_arfcn_consistency(freq, chan, false))
return false;
if (!chan)
return mDevice->setRxFreq(freq + shift * MCBTS_SPACING);
if (chan == 0) {
shift = (double) getFreqShift(mChans);
return mDevice->setRxFreq(freq + shift * MCBTS_SPACING);
}
double center = mDevice->getRxFreq();
if (!fltcmp(freq, center + (double) (chan - shift) * MCBTS_SPACING)) {
LOG(NOTICE) << "Channel " << chan << " RF Rx frequency offset is "
<< freq / 1e6 << " MHz";
}
return true;
return true;
}
double RadioInterfaceMulti::setRxGain(double db, size_t chan)

View File

@@ -345,7 +345,7 @@ static signalVector *convolve(const signalVector *x, const signalVector *h,
_x = x;
/*
* Four convolve types:
* Four convovle types:
* 1. Complex-Real (aligned)
* 2. Complex-Complex (aligned)
* 3. Complex-Real (!aligned)
@@ -723,7 +723,7 @@ static signalVector *mapEdgeSymbols(const BitVector &bits)
*
* Delay the EDGE downlink bursts by one symbol in order to match GMSK pulse
* shaping group delay. The difference in group delay arises from the dual
* pulse filter combination of the GMSK Laurent representation whereas 8-PSK
* pulse filter combination of the GMSK Laurent represenation whereas 8-PSK
* uses a single pulse linear filter.
*/
static signalVector *shapeEdgeBurst(const signalVector &symbols)

View File

@@ -1,7 +1,7 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
*
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribution.
* 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.

View File

@@ -47,7 +47,7 @@ void signalVector::operator=(const signalVector& vector)
complex *src = vector.mData;
for (i = 0; i < size(); i++, src++, dst++)
*dst = *src;
/* TODO: optimize for non non-trivially copiable types: */
/* TODO: optimize for non non-trivially copyable types: */
/*memcpy(mData, vector.mData, bytes()); */
mStart = mData + vector.getStart();
}
@@ -70,7 +70,7 @@ size_t signalVector::updateHistory()
complex *src = mStart + this->size() - num;
for (i = 0; i < num; i++, src++, dst++)
*dst = *src;
/* TODO: optimize for non non-trivially copiable types: */
/* TODO: optimize for non non-trivially copyable types: */
/*memmove(mData, mStart + this->size() - num, num * sizeof(complex)); */
return num;

View File

@@ -65,7 +65,7 @@ AC_PROG_LIBTOOL
dnl Checks for header files.
AC_HEADER_STDC
dnl This is required for GnuRadio includes to understand endianness correctly:
dnl This is required for GnuRadio includes to understand endianess correctly:
AC_CHECK_HEADERS([byteswap.h])
dnl Checks for typedefs, structures, and compiler characteristics.
@@ -75,18 +75,9 @@ AC_TYPE_SIZE_T
AC_HEADER_TIME
AC_C_BIGENDIAN
# Check if gettid is available (despite not being documented in glibc doc, it requires __USE_GNU on some systems)
# C compiler is used since __USE_GNU seems to be always defined for g++.
save_CPPFLAGS=$CPPFLAGS
AC_LANG_PUSH(C)
CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
AC_CHECK_FUNCS([gettid])
AC_LANG_POP(C)
CPPFLAGS=$save_CPPFLAGS
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.3.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.3.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.3.0)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.12.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.12.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 0.12.0)
AC_ARG_ENABLE(sanitize,
[AS_HELP_STRING(
@@ -134,6 +125,11 @@ AC_ARG_WITH(lms, [
[enable LimeSuite based transceiver])
])
AC_ARG_WITH(xtrx, [
AS_HELP_STRING([--with-xtrx],
[enable XTRX based transceiver])
])
AC_ARG_WITH(singledb, [
AS_HELP_STRING([--with-singledb],
[enable single daughterboard use on USRP1])
@@ -173,6 +169,10 @@ AS_IF([test "x$with_lms" = "xyes"], [
PKG_CHECK_MODULES(LMS, LimeSuite)
])
AS_IF([test "x$with_xtrx" = "xyes"], [
PKG_CHECK_MODULES(XTRX, libxtrx)
])
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)],
@@ -235,6 +235,7 @@ AS_IF([test "x$osmo_cv_cc_has___sync_fetch_and_and" = "xyes" && test "x$osmo_cv_
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(DEVICE_XTRX, [test "x$with_xtrx" = "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"])
@@ -319,6 +320,7 @@ AC_CONFIG_FILES([\
Transceiver52M/device/uhd/Makefile \
Transceiver52M/device/usrp1/Makefile \
Transceiver52M/device/lms/Makefile \
Transceiver52M/device/xtrx/Makefile \
tests/Makefile \
tests/CommonLibs/Makefile \
tests/Transceiver52M/Makefile \

View File

@@ -15,7 +15,7 @@ substr() { [ -z "${2##*$1*}" ]; }
mychroot_nocwd() {
# LC_ALL + LANGUAGE set to avoid lots of print errors due to locale not being set inside container
# PATH is needed to be able to reach binaries like ldconfig without logging in to root, which adds the paths to PATH.
# PROOT_NO_SECCOMP is required due to proot bug #106
# PROOT_NO_SECCOMP is requried due to proot bug #106
LC_ALL=C LANGUAGE=C PATH="$PATH:/usr/sbin:/sbin" PROOT_NO_SECCOMP=1 proot -r "$ROOTFS" -w / -b /proc --root-id -q qemu-arm-static "$@"
}
@@ -23,8 +23,15 @@ mychroot() {
mychroot_nocwd -w / "$@"
}
base="$PWD"
deps="$base/deps"
inst="$deps/install"
export deps inst
if [ -z "${INSIDE_CHROOT}" ]; then
osmo-clean-workspace.sh
# Only use ARM chroot if host is not ARM and the target is ARM:
if ! $(substr "arm" "$(uname -m)") && [ "x${INSTR}" = "x--with-neon" -o "x${INSTR}" = "x--with-neon-vfpv4" ]; then
@@ -62,20 +69,6 @@ if [ -z "${INSIDE_CHROOT}" ]; then
fi
fi
set -ex
if ! [ -x "$(command -v osmo-build-dep.sh)" ]; then
echo "Error: We need to have scripts/osmo-deps.sh from http://git.osmocom.org/osmo-ci/ in PATH !"
exit 2
fi
base="$PWD"
deps="$base/deps"
inst="$deps/install"
export deps inst
osmo-clean-workspace.sh
mkdir "$deps" || true
osmo-build-dep.sh libosmocore "" "--enable-sanitize --disable-doxygen --disable-pcsc"

View File

@@ -18,5 +18,9 @@ if DEVICE_LMS
SYSTEMD_SERVICES += osmo-trx-lms.service
endif
if DEVICE_XTRX
SYSTEMD_SERVICES += osmo-trx-xtrx.service
endif
systemdsystemunit_DATA = $(SYSTEMD_SERVICES)
endif # HAVE_SYSTEMD

View File

@@ -0,0 +1,11 @@
[Unit]
Description=Osmocom SDR BTS L1 Transceiver (XTRX backend)
[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/osmo-trx-xtrx -C /etc/osmocom/osmo-trx-xtrx.cfg
RestartSec=2
[Install]
WantedBy=multi-user.target

52
debian/changelog vendored
View File

@@ -1,55 +1,3 @@
osmo-trx (1.2.0) unstable; urgency=medium
[ Pau Espin Pedrol ]
* osmo-trx: log to stderr on signal received
* Drop old setPriority related code
* Transceiver: fix segfault during init if IP addr binding fails
* Transceiver: Check return value when binding IP addr for clock socket
* Transceiver: Clean up receival of downlink bursts
* Transceiver: Fix idle ul burst indications being dropped
* Transceiver: exit process when BTS drops connection
* Transceiver: Enable EDGE detection only on PDCH timeslots
* lms: Log available antennas if requested antenna fails
* device: Use LOGCHAN in set_antennas()
* Transceiver: Fix logging TN and version
* Transceiver: Use LOGCHAN in logRxBurst to unify log format
* Transceiver: Log error condition no burst in pullRadioVector()
* Transceiver: pullRadioVector(): Fix use of uninitialized value bi->tn
* Transceiver: Don't stop TRX if pulling from OFF timeslot
* radioInterface: Rename mRadio to mDevice
* radioInterfaceMulti: Check equals zero explicitly
* USRPDevice: Fix setRxGain return on error and getRxGain() returning always 0
* USRPDevice: Return previous txGain if setting value failed
* LMSDevice: Return previous txGain/rxGain if setting value failed
* radioInterface: Remove unusued getRxGain()
* radioDevice: Introduce getTxGain() API
* radioInterfaceMulti: Override setTxGain() to avoid chan!=0 calls
* UHDDevice: Drop unneeded MULTI_ARFCN checks
* radioInterface{Multi,Resamp}: Fix successful writeSamples() masking underrun from readSamples()
* radioInterface: Mark setRxGain as virtual
* Move multi-ARFCN chan amount modification from UHDDevice to parent class
* radioInterface: Atomically fetch and change underrun variable
* radioInterfaceMulti: write frequency offset direction (rx/tx) in log line
* Use new libosmocore logging lock API
* Transceiver: Fix wrong response upon CMD HANDOVER failure
* uhd: use value already cached in tmp variable
* Transceiver.cpp: Introduce and use new logging categories
[ Timo Jacobus ]
* Transceiver: Fixed copying of history into and from channelizer buffer.
[ Alexander Chemeris ]
* vty: Don't enable random filler bursts automatically with EDGE.
* vty: Simplify filler burst settings and improve help and readability.
[ Martin Hauke ]
* Fix common misspellings and typos
[ Harald Welte ]
* trx: exit() on unsupported positional arguments on command line
-- Pau Espin Pedrol <pespin@sysmocom.de> Fri, 03 Jan 2020 19:54:00 +0100
osmo-trx (1.1.1) unstable; urgency=medium
* UNRELEASED

21
debian/control vendored
View File

@@ -14,7 +14,7 @@ Build-Depends: debhelper (>= 9),
libtalloc-dev,
libusrp-dev,
liblimesuite-dev,
libosmocore-dev (>= 1.3.0),
libosmocore-dev (>= 0.12.0),
osmo-gsm-manuals-dev
Standards-Version: 3.9.6
Vcs-Browser: http://cgit.osmocom.org/osmo-trx
@@ -91,6 +91,25 @@ Description: SDR transceiver that implements Layer 1 of a GSM BTS (LimeSuite)
between different telecommunication associations for developing new
generations of mobile phone networks. (post-2G/GSM)
Package: osmo-trx-xtrx
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: SDR transceiver that implements Layer 1 of a GSM BTS (XTRX)
OsmoTRX is a software-defined radio transceiver that implements the Layer 1
physical layer of a BTS comprising the following 3GPP specifications:
.
TS 05.01 "Physical layer on the radio path"
TS 05.02 "Multiplexing and Multiple Access on the Radio Path"
TS 05.04 "Modulation"
TS 05.10 "Radio subsystem synchronization"
.
In this context, BTS is "Base transceiver station". It's the stations that
connect mobile phones to the mobile network.
.
3GPP is the "3rd Generation Partnership Project" which is the collaboration
between different telecommunication associations for developing new
generations of mobile phone networks. (post-2G/GSM)
Package: osmo-trx-doc
Architecture: all
Section: doc

4
debian/osmo-trx-xtrx.install vendored Normal file
View File

@@ -0,0 +1,4 @@
etc/osmocom/osmo-trx-xtrx.cfg
lib/systemd/system/osmo-trx-xtrx.service
/usr/bin/osmo-trx-xtrx
/usr/share/doc/osmo-trx/examples/osmo-trx-xtrx/osmo-trx-xtrx.cfg /usr/share/doc/osmo-trx/examples/osmo-trx-xtrx/

View File

@@ -7,7 +7,7 @@ index 8ff59f0..126c16a 100644
libtalloc-dev,
libusrp-dev,
- liblimesuite-dev,
libosmocore-dev (>= 1.3.0),
libosmocore-dev (>= 0.12.0),
osmo-gsm-manuals-dev
Standards-Version: 3.9.6
@@ -30,7 +29,7 @@ Package: osmo-trx-dbg

View File

@@ -14,6 +14,10 @@ if DEVICE_LMS
OSMOCONF_FILES += osmo-trx-lms/osmo-trx-lms.cfg
endif
if DEVICE_XTRX
OSMOCONF_FILES += osmo-trx-xtrx/osmo-trx-xtrx.cfg
endif
osmoconf_DATA = $(OSMOCONF_FILES)
EXTRA_DIST = $(OSMOCONF_FILES)

View File

@@ -0,0 +1,20 @@
log stderr
logging filter all 1
logging color 1
logging print category 1
logging timestamp 1
logging print file basename
logging level set-all info
!
line vty
no login
!
trx
bind-ip 127.0.0.1
remote-ip 127.0.0.1
base-port 5700
egprs disable
tx-sps 4
rx-sps 4
rt-prio 18
chan 0

View File

@@ -46,16 +46,15 @@ Multi-ARFCN support is available since osmo-trx release `0.2.0`, and it was
added specifically in commit `76764278169d252980853251daeb9f1ba0c246e1`.
This feature is useful for instance if you want to run more than 1 TRX with an
Ettus B200 device, or more than 2 TRXs with an Ettus B210 device, since they
support only 1 and 2 physical RF channels respectively. No device from other
providers or even other devices than B200 and B210 from Ettus are known to
support this feature.
Ettus B200 device, or 2 TRX with an Ettus B210 device, since they support only 1
and 2 physical RF channels respectively. No device from other providers or even
other devices than B200 and B210 from Ettus are known to support this feature.
With multi-ARFCN enabled, ARFCN spacing is fixed at 800 kHz or 4 GSM channels.
So if TRX-0 is set to ARFCN 51, TRX-1 _must_ be set to 55, and so on. Up to
three ARFCN's is supported for multi-TRX.
From BTS and BSC point of view, supporting multiple TRXs through multi-ARFCN
From BTS and BSC point of view, supporting multiple TRX through multi-ARFCN
feature in OsmoTRX doesn't make any difference from a regular multi-TRX setup,
leaving apart of course the mentioned ARFCN limitations explained above and as a
consequence physical installation and operational differences.

View File

@@ -3,7 +3,7 @@
This section specifies the format of USB packets used for in-band data
transmission and signaling on the USRP1. All packets are 512-byte long, and are
transferred using USB "bulk" transfers.
transfered using USB "bulk" transfers.
IN packets are sent towards the host. OUT packets are sent away from the host.

View File

@@ -12,7 +12,7 @@ B200 family and Fairwaves UmTRX family, and used to be the default backend used
for legacy @osmo-trx@ binary when per-backend binaries didn't exist yet.
Any device providing generic support for UHD should theoretically be able to be
run through this backend without much effort, but practical experience showed
run through this backend without much effort, but pracitcal experience showed
that some devices don't play well with it, such as the LimeSDR family of
devices, which showed far better results when using its native interface.

View File

@@ -18,11 +18,10 @@
<param name='terminal' doc='Write to terminal' />
</params>
</command>
<command id='write file [PATH]'>
<command id='write file'>
<params>
<param name='write' doc='Write running configuration to memory, network, or terminal' />
<param name='file' doc='Write to configuration file' />
<param name='[PATH]' doc='Set file path to store the config, or replace if already exists' />
</params>
</command>
<command id='write memory'>
@@ -97,6 +96,12 @@
<param name='history' doc='Display the session command history' />
</params>
</command>
<command id='show trx'>
<params>
<param name='show' doc='Show running system information' />
<param name='trx' doc='Display information on the TRX' />
</params>
</command>
<command id='logging enable'>
<params>
<param name='logging' doc='Configure logging' />
@@ -188,17 +193,14 @@
<param name='MASK' doc='List of logging categories to log, e.g. &apos;abc:mno:xyz&apos;. Available log categories depend on the specific application, refer to the &apos;logging level&apos; command. Optionally add individual log levels like &apos;abc,1:mno,3:xyz,5&apos;, where the level numbers are LOGL_DEBUG=1 LOGL_INFO=3 LOGL_NOTICE=5 LOGL_ERROR=7 LOGL_FATAL=8' />
</params>
</command>
<command id='logging level (main|trxclk|trxctrl|trxddl|trxdul|dev|devdrv|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal)'>
<command id='logging level (main|trxctrl|dev|lms|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal)'>
<params>
<param name='logging' doc='Configure logging' />
<param name='level' doc='Set the log level for a specified category' />
<param name='main' doc='Main generic category' />
<param name='trxclk' doc='TRX Master Clock' />
<param name='trxctrl' doc='TRX CTRL interface' />
<param name='trxddl' doc='TRX Data interface Downlink' />
<param name='trxdul' doc='TRX CTRL interface Uplink' />
<param name='dev' doc='Device/Driver specific code' />
<param name='devdrv' doc='Logging from external device driver library implementing lower level specifics' />
<param name='lms' doc='Logging from within LimeSuite itself' />
<param name='lglobal' doc='Library-internal global log family' />
<param name='llapd' doc='LAPD in libosmogsm' />
<param name='linp' doc='A-bis Intput Subsystem' />
@@ -257,43 +259,6 @@
<param name='force-all' doc='Release any globally forced log level set with &apos;logging level force-all &lt;level&gt;&apos;' />
</params>
</command>
<command id='logp (main|trxclk|trxctrl|trxddl|trxdul|dev|devdrv|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal) .LOGMESSAGE'>
<params>
<param name='logp' doc='Print a message on all log outputs; useful for placing markers in test logs' />
<param name='main' doc='Main generic category' />
<param name='trxclk' doc='TRX Master Clock' />
<param name='trxctrl' doc='TRX CTRL interface' />
<param name='trxddl' doc='TRX Data interface Downlink' />
<param name='trxdul' doc='TRX CTRL interface Uplink' />
<param name='dev' doc='Device/Driver specific code' />
<param name='devdrv' doc='Logging from external device driver library implementing lower level specifics' />
<param name='lglobal' doc='Library-internal global log family' />
<param name='llapd' doc='LAPD in libosmogsm' />
<param name='linp' doc='A-bis Intput Subsystem' />
<param name='lmux' doc='A-bis B-Subchannel TRAU Frame Multiplex' />
<param name='lmi' doc='A-bis Input Driver for Signalling' />
<param name='lmib' doc='A-bis Input Driver for B-Channels (voice)' />
<param name='lsms' doc='Layer3 Short Message Service (SMS)' />
<param name='lctrl' doc='Control Interface' />
<param name='lgtp' doc='GPRS GTP library' />
<param name='lstats' doc='Statistics messages and logging' />
<param name='lgsup' doc='Generic Subscriber Update Protocol' />
<param name='loap' doc='Osmocom Authentication Protocol' />
<param name='lss7' doc='libosmo-sigtran Signalling System 7' />
<param name='lsccp' doc='libosmo-sigtran SCCP Implementation' />
<param name='lsua' doc='libosmo-sigtran SCCP User Adaptation' />
<param name='lm3ua' doc='libosmo-sigtran MTP3 User Adaptation' />
<param name='lmgcp' doc='libosmo-mgcp Media Gateway Control Protocol' />
<param name='ljibuf' doc='libosmo-netif Jitter Buffer' />
<param name='lrspro' doc='Remote SIM protocol' />
<param name='debug' doc='Log debug messages and higher levels' />
<param name='info' doc='Log informational messages and higher levels' />
<param name='notice' doc='Log noticeable messages and higher levels' />
<param name='error' doc='Log error messages and higher levels' />
<param name='fatal' doc='Log only fatal messages' />
<param name='.LOGMESSAGE' doc='Arbitrary message to log on given category and log level' />
</params>
</command>
<command id='show logging vty'>
<params>
<param name='show' doc='Show running system information' />
@@ -307,12 +272,6 @@
<param name='alarms' doc='Show current logging configuration' />
</params>
</command>
<command id='show trx'>
<params>
<param name='show' doc='Show running system information' />
<param name='trx' doc='Display information on the TRX' />
</params>
</command>
<command id='show talloc-context (application|all) (full|brief|DEPTH)'>
<params>
<param name='show' doc='Show running system information' />
@@ -456,6 +415,12 @@
<param name='monitor' doc='Copy debug output to the current terminal line' />
</params>
</command>
<command id='show trx'>
<params>
<param name='show' doc='Show running system information' />
<param name='trx' doc='Display information on the TRX' />
</params>
</command>
<command id='logging enable'>
<params>
<param name='logging' doc='Configure logging' />
@@ -547,17 +512,14 @@
<param name='MASK' doc='List of logging categories to log, e.g. &apos;abc:mno:xyz&apos;. Available log categories depend on the specific application, refer to the &apos;logging level&apos; command. Optionally add individual log levels like &apos;abc,1:mno,3:xyz,5&apos;, where the level numbers are LOGL_DEBUG=1 LOGL_INFO=3 LOGL_NOTICE=5 LOGL_ERROR=7 LOGL_FATAL=8' />
</params>
</command>
<command id='logging level (main|trxclk|trxctrl|trxddl|trxdul|dev|devdrv|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal)'>
<command id='logging level (main|trxctrl|dev|lms|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal)'>
<params>
<param name='logging' doc='Configure logging' />
<param name='level' doc='Set the log level for a specified category' />
<param name='main' doc='Main generic category' />
<param name='trxclk' doc='TRX Master Clock' />
<param name='trxctrl' doc='TRX CTRL interface' />
<param name='trxddl' doc='TRX Data interface Downlink' />
<param name='trxdul' doc='TRX CTRL interface Uplink' />
<param name='dev' doc='Device/Driver specific code' />
<param name='devdrv' doc='Logging from external device driver library implementing lower level specifics' />
<param name='lms' doc='Logging from within LimeSuite itself' />
<param name='lglobal' doc='Library-internal global log family' />
<param name='llapd' doc='LAPD in libosmogsm' />
<param name='linp' doc='A-bis Intput Subsystem' />
@@ -616,43 +578,6 @@
<param name='force-all' doc='Release any globally forced log level set with &apos;logging level force-all &lt;level&gt;&apos;' />
</params>
</command>
<command id='logp (main|trxclk|trxctrl|trxddl|trxdul|dev|devdrv|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal) .LOGMESSAGE'>
<params>
<param name='logp' doc='Print a message on all log outputs; useful for placing markers in test logs' />
<param name='main' doc='Main generic category' />
<param name='trxclk' doc='TRX Master Clock' />
<param name='trxctrl' doc='TRX CTRL interface' />
<param name='trxddl' doc='TRX Data interface Downlink' />
<param name='trxdul' doc='TRX CTRL interface Uplink' />
<param name='dev' doc='Device/Driver specific code' />
<param name='devdrv' doc='Logging from external device driver library implementing lower level specifics' />
<param name='lglobal' doc='Library-internal global log family' />
<param name='llapd' doc='LAPD in libosmogsm' />
<param name='linp' doc='A-bis Intput Subsystem' />
<param name='lmux' doc='A-bis B-Subchannel TRAU Frame Multiplex' />
<param name='lmi' doc='A-bis Input Driver for Signalling' />
<param name='lmib' doc='A-bis Input Driver for B-Channels (voice)' />
<param name='lsms' doc='Layer3 Short Message Service (SMS)' />
<param name='lctrl' doc='Control Interface' />
<param name='lgtp' doc='GPRS GTP library' />
<param name='lstats' doc='Statistics messages and logging' />
<param name='lgsup' doc='Generic Subscriber Update Protocol' />
<param name='loap' doc='Osmocom Authentication Protocol' />
<param name='lss7' doc='libosmo-sigtran Signalling System 7' />
<param name='lsccp' doc='libosmo-sigtran SCCP Implementation' />
<param name='lsua' doc='libosmo-sigtran SCCP User Adaptation' />
<param name='lm3ua' doc='libosmo-sigtran MTP3 User Adaptation' />
<param name='lmgcp' doc='libosmo-mgcp Media Gateway Control Protocol' />
<param name='ljibuf' doc='libosmo-netif Jitter Buffer' />
<param name='lrspro' doc='Remote SIM protocol' />
<param name='debug' doc='Log debug messages and higher levels' />
<param name='info' doc='Log informational messages and higher levels' />
<param name='notice' doc='Log noticeable messages and higher levels' />
<param name='error' doc='Log error messages and higher levels' />
<param name='fatal' doc='Log only fatal messages' />
<param name='.LOGMESSAGE' doc='Arbitrary message to log on given category and log level' />
</params>
</command>
<command id='show logging vty'>
<params>
<param name='show' doc='Show running system information' />
@@ -666,12 +591,6 @@
<param name='alarms' doc='Show current logging configuration' />
</params>
</command>
<command id='show trx'>
<params>
<param name='show' doc='Show running system information' />
<param name='trx' doc='Display information on the TRX' />
</params>
</command>
<command id='show talloc-context (application|all) (full|brief|DEPTH)'>
<params>
<param name='show' doc='Show running system information' />
@@ -853,6 +772,16 @@
<param name='history' doc='Display the session command history' />
</params>
</command>
<command id='ctrl'>
<params>
<param name='ctrl' doc='Configure the Control Interface' />
</params>
</command>
<command id='trx'>
<params>
<param name='trx' doc='Configure the TRX' />
</params>
</command>
<command id='log stderr'>
<params>
<param name='log' doc='Configure logging sub-system' />
@@ -932,16 +861,6 @@
<param name='[HOSTNAME]' doc='Host name to send the GSMTAP logging to (UDP port 4729)' />
</params>
</command>
<command id='ctrl'>
<params>
<param name='ctrl' doc='Configure the Control Interface' />
</params>
</command>
<command id='trx'>
<params>
<param name='trx' doc='Configure the TRX' />
</params>
</command>
<command id='stats reporter statsd'>
<params>
<param name='stats' doc='Configure stats sub-system' />
@@ -1054,17 +973,14 @@
<param name='[last]' doc='Log source file info at the end of a log line. If omitted, log source file info just before the log text.' />
</params>
</command>
<command id='logging level (main|trxclk|trxctrl|trxddl|trxdul|dev|devdrv|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal)'>
<command id='logging level (main|trxctrl|dev|lms|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal)'>
<params>
<param name='logging' doc='Configure logging' />
<param name='level' doc='Set the log level for a specified category' />
<param name='main' doc='Main generic category' />
<param name='trxclk' doc='TRX Master Clock' />
<param name='trxctrl' doc='TRX CTRL interface' />
<param name='trxddl' doc='TRX Data interface Downlink' />
<param name='trxdul' doc='TRX CTRL interface Uplink' />
<param name='dev' doc='Device/Driver specific code' />
<param name='devdrv' doc='Logging from external device driver library implementing lower level specifics' />
<param name='lms' doc='Logging from within LimeSuite itself' />
<param name='lglobal' doc='Library-internal global log family' />
<param name='llapd' doc='LAPD in libosmogsm' />
<param name='linp' doc='A-bis Intput Subsystem' />
@@ -1263,10 +1179,24 @@
<param name='4' doc='(null)' />
</params>
</command>
<command id='test rtsc &lt;0-7&gt;'>
<params>
<param name='test' doc='Set the Random Normal Burst test mode with TSC' />
<param name='rtsc' doc='TSC' />
<param name='&lt;0-7&gt;' doc='(null)' />
</params>
</command>
<command id='test rach-delay &lt;0-68&gt;'>
<params>
<param name='test' doc='Set the Random Access Burst test mode with delay' />
<param name='rach-delay' doc='RACH delay' />
<param name='&lt;0-68&gt;' doc='(null)' />
</params>
</command>
<command id='clock-ref (internal|external|gpsdo)'>
<params>
<param name='clock-ref' doc='Set the Reference Clock' />
<param name='internal' doc='Enable internal reference (default)' />
<param name='internal' doc='Enable internal referece (default)' />
<param name='external' doc='Enable external 10 MHz reference' />
<param name='gpsdo' doc='Enable GPSDO reference' />
</params>
@@ -1317,29 +1247,10 @@
<param name='&lt;1-32&gt;' doc='Real time priority' />
</params>
</command>
<command id='filler type (zero|dummy|random-nb-gmsk|random-nb-8psk|random-ab)'>
<command id='filler dummy'>
<params>
<param name='filler' doc='Filler burst settings' />
<param name='type' doc='Filler burst type (default=zero)' />
<param name='zero' doc='Send an empty burst when there is nothing to send (default)' />
<param name='dummy' doc='Send a dummy burst when there is nothing to send on C0 (TRX0) and empty burst on other channels. Use for OpenBTS compatibility only, don&apos;t use with OsmoBTS as it breaks encryption.' />
<param name='random-nb-gmsk' doc='Send a GMSK modulated Normal Burst with random bits when there is nothing to send. Use for spectrum mask testing. Configure &apos;filler tsc&apos; to set training sequence.' />
<param name='random-nb-8psk' doc='Send an 8-PSK modulated Normal Burst with random bits when there is nothing to send. Use for spectrum mask testing. Configure &apos;filler tsc&apos; to set training sequence.' />
<param name='random-ab' doc='Send an Access Burst with random bits when there is nothing to send. Use for Rx/Tx alignment. Configure &apos;filler access-burst-delay&apos; to introduce artificial delay.' />
</params>
</command>
<command id='filler tsc &lt;0-7&gt;'>
<params>
<param name='filler' doc='Filler burst settings' />
<param name='tsc' doc='Set the TSC for GMSK/8-PSK Normal Burst random fillers. Used only with &apos;random-nb-gmsk&apos; and &apos;random-nb-8psk&apos; filler types. (default=0)' />
<param name='&lt;0-7&gt;' doc='TSC' />
</params>
</command>
<command id='filler access-burst-delay &lt;0-68&gt;'>
<params>
<param name='filler' doc='Filler burst settings' />
<param name='access-burst-delay' doc='Set the delay for Access Burst random fillers. Used only with &apos;random-ab&apos; filler type. (default=0)' />
<param name='&lt;0-68&gt;' doc='RACH delay in symbols' />
<param name='filler' doc='Enable C0 filler table' />
<param name='dummy' doc='Dummy method' />
</params>
</command>
<command id='ctr-error-threshold (rx_overruns|tx_underruns|rx_drop_events|rx_drop_samples|tx_drop_events|tx_drop_samples) &lt;0-65535&gt; (per-second|per-minute|per-hour|per-day)'>

View File

@@ -146,9 +146,9 @@ struct test_vec
float *h;
float *y;
int x_len; /* These are in # of _floats_ ! */
int h_len; /* These are in # of _floats_ ! */
int y_len; /* These are in # of _floats_ ! */
int x_len; /* Theses are in # of _floats_ ! */
int h_len; /* Theses are in # of _floats_ ! */
int y_len; /* Theses are in # of _floats_ ! */
};
/* Reset test vectors */