Compare commits

...

29 Commits

Author SHA1 Message Date
Kirill Zakharenko
9e5520660d release 1.2.0-fw.1 2020-05-01 19:16:59 +03:00
Eric
a7143bf7a1 transceiver: get rid of the ctrl threads
There is no need to have n threads handle n ctrl sockets, since they all
will immediately respond to commands, so handle them from the existing
main osmo select loop.

Care must be taken to ensure that calls from within the command handler
do not block, or at least don't block too long, which currently is the
case.

Change-Id: I642a34451e1825eafecf71a902df916ccee7944c
2020-04-14 19:10:51 +00:00
Philipp Maier
4ffdca10d4 doc: apply an rssi-offset of 28 by default.
Set an rssi offset of 28 in the example configs to make sure that the
power control loop gets RSSI values that match at least half way the
reality when the 1800 Mhz band is used. For other bands the value will
be different (See also related osmocom ticket)

Change-Id: I62725fe454f54e2c7cb7550dadb1e6fc94337d78
Related: OS#4468
2020-04-14 17:16:23 +00:00
Eric
1a26b4f085 transceiver: check the right vector
Change-Id: I03800ae094c35c306fa4ca29f84e71d958ffdbdc
2020-04-14 13:17:25 +00:00
Eric
c5d5586fbd configure.ac: fix libtool issue with clang and sanitizer
As pointed out at https://github.com/libexpat/libexpat/issues/312
libtool does not play nice with clang sanitizer builds at all.
For those builds LD shoud be set to clang too (and LDFLAGS needs the
sanitizer flags as well), because the clang compiler driver knows how
linking to the sanitizer libs works, but then at a later stage libtool
fails to actually produce the shared libraries and the build fails. This
is fixed by this patch.

Addtionally LD_LIBRARY_PATH has no effect on conftest runs during
configure time, so the rpath needs to be set to the asan library path to
ensure the configure run does not fail due to a missing asan library,
i.e.:

SANS='-fsanitize=memory -fsanitize-recover=all -shared-libsan'
export CC=clang-10
ASANPATH=$(dirname `$CC -print-file-name=libclang_rt.asan-x86_64.so`)
export LDFLAGS="-Wl,-rpath,$ASANPATH $SANS $LDFLAGS"

Change-Id: If3d9465068b2c654b935fc3d9ab41d799d5e02e8
2020-04-11 18:33:42 +00:00
Philipp Maier
cc971aa1a6 doc: do not set the base-port of the trx
In current config files a base port for osmo-trx is set. Lets remove
this setting so that compiled-in default (which is the same value)
is used.

Change-Id: I105d1c51424836daa6893e83a81c83cc7ac6afd4
2020-04-01 10:21:50 +00:00
Philipp Maier
748d8edbf8 debug: use LOGL_NOTICE for log category DDEV
The log category DDEV ueses LOGL_INFO as debug level. This is too
verbose, lets use LOGL_NOTICE instead

Change-Id: I56d45ce5c3f55574491ffa6e4d902d6ba7499d46
Related: OS#2577
2020-03-25 12:36:15 +01:00
Pau Espin Pedrol
dfc6e5ffc7 radioDevice: Drop unused isControl param from WriteSamples API
The out "isControl" parameter is only used by internal callers of
USRPDevice, and not used at all by any user of the generic API
(radioInterface*.cpp). Hence, we can get rid of it and keep it as a flag
for an internal API of USRPDevice.

Change-Id: I843384e24b76cdd28a95f9ee4e95e6157098e4a3
2020-03-12 19:35:47 +01:00
Pau Espin Pedrol
f8c0c464b8 radioDevice: Drop unused RSSI param from readSamples API
The out "RSSI" parameter is only filled by USRPDevice, and not used at
all by any user of the API (radioInterface*.cpp).

RSSI seems to be computed nowadays in the common path in
Transceiver::pullRadioVector().

Change-Id: I06c2ea5a9891d170bc468f952bbf2a7e64d95784
2020-03-12 19:34:28 +01:00
Pau Espin Pedrol
93707d0227 cosmetic: fix several typos found by codespell
Change-Id: Id1f6766572fd313463201e6d03964965f227db25
2020-02-25 17:03:00 +01:00
Pau Espin Pedrol
5291e8a654 debug.h: Fix print format of chan in CLOGCHAN
Under armv7l arch, size_t is actually an unsigned int and not a long
unsigned int, and compiler errors:

CommonLibs/debug.h:28:24: error: format ‘%lu’ expects argument of type
‘long unsigned int’, but argument 8 has type ‘size_t {aka unsigned int}’ [-Werror=format=]

Change-Id: I7f6ded5a984570b5267916d6c84eb7d019db73a8
2020-02-19 18:08:20 +01:00
Pau Espin Pedrol
7a07de1efd debug.h: Avoid printing pthread_t type
Using %lu for pthread_t was wrong on armv7l arch. Even worse, according
to pthread_self() man page, pthread_t cannot be assumed to be of a simple
type and hence printable:
"""
POSIX.1 allows an implementation wide freedom in choosing the type used
to represent a thread ID; for example, representation using either an
arithmetic  type  or a structure is permitted.
"""

Let's use gettid() instead. According to glibc documentation:
"""
The pid_t data type is a signed integer type which is capable of
representing a process ID. In the GNU C Library, this is an int.
"""
It may not be the same on other libc's though, so let's better cast to a
long int just in case.

Accordign to gettid() man, the libc function was only added recently
during glibc 2.30, however the system call has been around for quite
some time (linux 2.4.11). Let's accomodate use udner non-glibc or older
versions of it by having a direct syscall fallback.

Change-Id: I40265fd4c62e550014ba3ff3335ca053c5bc01f2
2020-02-19 18:08:20 +01:00
Pau Espin Pedrol
fd67262df8 contrib/jenkins.sh: Reorder sanity checks
Change-Id: Idfe12148aa7a8030bdaf56d11c1547ebc3f56d14
2020-02-19 11:53:30 +01:00
Pau Espin Pedrol
0569845a08 lms: Initial multi-arfcn support
With current state multi-arfcn can be used (eg. I can place a call
between 2 phones using TRX1 and sustain for as long as wanted), but from
time to time (around every 20seconds), a burst of Tx packed dropped
events from LimeSuite appears.

LimeNet-micro coefficients have yet not been tested.

Related: OS#4362
Change-Id: I7e67d90a8126546eeeeba376f816ec5d158d4712
2020-01-15 15:46:14 +01:00
Pau Espin Pedrol
c69b87f9bd lms: Make ts_offset and smpl rate coefs device-specific
Right now the values are the same for all devices, but they will differ
in forthcoming commits once multi-arfcn support is added.

Change-Id: I262d3a71848fc3070473e29e42820848e7591d02
2020-01-15 15:46:14 +01:00
Pau Espin Pedrol
a7bf6cd8a4 lms: Store device type specific parameters in one place
Add an enum containing each supported device type (LimeSDR-USB,
LimeSDR-Mini and LimeNet-Micro) plus "unknown", to leave some room for
yet-to-come devices to run with some generic parameters without
rebuilding osmo-trx.

Each device type is assigned a dev_desc structure, and all of them are
put in HashMap, similar to what's already done in UHDDevice.cpp.

Device type is infered from string provided by LMS_GetDeviceInfo(), as
it was already done before in several places. From now on, we only need
to parse the string once since we store the device type after first
during open time.

Later on, more fields will be moved to device-type specific structure,
such as Tx timing offset, clock rate, etc.

Change-Id: I7658615787c5bc41c365bab9c11733b701ac2ae5
2020-01-15 15:45:29 +01:00
Pau Espin Pedrol
e7f6a27ab6 lms: Move rx_buffers allocation to constructor
Release is done in destructor, so let's move allocation to constructor
since there's really no need to have them in open() which is already
quite complex and large.

Change-Id: I8a4fd973590c4c165abd8f2837b2da8fc14a2066
2020-01-15 15:35:01 +01:00
Pau Espin Pedrol
a979f5f32b lms: Make reference to std::vector unambiguous
Change-Id: Ieebdbd3d5082a02aea2441e6737783370511cbc1
2020-01-15 15:34:49 +01:00
Pau Espin Pedrol
b0e54265ad lms: Change radioDevice constructor arg name to avoid masking instance attr
channel number mangling based on multi-arfcn feature being enabled was
moved to generic radioDevice() to reuse code. Hence, the generic parent
constructor sets this->chans to 1 if multi-arfcn feature is requested.
However, LMSDevice constructor argument had same name as the class
instance attribute, taking preference. As a result, if multi-arfcn is
enabled in LMSDevice, the generic constructor first sets this->chans=1
but afterwards LMSDEvice constructor keeps calling .resize() with the
argument value "chans" instead of using this->chans.

Let's rename the argument in all radioDevice child class constructors to
avoid potential future bugs in all of them.

Change-Id: Id6c837e9133f22783dd92a81dfcc493e51bf2d21
2020-01-13 16:13:28 +01:00
Pau Espin Pedrol
62c9280590 lms: Improve smpl_buf error logging
Change-Id: I511abe2c333443b978a3767bd7b7e320e07c4930
2020-01-13 14:35:06 +01:00
Pau Espin Pedrol
1421adbc61 smpl_buf: Fix str_code() param and print unknown error val
Change-Id: I95fadac15b9ad337ebc7cfb44a20dcf803ff8a47
2020-01-13 14:34:19 +01:00
Pau Espin Pedrol
dccc82491c lms: Drop unused define
Change-Id: Iaf3361ed29dd552e5e52b62bc738fa20c6b583fe
2020-01-07 16:21:12 +01:00
Pau Espin Pedrol
bf58370675 lms: Move initialization of field started to constructor
Change-Id: I135a2ff4a419775169452be1128c7b30f7d638ad
2020-01-07 16:10:34 +01:00
Pau Espin Pedrol
7c84925ea4 doc: Update vty reference xml file
Change-Id: Ib2707204cbba6df813ffc08d7098093cf4393da0
2020-01-07 16:04:04 +01:00
Pau Espin Pedrol
fd99c6ce05 radioInterfaceMulti: Fail to tune on freq not following multi-arfcn restrictions
multi-arfcn feature uses a hardcoded disposition of logical channels on
a physical channel. Logical channels in the phisical channel are
separated by MCBTS_SPACING Hz, that is 4 GSM ARFCNs.

As a result, multi-arfcn restricts the TRX ARFCN setup to the following:
ARFCN(TRX0)=N, ARFCN(TRX1)=N+1*4, ARFCN(TRX2)=N+2*4, ...

Let's make sure radioInterfaceMulti verifies the requested Rx/Tx
frequencies for each logical channel over TRXC match the restriction
explained above. It will check freq going to be set is indeed separated
by MCBTS_SPACING from already set channels, making sure the ARFCN series
is consistent.

Otherwise, before this patch, one could set in osmo-bsc:
ARFCN(TRX0)=N, ARFCN(TRX1)=N+2

and osmo-trx would silently ack the related Rx/TxTUNE TRXC commands, but
actually still transmit on ARFCN N+4 instead. As a result, in this
scenario TRX!=0 were unusable with multi-arfcn.

Related: OS#4207
Change-Id: I2f3d66a611d3a489b3e4d9431994f4ec77b4460f
2020-01-07 16:04:04 +01:00
Pau Espin Pedrol
e947db8d98 doc: clarify number of channels on B210 with multi-arfcn enabled
Change-Id: I082d4d8c346f1be1569fe63baa856029e439cb2c
2020-01-07 16:04:04 +01:00
Pau Espin Pedrol
9279e0e123 uhd: Improve some logging lines printing UHD pretty-print output
Change-Id: If5aba28aaf8a3312d89b3e963184f9f20966d199
2020-01-07 16:04:04 +01:00
Pau Espin Pedrol
84231bd8b7 uhd: Use DEVDRV log category and support UHD >=3.11 logging framework
Change-Id: I36f1ff7d425a2144fb512ff393af02741eb4a3d4
2020-01-07 16:04:04 +01:00
Pau Espin Pedrol
aebbfe0ee7 Make logging category DLMS generic and reusable for other backends
Make sure old configs using "logging level lms <level>" are still accepted.
Initialization order of VTY componenets need to be resorted since newly
introduced command requires logging VTY node to be already setup
beforehand.

Change-Id: Ia195a74a62a8a3dd6267fb1359acaa5628208d8e
2020-01-07 16:04:04 +01:00
31 changed files with 651 additions and 283 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 convience but constituting a distinct document, not part of the
same file for convenience 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

@@ -58,6 +58,9 @@ 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

@@ -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 copyable type class, optimize:
/*TODO if not non-trivially copiable type class, optimize:
memcpy(dst,mStart,span*sizeof(T)); */
}

View File

@@ -21,7 +21,17 @@
* See the COPYING file in the main directory for details.
*/
#include <pthread.h>
#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 <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
@@ -63,11 +73,11 @@ static const struct log_info_cat default_categories[] = {
.name = "DDEV",
.description = "Device/Driver specific code",
.color = NULL,
.enabled = 1, .loglevel = LOGL_INFO,
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DLMS] = {
.name = "DLMS",
.description = "Logging from within LimeSuite itself",
[DDEVDRV] = {
.name = "DDEVDRV",
.description = "Logging from external device driver library implementing lower level specifics",
.color = NULL,
.enabled = 1, .loglevel = LOGL_NOTICE,
},
@@ -77,3 +87,15 @@ const struct log_info log_info = {
.cat = default_categories,
.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
}

View File

@@ -1,7 +1,7 @@
#pragma once
#include <stdbool.h>
#include <pthread.h>
#include <sys/types.h>
#include <osmocom/core/logging.h>
@@ -15,13 +15,15 @@ enum {
DTRXDDL,
DTRXDUL,
DDEV,
DLMS,
DDEVDRV,
};
pid_t my_gettid(void);
#define CLOGC(category, level, fmt, args...) do { \
LOGP(category, level, "[tid=%lu] " fmt, pthread_self(), ##args); \
LOGP(category, level, "[tid=%ld] " fmt, (long int) my_gettid(), ##args); \
} while(0)
#define CLOGCHAN(chan, category, level, fmt, args...) do { \
LOGP(category, level, "[tid=%lu][chan=%lu] " fmt, pthread_self(), chan, ##args); \
LOGP(category, level, "[tid=%ld][chan=%zu] " fmt, (long int) my_gettid(), chan, ##args); \
} while(0)

View File

@@ -32,6 +32,7 @@
#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>
@@ -41,7 +42,7 @@
static struct trx_ctx* g_trx_ctx;
static const struct value_string clock_ref_names[] = {
const struct value_string clock_ref_names[] = {
{ REF_INTERNAL, "internal" },
{ REF_EXTERNAL, "external" },
{ REF_GPS, "gpsdo" },
@@ -731,5 +732,7 @@ 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,6 +5,7 @@
#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 */

View File

@@ -45,6 +45,8 @@ extern "C" {
using namespace GSM;
Transceiver *transceiver;
#define USB_LATENCY_INTRVL 10,0
/* Number of running values use in noise average */
@@ -151,20 +153,30 @@ Transceiver::~Transceiver()
close(mClockSocket);
for (size_t i = 0; i < mChans; i++) {
if (mControlServiceLoopThreads[i]) {
mControlServiceLoopThreads[i]->cancel();
mControlServiceLoopThreads[i]->join();
delete mControlServiceLoopThreads[i];
}
mTxPriorityQueues[i].clear();
if (mCtrlSockets[i] >= 0)
close(mCtrlSockets[i]);
if (mDataSockets[i] >= 0)
close(mDataSockets[i]);
}
}
int Transceiver::ctrl_sock_cb(struct osmo_fd *bfd, unsigned int flags)
{
int rc = 0;
int chan = static_cast<int>(reinterpret_cast<uintptr_t>(bfd->data));
if (flags & OSMO_FD_READ)
rc = transceiver->ctrl_sock_handle_rx(chan);
if (rc < 0)
osmo_signal_dispatch(SS_MAIN, S_MAIN_STOP_REQUIRED, NULL);
if (flags & OSMO_FD_WRITE)
rc = transceiver->ctrl_sock_write(chan);
if (rc < 0)
osmo_signal_dispatch(SS_MAIN, S_MAIN_STOP_REQUIRED, NULL);
return rc;
}
/*
* Initialize transceiver
*
@@ -193,8 +205,7 @@ bool Transceiver::init(FillerType filler, size_t rtsc, unsigned rach_delay,
mEdge = edge;
mDataSockets.resize(mChans, -1);
mCtrlSockets.resize(mChans, -1);
mControlServiceLoopThreads.resize(mChans);
mCtrlSockets.resize(mChans);
mTxPriorityQueueServiceLoopThreads.resize(mChans);
mRxServiceLoopThreads.resize(mChans);
@@ -216,24 +227,34 @@ bool Transceiver::init(FillerType filler, size_t rtsc, unsigned rach_delay,
return false;
for (size_t i = 0; i < mChans; i++) {
int rv;
c_srcport = mBasePort + 2 * i + 1;
c_dstport = mBasePort + 2 * i + 101;
d_srcport = mBasePort + 2 * i + 2;
d_dstport = mBasePort + 2 * i + 102;
mCtrlSockets[i] = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
rv = osmo_sock_init2_ofd(&mCtrlSockets[i].conn_bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
mLocalAddr.c_str(), c_srcport,
mRemoteAddr.c_str(), c_dstport,
OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
if (mCtrlSockets[i] < 0)
if (rv < 0)
return false;
mCtrlSockets[i].conn_bfd.cb = ctrl_sock_cb;
mCtrlSockets[i].conn_bfd.data = reinterpret_cast<void*>(i);
mDataSockets[i] = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
mLocalAddr.c_str(), d_srcport,
mRemoteAddr.c_str(), d_dstport,
OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
if (mCtrlSockets[i] < 0)
if (mDataSockets[i] < 0)
return false;
if (i && filler == FILLER_DUMMY)
filler = FILLER_ZERO;
mStates[i].init(filler, mSPSTx, txFullScale, rtsc, rach_delay);
}
/* Randomize the central clock */
@@ -243,21 +264,6 @@ bool Transceiver::init(FillerType filler, size_t rtsc, unsigned rach_delay,
mLastClockUpdateTime = startTime;
mLatencyUpdateTime = startTime;
/* Start control threads */
for (size_t i = 0; i < mChans; i++) {
TrxChanThParams *params = (TrxChanThParams *)malloc(sizeof(struct TrxChanThParams));
params->trx = this;
params->num = i;
mControlServiceLoopThreads[i] = new Thread(stackSize);
mControlServiceLoopThreads[i]->start((void * (*)(void*))
ControlServiceLoopAdapter, (void*) params);
if (i && filler == FILLER_DUMMY)
filler = FILLER_ZERO;
mStates[i].init(filler, mSPSTx, txFullScale, rtsc, rach_delay);
}
return true;
}
@@ -719,8 +725,6 @@ void Transceiver::reset()
}
#define MAX_PACKET_LENGTH 100
/**
* Matches a buffer with a command.
* @param buf a buffer to look command in
@@ -750,27 +754,77 @@ static bool match_cmd(char *buf,
return true;
}
bool Transceiver::driveControl(size_t chan)
void Transceiver::ctrl_sock_send(ctrl_msg& m, int chan)
{
char buffer[MAX_PACKET_LENGTH + 1];
char response[MAX_PACKET_LENGTH + 1];
ctrl_sock_state& s = mCtrlSockets[chan];
struct osmo_fd *conn_bfd = &s.conn_bfd;
s.txmsgqueue.push_back(m);
conn_bfd->when |= OSMO_FD_WRITE;
}
int Transceiver::ctrl_sock_write(int chan)
{
int rc;
ctrl_sock_state& s = mCtrlSockets[chan];
if (s.conn_bfd.fd < 0) {
return -EIO;
}
while (s.txmsgqueue.size()) {
const ctrl_msg m = s.txmsgqueue.front();
s.conn_bfd.when &= ~OSMO_FD_WRITE;
/* try to send it over the socket */
rc = write(s.conn_bfd.fd, m.data, strlen(m.data) + 1);
if (rc == 0)
goto close;
if (rc < 0) {
if (errno == EAGAIN) {
s.conn_bfd.when |= OSMO_FD_WRITE;
break;
}
goto close;
}
s.txmsgqueue.pop_front();
}
return 0;
close:
LOGCHAN(chan, DTRXCTRL, NOTICE) << "mCtrlSockets write(" << s.conn_bfd.fd << ") failed: " << rc;
return -1;
}
int Transceiver::ctrl_sock_handle_rx(int chan)
{
ctrl_msg cmd_received;
ctrl_msg cmd_to_send;
char *buffer = cmd_received.data;
char *response = cmd_to_send.data;
char *command, *params;
int msgLen;
ctrl_sock_state& s = mCtrlSockets[chan];
/* Attempt to read from control socket */
msgLen = read(mCtrlSockets[chan], buffer, MAX_PACKET_LENGTH);
msgLen = read(s.conn_bfd.fd, buffer, sizeof(cmd_received.data)-1);
if (msgLen < 0 && errno == EAGAIN)
return 0; /* Try again later */
if (msgLen <= 0) {
LOGCHAN(chan, DTRXCTRL, NOTICE) << "mCtrlSockets read(" << mCtrlSockets[chan] << ") failed: " << msgLen;
return false;
LOGCHAN(chan, DTRXCTRL, NOTICE) << "mCtrlSockets read(" << s.conn_bfd.fd << ") failed: " << msgLen;
return -EIO;
}
/* Zero-terminate received string */
buffer[msgLen] = '\0';
/* Verify a command signature */
if (strncmp(buffer, "CMD ", 4)) {
LOGCHAN(chan, DTRXCTRL, NOTICE) << "bogus message on control interface";
return false;
return -EIO;
}
/* Set command pointer */
@@ -889,7 +943,7 @@ bool Transceiver::driveControl(size_t chan)
if ((timeslot < 0) || (timeslot > 7)) {
LOGCHAN(chan, DTRXCTRL, NOTICE) << "bogus message on control interface";
sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
return true;
return 0;
}
mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
setModulus(timeslot, chan);
@@ -921,12 +975,8 @@ bool Transceiver::driveControl(size_t chan)
}
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;
return false;
}
return true;
transceiver->ctrl_sock_send(cmd_to_send, chan);
return 0;
}
bool Transceiver::driveTxPriorityQueue(size_t chan)
@@ -940,7 +990,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, DTRXDDL, NOTICE) << "mDataSockets read(" << mDataSockets[chan] << ") failed: " << msgLen;
return false;
}
@@ -1179,28 +1229,6 @@ void *TxLowerLoopAdapter(Transceiver *transceiver)
return NULL;
}
void *ControlServiceLoopAdapter(TrxChanThParams *params)
{
char thread_name[16];
Transceiver *trx = params->trx;
size_t num = params->num;
free(params);
snprintf(thread_name, 16, "CtrlService%zu", num);
set_selfthread_name(thread_name);
while (1) {
if (!trx->driveControl(num)) {
LOGCHAN(num, DTRXCTRL, FATAL) << "Something went wrong in thread " << thread_name << ", requesting stop";
osmo_signal_dispatch(SS_MAIN, S_MAIN_STOP_REQUIRED, NULL);
break;
}
pthread_testcancel();
}
return NULL;
}
void *TxUpperLoopAdapter(TrxChanThParams *params)
{
char thread_name[16];

View File

@@ -33,11 +33,14 @@
extern "C" {
#include <osmocom/core/signal.h>
#include <osmocom/core/select.h>
#include "config_defs.h"
}
class Transceiver;
extern Transceiver *transceiver;
/** Channel descriptor for transceiver object and channel number pair */
struct TrxChanThParams {
Transceiver *trx;
@@ -142,12 +145,33 @@ public:
} ChannelCombination;
private:
struct ctrl_msg {
char data[101];
ctrl_msg() {};
};
struct ctrl_sock_state {
osmo_fd conn_bfd;
std::deque<ctrl_msg> txmsgqueue;
ctrl_sock_state() {
conn_bfd.fd = -1;
}
~ctrl_sock_state() {
if(conn_bfd.fd >= 0) {
close(conn_bfd.fd);
conn_bfd.fd = -1;
osmo_fd_unregister(&conn_bfd);
}
}
};
int mBasePort;
std::string mLocalAddr;
std::string mRemoteAddr;
std::vector<int> mDataSockets; ///< socket for writing to/reading from GSM core
std::vector<int> mCtrlSockets; ///< socket for writing/reading control commands from GSM core
std::vector<ctrl_sock_state> mCtrlSockets; ///< socket for writing/reading control commands from GSM core
int mClockSocket; ///< socket for writing clock updates to GSM core
std::vector<VectorQueue> mTxPriorityQueues; ///< priority queue of transmit bursts received from GSM core
@@ -156,7 +180,6 @@ private:
std::vector<Thread *> mRxServiceLoopThreads; ///< thread to pull bursts into receive FIFO
Thread *mRxLowerLoopThread; ///< thread to pull bursts into receive FIFO
Thread *mTxLowerLoopThread; ///< thread to push bursts into transmit FIFO
std::vector<Thread *> mControlServiceLoopThreads; ///< thread to process control messages from GSM core
std::vector<Thread *> mTxPriorityQueueServiceLoopThreads; ///< thread to process transmit bursts from GSM core
GSM::Time mTransmitLatency; ///< latency between basestation clock and transmit deadline clock
@@ -193,6 +216,12 @@ private:
/** send messages over the clock socket */
bool writeClockInterface(void);
static int ctrl_sock_cb(struct osmo_fd *bfd, unsigned int flags);
int ctrl_sock_write(int chan);
void ctrl_sock_send(ctrl_msg& m, int chan);
/** drive handling of control messages from GSM core */
int ctrl_sock_handle_rx(int chan);
int mSPSTx; ///< number of samples per Tx symbol
int mSPSRx; ///< number of samples per Rx symbol
size_t mChans;
@@ -229,9 +258,6 @@ protected:
/** drive transmission of GSM bursts */
void driveTxFIFO();
/** drive handling of control messages from GSM core */
bool driveControl(size_t chan);
/**
drive modulation and sorting of GSM bursts from GSM core
@return true if a burst was transferred successfully
@@ -242,7 +268,6 @@ protected:
friend void *TxUpperLoopAdapter(TrxChanThParams *params);
friend void *RxLowerLoopAdapter(Transceiver *transceiver);
friend void *TxLowerLoopAdapter(Transceiver *transceiver);
friend void *ControlServiceLoopAdapter(TrxChanThParams *params);
void reset();
@@ -256,8 +281,5 @@ void *RxUpperLoopAdapter(TrxChanThParams *params);
void *RxLowerLoopAdapter(Transceiver *transceiver);
void *TxLowerLoopAdapter(Transceiver *transceiver);
/** control message handler thread loop */
void *ControlServiceLoopAdapter(TrxChanThParams *params);
/** transmit queueing thread loop */
void *TxUpperLoopAdapter(TrxChanThParams *params);

View File

@@ -77,23 +77,20 @@ 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,
unsigned *RSSI = 0) = 0;
TIMESTAMP timestamp = 0xffffffff, bool *underrun = 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, bool isControl = false) = 0;
TIMESTAMP timestamp) = 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(ssize_t code)
std::string smpl_buf::str_code(int code)
{
switch (code) {
case ERROR_TIMESTAMP:
@@ -166,6 +166,8 @@ std::string smpl_buf::str_code(ssize_t code)
case ERROR_OVERFLOW:
return "Sample buffer: Overrun";
default:
return "Sample buffer: Unknown error";
std::stringstream ss;
ss << "Sample buffer: Unknown error " << code;
return ss.str();
}
}

View File

@@ -68,7 +68,7 @@ public:
@param code an error code
@return a formatted error string
*/
static std::string str_code(ssize_t code);
static std::string str_code(int code);
enum err_code {
ERROR_TIMESTAMP = -1,

View File

@@ -20,6 +20,10 @@
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <map>
#include "trx_vty.h"
#include "Logger.h"
#include "Threads.h"
#include "LMSDevice.h"
@@ -39,17 +43,74 @@ 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 */
LMSDevice::LMSDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chans, double lo_offset,
/* 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,
const std::vector<std::string>& tx_paths,
const std::vector<std::string>& rx_paths):
RadioDevice(tx_sps, rx_sps, iface, chans, lo_offset, tx_paths, rx_paths),
m_lms_dev(NULL)
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)
{
LOGC(DDEV, INFO) << "creating LMS device...";
@@ -59,6 +120,11 @@ 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()
@@ -93,7 +159,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(DLMS, lvl_map[lvl]) << msg;
LOGLV(DDEVDRV, lvl_map[lvl]) << msg;
}
static void print_range(const char* name, lms_range_t *range)
@@ -110,7 +176,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;
vector<string> filters;
std::vector<string> filters;
filters = comma_delimited_to_vector(args.c_str());
@@ -134,11 +200,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..";
@@ -175,19 +241,20 @@ int LMSDevice::open(const std::string &args, int ref, bool swap_channels)
delete [] info_list;
device_info = LMS_GetDeviceInfo(m_lms_dev);
m_dev_type = parse_dev_type(m_lms_dev);
dev_desc = dev_param_map.at(m_dev_type);
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 */
/* FIXME make external reference frequency configurable */
/* if reference clock is external, setup must happen _before_ calling LMS_Init */
if (ref == REF_EXTERNAL) {
LOGC(DDEV, INFO) << "Setting External clock reference to 10MHz";
/* Assume an external 10 MHz reference clock */
if (LMS_SetClockFreq(m_lms_dev, LMS_CLOCK_EXTREF, 10000000.0) < 0)
/* FIXME: Assume an external 10 MHz reference clock. make
external reference frequency configurable */
if (!do_clock_src_freq(REF_EXTERNAL, 10000000.0))
goto out_close;
}
@@ -197,22 +264,13 @@ int LMSDevice::open(const std::string &args, int ref, bool swap_channels)
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?*/
/* 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;
}
/* enable all used channels */
for (i=0; i<chans; i++) {
@@ -227,16 +285,22 @@ int LMSDevice::open(const std::string &args, int ref, bool swap_channels)
goto out_close;
print_range("Sample Rate", &range_sr);
LOGC(DDEV, INFO) << "Setting sample rate to " << GSMRATE*tx_sps << " " << tx_sps;
if (LMS_SetSampleRate(m_lms_dev, GSMRATE*tx_sps, 32) < 0)
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)
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;
/* 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 */
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);
/* configure antennas */
if (!set_antennas()) {
@@ -244,13 +308,7 @@ int LMSDevice::open(const std::string &args, int ref, bool swap_channels)
goto out_close;
}
/* 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;
return iface == MULTI_ARFCN ? MULTI_ARFCN : NORMAL;
out_close:
LOGC(DDEV, FATAL) << "Error in LMS open, closing: " << LMS_GetLastErrorMessage();
@@ -344,6 +402,43 @@ 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)
{
@@ -385,7 +480,7 @@ bool LMSDevice::do_filters(size_t chan)
double LMSDevice::maxTxGain()
{
return maxTxGainClamp;
return dev_param_map.at(m_dev_type).max_tx_gain;
}
double LMSDevice::minTxGain()
@@ -644,7 +739,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, unsigned *RSSI)
TIMESTAMP timestamp, bool * underrun)
{
int rc, num_smpls, expect_smpls;
ssize_t avail_smpls;
@@ -711,8 +806,9 @@ 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)) {
LOGC(DDEV, ERROR) << rx_buffers[i]->str_code(rc);
LOGC(DDEV, ERROR) << rx_buffers[i]->str_status(timestamp);
LOGCHAN(i, DDEV, ERROR) << rx_buffers[i]->str_code(rc) << ". "
<< rx_buffers[i]->str_status(timestamp)
<< ", (len=" << len << ")";
return 0;
}
}
@@ -762,8 +858,7 @@ 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 isControl)
bool * underrun, unsigned long long timestamp)
{
int rc = 0;
unsigned int i;
@@ -772,11 +867,6 @@ 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

@@ -41,6 +41,13 @@
* 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 {
@@ -59,7 +66,8 @@ private:
TIMESTAMP ts_initial, ts_offset;
std::vector<double> tx_gains, rx_gains;
double maxTxGainClamp;
enum lms_dev_type m_dev_type;
bool do_calib(size_t chan);
bool do_filters(size_t chan);
@@ -68,11 +76,12 @@ 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 chans, double lo_offset,
LMSDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chan_num, double lo_offset,
const std::vector<std::string>& tx_paths,
const std::vector<std::string>& rx_paths);
~LMSDevice();
@@ -97,24 +106,21 @@ 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, unsigned *RSSI = NULL);
NULL);
/**
Write samples to the LMS.
@param buf Contains the data to be written.
@param len number of samples to write.
@param underrun Set if LMS does not have data to transmit, e.g. data not being sent fast enough
@param timestamp The timestamp of the first sample of the data buffer.
@param isControl Set if data is a control packet, e.g. a ping command
@return The number of samples actually written
*/
int writeSamples(std::vector < short *>&bufs, int len, bool * underrun,
TIMESTAMP timestamp = 0xffffffff, bool isControl =
false);
TIMESTAMP timestamp = 0xffffffff);
/** Update the alignment between the read and write timestamps */
bool updateAlignment(TIMESTAMP timestamp);

View File

@@ -33,11 +33,12 @@
#include "config.h"
#endif
#ifndef USE_UHD_3_11
#ifdef USE_UHD_3_11
#include <uhd/utils/log_add.hpp>
#include <uhd/utils/thread.hpp>
#else
#include <uhd/utils/msg.hpp>
#include <uhd/utils/thread_priority.hpp>
#else
#include <uhd/utils/thread.hpp>
#endif
#define USRP_TX_AMPL 0.3
@@ -134,23 +135,52 @@ void *async_event_loop(uhd_device *dev)
return NULL;
}
#ifndef USE_UHD_3_11
#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
/*
Catch and drop underrun 'U' and overrun 'O' messages from stdout
since we already report using the logging facility. Direct
everything else appropriately.
*/
void uhd_msg_handler(uhd::msg::type_t type, const std::string &msg)
static void uhd_msg_handler(uhd::msg::type_t type, const std::string &msg)
{
switch (type) {
case uhd::msg::status:
LOGC(DDEV, INFO) << msg;
LOGC(DDEVDRV, INFO) << msg;
break;
case uhd::msg::warning:
LOGC(DDEV, WARNING) << msg;
LOGC(DDEVDRV, NOTICE) << msg;
break;
case uhd::msg::error:
LOGC(DDEV, ERROR) << msg;
LOGC(DDEVDRV, ERROR) << msg;
break;
case uhd::msg::fastpath:
break;
@@ -159,10 +189,10 @@ 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 chans, double lo_offset,
InterfaceType iface, size_t chan_num, 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),
: RadioDevice(tx_sps, rx_sps, iface, chan_num, 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),
@@ -418,6 +448,16 @@ 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);
@@ -526,7 +566,7 @@ int uhd_device::open(const std::string &args, int ref, bool swap_channels)
init_gains();
// Print configuration
LOGC(DDEV, INFO) << "\n" << usrp_dev->get_pp_string();
LOGC(DDEV, INFO) << "Device configuration: " << usrp_dev->get_pp_string();
if (iface == MULTI_ARFCN)
return MULTI_ARFCN;
@@ -604,10 +644,6 @@ 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);
@@ -685,7 +721,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, unsigned *RSSI)
TIMESTAMP timestamp, bool *underrun)
{
ssize_t rc;
uhd::time_spec_t ts;
@@ -768,7 +804,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,bool isControl)
unsigned long long timestamp)
{
uhd::tx_metadata_t metadata;
metadata.has_time_spec = true;
@@ -778,12 +814,6 @@ 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;
@@ -883,15 +913,18 @@ 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";
}
LOGC(DDEV, INFO) << "\n" << tres.to_pp_string() << std::endl;
LOGCHAN(chan, DDEV, INFO) << "set_freq(" << freq << ", " << str_dir << "): " << tres.to_pp_string() << std::endl;
if ((chans == 1) || ((chans == 2) && dev_type == UMTRX))
return true;
@@ -911,7 +944,7 @@ bool uhd_device::set_freq(double freq, size_t chan, bool tx)
rx_freqs[!chan] = usrp_dev->get_rx_freq(!chan);
}
LOGC(DDEV, INFO) << "\n" << tres.to_pp_string() << std::endl;
LOGCHAN(chan, DDEV, INFO) << "set_freq(" << freq << ", " << str_dir << "): " << tres.to_pp_string() << std::endl;
}
return true;

View File

@@ -62,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 chans, double offset,
size_t chan_num, double offset,
const std::vector<std::string>& tx_paths,
const std::vector<std::string>& rx_paths);
~uhd_device();
@@ -74,10 +74,10 @@ public:
enum TxWindowType getWindowType() { return tx_window; }
int readSamples(std::vector<short *> &bufs, int len, bool *overrun,
TIMESTAMP timestamp, bool *underrun, unsigned *RSSI);
TIMESTAMP timestamp, bool *underrun);
int writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
TIMESTAMP timestamp, bool isControl);
TIMESTAMP timestamp);
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 chans, double lo_offset,
size_t chan_num, 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)
RadioDevice(tx_sps, rx_sps, iface, chan_num, 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, unsigned *RSSI)
TIMESTAMP timestamp, bool *underrun)
{
#ifndef SWLOOPBACK
if (!m_uRx)
@@ -433,8 +433,10 @@ int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
*underrun = true;
LOGC(DDEV, DEBUG) << "UNDERRUN in TRX->USRP interface";
}
if (RSSI) *RSSI = (word0 >> 21) & 0x3f;
#if 0
/* FIXME: Do something with this ? */
unsigned RSSI = (word0 >> 21) & 0x3f;
#endif
if (!isAligned) continue;
unsigned cursorStart = pktTimestamp - timeStart + dataStart;
@@ -513,9 +515,8 @@ int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
#endif
}
int USRPDevice::writeSamples(std::vector<short *> &bufs, int len,
bool *underrun, unsigned long long timestamp,
bool isControl)
int USRPDevice::writeSamplesControl(std::vector<short *> &bufs, int len,
bool *underrun, unsigned long long timestamp, bool isControl)
{
writeLock.lock();
@@ -569,6 +570,12 @@ int USRPDevice::writeSamples(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
@@ -578,7 +585,7 @@ bool USRPDevice::updateAlignment(TIMESTAMP timestamp)
bool tmpUnderrun;
std::vector<short *> buf(1, data);
if (writeSamples(buf, 1, &tmpUnderrun, timestamp & 0x0ffffffffll, true)) {
if (writeSamplesControl(buf, 1, &tmpUnderrun, timestamp & 0x0ffffffffll, true)) {
pingTimestamp = timestamp;
return true;
}

View File

@@ -82,6 +82,9 @@ 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;
@@ -95,7 +98,7 @@ private:
public:
/** Object constructor */
USRPDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chans, double lo_offset,
USRPDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chan_num, double lo_offset,
const std::vector<std::string>& tx_paths,
const std::vector<std::string>& rx_paths);
@@ -117,23 +120,20 @@ 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,
unsigned *RSSI = NULL);
TIMESTAMP timestamp = 0xffffffff, bool *underrun = 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, bool isControl = false);
TIMESTAMP timestamp = 0xffffffff);
/** Update the alignment between the read and write timestamps */
bool updateAlignment(TIMESTAMP timestamp);

View File

@@ -79,7 +79,6 @@ static struct ctrl_handle *g_ctrlh;
static RadioDevice *usrp;
static RadioInterface *radio;
static Transceiver *transceiver;
/* Create radio interface
* The interface consists of sample rate changes, frequency shifts,
@@ -588,10 +587,10 @@ int main(int argc, char *argv[])
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

@@ -156,16 +156,24 @@ 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,6 +73,8 @@ void RadioInterfaceMulti::close()
powerScaling.resize(0);
history.resize(0);
active.resize(0);
rx_freq_state.resize(0);
tx_freq_state.resize(0);
RadioInterface::close();
}
@@ -148,6 +150,8 @@ 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;
@@ -362,42 +366,67 @@ 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)
{
if (chan >= mChans)
return false;
double shift;
double shift = (double) getFreqShift(mChans);
if (chan >= mChans)
return false;
if (!chan)
return mDevice->setTxFreq(freq + shift * MCBTS_SPACING);
if (!verify_arfcn_consistency(freq, chan, true))
return false;
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";
}
if (chan == 0) {
shift = (double) getFreqShift(mChans);
return mDevice->setTxFreq(freq + shift * MCBTS_SPACING);
}
return true;
return true;
}
bool RadioInterfaceMulti::tuneRx(double freq, size_t chan)
{
if (chan >= mChans)
return false;
double shift;
double shift = (double) getFreqShift(mChans);
if (chan >= mChans)
return false;
if (!chan)
return mDevice->setRxFreq(freq + shift * MCBTS_SPACING);
if (!verify_arfcn_consistency(freq, chan, false))
return false;
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";
}
if (chan == 0) {
shift = (double) getFreqShift(mChans);
return mDevice->setRxFreq(freq + shift * MCBTS_SPACING);
}
return true;
return true;
}
double RadioInterfaceMulti::setRxGain(double db, size_t chan)

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 copyable types: */
/* TODO: optimize for non non-trivially copiable 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 copyable types: */
/* TODO: optimize for non non-trivially copiable types: */
/*memmove(mData, mStart + this->size() - num, num * sizeof(complex)); */
return num;

View File

@@ -51,6 +51,11 @@ AC_PROG_INSTALL
AC_PATH_PROG([RM_PROG], [rm])
AC_LANG([C++])
dnl patching ${archive_cmds} to affect generation of file "libtool" to fix linking with clang
AS_CASE(["$LD"],[*clang*],
[AS_CASE(["${host_os}"],
[*linux*],[archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'])])
dnl check for pkg-config (explained in detail in libosmocore/configure.ac)
AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no)
if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
@@ -75,6 +80,15 @@ 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)

View File

@@ -23,15 +23,8 @@ 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
@@ -69,6 +62,20 @@ 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"

6
debian/changelog vendored
View File

@@ -1,3 +1,9 @@
osmo-trx (1.2.0-fw.1) unstable; urgency=medium
* relocated to master:a7143bf7a12e
-- Kirill Zakharenko <kirill.zakharenko@fairwaves.co> Fri, 1 May 2020 18:23:29 +0300
osmo-trx (1.2.0) unstable; urgency=medium
[ Pau Espin Pedrol ]

View File

@@ -12,7 +12,6 @@ line vty
trx
bind-ip 127.0.0.1
remote-ip 127.0.0.1
base-port 5700
egprs disable
tx-sps 4
rx-sps 4

View File

@@ -12,7 +12,6 @@ line vty
trx
bind-ip 127.0.0.1
remote-ip 127.0.0.1
base-port 5700
egprs disable
tx-sps 4
rx-sps 4

View File

@@ -12,7 +12,6 @@ line vty
trx
bind-ip 127.0.0.1
remote-ip 127.0.0.1
base-port 5700
dev-args addr=192.168.10.2,pa=NONE,pa_power_max_dbm=23,fifo_ctrl_window=0,status_port=12345
egprs disable
tx-sps 4

View File

@@ -12,8 +12,10 @@ line vty
trx
bind-ip 127.0.0.1
remote-ip 127.0.0.1
base-port 5700
egprs disable
! 28 dB offset below is valid only for the B2xx in 1800 MHz band, see
! https://osmocom.org/issues/4468 for more details
rssi-offset 28.000000
tx-sps 4
rx-sps 4
clock-ref external

View File

@@ -46,15 +46,16 @@ 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 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.
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.
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 TRX through multi-ARFCN
From BTS and BSC point of view, supporting multiple TRXs 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

@@ -18,10 +18,11 @@
<param name='terminal' doc='Write to terminal' />
</params>
</command>
<command id='write file'>
<command id='write file [PATH]'>
<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'>
@@ -96,12 +97,6 @@
<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' />
@@ -193,14 +188,17 @@
<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|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)'>
<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)'>
<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='lms' doc='Logging from within LimeSuite itself' />
<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' />
@@ -259,6 +257,43 @@
<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' />
@@ -272,6 +307,12 @@
<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' />
@@ -415,12 +456,6 @@
<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' />
@@ -512,14 +547,17 @@
<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|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)'>
<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)'>
<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='lms' doc='Logging from within LimeSuite itself' />
<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' />
@@ -578,6 +616,43 @@
<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' />
@@ -591,6 +666,12 @@
<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' />
@@ -772,16 +853,6 @@
<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' />
@@ -861,6 +932,16 @@
<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' />
@@ -973,14 +1054,17 @@
<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|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)'>
<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)'>
<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='lms' doc='Logging from within LimeSuite itself' />
<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' />
@@ -1179,20 +1263,6 @@
<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' />
@@ -1247,10 +1317,29 @@
<param name='&lt;1-32&gt;' doc='Real time priority' />
</params>
</command>
<command id='filler dummy'>
<command id='filler type (zero|dummy|random-nb-gmsk|random-nb-8psk|random-ab)'>
<params>
<param name='filler' doc='Enable C0 filler table' />
<param name='dummy' doc='Dummy method' />
<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' />
</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)'>