2011-10-12 07:44:40 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2008 Free Software Foundation, Inc.
|
|
|
|
*
|
2019-10-13 17:08:00 +00:00
|
|
|
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribution.
|
2011-10-12 07:44:40 +00:00
|
|
|
*
|
|
|
|
* This use of this software may be subject to additional restrictions.
|
|
|
|
* See the LEGAL file in the main directory for details.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __RADIO_DEVICE_H__
|
|
|
|
#define __RADIO_DEVICE_H__
|
|
|
|
|
2012-10-22 00:07:14 +00:00
|
|
|
#include <string>
|
2013-10-29 22:34:16 +00:00
|
|
|
#include <vector>
|
2011-10-12 07:44:40 +00:00
|
|
|
|
2018-04-24 16:43:51 +00:00
|
|
|
#include "GSMCommon.h"
|
2018-06-13 17:32:15 +00:00
|
|
|
#include "Logger.h"
|
2018-04-24 16:43:51 +00:00
|
|
|
|
2018-02-21 13:59:19 +00:00
|
|
|
extern "C" {
|
|
|
|
#include "config_defs.h"
|
2019-05-24 14:54:19 +00:00
|
|
|
#include "osmo_signal.h"
|
2018-02-21 13:59:19 +00:00
|
|
|
}
|
|
|
|
|
2011-10-12 07:44:40 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2016-06-18 07:42:33 +00:00
|
|
|
#define GSMRATE (1625e3/6)
|
2016-06-24 21:25:39 +00:00
|
|
|
#define MCBTS_SPACING 800000.0
|
2013-04-08 18:18:26 +00:00
|
|
|
|
2011-10-12 07:44:40 +00:00
|
|
|
/** a 64-bit virtual timestamp for radio data */
|
|
|
|
typedef unsigned long long TIMESTAMP;
|
|
|
|
|
|
|
|
/** A class to handle a USRP rev 4, with a two RFX900 daughterboards */
|
|
|
|
class RadioDevice {
|
|
|
|
|
|
|
|
public:
|
2011-11-26 03:18:55 +00:00
|
|
|
/* Available transport bus types */
|
2018-04-25 10:17:10 +00:00
|
|
|
enum TxWindowType { TX_WINDOW_USRP1, TX_WINDOW_FIXED, TX_WINDOW_LMS1 };
|
2011-11-26 03:18:55 +00:00
|
|
|
|
2013-04-08 18:18:26 +00:00
|
|
|
/* Radio interface types */
|
2016-06-22 23:09:44 +00:00
|
|
|
enum InterfaceType {
|
|
|
|
NORMAL,
|
|
|
|
RESAMP_64M,
|
|
|
|
RESAMP_100M,
|
2016-06-24 21:25:39 +00:00
|
|
|
MULTI_ARFCN,
|
2016-06-22 23:09:44 +00:00
|
|
|
};
|
|
|
|
|
2023-05-10 21:50:38 +00:00
|
|
|
static RadioDevice *make(InterfaceType type, const struct trx_cfg *cfg);
|
2011-11-26 03:16:54 +00:00
|
|
|
|
2011-11-26 03:17:13 +00:00
|
|
|
/** Initialize the USRP */
|
2023-05-10 21:50:38 +00:00
|
|
|
virtual int open() = 0;
|
2011-10-12 07:44:40 +00:00
|
|
|
|
2013-11-15 21:26:05 +00:00
|
|
|
virtual ~RadioDevice() { }
|
|
|
|
|
2011-10-12 07:44:40 +00:00
|
|
|
/** Start the USRP */
|
|
|
|
virtual bool start()=0;
|
|
|
|
|
|
|
|
/** Stop the USRP */
|
|
|
|
virtual bool stop()=0;
|
|
|
|
|
2013-04-05 19:36:30 +00:00
|
|
|
/** Get the Tx window type */
|
|
|
|
virtual enum TxWindowType getWindowType()=0;
|
2011-11-26 03:18:55 +00:00
|
|
|
|
2011-10-12 07:44:40 +00:00
|
|
|
/**
|
|
|
|
Read samples from the radio.
|
|
|
|
@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 radio does not have data to transmit, e.g. data not being sent fast enough
|
|
|
|
@return The number of samples actually read
|
|
|
|
*/
|
2013-10-29 22:34:16 +00:00
|
|
|
virtual int readSamples(std::vector<short *> &bufs, int len, bool *overrun,
|
2020-03-12 18:08:46 +00:00
|
|
|
TIMESTAMP timestamp = 0xffffffff, bool *underrun = 0) = 0;
|
2011-10-12 07:44:40 +00:00
|
|
|
/**
|
|
|
|
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.
|
|
|
|
@return The number of samples actually written
|
|
|
|
*/
|
2013-10-29 22:34:16 +00:00
|
|
|
virtual int writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
|
2020-03-12 18:35:33 +00:00
|
|
|
TIMESTAMP timestamp) = 0;
|
2013-10-29 22:34:16 +00:00
|
|
|
|
2011-10-12 07:44:40 +00:00
|
|
|
/** Update the alignment between the read and write timestamps */
|
|
|
|
virtual bool updateAlignment(TIMESTAMP timestamp)=0;
|
2013-10-29 22:34:16 +00:00
|
|
|
|
2011-10-12 07:44:40 +00:00
|
|
|
/** Set the transmitter frequency */
|
2013-10-29 22:34:16 +00:00
|
|
|
virtual bool setTxFreq(double wFreq, size_t chan = 0) = 0;
|
2011-10-12 07:44:40 +00:00
|
|
|
|
|
|
|
/** Set the receiver frequency */
|
2013-10-29 22:34:16 +00:00
|
|
|
virtual bool setRxFreq(double wFreq, size_t chan = 0) = 0;
|
2011-10-12 07:44:40 +00:00
|
|
|
|
|
|
|
/** Returns the starting write Timestamp*/
|
|
|
|
virtual TIMESTAMP initialWriteTimestamp(void)=0;
|
|
|
|
|
|
|
|
/** Returns the starting read Timestamp*/
|
|
|
|
virtual TIMESTAMP initialReadTimestamp(void)=0;
|
|
|
|
|
|
|
|
/** returns the full-scale transmit amplitude **/
|
|
|
|
virtual double fullScaleInputValue()=0;
|
|
|
|
|
|
|
|
/** returns the full-scale receive amplitude **/
|
|
|
|
virtual double fullScaleOutputValue()=0;
|
|
|
|
|
|
|
|
/** sets the receive chan gain, returns the gain setting **/
|
2013-10-29 22:34:16 +00:00
|
|
|
virtual double setRxGain(double dB, size_t chan = 0) = 0;
|
2011-10-12 07:44:40 +00:00
|
|
|
|
|
|
|
/** gets the current receive gain **/
|
2013-10-29 22:34:16 +00:00
|
|
|
virtual double getRxGain(size_t chan = 0) = 0;
|
2011-10-12 07:44:40 +00:00
|
|
|
|
|
|
|
/** return maximum Rx Gain **/
|
|
|
|
virtual double maxRxGain(void) = 0;
|
|
|
|
|
|
|
|
/** return minimum Rx Gain **/
|
|
|
|
virtual double minRxGain(void) = 0;
|
|
|
|
|
2020-10-13 15:03:37 +00:00
|
|
|
/** return base RSSI offset to apply for received samples **/
|
|
|
|
virtual double rssiOffset(size_t chan) = 0;
|
|
|
|
|
2020-05-29 14:39:07 +00:00
|
|
|
/** returns the Nominal transmit output power of the transceiver in dBm, negative on error **/
|
|
|
|
virtual int getNominalTxPower(size_t chan = 0) = 0;
|
|
|
|
|
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
|
|
|
/** sets the RX path to use, returns true if successful and false otherwise */
|
|
|
|
virtual bool setRxAntenna(const std::string &ant, size_t chan = 0) = 0;
|
|
|
|
|
|
|
|
/** return the used RX path */
|
|
|
|
virtual std::string getRxAntenna(size_t chan = 0) = 0;
|
|
|
|
|
|
|
|
/** sets the RX path to use, returns true if successful and false otherwise */
|
|
|
|
virtual bool setTxAntenna(const std::string &ant, size_t chan = 0) = 0;
|
|
|
|
|
|
|
|
/** return the used RX path */
|
|
|
|
virtual std::string getTxAntenna(size_t chan = 0) = 0;
|
|
|
|
|
2018-04-24 15:48:52 +00:00
|
|
|
/** return whether user drives synchronization of Tx/Rx of USRP */
|
|
|
|
virtual bool requiresRadioAlign() = 0;
|
|
|
|
|
2018-04-24 16:43:51 +00:00
|
|
|
/** Minimum latency that the device can achieve */
|
|
|
|
virtual GSM::Time minLatency() = 0;
|
|
|
|
|
2011-10-12 07:44:40 +00:00
|
|
|
/** Return internal status values */
|
2013-10-29 22:34:16 +00:00
|
|
|
virtual double getTxFreq(size_t chan = 0) = 0;
|
|
|
|
virtual double getRxFreq(size_t chan = 0) = 0;
|
2011-10-12 07:44:40 +00:00
|
|
|
virtual double getSampleRate()=0;
|
|
|
|
|
2020-06-19 16:11:54 +00:00
|
|
|
virtual double setPowerAttenuation(int atten, size_t chan) = 0;
|
|
|
|
virtual double getPowerAttenuation(size_t chan=0) = 0;
|
2020-06-08 11:44:24 +00:00
|
|
|
|
2018-06-13 21:21:57 +00:00
|
|
|
protected:
|
|
|
|
size_t tx_sps, rx_sps;
|
|
|
|
InterfaceType iface;
|
|
|
|
size_t chans;
|
|
|
|
double lo_offset;
|
2018-06-13 17:32:15 +00:00
|
|
|
std::vector<std::string> tx_paths, rx_paths;
|
2019-05-24 14:54:19 +00:00
|
|
|
std::vector<struct device_counters> m_ctr;
|
2023-05-10 21:50:38 +00:00
|
|
|
const struct trx_cfg *cfg;
|
|
|
|
|
|
|
|
#define charp2str(a) ((a) ? std::string(a) : std::string(""))
|
|
|
|
|
|
|
|
RadioDevice(InterfaceType type, const struct trx_cfg *cfg)
|
|
|
|
: tx_sps(cfg->tx_sps), rx_sps(cfg->rx_sps), iface(type), chans(cfg->num_chans), lo_offset(cfg->offset),
|
|
|
|
m_ctr(chans), cfg(cfg)
|
|
|
|
{
|
|
|
|
/* Generate vector of rx/tx_path: */
|
|
|
|
for (unsigned int i = 0; i < cfg->num_chans; i++) {
|
|
|
|
rx_paths.push_back(charp2str(cfg->chans[i].rx_path));
|
|
|
|
tx_paths.push_back(charp2str(cfg->chans[i].tx_path));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (iface == MULTI_ARFCN) {
|
|
|
|
LOGC(DDEV, INFO) << "Multi-ARFCN: " << chans << " logical chans -> 1 physical chans";
|
|
|
|
chans = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i < chans; i++) {
|
|
|
|
memset(&m_ctr[i], 0, sizeof(m_ctr[i]));
|
|
|
|
m_ctr[i].chan = i;
|
|
|
|
}
|
|
|
|
}
|
2018-06-13 21:21:57 +00:00
|
|
|
|
2018-06-13 17:32:15 +00:00
|
|
|
bool set_antennas() {
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < tx_paths.size(); i++) {
|
|
|
|
if (tx_paths[i] == "")
|
|
|
|
continue;
|
2020-09-11 11:03:56 +00:00
|
|
|
if (iface == MULTI_ARFCN && i > 0) {
|
|
|
|
LOGCHAN(i, DDEV, NOTICE) << "Not setting Tx antenna "
|
|
|
|
<< tx_paths[i]
|
|
|
|
<< " for a logical channel";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-08-26 15:11:12 +00:00
|
|
|
LOGCHAN(i, DDEV, DEBUG) << "Configuring Tx antenna " << tx_paths[i];
|
2018-06-13 17:32:15 +00:00
|
|
|
if (!setTxAntenna(tx_paths[i], i)) {
|
2019-08-26 15:11:12 +00:00
|
|
|
LOGCHAN(i, DDEV, ALERT) << "Failed configuring Tx antenna " << tx_paths[i];
|
2018-06-13 17:32:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < rx_paths.size(); i++) {
|
|
|
|
if (rx_paths[i] == "")
|
|
|
|
continue;
|
2020-09-11 11:03:56 +00:00
|
|
|
if (iface == MULTI_ARFCN && i > 0) {
|
|
|
|
LOGCHAN(i, DDEV, NOTICE) << "Not setting Rx antenna "
|
|
|
|
<< rx_paths[i]
|
|
|
|
<< " for a logical channel";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-08-26 15:11:12 +00:00
|
|
|
LOGCHAN(i, DDEV, DEBUG) << "Configuring Rx antenna " << rx_paths[i];
|
2018-06-13 17:32:15 +00:00
|
|
|
if (!setRxAntenna(rx_paths[i], i)) {
|
2019-08-26 15:11:12 +00:00
|
|
|
LOGCHAN(i, DDEV, ALERT) << "Failed configuring Rx antenna " << rx_paths[i];
|
2018-06-13 17:32:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LOG(INFO) << "Antennas configured successfully";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-12 07:44:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|