Initial XTRX support
Change-Id: I1067dfef53aa2669cc7c189cccae10074c674390
This commit is contained in:
parent
1c98bf07d8
commit
875fd492ab
|
@ -114,3 +114,12 @@ osmo_trx_ipc_LDADD = \
|
|||
osmo_trx_ipc_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
endif
|
||||
|
||||
if DEVICE_XTRX
|
||||
bin_PROGRAMS += osmo-trx-xtrx
|
||||
osmo_trx_xtrx_SOURCES = osmo-trx.cpp
|
||||
osmo_trx_xtrx_LDADD = \
|
||||
$(builddir)/device/xtrx/libdevice.la \
|
||||
$(COMMON_LDADD) \
|
||||
$(XTRX_LIBS)
|
||||
osmo_trx_xtrx_CPPFLAGS = $(AM_CPPFLAGS) $(XTRX_CFLAGS)
|
||||
endif
|
||||
|
|
|
@ -17,3 +17,7 @@ endif
|
|||
if DEVICE_LMS
|
||||
SUBDIRS += lms
|
||||
endif
|
||||
|
||||
if DEVICE_XTRX
|
||||
SUBDIRS += xtrx
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
include $(top_srcdir)/Makefile.common
|
||||
|
||||
AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) -I${srcdir}/../common
|
||||
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)
|
||||
|
||||
noinst_HEADERS = XTRXDevice.h
|
||||
|
||||
noinst_LTLIBRARIES = libdevice.la
|
||||
|
||||
libdevice_la_SOURCES = XTRXDevice.cpp
|
|
@ -0,0 +1,459 @@
|
|||
/*
|
||||
* Copyright 2018 Sergey Kostanbaev <sergey.kostanbaev@fairwaves.co>
|
||||
* Copyright 2019 Alexander Chemeris <alexander.chemeris@fairwaves.co>
|
||||
*
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "Threads.h"
|
||||
#include "XTRXDevice.h"
|
||||
|
||||
#include <Logger.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
const double defaultRXBandwidth = 0.5e6;
|
||||
const double defaultTXBandwidth = 1.5e6;
|
||||
|
||||
// Rx/Tx timestamp difference in samples.
|
||||
// Transmitted IQ stream is sent this many samples ahead of the Rx stream
|
||||
// to compensate for the frontend delay between Rx and Tx
|
||||
static int time_tx_corr = 60;
|
||||
|
||||
XTRXDevice::XTRXDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chans, double lo_offset,
|
||||
const std::vector<std::string>& tx_paths,
|
||||
const std::vector<std::string>& rx_paths)
|
||||
: RadioDevice(tx_sps, rx_sps, iface, chans, lo_offset, tx_paths, rx_paths)
|
||||
{
|
||||
LOG(INFO) << "creating XTRX device:"
|
||||
<< " RXSPS: " << rx_sps
|
||||
<< " TXSPS: " << tx_sps
|
||||
<< " chans: " << chans
|
||||
<< " lo_off: " << lo_offset
|
||||
<< " rx_path(0): " << (rx_paths.size() ? rx_paths[0] : "<>")
|
||||
<< " tx_path(0): " << (tx_paths.size() ? tx_paths[0] : "<>");
|
||||
|
||||
txsps = tx_sps;
|
||||
rxsps = rx_sps;
|
||||
|
||||
rxGain = 0;
|
||||
txGain = 0;
|
||||
|
||||
loopback = false;
|
||||
device = NULL;
|
||||
}
|
||||
|
||||
static int parse_config(const char* line, const char* argument, int default_value)
|
||||
{
|
||||
const char* arg_found = strstr(line, argument);
|
||||
if (!arg_found)
|
||||
return default_value;
|
||||
|
||||
const char* qe_pos = strchr(arg_found, '=');
|
||||
if (!qe_pos)
|
||||
return default_value;
|
||||
|
||||
int res = strtol(qe_pos + 1, NULL, 10);
|
||||
if (res == 0 && errno) {
|
||||
return default_value;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int XTRXDevice::open(const std::string &args, int ref, bool swap_channels)
|
||||
{
|
||||
LOG(INFO) << "Opening XTRX device '" << args << "'..";
|
||||
|
||||
int loglevel = parse_config(args.c_str(), "loglevel", 3);
|
||||
int lb_param = parse_config(args.c_str(), "loopback", 0);
|
||||
time_tx_corr = parse_config(args.c_str(), "tcorr", time_tx_corr);
|
||||
int fref = parse_config(args.c_str(), "refclk", 26000000);
|
||||
int rxdec = parse_config(args.c_str(), "rxdec", 0);
|
||||
|
||||
char xtrx_name[500];
|
||||
const char* lend = strchr(args.c_str(), ',');
|
||||
int len = (lend) ? (lend - args.c_str()) : sizeof(xtrx_name) - 1;
|
||||
strncpy(xtrx_name, args.c_str(), len);
|
||||
xtrx_name[len] = 0;
|
||||
|
||||
if ((txsps % 2) || (rxsps % 2)) {
|
||||
LOG(ALERT) << "XTRX TxSPS/RxSPS must be even!";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lb_param) {
|
||||
LOG(ALERT) << "XTRX LOOPBACK mode is set!";
|
||||
loopback = true;
|
||||
}
|
||||
|
||||
int res = xtrx_open(xtrx_name, loglevel, &device);
|
||||
if (res) {
|
||||
LOG(ALERT) << "Failed openning XTRX device \"" << xtrx_name << "\", code " << res;
|
||||
return -1;
|
||||
}
|
||||
double actualMasterClock = 0;
|
||||
|
||||
if (fref > 0) {
|
||||
xtrx_set_ref_clk(device, fref, XTRX_CLKSRC_INT);
|
||||
}
|
||||
|
||||
res = xtrx_set_samplerate(device,
|
||||
GSMRATE * (double) std::min(txsps, rxsps) * 32 * 4 * ((rxdec) ? 2 : 1),
|
||||
GSMRATE * (double) rxsps,
|
||||
GSMRATE * (double) txsps,
|
||||
(rxdec) ? XTRX_SAMPLERATE_FORCE_RX_DECIM : 0,
|
||||
&actualMasterClock,
|
||||
&actualRXSampleRate,
|
||||
&actualTXSampleRate);
|
||||
if (res) {
|
||||
LOG(ALERT) << "XTRX failed to set samplerate RX: " << GSMRATE * (double) rxsps
|
||||
<< " TX: " << GSMRATE * (double) txsps
|
||||
<< " res: " << res;
|
||||
return -1;
|
||||
} else {
|
||||
LOG(INFO) << "XTRX set samplerate Master: " << actualMasterClock
|
||||
<< " RX: " << actualRXSampleRate
|
||||
<< " TX: " << actualTXSampleRate;
|
||||
}
|
||||
|
||||
double bw;
|
||||
double actualbw;
|
||||
|
||||
actualbw = 0;
|
||||
bw = defaultRXBandwidth;
|
||||
res = xtrx_tune_rx_bandwidth(device, XTRX_CH_AB, bw, &actualbw);
|
||||
if (res) {
|
||||
LOG(ALERT) << "XTRX failed to set RX bandwidth: " << bw
|
||||
<< " res: " << res;
|
||||
} else {
|
||||
LOG(INFO) << "XTRX set RX bandwidth: " << actualbw;
|
||||
}
|
||||
|
||||
actualbw = 0;
|
||||
bw = defaultTXBandwidth;
|
||||
res = xtrx_tune_tx_bandwidth(device, XTRX_CH_AB, bw, &actualbw);
|
||||
if (res) {
|
||||
LOG(ALERT) << "XTRX failed to set TX bandwidth: " << bw
|
||||
<< " res: " << res;
|
||||
} else {
|
||||
LOG(INFO) << "XTRX set TX bandwidth: " << actualbw;
|
||||
}
|
||||
|
||||
samplesRead = 0;
|
||||
samplesWritten = 0;
|
||||
started = false;
|
||||
|
||||
return NORMAL;
|
||||
}
|
||||
|
||||
XTRXDevice::~XTRXDevice()
|
||||
{
|
||||
if (device) {
|
||||
xtrx_close(device);
|
||||
}
|
||||
}
|
||||
|
||||
bool XTRXDevice::start()
|
||||
{
|
||||
LOG(INFO) << "starting XTRX...";
|
||||
if (started) {
|
||||
LOGC(DDEV, ERROR) << "Device already started";
|
||||
return false;
|
||||
}
|
||||
|
||||
dataStart = 0;
|
||||
dataEnd = 0;
|
||||
timeStart = 0;
|
||||
timeEnd = 0;
|
||||
timeRx = initialReadTimestamp();
|
||||
timestampOffset = 0;
|
||||
latestWriteTimestamp = 0;
|
||||
lastPktTimestamp = 0;
|
||||
hi32Timestamp = 0;
|
||||
isAligned = false;
|
||||
|
||||
xtrx_stop(device, XTRX_TX);
|
||||
xtrx_stop(device, XTRX_RX);
|
||||
|
||||
xtrx_set_antenna(device, XTRX_TX_AUTO);
|
||||
xtrx_set_antenna(device, XTRX_RX_AUTO);
|
||||
|
||||
xtrx_run_params_t params;
|
||||
params.dir = XTRX_TRX;
|
||||
params.nflags = (loopback) ? XTRX_RUN_DIGLOOPBACK : 0;
|
||||
|
||||
params.rx.chs = XTRX_CH_AB;
|
||||
params.rx.flags = XTRX_RSP_SISO_MODE;
|
||||
params.rx.hfmt = XTRX_IQ_INT16;
|
||||
params.rx.wfmt = XTRX_WF_16;
|
||||
params.rx.paketsize = 625 * rxsps;
|
||||
|
||||
params.tx.chs = XTRX_CH_AB;
|
||||
params.tx.flags = XTRX_RSP_SISO_MODE;
|
||||
params.tx.hfmt = XTRX_IQ_INT16;
|
||||
params.tx.wfmt = XTRX_WF_16;
|
||||
params.tx.paketsize = 625 * txsps;
|
||||
|
||||
if (loopback) {
|
||||
params.tx.flags |= XTRX_RSP_SWAP_AB | XTRX_RSP_SWAP_IQ;
|
||||
}
|
||||
|
||||
params.tx_repeat_buf = NULL;
|
||||
params.rx_stream_start = initialReadTimestamp();
|
||||
|
||||
int res = xtrx_run_ex(device, ¶ms);
|
||||
if (res) {
|
||||
LOG(ALERT) << "XTRX start failed res: " << res;
|
||||
} else {
|
||||
LOG(INFO) << "XTRX started";
|
||||
started = true;
|
||||
}
|
||||
return started;
|
||||
}
|
||||
|
||||
bool XTRXDevice::stop()
|
||||
{
|
||||
if (started) {
|
||||
int res = xtrx_stop(device, XTRX_TRX);
|
||||
if (res) {
|
||||
LOG(ALERT) << "XTRX stop failed res: " << res;
|
||||
} else {
|
||||
LOG(INFO) << "XTRX stopped";
|
||||
started = false;
|
||||
}
|
||||
}
|
||||
return !started;
|
||||
}
|
||||
|
||||
TIMESTAMP XTRXDevice::initialWriteTimestamp()
|
||||
{
|
||||
if (/*(iface == MULTI_ARFCN) || */(rxsps == txsps))
|
||||
return initialReadTimestamp();
|
||||
else
|
||||
return initialReadTimestamp() * txsps;
|
||||
}
|
||||
|
||||
double XTRXDevice::maxTxGain()
|
||||
{
|
||||
return 30;
|
||||
}
|
||||
|
||||
double XTRXDevice::minTxGain()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
double XTRXDevice::maxRxGain()
|
||||
{
|
||||
return 30;
|
||||
}
|
||||
|
||||
double XTRXDevice::minRxGain()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
double XTRXDevice::setTxGain(double dB, size_t chan)
|
||||
{
|
||||
if (chan) {
|
||||
LOG(ALERT) << "Invalid channel " << chan;
|
||||
return 0.0;
|
||||
}
|
||||
LOG(NOTICE) << "Setting TX gain to " << dB << " dB.";
|
||||
|
||||
int res = xtrx_set_gain(device, XTRX_CH_AB, XTRX_TX_PAD_GAIN, dB - 30, &txGain);
|
||||
if (res) {
|
||||
LOG(ERR) << "Error setting TX gain res: " << res;
|
||||
} else {
|
||||
LOG(NOTICE) << "Actual TX gain: " << txGain << " dB.";
|
||||
}
|
||||
|
||||
return txGain;
|
||||
}
|
||||
|
||||
|
||||
double XTRXDevice::setRxGain(double dB, size_t chan)
|
||||
{
|
||||
if (chan) {
|
||||
LOG(ALERT) << "Invalid channel " << chan;
|
||||
return 0.0;
|
||||
}
|
||||
LOG(NOTICE) << "Setting RX gain to " << dB << " dB.";
|
||||
|
||||
int res = xtrx_set_gain(device, XTRX_CH_AB, XTRX_RX_LNA_GAIN, dB, &rxGain);
|
||||
if (res) {
|
||||
LOG(ERR) << "Error setting RX gain res: " << res;
|
||||
} else {
|
||||
LOG(NOTICE) << "Actual RX gain: " << rxGain << " dB.";
|
||||
}
|
||||
|
||||
return rxGain;
|
||||
}
|
||||
|
||||
// NOTE: Assumes sequential reads
|
||||
int XTRXDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
|
||||
TIMESTAMP timestamp, bool *underrun, unsigned *RSSI)
|
||||
{
|
||||
if (!started)
|
||||
return -1;
|
||||
|
||||
struct xtrx_recv_ex_info ri;
|
||||
ri.samples = len;
|
||||
ri.buffer_count = bufs.size();
|
||||
ri.buffers = (void* const*)&bufs[0];
|
||||
ri.flags = 0;
|
||||
|
||||
int res = xtrx_recv_sync_ex(device, &ri);
|
||||
if (res) {
|
||||
LOG(ALERT) << "xtrx_recv_sync failed res " << res << " current TS " << timeRx << " req TS" << timestamp;
|
||||
return -1;
|
||||
}
|
||||
timeRx += len;
|
||||
|
||||
// TODO get rid of it!
|
||||
int i;
|
||||
for (i = 0; i < len * 2; i++)
|
||||
bufs[0][i] <<= 4;
|
||||
|
||||
if (underrun)
|
||||
*underrun = (ri.out_events & RCVEX_EVENT_FILLED_ZERO);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int XTRXDevice::writeSamples(std::vector<short *> &bufs, int len,
|
||||
bool *underrun, unsigned long long timestamp,
|
||||
bool isControl)
|
||||
{
|
||||
if (!started)
|
||||
return 0;
|
||||
|
||||
xtrx_send_ex_info_t nfo;
|
||||
nfo.buffers = (const void* const*)&bufs[0];
|
||||
nfo.buffer_count = bufs.size();
|
||||
nfo.flags = XTRX_TX_DONT_BUFFER;
|
||||
nfo.samples = len;
|
||||
nfo.ts = timestamp - time_tx_corr;
|
||||
|
||||
int res = xtrx_send_sync_ex(device, &nfo);
|
||||
if (res != 0) {
|
||||
LOG(ALERT) << "xtrx_send_sync_ex returned " << res << " len=" << len << " ts=" << timestamp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*underrun) {
|
||||
*underrun = (nfo.out_flags & XTRX_TX_DISCARDED_TO);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
bool XTRXDevice::setRxAntenna(const std::string & ant, size_t chan)
|
||||
{
|
||||
LOG(ALERT) << "CH" << chan << ": RX ANTENNA: " << ant.c_str() << " (SETTING RX ANTENNA IS NOT IMPLEMENTED)";
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string XTRXDevice::getRxAntenna(size_t chan)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
bool XTRXDevice::setTxAntenna(const std::string & ant, size_t chan)
|
||||
{
|
||||
LOG(ALERT) << "CH" << chan << ": TX ANTENNA: " << ant.c_str() << " (SETTING TX ANTENNA IS NOT IMPLEMENTED)";
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string XTRXDevice::getTxAntenna(size_t chan )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
bool XTRXDevice::requiresRadioAlign()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
GSM::Time XTRXDevice::minLatency()
|
||||
{
|
||||
return GSM::Time(6,7);
|
||||
}
|
||||
|
||||
bool XTRXDevice::updateAlignment(TIMESTAMP timestamp)
|
||||
{
|
||||
LOG(ALERT) << "Update Aligment " << timestamp;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XTRXDevice::setTxFreq(double wFreq, size_t chan)
|
||||
{
|
||||
int res;
|
||||
double actual = 0;
|
||||
|
||||
if (chan) {
|
||||
LOG(ALERT) << "Invalid channel " << chan;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((res = xtrx_tune(device, XTRX_TUNE_TX_FDD, wFreq, &actual)) == 0) {
|
||||
LOG(INFO) << "set RX: " << wFreq << std::endl
|
||||
<< " actual freq: " << actual << std::endl;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
LOG(ALERT) << "set RX: " << wFreq << "failed (code: " << res << ")" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool XTRXDevice::setRxFreq(double wFreq, size_t chan)
|
||||
{
|
||||
int res;
|
||||
double actual = 0;
|
||||
|
||||
if (chan) {
|
||||
LOG(ALERT) << "Invalid channel " << chan;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((res = xtrx_tune(device, XTRX_TUNE_RX_FDD, wFreq, &actual)) == 0) {
|
||||
LOG(INFO) << "set RX: " << wFreq << std::endl
|
||||
<< " actual freq: " << actual << std::endl;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
LOG(ALERT) << "set RX: " << wFreq << "failed (code: " << res << ")" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps,
|
||||
InterfaceType iface, size_t chans, double lo_offset,
|
||||
const std::vector < std::string > &tx_paths,
|
||||
const std::vector < std::string > &rx_paths)
|
||||
{
|
||||
return new XTRXDevice(tx_sps, rx_sps, iface, chans, lo_offset, tx_paths, rx_paths);
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
#ifndef _XTRX_DEVICE_H_
|
||||
#define _XTRX_DEVICE_H_
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "radioDevice.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/time.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "Threads.h"
|
||||
#include <xtrx_api.h>
|
||||
|
||||
class XTRXDevice: public RadioDevice {
|
||||
private:
|
||||
int txsps;
|
||||
int rxsps;
|
||||
double actualTXSampleRate; ///< the actual XTRX sampling rate
|
||||
double actualRXSampleRate; ///< the actual XTRX sampling rate
|
||||
//unsigned int decimRate; ///< the XTRX decimation rate
|
||||
//unsigned int interRate; ///< the XTRX decimation rate
|
||||
|
||||
unsigned long long samplesRead; ///< number of samples read from XTRX
|
||||
unsigned long long samplesWritten; ///< number of samples sent to XTRX
|
||||
|
||||
bool started; ///< flag indicates XTRX has started
|
||||
|
||||
short *data;
|
||||
unsigned long dataStart;
|
||||
unsigned long dataEnd;
|
||||
TIMESTAMP timeStart;
|
||||
TIMESTAMP timeEnd;
|
||||
|
||||
TIMESTAMP timeRx;
|
||||
bool isAligned;
|
||||
|
||||
Mutex writeLock;
|
||||
|
||||
short *currData; ///< internal data buffer when reading from XTRX
|
||||
TIMESTAMP currTimestamp; ///< timestamp of internal data buffer
|
||||
unsigned currLen; ///< size of internal data buffer
|
||||
|
||||
TIMESTAMP timestampOffset; ///< timestamp offset b/w Tx and Rx blocks
|
||||
TIMESTAMP latestWriteTimestamp; ///< timestamp of most recent ping command
|
||||
TIMESTAMP pingTimestamp; ///< timestamp of most recent ping response
|
||||
|
||||
unsigned long hi32Timestamp;
|
||||
unsigned long lastPktTimestamp;
|
||||
|
||||
double rxGain;
|
||||
double txGain;
|
||||
bool loopback;
|
||||
|
||||
xtrx_dev* device;
|
||||
public:
|
||||
|
||||
/** Object constructor */
|
||||
XTRXDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chans, double lo_offset,
|
||||
const std::vector<std::string>& tx_paths,
|
||||
const std::vector<std::string>& rx_paths);
|
||||
|
||||
~XTRXDevice();
|
||||
|
||||
/** Instantiate the XTRX */
|
||||
int open(const std::string &args, int ref, bool swap_channels);
|
||||
|
||||
/** Start the XTRX */
|
||||
bool start();
|
||||
|
||||
/** Stop the XTRX */
|
||||
bool stop();
|
||||
|
||||
/** Set priority not supported */
|
||||
void setPriority(float prio = 0.5) { }
|
||||
|
||||
enum TxWindowType getWindowType() { return TX_WINDOW_FIXED; }
|
||||
|
||||
/**
|
||||
Read samples from the XTRX.
|
||||
@param buf preallocated buf to contain read result
|
||||
@param len number of samples desired
|
||||
@param overrun Set if read buffer has been overrun, e.g. data not being read fast enough
|
||||
@param timestamp The timestamp of the first samples to be read
|
||||
@param underrun Set if XTRX does not have data to transmit, e.g. data not being sent fast enough
|
||||
@param RSSI The received signal strength of the read result
|
||||
@return The number of samples actually read
|
||||
*/
|
||||
int readSamples(std::vector<short *> &buf, int len, bool *overrun,
|
||||
TIMESTAMP timestamp = 0xffffffff, bool *underrun = NULL,
|
||||
unsigned *RSSI = NULL);
|
||||
/**
|
||||
Write samples to the XTRX.
|
||||
@param buf Contains the data to be written.
|
||||
@param len number of samples to write.
|
||||
@param underrun Set if XTRX does not have data to transmit, e.g. data not being sent fast enough
|
||||
@param timestamp The timestamp of the first sample of the data buffer.
|
||||
@param isControl Set if data is a control packet, e.g. a ping command
|
||||
@return The number of samples actually written
|
||||
*/
|
||||
int writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
|
||||
TIMESTAMP timestamp = 0xffffffff, bool isControl = false);
|
||||
|
||||
/** Update the alignment between the read and write timestamps */
|
||||
bool updateAlignment(TIMESTAMP timestamp);
|
||||
|
||||
/** Set the transmitter frequency */
|
||||
bool setTxFreq(double wFreq, size_t chan = 0);
|
||||
|
||||
/** Set the receiver frequency */
|
||||
bool setRxFreq(double wFreq, size_t chan = 0);
|
||||
|
||||
/** Returns the starting write Timestamp*/
|
||||
TIMESTAMP initialWriteTimestamp(void);
|
||||
|
||||
/** Returns the starting read Timestamp*/
|
||||
TIMESTAMP initialReadTimestamp(void) { return 20000;}
|
||||
|
||||
/** returns the full-scale transmit amplitude **/
|
||||
double fullScaleInputValue() {return (double) 32767*0.7;}
|
||||
|
||||
/** returns the full-scale receive amplitude **/
|
||||
double fullScaleOutputValue() {return (double) 32767;}
|
||||
|
||||
/** sets the receive chan gain, returns the gain setting **/
|
||||
double setRxGain(double dB, size_t chan = 0);
|
||||
|
||||
/** get the current receive gain */
|
||||
double getRxGain(size_t chan = 0) { return rxGain; }
|
||||
|
||||
/** return maximum Rx Gain **/
|
||||
double maxRxGain(void);
|
||||
|
||||
/** return minimum Rx Gain **/
|
||||
double minRxGain(void);
|
||||
|
||||
/** sets the transmit chan gain, returns the gain setting **/
|
||||
double setTxGain(double dB, size_t chan = 0);
|
||||
|
||||
/** gets the current transmit gain **/
|
||||
double getTxGain(size_t chan = 0) { return txGain; }
|
||||
|
||||
/** return maximum Tx Gain **/
|
||||
double maxTxGain(void);
|
||||
|
||||
/** return minimum Rx Gain **/
|
||||
double minTxGain(void);
|
||||
|
||||
/** sets the RX path to use, returns true if successful and false otherwise */
|
||||
bool setRxAntenna(const std::string & ant, size_t chan = 0);
|
||||
|
||||
/** return the used RX path */
|
||||
std::string getRxAntenna(size_t chan = 0);
|
||||
|
||||
/** sets the RX path to use, returns true if successful and false otherwise */
|
||||
bool setTxAntenna(const std::string & ant, size_t chan = 0);
|
||||
|
||||
/** return the used RX path */
|
||||
std::string getTxAntenna(size_t chan = 0);
|
||||
|
||||
/** return whether user drives synchronization of Tx/Rx of USRP */
|
||||
bool requiresRadioAlign();
|
||||
|
||||
/** return whether user drives synchronization of Tx/Rx of USRP */
|
||||
virtual GSM::Time minLatency();
|
||||
|
||||
/** Return internal status values */
|
||||
inline double getTxFreq(size_t chan = 0) { return 0; }
|
||||
inline double getRxFreq(size_t chan = 0) { return 0; }
|
||||
inline double getSampleRate() { return actualTXSampleRate; }
|
||||
inline double numberRead() { return samplesRead; }
|
||||
inline double numberWritten() { return samplesWritten; }
|
||||
|
||||
};
|
||||
|
||||
#endif // _XTRX_DEVICE_H_
|
||||
|
11
configure.ac
11
configure.ac
|
@ -138,6 +138,11 @@ AC_ARG_WITH(ipc, [
|
|||
[enable IPC])
|
||||
])
|
||||
|
||||
AC_ARG_WITH(xtrx, [
|
||||
AS_HELP_STRING([--with-xtrx],
|
||||
[enable XTRX based transceiver])
|
||||
])
|
||||
|
||||
AC_ARG_WITH(singledb, [
|
||||
AS_HELP_STRING([--with-singledb],
|
||||
[enable single daughterboard use on USRP1])
|
||||
|
@ -177,6 +182,10 @@ AS_IF([test "x$with_lms" = "xyes"], [
|
|||
PKG_CHECK_MODULES(LMS, LimeSuite)
|
||||
])
|
||||
|
||||
AS_IF([test "x$with_xtrx" = "xyes"], [
|
||||
PKG_CHECK_MODULES(XTRX, libxtrx)
|
||||
])
|
||||
|
||||
AS_IF([test "x$with_uhd" = "xyes"],[
|
||||
PKG_CHECK_MODULES(UHD, uhd >= 003.011,
|
||||
[AC_DEFINE(USE_UHD_3_11, 1, UHD version 3.11.0 or higher)],
|
||||
|
@ -248,6 +257,7 @@ AM_CONDITIONAL(DEVICE_UHD, [test "x$with_uhd" = "xyes"])
|
|||
AM_CONDITIONAL(DEVICE_USRP1, [test "x$with_usrp1" = "xyes"])
|
||||
AM_CONDITIONAL(DEVICE_LMS, [test "x$with_lms" = "xyes"])
|
||||
AM_CONDITIONAL(DEVICE_IPC, [test "x$with_ipc" = "xyes"])
|
||||
AM_CONDITIONAL(DEVICE_XTRX, [test "x$with_xtrx" = "xyes"])
|
||||
AM_CONDITIONAL(ARCH_ARM, [test "x$with_neon" = "xyes" || test "x$with_neon_vfpv4" = "xyes"])
|
||||
AM_CONDITIONAL(ARCH_ARM_A15, [test "x$with_neon_vfpv4" = "xyes"])
|
||||
|
||||
|
@ -333,6 +343,7 @@ AC_CONFIG_FILES([\
|
|||
Transceiver52M/device/usrp1/Makefile \
|
||||
Transceiver52M/device/lms/Makefile \
|
||||
Transceiver52M/device/ipc/Makefile \
|
||||
Transceiver52M/device/xtrx/Makefile \
|
||||
tests/Makefile \
|
||||
tests/CommonLibs/Makefile \
|
||||
tests/Transceiver52M/Makefile \
|
||||
|
|
|
@ -2,7 +2,8 @@ EXTRA_DIST = \
|
|||
osmo-trx-lms.service \
|
||||
osmo-trx-uhd.service \
|
||||
osmo-trx-usrp1.service \
|
||||
osmo-trx-ipc.service
|
||||
osmo-trx-ipc.service \
|
||||
osmo-trx-xtrx.service
|
||||
|
||||
if HAVE_SYSTEMD
|
||||
SYSTEMD_SERVICES =
|
||||
|
@ -23,5 +24,9 @@ if DEVICE_IPC
|
|||
SYSTEMD_SERVICES += osmo-trx-ipc.service
|
||||
endif
|
||||
|
||||
if DEVICE_XTRX
|
||||
SYSTEMD_SERVICES += osmo-trx-xtrx.service
|
||||
endif
|
||||
|
||||
systemdsystemunit_DATA = $(SYSTEMD_SERVICES)
|
||||
endif # HAVE_SYSTEMD
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
[Unit]
|
||||
Description=Osmocom SDR BTS L1 Transceiver (XTRX backend)
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
ExecStart=/usr/bin/osmo-trx-xtrx -C /etc/osmocom/osmo-trx-xtrx.cfg
|
||||
RestartSec=2
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -110,6 +110,25 @@ Description: SDR transceiver that implements Layer 1 of a GSM BTS (generic IPC)
|
|||
between different telecommunication associations for developing new
|
||||
generations of mobile phone networks. (post-2G/GSM)
|
||||
|
||||
Package: osmo-trx-xtrx
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: SDR transceiver that implements Layer 1 of a GSM BTS (XTRX)
|
||||
OsmoTRX is a software-defined radio transceiver that implements the Layer 1
|
||||
physical layer of a BTS comprising the following 3GPP specifications:
|
||||
.
|
||||
TS 05.01 "Physical layer on the radio path"
|
||||
TS 05.02 "Multiplexing and Multiple Access on the Radio Path"
|
||||
TS 05.04 "Modulation"
|
||||
TS 05.10 "Radio subsystem synchronization"
|
||||
.
|
||||
In this context, BTS is "Base transceiver station". It's the stations that
|
||||
connect mobile phones to the mobile network.
|
||||
.
|
||||
3GPP is the "3rd Generation Partnership Project" which is the collaboration
|
||||
between different telecommunication associations for developing new
|
||||
generations of mobile phone networks. (post-2G/GSM)
|
||||
|
||||
Package: osmo-trx-doc
|
||||
Architecture: all
|
||||
Section: doc
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
etc/osmocom/osmo-trx-xtrx.cfg
|
||||
lib/systemd/system/osmo-trx-xtrx.service
|
||||
/usr/bin/osmo-trx-xtrx
|
||||
/usr/share/doc/osmo-trx/examples/osmo-trx-xtrx/osmo-trx-xtrx.cfg /usr/share/doc/osmo-trx/examples/osmo-trx-xtrx/
|
|
@ -18,6 +18,10 @@ if DEVICE_IPC
|
|||
OSMOCONF_FILES += osmo-trx-ipc/osmo-trx-ipc.cfg
|
||||
endif
|
||||
|
||||
if DEVICE_XTRX
|
||||
OSMOCONF_FILES += osmo-trx-xtrx/osmo-trx-xtrx.cfg
|
||||
endif
|
||||
|
||||
osmoconf_DATA = $(OSMOCONF_FILES)
|
||||
EXTRA_DIST = $(OSMOCONF_FILES)
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
log stderr
|
||||
logging filter all 1
|
||||
logging color 1
|
||||
logging print category 1
|
||||
logging timestamp 1
|
||||
logging print file basename
|
||||
logging level set-all info
|
||||
!
|
||||
line vty
|
||||
no login
|
||||
!
|
||||
trx
|
||||
bind-ip 127.0.0.1
|
||||
remote-ip 127.0.0.1
|
||||
base-port 5700
|
||||
egprs disable
|
||||
tx-sps 4
|
||||
rx-sps 4
|
||||
rt-prio 18
|
||||
chan 0
|
Loading…
Reference in New Issue