mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-trx.git
synced 2025-11-16 11:51:45 +00:00
Transceiver52M: Set resampling option automatically based on device
Remove the built time resampling selection and link both options. Move the normal push/pullBuffer() calls back to the base class and overload them in the inherited resampling class. USRP2/N2xx devices are the only devices that require resampling so return that resampling is necessary on the device open(), which is the point at which the device type will be known. The GSM transceiver only operates at a whole number multiple of the GSM rate and doesn't care about the actual device rate and if resampling is used. Therefore GSM specific portion of the transceiver should only need to submit the samples-per-symbol value to the device interface. Then, the device should be able to determine the appropriate sample rate (400 ksps or 270.833 ksps) and if resampling is appropriate. Signed-off-by: Thomas Tsou <tom@tsou.cc>
This commit is contained in:
@@ -55,15 +55,9 @@ COMMON_SOURCES = \
|
|||||||
Transceiver.cpp \
|
Transceiver.cpp \
|
||||||
DummyLoad.cpp
|
DummyLoad.cpp
|
||||||
|
|
||||||
if RESAMPLE
|
|
||||||
libtransceiver_la_SOURCES = \
|
libtransceiver_la_SOURCES = \
|
||||||
$(COMMON_SOURCES) \
|
$(COMMON_SOURCES) \
|
||||||
radioIOResamp.cpp
|
radioInterfaceResamp.cpp
|
||||||
else
|
|
||||||
libtransceiver_la_SOURCES = \
|
|
||||||
$(COMMON_SOURCES) \
|
|
||||||
radioIO.cpp
|
|
||||||
endif
|
|
||||||
|
|
||||||
noinst_PROGRAMS = \
|
noinst_PROGRAMS = \
|
||||||
USRPping \
|
USRPping \
|
||||||
|
|||||||
@@ -32,7 +32,9 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define B100_CLK_RT 52e6
|
#define B100_CLK_RT 52e6
|
||||||
|
#define B100_BASE_RT GSMRATE
|
||||||
|
#define USRP2_BASE_RT 400e3
|
||||||
#define TX_AMPL 0.3
|
#define TX_AMPL 0.3
|
||||||
#define SAMPLE_BUF_SZ (1 << 20)
|
#define SAMPLE_BUF_SZ (1 << 20)
|
||||||
|
|
||||||
@@ -91,6 +93,29 @@ static double get_dev_offset(enum uhd_dev_type type, int sps)
|
|||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Select sample rate based on device type and requested samples-per-symbol.
|
||||||
|
* The base rate is either GSM symbol rate, 270.833 kHz, or the minimum
|
||||||
|
* usable channel spacing of 400 kHz.
|
||||||
|
*/
|
||||||
|
static double select_rate(uhd_dev_type type, int sps)
|
||||||
|
{
|
||||||
|
if ((sps != 4) && (sps != 2) && (sps != 1))
|
||||||
|
return -9999.99;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case USRP2:
|
||||||
|
return USRP2_BASE_RT * sps;
|
||||||
|
break;
|
||||||
|
case B100:
|
||||||
|
return B100_BASE_RT * sps;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(ALERT) << "Unknown device type " << type;
|
||||||
|
return -9999.99;
|
||||||
|
}
|
||||||
|
|
||||||
/** Timestamp conversion
|
/** Timestamp conversion
|
||||||
@param timestamp a UHD or OpenBTS timestamp
|
@param timestamp a UHD or OpenBTS timestamp
|
||||||
@param rate sample rate
|
@param rate sample rate
|
||||||
@@ -181,10 +206,10 @@ private:
|
|||||||
*/
|
*/
|
||||||
class uhd_device : public RadioDevice {
|
class uhd_device : public RadioDevice {
|
||||||
public:
|
public:
|
||||||
uhd_device(double rate, int sps, bool skip_rx);
|
uhd_device(int sps, bool skip_rx);
|
||||||
~uhd_device();
|
~uhd_device();
|
||||||
|
|
||||||
bool open(const std::string &args);
|
int open(const std::string &args);
|
||||||
bool start();
|
bool start();
|
||||||
bool stop();
|
bool stop();
|
||||||
void restart(uhd::time_spec_t ts);
|
void restart(uhd::time_spec_t ts);
|
||||||
@@ -306,9 +331,8 @@ void uhd_msg_handler(uhd::msg::type_t type, const std::string &msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uhd_device::uhd_device(double rate, int sps, bool skip_rx)
|
uhd_device::uhd_device(int sps, bool skip_rx)
|
||||||
: desired_smpl_rt(rate), actual_smpl_rt(0),
|
: tx_gain(0.0), tx_gain_min(0.0), tx_gain_max(0.0),
|
||||||
tx_gain(0.0), tx_gain_min(0.0), tx_gain_max(0.0),
|
|
||||||
rx_gain(0.0), rx_gain_min(0.0), rx_gain_max(0.0),
|
rx_gain(0.0), rx_gain_min(0.0), rx_gain_max(0.0),
|
||||||
tx_freq(0.0), rx_freq(0.0), tx_spp(0), rx_spp(0),
|
tx_freq(0.0), rx_freq(0.0), tx_spp(0), rx_spp(0),
|
||||||
started(false), aligned(false), rx_pkt_cnt(0), drop_cnt(0),
|
started(false), aligned(false), rx_pkt_cnt(0), drop_cnt(0),
|
||||||
@@ -374,6 +398,9 @@ int uhd_device::set_master_clk(double clk_rate)
|
|||||||
|
|
||||||
int uhd_device::set_rates(double rate)
|
int uhd_device::set_rates(double rate)
|
||||||
{
|
{
|
||||||
|
double offset_limit = 10.0;
|
||||||
|
double tx_offset, rx_offset;
|
||||||
|
|
||||||
// B100 is the only device where we set FPGA clocking
|
// B100 is the only device where we set FPGA clocking
|
||||||
if (dev_type == B100) {
|
if (dev_type == B100) {
|
||||||
if (set_master_clk(B100_CLK_RT) < 0)
|
if (set_master_clk(B100_CLK_RT) < 0)
|
||||||
@@ -385,14 +412,14 @@ int uhd_device::set_rates(double rate)
|
|||||||
usrp_dev->set_rx_rate(rate);
|
usrp_dev->set_rx_rate(rate);
|
||||||
actual_smpl_rt = usrp_dev->get_tx_rate();
|
actual_smpl_rt = usrp_dev->get_tx_rate();
|
||||||
|
|
||||||
if (actual_smpl_rt != rate) {
|
tx_offset = actual_smpl_rt - rate;
|
||||||
|
rx_offset = usrp_dev->get_rx_rate() - rate;
|
||||||
|
if ((tx_offset > offset_limit) || (rx_offset > offset_limit)) {
|
||||||
LOG(ALERT) << "Actual sample rate differs from desired rate";
|
LOG(ALERT) << "Actual sample rate differs from desired rate";
|
||||||
|
LOG(ALERT) << "Tx/Rx (" << actual_smpl_rt << "/"
|
||||||
|
<< usrp_dev->get_rx_rate() << ")";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (usrp_dev->get_rx_rate() != actual_smpl_rt) {
|
|
||||||
LOG(ALERT) << "Transmit and receive sample rates do not match";
|
|
||||||
return -1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -427,15 +454,15 @@ bool uhd_device::parse_dev_type()
|
|||||||
{
|
{
|
||||||
std::string mboard_str, dev_str;
|
std::string mboard_str, dev_str;
|
||||||
uhd::property_tree::sptr prop_tree;
|
uhd::property_tree::sptr prop_tree;
|
||||||
size_t usrp1_str, usrp2_str, b100_str1, b100_str2;
|
size_t usrp1_str, usrp2_str, b100_str;
|
||||||
|
|
||||||
prop_tree = usrp_dev->get_device()->get_tree();
|
prop_tree = usrp_dev->get_device()->get_tree();
|
||||||
dev_str = prop_tree->access<std::string>("/name").get();
|
dev_str = prop_tree->access<std::string>("/name").get();
|
||||||
mboard_str = usrp_dev->get_mboard_name();
|
mboard_str = usrp_dev->get_mboard_name();
|
||||||
|
|
||||||
usrp1_str = dev_str.find("USRP1");
|
usrp1_str = dev_str.find("USRP1");
|
||||||
b100_str1 = dev_str.find("B-Series");
|
usrp2_str = dev_str.find("USRP2");
|
||||||
b100_str2 = mboard_str.find("B100");
|
b100_str = mboard_str.find("B100");
|
||||||
|
|
||||||
if (usrp1_str != std::string::npos) {
|
if (usrp1_str != std::string::npos) {
|
||||||
LOG(ALERT) << "USRP1 is not supported using the UHD driver";
|
LOG(ALERT) << "USRP1 is not supported using the UHD driver";
|
||||||
@@ -444,14 +471,17 @@ bool uhd_device::parse_dev_type()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((b100_str1 != std::string::npos) || (b100_str2 != std::string::npos)) {
|
if (b100_str != std::string::npos) {
|
||||||
tx_window = TX_WINDOW_USRP1;
|
tx_window = TX_WINDOW_USRP1;
|
||||||
LOG(INFO) << "Using USRP1 type transmit window for "
|
LOG(INFO) << "Using USRP1 type transmit window for "
|
||||||
<< dev_str << " " << mboard_str;
|
<< dev_str << " " << mboard_str;
|
||||||
dev_type = B100;
|
dev_type = B100;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else if (usrp2_str != std::string::npos) {
|
||||||
dev_type = USRP2;
|
dev_type = USRP2;
|
||||||
|
} else {
|
||||||
|
LOG(ALERT) << "Unknown UHD device type";
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
tx_window = TX_WINDOW_FIXED;
|
tx_window = TX_WINDOW_FIXED;
|
||||||
@@ -460,7 +490,7 @@ bool uhd_device::parse_dev_type()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool uhd_device::open(const std::string &args)
|
int uhd_device::open(const std::string &args)
|
||||||
{
|
{
|
||||||
// Register msg handler
|
// Register msg handler
|
||||||
uhd::msg::register_handler(&uhd_msg_handler);
|
uhd::msg::register_handler(&uhd_msg_handler);
|
||||||
@@ -470,7 +500,7 @@ bool uhd_device::open(const std::string &args)
|
|||||||
uhd::device_addrs_t dev_addrs = uhd::device::find(addr);
|
uhd::device_addrs_t dev_addrs = uhd::device::find(addr);
|
||||||
if (dev_addrs.size() == 0) {
|
if (dev_addrs.size() == 0) {
|
||||||
LOG(ALERT) << "No UHD devices found with address '" << args << "'";
|
LOG(ALERT) << "No UHD devices found with address '" << args << "'";
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the first found device
|
// Use the first found device
|
||||||
@@ -479,12 +509,12 @@ bool uhd_device::open(const std::string &args)
|
|||||||
usrp_dev = uhd::usrp::multi_usrp::make(dev_addrs[0]);
|
usrp_dev = uhd::usrp::multi_usrp::make(dev_addrs[0]);
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
LOG(ALERT) << "UHD make failed, device " << dev_addrs[0].to_string();
|
LOG(ALERT) << "UHD make failed, device " << dev_addrs[0].to_string();
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for a valid device type and set bus type
|
// Check for a valid device type and set bus type
|
||||||
if (!parse_dev_type())
|
if (!parse_dev_type())
|
||||||
return false;
|
return -1;
|
||||||
|
|
||||||
#ifdef EXTREF
|
#ifdef EXTREF
|
||||||
set_ref_clk(true);
|
set_ref_clk(true);
|
||||||
@@ -499,8 +529,9 @@ bool uhd_device::open(const std::string &args)
|
|||||||
rx_spp = rx_stream->get_max_num_samps();
|
rx_spp = rx_stream->get_max_num_samps();
|
||||||
|
|
||||||
// Set rates
|
// Set rates
|
||||||
|
desired_smpl_rt = select_rate(dev_type, sps);
|
||||||
if (set_rates(desired_smpl_rt) < 0)
|
if (set_rates(desired_smpl_rt) < 0)
|
||||||
return false;
|
return -1;
|
||||||
|
|
||||||
// Create receive buffer
|
// Create receive buffer
|
||||||
size_t buf_len = SAMPLE_BUF_SZ / sizeof(uint32_t);
|
size_t buf_len = SAMPLE_BUF_SZ / sizeof(uint32_t);
|
||||||
@@ -521,7 +552,10 @@ bool uhd_device::open(const std::string &args)
|
|||||||
// Print configuration
|
// Print configuration
|
||||||
LOG(INFO) << "\n" << usrp_dev->get_pp_string();
|
LOG(INFO) << "\n" << usrp_dev->get_pp_string();
|
||||||
|
|
||||||
return true;
|
if (dev_type == USRP2)
|
||||||
|
return RESAMP;
|
||||||
|
|
||||||
|
return NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool uhd_device::flush_recv(size_t num_pkts)
|
bool uhd_device::flush_recv(size_t num_pkts)
|
||||||
@@ -1021,7 +1055,7 @@ std::string smpl_buf::str_code(ssize_t code)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RadioDevice *RadioDevice::make(double smpl_rt, int sps, bool skip_rx)
|
RadioDevice *RadioDevice::make(int sps, bool skip_rx)
|
||||||
{
|
{
|
||||||
return new uhd_device(smpl_rt, sps, skip_rx);
|
return new uhd_device(sps, skip_rx);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,11 +59,11 @@ const dboardConfigType dboardConfig = TXA_RXB;
|
|||||||
|
|
||||||
const double USRPDevice::masterClockRate = 52.0e6;
|
const double USRPDevice::masterClockRate = 52.0e6;
|
||||||
|
|
||||||
USRPDevice::USRPDevice (double _desiredSampleRate, bool skipRx)
|
USRPDevice::USRPDevice(int sps, bool skipRx)
|
||||||
: skipRx(skipRx)
|
: skipRx(skipRx)
|
||||||
{
|
{
|
||||||
LOG(INFO) << "creating USRP device...";
|
LOG(INFO) << "creating USRP device...";
|
||||||
decimRate = (unsigned int) round(masterClockRate/_desiredSampleRate);
|
decimRate = (unsigned int) round(masterClockRate/((GSMRATE) * (double) sps));
|
||||||
actualSampleRate = masterClockRate/decimRate;
|
actualSampleRate = masterClockRate/decimRate;
|
||||||
rxGain = 0;
|
rxGain = 0;
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ USRPDevice::USRPDevice (double _desiredSampleRate, bool skipRx)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool USRPDevice::open(const std::string &)
|
int USRPDevice::open(const std::string &)
|
||||||
{
|
{
|
||||||
writeLock.unlock();
|
writeLock.unlock();
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ bool USRPDevice::open(const std::string &)
|
|||||||
catch(...) {
|
catch(...) {
|
||||||
LOG(ALERT) << "make failed on Rx";
|
LOG(ALERT) << "make failed on Rx";
|
||||||
m_uRx.reset();
|
m_uRx.reset();
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_uRx->fpga_master_clock_freq() != masterClockRate)
|
if (m_uRx->fpga_master_clock_freq() != masterClockRate)
|
||||||
@@ -105,7 +105,7 @@ bool USRPDevice::open(const std::string &)
|
|||||||
LOG(ALERT) << "WRONG FPGA clock freq = " << m_uRx->fpga_master_clock_freq()
|
LOG(ALERT) << "WRONG FPGA clock freq = " << m_uRx->fpga_master_clock_freq()
|
||||||
<< ", desired clock freq = " << masterClockRate;
|
<< ", desired clock freq = " << masterClockRate;
|
||||||
m_uRx.reset();
|
m_uRx.reset();
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ bool USRPDevice::open(const std::string &)
|
|||||||
catch(...) {
|
catch(...) {
|
||||||
LOG(ALERT) << "make failed on Tx";
|
LOG(ALERT) << "make failed on Tx";
|
||||||
m_uTx.reset();
|
m_uTx.reset();
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_uTx->fpga_master_clock_freq() != masterClockRate)
|
if (m_uTx->fpga_master_clock_freq() != masterClockRate)
|
||||||
@@ -128,7 +128,7 @@ bool USRPDevice::open(const std::string &)
|
|||||||
LOG(ALERT) << "WRONG FPGA clock freq = " << m_uTx->fpga_master_clock_freq()
|
LOG(ALERT) << "WRONG FPGA clock freq = " << m_uTx->fpga_master_clock_freq()
|
||||||
<< ", desired clock freq = " << masterClockRate;
|
<< ", desired clock freq = " << masterClockRate;
|
||||||
m_uTx.reset();
|
m_uTx.reset();
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skipRx) m_uRx->stop();
|
if (!skipRx) m_uRx->stop();
|
||||||
@@ -165,7 +165,7 @@ bool USRPDevice::open(const std::string &)
|
|||||||
samplesWritten = 0;
|
samplesWritten = 0;
|
||||||
started = false;
|
started = false;
|
||||||
|
|
||||||
return true;
|
return NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -556,7 +556,7 @@ bool USRPDevice::setTxFreq(double wFreq) { return true;};
|
|||||||
bool USRPDevice::setRxFreq(double wFreq) { return true;};
|
bool USRPDevice::setRxFreq(double wFreq) { return true;};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
RadioDevice *RadioDevice::make(double desiredSampleRate, bool skipRx)
|
RadioDevice *RadioDevice::make(int sps, bool skipRx)
|
||||||
{
|
{
|
||||||
return new USRPDevice(desiredSampleRate, skipRx);
|
return new USRPDevice(sps, skipRx);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,10 +112,10 @@ private:
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
/** Object constructor */
|
/** Object constructor */
|
||||||
USRPDevice (double _desiredSampleRate, bool skipRx);
|
USRPDevice(int sps, bool skipRx);
|
||||||
|
|
||||||
/** Instantiate the USRP */
|
/** Instantiate the USRP */
|
||||||
bool open(const std::string &);
|
int open(const std::string &);
|
||||||
|
|
||||||
/** Start the USRP */
|
/** Start the USRP */
|
||||||
bool start();
|
bool start();
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define GSMRATE 1625e3/6
|
||||||
|
|
||||||
/** a 64-bit virtual timestamp for radio data */
|
/** a 64-bit virtual timestamp for radio data */
|
||||||
typedef unsigned long long TIMESTAMP;
|
typedef unsigned long long TIMESTAMP;
|
||||||
|
|
||||||
@@ -31,10 +33,13 @@ class RadioDevice {
|
|||||||
/* Available transport bus types */
|
/* Available transport bus types */
|
||||||
enum TxWindowType { TX_WINDOW_USRP1, TX_WINDOW_FIXED };
|
enum TxWindowType { TX_WINDOW_USRP1, TX_WINDOW_FIXED };
|
||||||
|
|
||||||
static RadioDevice *make(double desiredSampleRate, int sps, bool skipRx = false);
|
/* Radio interface types */
|
||||||
|
enum RadioInterfaceType { NORMAL, RESAMP };
|
||||||
|
|
||||||
|
static RadioDevice *make(int sps, bool skipRx = false);
|
||||||
|
|
||||||
/** Initialize the USRP */
|
/** Initialize the USRP */
|
||||||
virtual bool open(const std::string &args)=0;
|
virtual int open(const std::string &args)=0;
|
||||||
|
|
||||||
/** Start the USRP */
|
/** Start the USRP */
|
||||||
virtual bool start()=0;
|
virtual bool start()=0;
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
/*
|
|
||||||
* Radio device I/O interface
|
|
||||||
* Written by Thomas Tsou <ttsou@vt.edu>
|
|
||||||
*
|
|
||||||
* Copyright 2011 Free Software Foundation, Inc.
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
* See the COPYING file in the main directory for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <radioInterface.h>
|
|
||||||
#include <Logger.h>
|
|
||||||
|
|
||||||
/* Device side buffers */
|
|
||||||
static short rx_buf[OUTCHUNK * 2 * 2];
|
|
||||||
static short tx_buf[INCHUNK * 2 * 2];
|
|
||||||
|
|
||||||
/* Complex float to short conversion */
|
|
||||||
static int float_to_short(short *shrt_out, float *flt_in, int num)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
|
||||||
shrt_out[2 * i + 0] = flt_in[2 * i + 0];
|
|
||||||
shrt_out[2 * i + 1] = flt_in[2 * i + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Comlpex short to float conversion */
|
|
||||||
static int short_to_float(float *flt_out, short *shrt_in, int num)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
|
||||||
flt_out[2 * i + 0] = shrt_in[2 * i + 0];
|
|
||||||
flt_out[2 * i + 1] = shrt_in[2 * i + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Receive a timestamped chunk from the device */
|
|
||||||
void RadioInterface::pullBuffer()
|
|
||||||
{
|
|
||||||
bool local_underrun;
|
|
||||||
|
|
||||||
/* Read samples. Fail if we don't get what we want. */
|
|
||||||
int num_rd = mRadio->readSamples(rx_buf, OUTCHUNK, &overrun,
|
|
||||||
readTimestamp, &local_underrun);
|
|
||||||
|
|
||||||
LOG(DEBUG) << "Rx read " << num_rd << " samples from device";
|
|
||||||
assert(num_rd == OUTCHUNK);
|
|
||||||
|
|
||||||
underrun |= local_underrun;
|
|
||||||
readTimestamp += (TIMESTAMP) num_rd;
|
|
||||||
|
|
||||||
short_to_float(rcvBuffer + 2 * rcvCursor, rx_buf, num_rd);
|
|
||||||
rcvCursor += num_rd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send timestamped chunk to the device with arbitrary size */
|
|
||||||
void RadioInterface::pushBuffer()
|
|
||||||
{
|
|
||||||
if (sendCursor < INCHUNK)
|
|
||||||
return;
|
|
||||||
|
|
||||||
float_to_short(tx_buf, sendBuffer, sendCursor);
|
|
||||||
|
|
||||||
/* Write samples. Fail if we don't get what we want. */
|
|
||||||
int num_smpls = mRadio->writeSamples(tx_buf,
|
|
||||||
sendCursor,
|
|
||||||
&underrun,
|
|
||||||
writeTimestamp);
|
|
||||||
assert(num_smpls == sendCursor);
|
|
||||||
|
|
||||||
writeTimestamp += (TIMESTAMP) num_smpls;
|
|
||||||
sendCursor = 0;
|
|
||||||
}
|
|
||||||
@@ -27,6 +27,28 @@
|
|||||||
|
|
||||||
bool started = false;
|
bool started = false;
|
||||||
|
|
||||||
|
/* Device side buffers */
|
||||||
|
static short rx_buf[OUTCHUNK * 2 * 2];
|
||||||
|
static short tx_buf[INCHUNK * 2 * 2];
|
||||||
|
|
||||||
|
/* Complex float to short conversion */
|
||||||
|
static void floatToShort(short *out, float *in, int num)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < num; i++) {
|
||||||
|
out[2 * i + 0] = (short) in[2 * i + 0];
|
||||||
|
out[2 * i + 1] = (short) in[2 * i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Complex short to float conversion */
|
||||||
|
static void shortToFloat(float *out, short *in, int num)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < num; i++) {
|
||||||
|
out[2 * i + 0] = (float) in[2 * i + 0];
|
||||||
|
out[2 * i + 1] = (float) in[2 * i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RadioInterface::RadioInterface(RadioDevice *wRadio,
|
RadioInterface::RadioInterface(RadioDevice *wRadio,
|
||||||
int wReceiveOffset,
|
int wReceiveOffset,
|
||||||
int wSPS,
|
int wSPS,
|
||||||
@@ -236,3 +258,41 @@ double RadioInterface::getRxGain()
|
|||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Receive a timestamped chunk from the device */
|
||||||
|
void RadioInterface::pullBuffer()
|
||||||
|
{
|
||||||
|
bool local_underrun;
|
||||||
|
|
||||||
|
/* Read samples. Fail if we don't get what we want. */
|
||||||
|
int num_rd = mRadio->readSamples(rx_buf, OUTCHUNK, &overrun,
|
||||||
|
readTimestamp, &local_underrun);
|
||||||
|
|
||||||
|
LOG(DEBUG) << "Rx read " << num_rd << " samples from device";
|
||||||
|
assert(num_rd == OUTCHUNK);
|
||||||
|
|
||||||
|
underrun |= local_underrun;
|
||||||
|
readTimestamp += (TIMESTAMP) num_rd;
|
||||||
|
|
||||||
|
shortToFloat(rcvBuffer + 2 * rcvCursor, rx_buf, num_rd);
|
||||||
|
rcvCursor += num_rd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send timestamped chunk to the device with arbitrary size */
|
||||||
|
void RadioInterface::pushBuffer()
|
||||||
|
{
|
||||||
|
if (sendCursor < INCHUNK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
floatToShort(tx_buf, sendBuffer, sendCursor);
|
||||||
|
|
||||||
|
/* Write samples. Fail if we don't get what we want. */
|
||||||
|
int num_smpls = mRadio->writeSamples(tx_buf,
|
||||||
|
sendCursor,
|
||||||
|
&underrun,
|
||||||
|
writeTimestamp);
|
||||||
|
assert(num_smpls == sendCursor);
|
||||||
|
|
||||||
|
writeTimestamp += (TIMESTAMP) num_smpls;
|
||||||
|
sendCursor = 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ static const unsigned gSlotLen = 148; ///< number of symbols per slot, not
|
|||||||
/** class to interface the transceiver with the USRP */
|
/** class to interface the transceiver with the USRP */
|
||||||
class RadioInterface {
|
class RadioInterface {
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
|
|
||||||
Thread mAlignRadioServiceLoopThread; ///< thread that synchronizes transmit and receive sections
|
Thread mAlignRadioServiceLoopThread; ///< thread that synchronizes transmit and receive sections
|
||||||
|
|
||||||
@@ -63,6 +63,8 @@ private:
|
|||||||
int mNumARFCNs;
|
int mNumARFCNs;
|
||||||
signalVector *finalVec, *finalVec9;
|
signalVector *finalVec, *finalVec9;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
/** format samples to USRP */
|
/** format samples to USRP */
|
||||||
int radioifyVector(signalVector &wVector,
|
int radioifyVector(signalVector &wVector,
|
||||||
float *floatVector,
|
float *floatVector,
|
||||||
@@ -73,10 +75,10 @@ private:
|
|||||||
int unRadioifyVector(float *floatVector, signalVector &wVector);
|
int unRadioifyVector(float *floatVector, signalVector &wVector);
|
||||||
|
|
||||||
/** push GSM bursts into the transmit buffer */
|
/** push GSM bursts into the transmit buffer */
|
||||||
void pushBuffer(void);
|
virtual void pushBuffer(void);
|
||||||
|
|
||||||
/** pull GSM bursts from the receive buffer */
|
/** pull GSM bursts from the receive buffer */
|
||||||
void pullBuffer(void);
|
virtual void pullBuffer(void);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -154,3 +156,18 @@ protected:
|
|||||||
/** synchronization thread loop */
|
/** synchronization thread loop */
|
||||||
void *AlignRadioServiceLoopAdapter(RadioInterface*);
|
void *AlignRadioServiceLoopAdapter(RadioInterface*);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class RadioInterfaceResamp : public RadioInterface {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void pushBuffer();
|
||||||
|
void pullBuffer();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
RadioInterfaceResamp(RadioDevice* wRadio = NULL,
|
||||||
|
int receiveOffset = 3,
|
||||||
|
int wSPS = SAMPSPERSYM,
|
||||||
|
GSM::Time wStartTime = GSM::Time(0));
|
||||||
|
};
|
||||||
|
|||||||
@@ -271,8 +271,16 @@ int tx_resmpl_flt_int(short *smpls_out, float *smpls_in, int num_smpls)
|
|||||||
return num_resmpl;
|
return num_resmpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RadioInterfaceResamp::RadioInterfaceResamp(RadioDevice *wRadio,
|
||||||
|
int wReceiveOffset,
|
||||||
|
int wSPS,
|
||||||
|
GSM::Time wStartTime)
|
||||||
|
: RadioInterface(wRadio, wReceiveOffset, wSPS, wStartTime)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/* Receive a timestamped chunk from the device */
|
/* Receive a timestamped chunk from the device */
|
||||||
void RadioInterface::pullBuffer()
|
void RadioInterfaceResamp::pullBuffer()
|
||||||
{
|
{
|
||||||
int num_cv, num_rd;
|
int num_cv, num_rd;
|
||||||
bool local_underrun;
|
bool local_underrun;
|
||||||
@@ -297,7 +305,7 @@ void RadioInterface::pullBuffer()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Send a timestamped chunk to the device */
|
/* Send a timestamped chunk to the device */
|
||||||
void RadioInterface::pushBuffer()
|
void RadioInterfaceResamp::pushBuffer()
|
||||||
{
|
{
|
||||||
int num_cv, num_wr;
|
int num_cv, num_wr;
|
||||||
|
|
||||||
@@ -36,12 +36,6 @@
|
|||||||
#include <Logger.h>
|
#include <Logger.h>
|
||||||
#include <Configuration.h>
|
#include <Configuration.h>
|
||||||
|
|
||||||
#ifdef RESAMPLE
|
|
||||||
#define DEVICERATE 400e3
|
|
||||||
#else
|
|
||||||
#define DEVICERATE 1625e3/6
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
ConfigurationTable gConfig("/etc/OpenBTS/OpenBTS.db");
|
ConfigurationTable gConfig("/etc/OpenBTS/OpenBTS.db");
|
||||||
@@ -88,13 +82,26 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
srandom(time(NULL));
|
srandom(time(NULL));
|
||||||
|
|
||||||
RadioDevice *usrp = RadioDevice::make(DEVICERATE * SAMPSPERSYM, SAMPSPERSYM);
|
RadioDevice *usrp = RadioDevice::make(SAMPSPERSYM);
|
||||||
if (!usrp->open(deviceArgs)) {
|
int radioType = usrp->open(deviceArgs);
|
||||||
|
if (radioType < 0) {
|
||||||
LOG(ALERT) << "Transceiver exiting..." << std::endl;
|
LOG(ALERT) << "Transceiver exiting..." << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
RadioInterface* radio = new RadioInterface(usrp,3,SAMPSPERSYM,false);
|
RadioInterface* radio;
|
||||||
|
switch (radioType) {
|
||||||
|
case RadioDevice::NORMAL:
|
||||||
|
radio = new RadioInterface(usrp, 3, SAMPSPERSYM, false);
|
||||||
|
break;
|
||||||
|
case RadioDevice::RESAMP:
|
||||||
|
radio = new RadioInterfaceResamp(usrp, 3, SAMPSPERSYM, false);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG(ALERT) << "Unsupported configuration";
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
Transceiver *trx = new Transceiver(gConfig.getNum("TRX.Port"),gConfig.getStr("TRX.IP").c_str(),SAMPSPERSYM,GSM::Time(3,0),radio);
|
Transceiver *trx = new Transceiver(gConfig.getNum("TRX.Port"),gConfig.getStr("TRX.IP").c_str(),SAMPSPERSYM,GSM::Time(3,0),radio);
|
||||||
trx->receiveFIFO(radio->receiveFIFO());
|
trx->receiveFIFO(radio->receiveFIFO());
|
||||||
/*
|
/*
|
||||||
|
|||||||
10
configure.ac
10
configure.ac
@@ -72,11 +72,6 @@ AC_ARG_WITH(singledb, [
|
|||||||
[enable single daughterboard use on USRP1])
|
[enable single daughterboard use on USRP1])
|
||||||
])
|
])
|
||||||
|
|
||||||
AC_ARG_WITH(resamp, [
|
|
||||||
AS_HELP_STRING([--with-resamp],
|
|
||||||
[enable resampling for non-52MHz devices])
|
|
||||||
])
|
|
||||||
|
|
||||||
AC_ARG_WITH(extref, [
|
AC_ARG_WITH(extref, [
|
||||||
AS_HELP_STRING([--with-extref],
|
AS_HELP_STRING([--with-extref],
|
||||||
[enable external reference on UHD devices])
|
[enable external reference on UHD devices])
|
||||||
@@ -102,10 +97,6 @@ AS_IF([test "x$with_uhd" = "xyes"],[
|
|||||||
AC_DEFINE(USE_UHD, 1, Define to 1 if using UHD)
|
AC_DEFINE(USE_UHD, 1, Define to 1 if using UHD)
|
||||||
])
|
])
|
||||||
|
|
||||||
AS_IF([test "x$with_resamp" = "xyes"], [
|
|
||||||
AC_DEFINE(RESAMPLE, 1, Define to 1 for resampling)
|
|
||||||
])
|
|
||||||
|
|
||||||
AS_IF([test "x$with_extref" = "xyes"], [
|
AS_IF([test "x$with_extref" = "xyes"], [
|
||||||
AC_DEFINE(EXTREF, 1, Define to 1 for external reference)
|
AC_DEFINE(EXTREF, 1, Define to 1 for external reference)
|
||||||
])
|
])
|
||||||
@@ -114,7 +105,6 @@ AS_IF([test "x$with_singledb" = "xyes"], [
|
|||||||
AC_DEFINE(SINGLEDB, 1, Define to 1 for single daughterboard)
|
AC_DEFINE(SINGLEDB, 1, Define to 1 for single daughterboard)
|
||||||
])
|
])
|
||||||
|
|
||||||
AM_CONDITIONAL(RESAMPLE, [test "x$with_resamp" = "xyes"])
|
|
||||||
AM_CONDITIONAL(UHD, [test "x$with_uhd" = "xyes"])
|
AM_CONDITIONAL(UHD, [test "x$with_uhd" = "xyes"])
|
||||||
AM_CONDITIONAL(USRP1, [test "x$with_usrp1" = "xyes"])
|
AM_CONDITIONAL(USRP1, [test "x$with_usrp1" = "xyes"])
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user