2013-11-16 02:14:33 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2013 Thomas Tsou <tom@tsou.cc>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library 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
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "Transceiver.h"
|
|
|
|
#include "radioDevice.h"
|
2018-12-12 15:03:38 +00:00
|
|
|
#include "Utils.h"
|
2013-11-16 02:14:33 +00:00
|
|
|
|
|
|
|
#include <time.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
2018-10-23 11:12:17 +00:00
|
|
|
#include <getopt.h>
|
2017-06-29 13:35:22 +00:00
|
|
|
#include <sched.h>
|
Add support to set Rx/TxAntenna
Some devices have different Rx or Tx ports with different RF characteristics.
For instance LimeSDR has H (High), L (Low) and W (Wide) band Rx ports,
each of one being more suitable to a specific range of frequencies.
In case one wants to support several GSM bands, the best option is to
use the WideBand port and connect the antenna physically to that port in
the board. Then the firmware must be instructed ro read from that port.
Support for Rx/Tx port configuration is already in there for all the
layers (Limesuite, SoapySDR, SoapyUHD, UHD), but we are missing the
required bits in osmo-trx to make use of the available UHD API. This
commit addresses it.
Before this patch, the Rx/Tx paths configured could be changed by means
of the LimeSuiteGUI app, but after running osmo-trx, the values were
changed to the default ones.
One can now start using osmo-trx with 1 channel and specific Rx/Tx ports
by using for instance: osmo-trx -c 1 -y BAND1 -z LNAW
Default behaviour if no specific path or an empry path is passed ("") is
to do the same as preiously, ie. nothing by not calling the
set{T,R}xAntenna APIs.
One can also configure only specific channels, for instance to configure
only the first Tx channel and the second Rx channel:
osmo-trx -c 2 -y BAND1, -z ,LNAW
Change-Id: I1735e6ab05a05b0312d6d679b16ebd4a2260fa23
2018-02-05 12:05:06 +00:00
|
|
|
#include <vector>
|
|
|
|
#include <string>
|
|
|
|
#include <sstream>
|
|
|
|
#include <iostream>
|
2013-11-16 02:14:33 +00:00
|
|
|
|
|
|
|
#include <GSMCommon.h>
|
|
|
|
#include <Logger.h>
|
|
|
|
|
2017-03-15 17:09:35 +00:00
|
|
|
extern "C" {
|
2018-02-21 19:15:47 +00:00
|
|
|
#include <osmocom/core/talloc.h>
|
2018-02-21 19:15:18 +00:00
|
|
|
#include <osmocom/core/application.h>
|
2018-02-21 19:15:47 +00:00
|
|
|
#include <osmocom/core/msgb.h>
|
2018-02-20 15:48:15 +00:00
|
|
|
#include <osmocom/core/stats.h>
|
|
|
|
#include <osmocom/vty/logging.h>
|
|
|
|
#include <osmocom/vty/ports.h>
|
|
|
|
#include <osmocom/vty/misc.h>
|
|
|
|
#include <osmocom/vty/telnet_interface.h>
|
|
|
|
#include <osmocom/ctrl/control_vty.h>
|
|
|
|
#include <osmocom/ctrl/ports.h>
|
|
|
|
#include <osmocom/ctrl/control_if.h>
|
|
|
|
#include <osmocom/vty/stats.h>
|
2018-06-15 13:19:21 +00:00
|
|
|
#include <osmocom/vty/command.h>
|
|
|
|
|
2017-03-15 17:09:35 +00:00
|
|
|
#include "convolve.h"
|
|
|
|
#include "convert.h"
|
2018-02-20 15:48:15 +00:00
|
|
|
#include "trx_vty.h"
|
|
|
|
#include "debug.h"
|
2018-09-03 14:50:49 +00:00
|
|
|
#include "osmo_signal.h"
|
2017-03-15 17:09:35 +00:00
|
|
|
}
|
|
|
|
|
2018-02-20 15:48:15 +00:00
|
|
|
#define DEFAULT_CONFIG_FILE "osmo-trx.cfg"
|
2013-11-16 02:14:33 +00:00
|
|
|
|
2018-02-21 17:47:35 +00:00
|
|
|
#define charp2str(a) ((a) ? std::string(a) : std::string(""))
|
|
|
|
|
|
|
|
static char* config_file = (char*)DEFAULT_CONFIG_FILE;
|
2013-11-16 02:14:33 +00:00
|
|
|
|
|
|
|
volatile bool gshutdown = false;
|
|
|
|
|
2018-02-21 19:15:47 +00:00
|
|
|
static void *tall_trx_ctx;
|
2018-02-20 15:48:15 +00:00
|
|
|
static struct trx_ctx *g_trx_ctx;
|
|
|
|
static struct ctrl_handle *g_ctrlh;
|
2018-02-21 19:15:47 +00:00
|
|
|
|
2018-02-21 10:59:26 +00:00
|
|
|
static RadioDevice *usrp;
|
|
|
|
static RadioInterface *radio;
|
|
|
|
static Transceiver *transceiver;
|
|
|
|
|
2013-11-16 02:14:33 +00:00
|
|
|
/* Create radio interface
|
|
|
|
* The interface consists of sample rate changes, frequency shifts,
|
|
|
|
* channel multiplexing, and other conversions. The transceiver core
|
|
|
|
* accepts input vectors sampled at multiples of the GSM symbol rate.
|
|
|
|
* The radio interface connects the main transceiver with the device
|
|
|
|
* object, which may be operating some other rate.
|
|
|
|
*/
|
2018-02-21 17:47:35 +00:00
|
|
|
RadioInterface *makeRadioInterface(struct trx_ctx *trx,
|
2013-11-16 02:14:33 +00:00
|
|
|
RadioDevice *usrp, int type)
|
|
|
|
{
|
|
|
|
RadioInterface *radio = NULL;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case RadioDevice::NORMAL:
|
2018-02-21 17:47:35 +00:00
|
|
|
radio = new RadioInterface(usrp, trx->cfg.tx_sps,
|
|
|
|
trx->cfg.rx_sps, trx->cfg.num_chans);
|
2013-11-16 02:14:33 +00:00
|
|
|
break;
|
|
|
|
case RadioDevice::RESAMP_64M:
|
|
|
|
case RadioDevice::RESAMP_100M:
|
2018-02-21 17:47:35 +00:00
|
|
|
radio = new RadioInterfaceResamp(usrp, trx->cfg.tx_sps,
|
|
|
|
trx->cfg.rx_sps);
|
2013-11-16 02:14:33 +00:00
|
|
|
break;
|
2016-06-24 21:25:39 +00:00
|
|
|
case RadioDevice::MULTI_ARFCN:
|
2018-02-21 17:47:35 +00:00
|
|
|
radio = new RadioInterfaceMulti(usrp, trx->cfg.tx_sps,
|
|
|
|
trx->cfg.rx_sps, trx->cfg.num_chans);
|
2016-06-24 21:25:39 +00:00
|
|
|
break;
|
2013-11-16 02:14:33 +00:00
|
|
|
default:
|
|
|
|
LOG(ALERT) << "Unsupported radio interface configuration";
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!radio->init(type)) {
|
|
|
|
LOG(ALERT) << "Failed to initialize radio interface";
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return radio;
|
|
|
|
}
|
|
|
|
|
2018-09-03 14:50:49 +00:00
|
|
|
/* Callback function to be called every time we receive a signal from TRANSC */
|
|
|
|
static int transc_sig_cb(unsigned int subsys, unsigned int signal,
|
|
|
|
void *handler_data, void *signal_data)
|
|
|
|
{
|
|
|
|
switch (signal) {
|
|
|
|
case S_TRANSC_STOP_REQUIRED:
|
|
|
|
gshutdown = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-11-16 02:14:33 +00:00
|
|
|
/* Create transceiver core
|
|
|
|
* The multi-threaded modem core operates at multiples of the GSM rate of
|
|
|
|
* 270.8333 ksps and consists of GSM specific modulation, demodulation,
|
|
|
|
* and decoding schemes. Also included are the socket interfaces for
|
|
|
|
* connecting to the upper layer stack.
|
|
|
|
*/
|
2018-02-21 17:47:35 +00:00
|
|
|
int makeTransceiver(struct trx_ctx *trx, RadioInterface *radio)
|
2013-11-16 02:14:33 +00:00
|
|
|
{
|
|
|
|
VectorFIFO *fifo;
|
|
|
|
|
2018-02-21 17:47:35 +00:00
|
|
|
transceiver = new Transceiver(trx->cfg.base_port, trx->cfg.bind_addr,
|
|
|
|
trx->cfg.remote_addr, trx->cfg.tx_sps,
|
|
|
|
trx->cfg.rx_sps, trx->cfg.num_chans, GSM::Time(3,0),
|
|
|
|
radio, trx->cfg.rssi_offset);
|
|
|
|
if (!transceiver->init(trx->cfg.filler, trx->cfg.rtsc,
|
|
|
|
trx->cfg.rach_delay, trx->cfg.egprs)) {
|
2013-11-16 02:14:33 +00:00
|
|
|
LOG(ALERT) << "Failed to initialize transceiver";
|
2018-02-21 10:59:26 +00:00
|
|
|
return -1;
|
2013-11-16 02:14:33 +00:00
|
|
|
}
|
|
|
|
|
2018-09-03 14:50:49 +00:00
|
|
|
transceiver->setSignalHandler(transc_sig_cb);
|
|
|
|
|
2018-02-21 17:47:35 +00:00
|
|
|
for (size_t i = 0; i < trx->cfg.num_chans; i++) {
|
2013-11-16 02:14:33 +00:00
|
|
|
fifo = radio->receiveFIFO(i);
|
2018-02-21 10:59:26 +00:00
|
|
|
if (fifo && transceiver->receiveFIFO(fifo, i))
|
2013-11-16 02:14:33 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
LOG(ALERT) << "Could not attach FIFO to channel " << i;
|
2018-02-21 10:59:26 +00:00
|
|
|
return -1;
|
2013-11-16 02:14:33 +00:00
|
|
|
}
|
2018-02-21 10:59:26 +00:00
|
|
|
return 0;
|
2013-11-16 02:14:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void sig_handler(int signo)
|
|
|
|
{
|
2018-02-21 19:15:18 +00:00
|
|
|
fprintf(stdout, "signal %d received\n", signo);
|
|
|
|
switch (signo) {
|
|
|
|
case SIGINT:
|
|
|
|
case SIGTERM:
|
|
|
|
fprintf(stdout, "shutting down\n");
|
|
|
|
gshutdown = true;
|
|
|
|
break;
|
2018-02-21 19:15:47 +00:00
|
|
|
case SIGABRT:
|
|
|
|
case SIGUSR1:
|
|
|
|
talloc_report(tall_trx_ctx, stderr);
|
|
|
|
talloc_report_full(tall_trx_ctx, stderr);
|
|
|
|
break;
|
|
|
|
case SIGUSR2:
|
|
|
|
talloc_report_full(tall_trx_ctx, stderr);
|
|
|
|
break;
|
2018-02-21 19:15:18 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2013-11-16 02:14:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void setup_signal_handlers()
|
|
|
|
{
|
2018-02-21 19:15:18 +00:00
|
|
|
/* Handle keyboard interrupt SIGINT */
|
|
|
|
signal(SIGINT, &sig_handler);
|
|
|
|
signal(SIGTERM, &sig_handler);
|
|
|
|
signal(SIGABRT, &sig_handler);
|
|
|
|
signal(SIGUSR1, &sig_handler);
|
|
|
|
signal(SIGUSR2, &sig_handler);
|
|
|
|
osmo_init_ignore_signals();
|
2013-11-16 02:14:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void print_help()
|
|
|
|
{
|
|
|
|
fprintf(stdout, "Options:\n"
|
2018-10-23 11:12:17 +00:00
|
|
|
" -h, --help This text\n"
|
|
|
|
" -C, --config Filename The config file to use\n"
|
|
|
|
" -V, --version Print the version of OsmoTRX\n"
|
2018-02-20 19:01:10 +00:00
|
|
|
);
|
2013-11-16 02:14:33 +00:00
|
|
|
}
|
|
|
|
|
2018-02-21 17:47:35 +00:00
|
|
|
static void print_deprecated(char opt)
|
|
|
|
{
|
|
|
|
LOG(WARNING) << "Cmd line option '" << opt << "' is deprecated and will be soon removed."
|
|
|
|
<< " Please use VTY cfg option instead."
|
|
|
|
<< " All cmd line options are already being overriden by VTY options if set.";
|
|
|
|
}
|
|
|
|
|
|
|
|
static void handle_options(int argc, char **argv, struct trx_ctx* trx)
|
2013-11-16 02:14:33 +00:00
|
|
|
{
|
|
|
|
int option;
|
2018-02-21 17:47:35 +00:00
|
|
|
unsigned int i;
|
|
|
|
std::vector<std::string> rx_paths, tx_paths;
|
|
|
|
bool rx_paths_set = false, tx_paths_set = false;
|
2018-10-23 11:12:17 +00:00
|
|
|
static struct option long_options[] = {
|
|
|
|
{"help", 0, 0, 'h'},
|
|
|
|
{"config", 1, 0, 'C'},
|
|
|
|
{"version", 0, 0, 'V'},
|
|
|
|
{NULL, 0, 0, 0}
|
|
|
|
};
|
2013-11-16 02:14:33 +00:00
|
|
|
|
2018-10-23 11:12:17 +00:00
|
|
|
while ((option = getopt_long(argc, argv, "ha:l:i:j:p:c:dmxgfo:s:b:r:A:R:Set:y:z:C:V", long_options,
|
|
|
|
NULL)) != -1) {
|
2013-11-16 02:14:33 +00:00
|
|
|
switch (option) {
|
|
|
|
case 'h':
|
|
|
|
print_help();
|
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
case 'a':
|
2018-02-21 17:47:35 +00:00
|
|
|
print_deprecated(option);
|
|
|
|
osmo_talloc_replace_string(trx, &trx->cfg.dev_args, optarg);
|
2013-11-16 02:14:33 +00:00
|
|
|
break;
|
2018-03-06 17:38:22 +00:00
|
|
|
case 'l':
|
|
|
|
print_deprecated(option);
|
|
|
|
log_set_log_level(osmo_stderr_target, atoi(optarg));
|
|
|
|
break;
|
2013-11-16 02:14:33 +00:00
|
|
|
case 'i':
|
2018-02-21 17:47:35 +00:00
|
|
|
print_deprecated(option);
|
|
|
|
osmo_talloc_replace_string(trx, &trx->cfg.remote_addr, optarg);
|
2017-08-16 14:53:23 +00:00
|
|
|
break;
|
|
|
|
case 'j':
|
2018-02-21 17:47:35 +00:00
|
|
|
print_deprecated(option);
|
|
|
|
osmo_talloc_replace_string(trx, &trx->cfg.bind_addr, optarg);
|
2013-11-16 02:14:33 +00:00
|
|
|
break;
|
|
|
|
case 'p':
|
2018-02-21 17:47:35 +00:00
|
|
|
print_deprecated(option);
|
|
|
|
trx->cfg.base_port = atoi(optarg);
|
2013-11-16 02:14:33 +00:00
|
|
|
break;
|
|
|
|
case 'c':
|
2018-02-21 17:47:35 +00:00
|
|
|
print_deprecated(option);
|
|
|
|
trx->cfg.num_chans = atoi(optarg);
|
2013-11-16 02:14:33 +00:00
|
|
|
break;
|
2016-06-24 21:25:39 +00:00
|
|
|
case 'm':
|
2018-02-21 17:47:35 +00:00
|
|
|
print_deprecated(option);
|
|
|
|
trx->cfg.multi_arfcn = true;
|
2016-06-24 21:25:39 +00:00
|
|
|
break;
|
2013-11-16 02:14:33 +00:00
|
|
|
case 'x':
|
2018-02-21 17:47:35 +00:00
|
|
|
print_deprecated(option);
|
|
|
|
trx->cfg.clock_ref = REF_EXTERNAL;
|
2013-11-16 02:14:33 +00:00
|
|
|
break;
|
2016-07-18 02:29:08 +00:00
|
|
|
case 'g':
|
2018-02-21 17:47:35 +00:00
|
|
|
print_deprecated(option);
|
|
|
|
trx->cfg.clock_ref = REF_GPS;
|
2016-07-18 02:29:08 +00:00
|
|
|
break;
|
2014-01-25 07:34:03 +00:00
|
|
|
case 'f':
|
2018-02-21 17:47:35 +00:00
|
|
|
print_deprecated(option);
|
|
|
|
trx->cfg.filler = FILLER_DUMMY;
|
2014-01-25 07:34:03 +00:00
|
|
|
break;
|
2014-03-06 19:16:11 +00:00
|
|
|
case 'o':
|
2018-02-21 17:47:35 +00:00
|
|
|
print_deprecated(option);
|
|
|
|
trx->cfg.offset = atof(optarg);
|
2014-03-06 19:16:11 +00:00
|
|
|
break;
|
2013-11-16 02:14:33 +00:00
|
|
|
case 's':
|
2018-02-21 17:47:35 +00:00
|
|
|
print_deprecated(option);
|
|
|
|
trx->cfg.tx_sps = atoi(optarg);
|
2015-05-20 01:26:31 +00:00
|
|
|
break;
|
2016-06-27 22:39:16 +00:00
|
|
|
case 'b':
|
2018-02-21 17:47:35 +00:00
|
|
|
print_deprecated(option);
|
|
|
|
trx->cfg.rx_sps = atoi(optarg);
|
2016-06-27 22:39:16 +00:00
|
|
|
break;
|
2015-05-20 01:26:31 +00:00
|
|
|
case 'r':
|
2018-02-21 17:47:35 +00:00
|
|
|
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;
|
2013-11-16 02:14:33 +00:00
|
|
|
break;
|
2016-03-23 14:06:32 +00:00
|
|
|
case 'A':
|
2018-02-21 17:47:35 +00:00
|
|
|
print_deprecated(option);
|
|
|
|
trx->cfg.rach_delay_set = true;
|
|
|
|
trx->cfg.rach_delay = atoi(optarg);
|
|
|
|
trx->cfg.filler = FILLER_ACCESS_RAND;
|
2016-03-23 14:06:32 +00:00
|
|
|
break;
|
2015-06-04 03:47:56 +00:00
|
|
|
case 'R':
|
2018-02-21 17:47:35 +00:00
|
|
|
print_deprecated(option);
|
|
|
|
trx->cfg.rssi_offset = atof(optarg);
|
2015-06-04 03:47:56 +00:00
|
|
|
break;
|
2015-06-07 05:07:45 +00:00
|
|
|
case 'S':
|
2018-02-21 17:47:35 +00:00
|
|
|
print_deprecated(option);
|
|
|
|
trx->cfg.swap_channels = true;
|
2015-06-07 05:07:45 +00:00
|
|
|
break;
|
2016-03-06 11:44:34 +00:00
|
|
|
case 'e':
|
2018-02-21 17:47:35 +00:00
|
|
|
print_deprecated(option);
|
|
|
|
trx->cfg.egprs = true;
|
2016-03-06 11:44:34 +00:00
|
|
|
break;
|
2017-06-29 13:35:22 +00:00
|
|
|
case 't':
|
2018-02-21 17:47:35 +00:00
|
|
|
print_deprecated(option);
|
|
|
|
trx->cfg.sched_rr = atoi(optarg);
|
2017-06-29 13:35:22 +00:00
|
|
|
break;
|
Add support to set Rx/TxAntenna
Some devices have different Rx or Tx ports with different RF characteristics.
For instance LimeSDR has H (High), L (Low) and W (Wide) band Rx ports,
each of one being more suitable to a specific range of frequencies.
In case one wants to support several GSM bands, the best option is to
use the WideBand port and connect the antenna physically to that port in
the board. Then the firmware must be instructed ro read from that port.
Support for Rx/Tx port configuration is already in there for all the
layers (Limesuite, SoapySDR, SoapyUHD, UHD), but we are missing the
required bits in osmo-trx to make use of the available UHD API. This
commit addresses it.
Before this patch, the Rx/Tx paths configured could be changed by means
of the LimeSuiteGUI app, but after running osmo-trx, the values were
changed to the default ones.
One can now start using osmo-trx with 1 channel and specific Rx/Tx ports
by using for instance: osmo-trx -c 1 -y BAND1 -z LNAW
Default behaviour if no specific path or an empry path is passed ("") is
to do the same as preiously, ie. nothing by not calling the
set{T,R}xAntenna APIs.
One can also configure only specific channels, for instance to configure
only the first Tx channel and the second Rx channel:
osmo-trx -c 2 -y BAND1, -z ,LNAW
Change-Id: I1735e6ab05a05b0312d6d679b16ebd4a2260fa23
2018-02-05 12:05:06 +00:00
|
|
|
case 'y':
|
2018-02-21 17:47:35 +00:00
|
|
|
print_deprecated(option);
|
|
|
|
tx_paths = comma_delimited_to_vector(optarg);
|
|
|
|
tx_paths_set = true;
|
Add support to set Rx/TxAntenna
Some devices have different Rx or Tx ports with different RF characteristics.
For instance LimeSDR has H (High), L (Low) and W (Wide) band Rx ports,
each of one being more suitable to a specific range of frequencies.
In case one wants to support several GSM bands, the best option is to
use the WideBand port and connect the antenna physically to that port in
the board. Then the firmware must be instructed ro read from that port.
Support for Rx/Tx port configuration is already in there for all the
layers (Limesuite, SoapySDR, SoapyUHD, UHD), but we are missing the
required bits in osmo-trx to make use of the available UHD API. This
commit addresses it.
Before this patch, the Rx/Tx paths configured could be changed by means
of the LimeSuiteGUI app, but after running osmo-trx, the values were
changed to the default ones.
One can now start using osmo-trx with 1 channel and specific Rx/Tx ports
by using for instance: osmo-trx -c 1 -y BAND1 -z LNAW
Default behaviour if no specific path or an empry path is passed ("") is
to do the same as preiously, ie. nothing by not calling the
set{T,R}xAntenna APIs.
One can also configure only specific channels, for instance to configure
only the first Tx channel and the second Rx channel:
osmo-trx -c 2 -y BAND1, -z ,LNAW
Change-Id: I1735e6ab05a05b0312d6d679b16ebd4a2260fa23
2018-02-05 12:05:06 +00:00
|
|
|
break;
|
|
|
|
case 'z':
|
2018-02-21 17:47:35 +00:00
|
|
|
print_deprecated(option);
|
|
|
|
rx_paths = comma_delimited_to_vector(optarg);
|
|
|
|
rx_paths_set = true;
|
Add support to set Rx/TxAntenna
Some devices have different Rx or Tx ports with different RF characteristics.
For instance LimeSDR has H (High), L (Low) and W (Wide) band Rx ports,
each of one being more suitable to a specific range of frequencies.
In case one wants to support several GSM bands, the best option is to
use the WideBand port and connect the antenna physically to that port in
the board. Then the firmware must be instructed ro read from that port.
Support for Rx/Tx port configuration is already in there for all the
layers (Limesuite, SoapySDR, SoapyUHD, UHD), but we are missing the
required bits in osmo-trx to make use of the available UHD API. This
commit addresses it.
Before this patch, the Rx/Tx paths configured could be changed by means
of the LimeSuiteGUI app, but after running osmo-trx, the values were
changed to the default ones.
One can now start using osmo-trx with 1 channel and specific Rx/Tx ports
by using for instance: osmo-trx -c 1 -y BAND1 -z LNAW
Default behaviour if no specific path or an empry path is passed ("") is
to do the same as preiously, ie. nothing by not calling the
set{T,R}xAntenna APIs.
One can also configure only specific channels, for instance to configure
only the first Tx channel and the second Rx channel:
osmo-trx -c 2 -y BAND1, -z ,LNAW
Change-Id: I1735e6ab05a05b0312d6d679b16ebd4a2260fa23
2018-02-05 12:05:06 +00:00
|
|
|
break;
|
2018-02-20 15:48:15 +00:00
|
|
|
case 'C':
|
2018-02-21 17:47:35 +00:00
|
|
|
config_file = optarg;
|
2018-02-20 15:48:15 +00:00
|
|
|
break;
|
2018-06-15 13:19:21 +00:00
|
|
|
case 'V':
|
|
|
|
print_version(1);
|
|
|
|
exit(0);
|
|
|
|
break;
|
2013-11-16 02:14:33 +00:00
|
|
|
default:
|
2018-02-21 17:47:35 +00:00
|
|
|
goto bad_config;
|
2013-11-16 02:14:33 +00:00
|
|
|
}
|
|
|
|
}
|
2015-05-20 01:26:31 +00:00
|
|
|
|
2018-02-21 17:47:35 +00:00
|
|
|
/* Cmd line option specific validation & setup */
|
2016-03-07 06:19:15 +00:00
|
|
|
|
2018-02-21 17:47:35 +00:00
|
|
|
if (trx->cfg.num_chans > TRX_CHAN_MAX) {
|
|
|
|
LOG(ERROR) << "Too many channels requested, maximum is " << TRX_CHAN_MAX;
|
2016-07-20 23:35:03 +00:00
|
|
|
goto bad_config;
|
2015-05-20 01:26:31 +00:00
|
|
|
}
|
2018-02-21 17:47:35 +00:00
|
|
|
if ((tx_paths_set && tx_paths.size() != trx->cfg.num_chans) ||
|
|
|
|
(rx_paths_set && rx_paths.size() != trx->cfg.num_chans)) {
|
|
|
|
LOG(ERROR) << "Num of channels and num of Rx/Tx Antennas doesn't match";
|
2016-07-20 23:35:03 +00:00
|
|
|
goto bad_config;
|
2015-05-20 01:26:31 +00:00
|
|
|
}
|
2018-02-21 17:47:35 +00:00
|
|
|
for (i = 0; i < trx->cfg.num_chans; i++) {
|
|
|
|
trx->cfg.chans[i].trx = trx;
|
|
|
|
trx->cfg.chans[i].idx = i;
|
|
|
|
if (tx_paths_set)
|
|
|
|
osmo_talloc_replace_string(trx, &trx->cfg.chans[i].tx_path, tx_paths[i].c_str());
|
|
|
|
if (rx_paths_set)
|
|
|
|
osmo_talloc_replace_string(trx, &trx->cfg.chans[i].rx_path, rx_paths[i].c_str());
|
Add support to set Rx/TxAntenna
Some devices have different Rx or Tx ports with different RF characteristics.
For instance LimeSDR has H (High), L (Low) and W (Wide) band Rx ports,
each of one being more suitable to a specific range of frequencies.
In case one wants to support several GSM bands, the best option is to
use the WideBand port and connect the antenna physically to that port in
the board. Then the firmware must be instructed ro read from that port.
Support for Rx/Tx port configuration is already in there for all the
layers (Limesuite, SoapySDR, SoapyUHD, UHD), but we are missing the
required bits in osmo-trx to make use of the available UHD API. This
commit addresses it.
Before this patch, the Rx/Tx paths configured could be changed by means
of the LimeSuiteGUI app, but after running osmo-trx, the values were
changed to the default ones.
One can now start using osmo-trx with 1 channel and specific Rx/Tx ports
by using for instance: osmo-trx -c 1 -y BAND1 -z LNAW
Default behaviour if no specific path or an empry path is passed ("") is
to do the same as preiously, ie. nothing by not calling the
set{T,R}xAntenna APIs.
One can also configure only specific channels, for instance to configure
only the first Tx channel and the second Rx channel:
osmo-trx -c 2 -y BAND1, -z ,LNAW
Change-Id: I1735e6ab05a05b0312d6d679b16ebd4a2260fa23
2018-02-05 12:05:06 +00:00
|
|
|
}
|
|
|
|
|
2016-07-20 23:35:03 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
bad_config:
|
|
|
|
print_help();
|
|
|
|
exit(0);
|
2013-11-16 02:14:33 +00:00
|
|
|
}
|
|
|
|
|
2018-02-21 17:47:35 +00:00
|
|
|
int trx_validate_config(struct trx_ctx *trx)
|
|
|
|
{
|
|
|
|
if (trx->cfg.multi_arfcn && trx->cfg.num_chans > 5) {
|
|
|
|
LOG(ERROR) << "Unsupported number of channels";
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Force 4 SPS for EDGE or multi-ARFCN configurations */
|
|
|
|
if ((trx->cfg.egprs || trx->cfg.multi_arfcn) &&
|
2018-10-21 10:15:30 +00:00
|
|
|
(trx->cfg.tx_sps!=4 || trx->cfg.rx_sps!=4)) {
|
2018-02-21 17:47:35 +00:00
|
|
|
LOG(ERROR) << "EDGE and Multi-Carrier options require 4 tx and rx sps. Check you config.";
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int set_sched_rr(unsigned int prio)
|
2017-06-29 13:35:22 +00:00
|
|
|
{
|
|
|
|
struct sched_param param;
|
|
|
|
int rc;
|
|
|
|
memset(¶m, 0, sizeof(param));
|
|
|
|
param.sched_priority = prio;
|
2018-12-03 17:21:13 +00:00
|
|
|
LOG(INFO) << "Setting SCHED_RR priority " << param.sched_priority;
|
2017-06-29 13:35:22 +00:00
|
|
|
rc = sched_setscheduler(getpid(), SCHED_RR, ¶m);
|
|
|
|
if (rc != 0) {
|
2018-02-21 17:47:35 +00:00
|
|
|
LOG(ERROR) << "Config: Setting SCHED_RR failed";
|
2017-06-29 13:35:22 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-02-21 17:47:35 +00:00
|
|
|
static void print_config(struct trx_ctx *trx)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
std::ostringstream ost("");
|
|
|
|
|
|
|
|
ost << "Config Settings" << std::endl;
|
2018-03-06 17:38:22 +00:00
|
|
|
ost << " Log Level............... " << (unsigned int) osmo_stderr_target->loglevel << std::endl;
|
2018-02-21 17:47:35 +00:00
|
|
|
ost << " Device args............. " << charp2str(trx->cfg.dev_args) << std::endl;
|
|
|
|
ost << " TRX Base Port........... " << trx->cfg.base_port << std::endl;
|
|
|
|
ost << " TRX Address............. " << charp2str(trx->cfg.bind_addr) << std::endl;
|
2018-04-28 19:25:09 +00:00
|
|
|
ost << " GSM BTS Address......... " << charp2str(trx->cfg.remote_addr) << std::endl;
|
2018-02-21 17:47:35 +00:00
|
|
|
ost << " Channels................ " << trx->cfg.num_chans << std::endl;
|
|
|
|
ost << " Tx Samples-per-Symbol... " << trx->cfg.tx_sps << std::endl;
|
|
|
|
ost << " Rx Samples-per-Symbol... " << trx->cfg.rx_sps << std::endl;
|
|
|
|
ost << " EDGE support............ " << trx->cfg.egprs << std::endl;
|
|
|
|
ost << " Reference............... " << trx->cfg.clock_ref << 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;
|
|
|
|
ost << " Swap channels........... " << trx->cfg.swap_channels << std::endl;
|
|
|
|
ost << " Tx Antennas.............";
|
|
|
|
for (i = 0; i < trx->cfg.num_chans; i++) {
|
|
|
|
std::string p = charp2str(trx->cfg.chans[i].tx_path);
|
|
|
|
ost << " '" << ((p != "") ? p : "<default>") << "'";
|
|
|
|
}
|
|
|
|
ost << std::endl;
|
|
|
|
ost << " Rx Antennas.............";
|
|
|
|
for (i = 0; i < trx->cfg.num_chans; i++) {
|
|
|
|
std::string p = charp2str(trx->cfg.chans[i].rx_path);
|
|
|
|
ost << " '" << ((p != "") ? p : "<default>") << "'";
|
|
|
|
}
|
|
|
|
ost << std::endl;
|
|
|
|
|
2018-12-03 17:21:13 +00:00
|
|
|
LOG(INFO) << ost << std::endl;
|
2018-02-21 17:47:35 +00:00
|
|
|
}
|
|
|
|
|
2018-02-21 10:59:26 +00:00
|
|
|
static void trx_stop()
|
|
|
|
{
|
2018-12-03 17:21:13 +00:00
|
|
|
LOG(NOTICE) << "Shutting down transceiver..." << std::endl;
|
2018-02-21 10:59:26 +00:00
|
|
|
|
|
|
|
delete transceiver;
|
|
|
|
delete radio;
|
|
|
|
delete usrp;
|
|
|
|
}
|
|
|
|
|
2018-02-21 17:47:35 +00:00
|
|
|
static int trx_start(struct trx_ctx *trx)
|
2013-11-16 02:14:33 +00:00
|
|
|
{
|
2018-02-21 17:47:35 +00:00
|
|
|
int type, chans;
|
|
|
|
unsigned int i;
|
|
|
|
std::vector<std::string> rx_paths, tx_paths;
|
2016-06-22 23:09:44 +00:00
|
|
|
RadioDevice::InterfaceType iface = RadioDevice::NORMAL;
|
2018-02-21 10:59:26 +00:00
|
|
|
|
|
|
|
/* Create the low level device object */
|
2018-02-21 17:47:35 +00:00
|
|
|
if (trx->cfg.multi_arfcn)
|
2018-02-21 10:59:26 +00:00
|
|
|
iface = RadioDevice::MULTI_ARFCN;
|
|
|
|
|
2018-02-21 17:47:35 +00:00
|
|
|
/* Generate vector of rx/tx_path: */
|
|
|
|
for (i = 0; i < trx->cfg.num_chans; i++) {
|
|
|
|
rx_paths.push_back(charp2str(trx->cfg.chans[i].rx_path));
|
|
|
|
tx_paths.push_back(charp2str(trx->cfg.chans[i].tx_path));
|
|
|
|
}
|
2018-02-21 10:59:26 +00:00
|
|
|
|
2018-02-21 17:47:35 +00:00
|
|
|
usrp = RadioDevice::make(trx->cfg.tx_sps, trx->cfg.rx_sps, iface,
|
|
|
|
trx->cfg.num_chans, trx->cfg.offset,
|
|
|
|
tx_paths, rx_paths);
|
|
|
|
type = usrp->open(charp2str(trx->cfg.dev_args), trx->cfg.clock_ref, trx->cfg.swap_channels);
|
2018-02-21 10:59:26 +00:00
|
|
|
if (type < 0) {
|
|
|
|
LOG(ALERT) << "Failed to create radio device" << std::endl;
|
|
|
|
goto shutdown;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Setup the appropriate device interface */
|
2018-02-21 17:47:35 +00:00
|
|
|
radio = makeRadioInterface(trx, usrp, type);
|
2018-02-21 10:59:26 +00:00
|
|
|
if (!radio)
|
|
|
|
goto shutdown;
|
|
|
|
|
|
|
|
/* Create the transceiver core */
|
2018-02-21 17:47:35 +00:00
|
|
|
if (makeTransceiver(trx, radio) < 0)
|
2018-02-21 10:59:26 +00:00
|
|
|
goto shutdown;
|
|
|
|
|
|
|
|
chans = transceiver->numChans();
|
2018-12-03 17:21:13 +00:00
|
|
|
LOG(NOTICE) << "-- Transceiver active with "
|
2018-02-21 10:59:26 +00:00
|
|
|
<< chans << " channel(s)" << std::endl;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
shutdown:
|
|
|
|
trx_stop();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2018-02-20 15:48:15 +00:00
|
|
|
int rc;
|
2013-11-16 02:14:33 +00:00
|
|
|
|
2018-02-21 19:15:47 +00:00
|
|
|
tall_trx_ctx = talloc_named_const(NULL, 0, "OsmoTRX");
|
|
|
|
msgb_talloc_ctx_init(tall_trx_ctx, 0);
|
2018-02-20 15:48:15 +00:00
|
|
|
g_vty_info.tall_ctx = tall_trx_ctx;
|
|
|
|
|
2018-02-21 19:15:18 +00:00
|
|
|
setup_signal_handlers();
|
|
|
|
|
2018-02-21 14:41:03 +00:00
|
|
|
g_trx_ctx = vty_trx_ctx_alloc(tall_trx_ctx);
|
2018-02-20 15:48:15 +00:00
|
|
|
|
2017-03-16 11:09:34 +00:00
|
|
|
#ifdef HAVE_SSE3
|
|
|
|
printf("Info: SSE3 support compiled in");
|
2017-05-19 22:46:51 +00:00
|
|
|
#ifdef HAVE___BUILTIN_CPU_SUPPORTS
|
2017-03-16 11:09:34 +00:00
|
|
|
if (__builtin_cpu_supports("sse3"))
|
|
|
|
printf(" and supported by CPU\n");
|
|
|
|
else
|
|
|
|
printf(", but not supported by CPU\n");
|
2017-05-19 22:46:51 +00:00
|
|
|
#else
|
|
|
|
printf(", but runtime SIMD detection disabled\n");
|
|
|
|
#endif
|
2017-03-16 11:09:34 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_SSE4_1
|
|
|
|
printf("Info: SSE4.1 support compiled in");
|
2017-05-19 22:46:51 +00:00
|
|
|
#ifdef HAVE___BUILTIN_CPU_SUPPORTS
|
2017-03-16 11:09:34 +00:00
|
|
|
if (__builtin_cpu_supports("sse4.1"))
|
|
|
|
printf(" and supported by CPU\n");
|
|
|
|
else
|
|
|
|
printf(", but not supported by CPU\n");
|
2017-05-19 22:46:51 +00:00
|
|
|
#else
|
|
|
|
printf(", but runtime SIMD detection disabled\n");
|
|
|
|
#endif
|
2017-03-16 11:09:34 +00:00
|
|
|
#endif
|
|
|
|
|
2017-03-15 17:09:35 +00:00
|
|
|
convolve_init();
|
|
|
|
convert_init();
|
|
|
|
|
2018-04-16 12:50:11 +00:00
|
|
|
osmo_init_logging2(tall_trx_ctx, &log_info);
|
2018-02-20 15:48:15 +00:00
|
|
|
osmo_stats_init(tall_trx_ctx);
|
|
|
|
vty_init(&g_vty_info);
|
|
|
|
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();
|
|
|
|
|
2018-02-21 17:47:35 +00:00
|
|
|
handle_options(argc, argv, g_trx_ctx);
|
2013-11-16 02:14:33 +00:00
|
|
|
|
2018-02-20 15:48:15 +00:00
|
|
|
rate_ctr_init(tall_trx_ctx);
|
|
|
|
|
2018-02-21 17:47:35 +00:00
|
|
|
rc = vty_read_config_file(config_file, NULL);
|
2018-02-20 15:48:15 +00:00
|
|
|
if (rc < 0) {
|
2018-02-21 17:47:35 +00:00
|
|
|
fprintf(stderr, "Failed to open config file: '%s'\n", config_file);
|
2018-02-20 15:48:15 +00:00
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = telnet_init_dynif(tall_trx_ctx, NULL, vty_get_bind_addr(), OSMO_VTY_PORT_TRX);
|
|
|
|
if (rc < 0)
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
g_ctrlh = ctrl_interface_setup(NULL, OSMO_CTRL_PORT_TRX, NULL);
|
|
|
|
if (!g_ctrlh) {
|
2018-12-03 17:21:13 +00:00
|
|
|
LOG(ERROR) << "Failed to create CTRL interface.\n";
|
2018-02-20 15:48:15 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2018-02-21 17:47:35 +00:00
|
|
|
/* Backward compatibility: Hack to have 1 channel allocated by default.
|
|
|
|
* Can be Dropped once we * get rid of "-c" cmdline param */
|
|
|
|
if (g_trx_ctx->cfg.num_chans == 0) {
|
|
|
|
g_trx_ctx->cfg.num_chans = 1;
|
|
|
|
g_trx_ctx->cfg.chans[0].trx = g_trx_ctx;
|
|
|
|
g_trx_ctx->cfg.chans[0].idx = 0;
|
|
|
|
LOG(ERROR) << "No explicit channel config found. Make sure you" \
|
|
|
|
" configure channels in VTY config. Using 1 channel as default," \
|
|
|
|
" but expect your config to break in the future.";
|
2017-06-29 13:35:22 +00:00
|
|
|
}
|
|
|
|
|
2018-02-21 17:47:35 +00:00
|
|
|
print_config(g_trx_ctx);
|
|
|
|
|
|
|
|
if (trx_validate_config(g_trx_ctx) < 0) {
|
|
|
|
LOG(ERROR) << "Config failure - exiting";
|
2013-11-16 02:14:33 +00:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
2018-02-21 17:47:35 +00:00
|
|
|
if (g_trx_ctx->cfg.sched_rr) {
|
|
|
|
if (set_sched_rr(g_trx_ctx->cfg.sched_rr) < 0)
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
2013-11-16 02:14:33 +00:00
|
|
|
srandom(time(NULL));
|
|
|
|
|
2018-02-21 17:47:35 +00:00
|
|
|
if(trx_start(g_trx_ctx) < 0)
|
2018-02-21 10:59:26 +00:00
|
|
|
return EXIT_FAILURE;
|
2013-11-16 02:14:33 +00:00
|
|
|
|
|
|
|
while (!gshutdown)
|
2018-02-20 15:48:15 +00:00
|
|
|
osmo_select_main(0);
|
2013-11-16 02:14:33 +00:00
|
|
|
|
2018-02-21 10:59:26 +00:00
|
|
|
trx_stop();
|
2013-11-16 02:14:33 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|