aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Tsou <tom.tsou@ettus.com>2016-06-24 14:25:39 -0700
committerTom Tsou <tom.tsou@ettus.com>2016-07-01 03:14:15 -0700
commit76764278169d252980853251daeb9f1ba0c246e1 (patch)
tree0d1631e938ae48d72d0b2b5d5e102116ab2d5b9d
parent35222296fef378977a83a4ee89d8c3ef9bc62a3f (diff)
mcbts: Add multi-ARFCN radio support
Add new radio interface "radioInterfaceMulti" for multi-carrier support. Only USRP B200/B210 devices are supported because of sample rate requirements (3.2 Msps). Only 4 SPS operation Tx/RX is supported. 8-PSK is supported. Other options may be added at a later time Signed-off-by: Tom Tsou <tom.tsou@ettus.com>
-rw-r--r--Transceiver52M/Makefile.am1
-rw-r--r--Transceiver52M/UHDDevice.cpp54
-rw-r--r--Transceiver52M/osmo-trx.cpp45
-rw-r--r--Transceiver52M/radioDevice.h2
-rw-r--r--Transceiver52M/radioInterface.h32
-rw-r--r--Transceiver52M/radioInterfaceMulti.cpp387
-rw-r--r--Transceiver52M/sigProcLib.cpp16
7 files changed, 512 insertions, 25 deletions
diff --git a/Transceiver52M/Makefile.am b/Transceiver52M/Makefile.am
index 52ec995..667217f 100644
--- a/Transceiver52M/Makefile.am
+++ b/Transceiver52M/Makefile.am
@@ -67,6 +67,7 @@ libtransceiver_la_SOURCES = \
$(COMMON_SOURCES) \
Resampler.cpp \
radioInterfaceResamp.cpp \
+ radioInterfaceMulti.cpp \
radioInterfaceDiversity.cpp
bin_PROGRAMS = osmo-trx
diff --git a/Transceiver52M/UHDDevice.cpp b/Transceiver52M/UHDDevice.cpp
index 5ffaa62..af9fc98 100644
--- a/Transceiver52M/UHDDevice.cpp
+++ b/Transceiver52M/UHDDevice.cpp
@@ -35,6 +35,7 @@
#endif
#define B2XX_CLK_RT 26e6
+#define B2XX_MCBTS_CLK_RT 3.2e6
#define E1XX_CLK_RT 52e6
#define B100_BASE_RT 400000
#define USRP2_BASE_RT 390625
@@ -61,6 +62,7 @@ enum uhd_dev_type {
B100,
B200,
B210,
+ B2XX_MCBTS,
E1XX,
E3XX,
X3XX,
@@ -110,6 +112,7 @@ static struct uhd_dev_offset uhd_offsets[] = {
{ B200, 4, 1, B2XX_TIMING_4SPS, "B200 4/1 Tx/Rx SPS" },
{ B210, 1, 1, B2XX_TIMING_1SPS, "B210 1 SPS" },
{ B210, 4, 1, B2XX_TIMING_4SPS, "B210 4/1 Tx/Rx SPS" },
+ { B2XX_MCBTS, 4, 4, 1.07188e-4, "B200/B210 4 SPS Multi-ARFCN" },
{ E1XX, 1, 1, 9.5192e-5, "E1XX 1 SPS" },
{ E1XX, 4, 1, 6.5571e-5, "E1XX 4/1 Tx/Rx SPS" },
{ E3XX, 1, 1, 1.84616e-4, "E3XX 1 SPS" },
@@ -150,9 +153,20 @@ static double select_rate(uhd_dev_type type, int sps,
return -9999.99;
}
+
if ((sps != 4) && (sps != 1))
return -9999.99;
+ if (iface == RadioDevice::MULTI_ARFCN) {
+ switch (type) {
+ case B2XX_MCBTS:
+ return 4 * MCBTS_SPACING;
+ default:
+ LOG(ALERT) << "Invalid device combination";
+ return -9999.99;
+ }
+ }
+
switch (type) {
case USRP2:
case X3XX:
@@ -542,12 +556,15 @@ int uhd_device::set_rates(double tx_rate, double rx_rate)
if ((dev_type == B200) || (dev_type == B210) || (dev_type == E3XX)) {
if (set_master_clk(B2XX_CLK_RT) < 0)
return -1;
- }
- else if (dev_type == E1XX) {
+ } else if (dev_type == E1XX) {
if (set_master_clk(E1XX_CLK_RT) < 0)
return -1;
+ } else if (dev_type == B2XX_MCBTS) {
+ if (set_master_clk(B2XX_MCBTS_CLK_RT) < 0)
+ return -1;
}
+
// Set sample rates
try {
usrp_dev->set_tx_rate(tx_rate);
@@ -574,6 +591,9 @@ int uhd_device::set_rates(double tx_rate, double rx_rate)
double uhd_device::setTxGain(double db, size_t chan)
{
+ if (iface == MULTI_ARFCN)
+ chan = 0;
+
if (chan >= tx_gains.size()) {
LOG(ALERT) << "Requested non-existent channel" << chan;
return 0.0f;
@@ -620,6 +640,9 @@ double uhd_device::setRxGain(double db, size_t chan)
double uhd_device::getRxGain(size_t chan)
{
+ if (iface == MULTI_ARFCN)
+ chan = 0;
+
if (chan >= rx_gains.size()) {
LOG(ALERT) << "Requested non-existent channel " << chan;
return 0.0f;
@@ -762,11 +785,24 @@ int uhd_device::open(const std::string &args, bool extref, bool swap_channels)
}
// Verify and set channels
- if ((dev_type == B210) && (chans == 2)) {
- } else if ((dev_type == UMTRX) && (chans == 2)) {
- uhd::usrp::subdev_spec_t subdev_spec(swap_channels?"B:0 A:0":"A:0 B:0");
- usrp_dev->set_tx_subdev_spec(subdev_spec);
- usrp_dev->set_rx_subdev_spec(subdev_spec);
+ if (iface == MULTI_ARFCN) {
+ if ((dev_type != B200) && (dev_type != B210)) {
+ LOG(ALERT) << "Unsupported device configuration";
+ return -1;
+ }
+
+ dev_type = B2XX_MCBTS;
+ chans = 1;
+ } else if (chans == 2) {
+ if (dev_type == B210) {
+ } else if (dev_type == UMTRX) {
+ uhd::usrp::subdev_spec_t subdev_spec(swap_channels?"B:0 A:0":"A:0 B:0");
+ usrp_dev->set_tx_subdev_spec(subdev_spec);
+ usrp_dev->set_rx_subdev_spec(subdev_spec);
+ } else {
+ LOG(ALERT) << "Invalid device configuration";
+ return -1;
+ }
} else if (chans != 1) {
LOG(ALERT) << "Invalid channel combination for device";
return -1;
@@ -839,6 +875,8 @@ int uhd_device::open(const std::string &args, bool extref, bool swap_channels)
if (iface == DIVERSITY)
return DIVERSITY;
+ if (iface == MULTI_ARFCN)
+ return MULTI_ARFCN;
switch (dev_type) {
case B100:
@@ -1295,7 +1333,7 @@ double uhd_device::getRxFreq(size_t chan)
*/
TIMESTAMP uhd_device::initialWriteTimestamp()
{
- if (rx_sps == tx_sps)
+ if ((iface == MULTI_ARFCN) || (rx_sps == tx_sps))
return ts_initial;
else
return ts_initial * tx_sps;
diff --git a/Transceiver52M/osmo-trx.cpp b/Transceiver52M/osmo-trx.cpp
index 9dcda5f..ac9cc48 100644
--- a/Transceiver52M/osmo-trx.cpp
+++ b/Transceiver52M/osmo-trx.cpp
@@ -74,6 +74,7 @@ struct trx_config {
bool extref;
Transceiver::FillerType filler;
bool diversity;
+ bool mcbts;
double offset;
double rssi_offset;
bool swap_channels;
@@ -127,7 +128,7 @@ bool testConfig()
*/
bool trx_setup_config(struct trx_config *config)
{
- std::string refstr, fillstr, divstr, edgestr;
+ std::string refstr, fillstr, divstr, mcstr, edgestr;
if (!testConfig())
return false;
@@ -163,13 +164,29 @@ bool trx_setup_config(struct trx_config *config)
config->diversity = DEFAULT_DIVERSITY;
}
- /* Diversity only supported on 2 channels */
- if (config->diversity)
+ if (!config->chans)
+ config->chans = DEFAULT_CHANS;
+
+ if (config->mcbts && ((config->chans < 0) || (config->chans > 5))) {
+ std::cout << "Unsupported number of channels" << std::endl;
+ return false;
+ }
+
+ /* Diversity only supported on 2 channels without multi-carrier */
+ if (config->diversity && config->mcbts) {
+ std::cout << "Multi-carrier diversity unsupported" << std::endl;
+ return false;
+ }
+ if (config->diversity && (config->chans != 2)) {
+ std::cout << "Setting channels to 2 for diversity" << std::endl;
config->chans = 2;
+ }
edgestr = config->edge ? "Enabled" : "Disabled";
refstr = config->extref ? "Enabled" : "Disabled";
divstr = config->diversity ? "Enabled" : "Disabled";
+ mcstr = config->mcbts ? "Enabled" : "Disabled";
+
switch (config->filler) {
case Transceiver::FILLER_DUMMY:
fillstr = "Dummy bursts";
@@ -200,6 +217,7 @@ bool trx_setup_config(struct trx_config *config)
ost << " EDGE support............ " << edgestr << std::endl;
ost << " External Reference...... " << refstr << std::endl;
ost << " C0 Filler Table......... " << fillstr << std::endl;
+ ost << " Multi-Carrier........... " << mcstr << std::endl;
ost << " Diversity............... " << divstr << std::endl;
ost << " Tuning offset........... " << config->offset << std::endl;
ost << " RSSI to dBm offset...... " << config->rssi_offset << std::endl;
@@ -235,6 +253,10 @@ RadioInterface *makeRadioInterface(struct trx_config *config,
radio = new RadioInterfaceDiversity(usrp, config->tx_sps,
config->chans);
break;
+ case RadioDevice::MULTI_ARFCN:
+ radio = new RadioInterfaceMulti(usrp, config->tx_sps,
+ config->rx_sps, config->chans);
+ break;
default:
LOG(ALERT) << "Unsupported radio interface configuration";
return NULL;
@@ -309,6 +331,7 @@ static void print_help()
" -p Base port number\n"
" -e Enable EDGE receiver\n"
" -d Enable dual channel diversity receiver\n"
+ " -m Enable multi-ARFCN transceiver (default=disabled)\n"
" -x Enable external 10 MHz reference\n"
" -s Tx samples-per-symbol (1 or 4)\n"
" -b Rx samples-per-symbol (1 or 4)\n"
@@ -334,13 +357,14 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
config->rach_delay = 0;
config->extref = false;
config->filler = Transceiver::FILLER_ZERO;
+ config->mcbts = false;
config->diversity = false;
config->offset = 0.0;
config->rssi_offset = 0.0;
config->swap_channels = false;
config->edge = false;
- while ((option = getopt(argc, argv, "ha:l:i:p:c:dxfo:s:b:r:A:R:Se")) != -1) {
+ while ((option = getopt(argc, argv, "ha:l:i:p:c:dmxfo:s:b:r:A:R:Se")) != -1) {
switch (option) {
case 'h':
print_help();
@@ -361,6 +385,9 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
case 'c':
config->chans = atoi(optarg);
break;
+ case 'm':
+ config->mcbts = true;
+ break;
case 'd':
config->diversity = true;
break;
@@ -403,8 +430,8 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
}
}
- /* Force 4 SPS for EDGE configurations */
- if (config->edge) {
+ /* Force 4 SPS for EDGE or multi-ARFCN configurations */
+ if ((config->edge) || (config->mcbts)) {
config->tx_sps = 4;
config->rx_sps = 4;
}
@@ -412,7 +439,8 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
if (config->edge && (config->filler == Transceiver::FILLER_NORM_RAND))
config->filler = Transceiver::FILLER_EDGE_RAND;
- if ((config->tx_sps != 1) && (config->tx_sps != 4)) {
+ if ((config->tx_sps != 1) && (config->tx_sps != 4) &&
+ (config->rx_sps != 1) && (config->rx_sps != 4)) {
printf("Unsupported samples-per-symbol %i\n\n", config->tx_sps);
print_help();
exit(0);
@@ -455,6 +483,9 @@ int main(int argc, char *argv[])
srandom(time(NULL));
/* Create the low level device object */
+ if (config.mcbts)
+ iface = RadioDevice::MULTI_ARFCN;
+
usrp = RadioDevice::make(config.tx_sps, config.rx_sps, iface,
config.chans, config.offset);
type = usrp->open(config.dev_args, config.extref, config.swap_channels);
diff --git a/Transceiver52M/radioDevice.h b/Transceiver52M/radioDevice.h
index a992483..142fcf6 100644
--- a/Transceiver52M/radioDevice.h
+++ b/Transceiver52M/radioDevice.h
@@ -23,6 +23,7 @@
#endif
#define GSMRATE (1625e3/6)
+#define MCBTS_SPACING 800000.0
/** a 64-bit virtual timestamp for radio data */
typedef unsigned long long TIMESTAMP;
@@ -39,6 +40,7 @@ class RadioDevice {
NORMAL,
RESAMP_64M,
RESAMP_100M,
+ MULTI_ARFCN,
DIVERSITY,
};
diff --git a/Transceiver52M/radioInterface.h b/Transceiver52M/radioInterface.h
index 1f225a2..b63cc4c 100644
--- a/Transceiver52M/radioInterface.h
+++ b/Transceiver52M/radioInterface.h
@@ -22,6 +22,8 @@
#include "radioClock.h"
#include "radioBuffer.h"
#include "Resampler.h"
+#include "Channelizer.h"
+#include "Synthesis.h"
static const unsigned gSlotLen = 148; ///< number of symbols per slot, not counting guard periods
@@ -101,7 +103,7 @@ public:
RadioClock* getClock(void) { return &mClock;};
/** set transmit frequency */
- bool tuneTx(double freq, size_t chan = 0);
+ virtual bool tuneTx(double freq, size_t chan = 0);
/** set receive frequency */
virtual bool tuneRx(double freq, size_t chan = 0);
@@ -164,6 +166,34 @@ public:
void close();
};
+class RadioInterfaceMulti : public RadioInterface {
+private:
+ bool pushBuffer();
+ void pullBuffer();
+
+ signalVector *outerSendBuffer;
+ signalVector *outerRecvBuffer;
+ std::vector<signalVector *> history;
+ std::vector<bool> active;
+
+ Resampler *dnsampler;
+ Resampler *upsampler;
+ Channelizer *channelizer;
+ Synthesis *synthesis;
+
+public:
+ RadioInterfaceMulti(RadioDevice* radio, size_t tx_sps,
+ size_t rx_sps, size_t chans = 1);
+ ~RadioInterfaceMulti();
+
+ bool init(int type);
+ void close();
+
+ bool tuneTx(double freq, size_t chan);
+ bool tuneRx(double freq, size_t chan);
+ double setRxGain(double dB, size_t chan);
+};
+
class RadioInterfaceDiversity : public RadioInterface {
public:
RadioInterfaceDiversity(RadioDevice* wRadio,
diff --git a/Transceiver52M/radioInterfaceMulti.cpp b/Transceiver52M/radioInterfaceMulti.cpp
new file mode 100644
index 0000000..ba81fe1
--- /dev/null
+++ b/Transceiver52M/radioInterfaceMulti.cpp
@@ -0,0 +1,387 @@
+/*
+ * Multi-carrier radio interface
+ *
+ * Copyright (C) 2016 Ettus Research LLC
+ *
+ * Author: Tom Tsou <tom.tsou@ettus.com>
+ *
+ * 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>
+
+#include "Resampler.h"
+
+extern "C" {
+#include "convert.h"
+}
+
+/* Resampling parameters for 64 MHz clocking */
+#define RESAMP_INRATE 65
+#define RESAMP_OUTRATE (96 / 2)
+
+/* Universal resampling parameters */
+#define NUMCHUNKS 24
+
+#define MCHANS 4
+
+RadioInterfaceMulti::RadioInterfaceMulti(RadioDevice *radio, size_t tx_sps,
+ size_t rx_sps, size_t chans)
+ : RadioInterface(radio, tx_sps, rx_sps, chans),
+ outerSendBuffer(NULL), outerRecvBuffer(NULL),
+ dnsampler(NULL), upsampler(NULL), channelizer(NULL), synthesis(NULL)
+{
+}
+
+RadioInterfaceMulti::~RadioInterfaceMulti()
+{
+ close();
+}
+
+void RadioInterfaceMulti::close()
+{
+ delete outerSendBuffer;
+ delete outerRecvBuffer;
+ delete dnsampler;
+ delete upsampler;
+ delete channelizer;
+ delete synthesis;
+
+ outerSendBuffer = NULL;
+ outerRecvBuffer = NULL;
+ dnsampler = NULL;
+ upsampler = NULL;
+ channelizer = NULL;
+ synthesis = NULL;
+
+ mReceiveFIFO.resize(0);
+ powerScaling.resize(0);
+ history.resize(0);
+ active.resize(0);
+
+ RadioInterface::close();
+}
+
+static int getLogicalChan(size_t pchan, size_t chans)
+{
+ switch (chans) {
+ case 1:
+ if (pchan == 0)
+ return 0;
+ else
+ return -1;
+ break;
+ case 2:
+ if (pchan == 0)
+ return 0;
+ if (pchan == 3)
+ return 1;
+ else
+ return -1;
+ break;
+ case 3:
+ if (pchan == 1)
+ return 0;
+ if (pchan == 0)
+ return 1;
+ if (pchan == 3)
+ return 2;
+ else
+ return -1;
+ break;
+ default:
+ break;
+ };
+
+ return -1;
+}
+
+static int getFreqShift(size_t chans)
+{
+ switch (chans) {
+ case 1:
+ return 0;
+ case 2:
+ return 0;
+ case 3:
+ return 1;
+ default:
+ break;
+ };
+
+ return -1;
+}
+
+/* Initialize I/O specific objects */
+bool RadioInterfaceMulti::init(int type)
+{
+ float cutoff = 1.0f;
+ size_t inchunk = 0, outchunk = 0;
+
+ if (mChans > MCHANS - 1) {
+ LOG(ALERT) << "Invalid channel configuration " << mChans;
+ return false;
+ }
+
+ close();
+
+ sendBuffer.resize(mChans);
+ recvBuffer.resize(mChans);
+ convertSendBuffer.resize(1);
+ convertRecvBuffer.resize(1);
+
+ mReceiveFIFO.resize(mChans);
+ powerScaling.resize(mChans);
+ history.resize(mChans);
+ active.resize(MCHANS, false);
+
+ inchunk = RESAMP_INRATE * 4;
+ outchunk = RESAMP_OUTRATE * 4;
+
+ if (inchunk * NUMCHUNKS < 625 * 2) {
+ LOG(ALERT) << "Invalid inner chunk size " << inchunk;
+ return false;
+ }
+
+ dnsampler = new Resampler(RESAMP_INRATE, RESAMP_OUTRATE);
+ if (!dnsampler->init(1.0)) {
+ LOG(ALERT) << "Rx resampler failed to initialize";
+ return false;
+ }
+
+ upsampler = new Resampler(RESAMP_OUTRATE, RESAMP_INRATE);
+ if (!upsampler->init(cutoff)) {
+ LOG(ALERT) << "Tx resampler failed to initialize";
+ return false;
+ }
+
+ channelizer = new Channelizer(MCHANS, outchunk);
+ if (!channelizer->init()) {
+ LOG(ALERT) << "Rx channelizer failed to initialize";
+ return false;
+ }
+
+ synthesis = new Synthesis(MCHANS, outchunk);
+ if (!synthesis->init()) {
+ LOG(ALERT) << "Tx synthesis filter failed to initialize";
+ return false;
+ }
+
+ /*
+ * Allocate high and low rate buffers. The high rate receive
+ * buffer and low rate transmit vectors feed into the resampler
+ * and requires headroom equivalent to the filter length. Low
+ * rate buffers are allocated in the main radio interface code.
+ */
+ for (size_t i = 0; i < mChans; i++) {
+ sendBuffer[i] = new RadioBuffer(NUMCHUNKS, inchunk,
+ upsampler->len(), true);
+ recvBuffer[i] = new RadioBuffer(NUMCHUNKS, inchunk,
+ 0, false);
+ history[i] = new signalVector(dnsampler->len());
+
+ synthesis->resetBuffer(i);
+ }
+
+ outerSendBuffer = new signalVector(synthesis->outputLen());
+ outerRecvBuffer = new signalVector(channelizer->inputLen());
+
+ convertSendBuffer[0] = new short[2 * synthesis->outputLen()];
+ convertRecvBuffer[0] = new short[2 * channelizer->inputLen()];
+
+ /* Configure channels */
+ switch (mChans) {
+ case 1:
+ active[0] = true;
+ break;
+ case 2:
+ active[0] = true;
+ active[3] = true;
+ break;
+ case 3:
+ active[0] = true;
+ active[1] = true;
+ active[3] = true;
+ break;
+ default:
+ LOG(ALERT) << "Unsupported channel combination";
+ return false;
+ }
+
+ return true;
+}
+
+/* Receive a timestamped chunk from the device */
+void RadioInterfaceMulti::pullBuffer()
+{
+ bool local_underrun;
+ size_t num;
+ float *buf;
+
+ if (recvBuffer[0]->getFreeSegments() <= 0)
+ return;
+
+ /* Outer buffer access size is fixed */
+ num = mRadio->readSamples(convertRecvBuffer,
+ outerRecvBuffer->size(),
+ &overrun,
+ readTimestamp,
+ &local_underrun);
+ if (num != channelizer->inputLen()) {
+ LOG(ALERT) << "Receive error " << num << ", " << channelizer->inputLen();
+ return;
+ }
+
+ convert_short_float((float *) outerRecvBuffer->begin(),
+ convertRecvBuffer[0], 2 * outerRecvBuffer->size());
+
+ underrun |= local_underrun;
+ readTimestamp += num;
+
+ channelizer->rotate((float *) outerRecvBuffer->begin(),
+ outerRecvBuffer->size());
+
+ for (size_t pchan = 0; pchan < MCHANS; pchan++) {
+ if (!active[pchan])
+ continue;
+
+ int lchan = getLogicalChan(pchan, mChans);
+ if (lchan < 0) {
+ LOG(ALERT) << "Invalid logical channel " << pchan;
+ continue;
+ }
+
+ /*
+ * Update history by writing into the head portion of the
+ * channelizer output buffer. For this to work, filter length of
+ * the polyphase channelizer partition filter should be equal to
+ * or larger than the resampling filter.
+ */
+ buf = channelizer->outputBuffer(pchan);
+ size_t cLen = channelizer->outputLen();
+ size_t hLen = dnsampler->len();
+ size_t hSize = 2 * hLen * sizeof(float);
+
+ memcpy(&buf[2 * -hLen], history[lchan]->begin(), hSize);
+ memcpy(history[lchan]->begin(), &buf[2 * (cLen - hLen)], hSize);
+
+ float *wr_segment = recvBuffer[lchan]->getWriteSegment();
+
+ /* Write to the end of the inner receive buffer */
+ if (!dnsampler->rotate(channelizer->outputBuffer(pchan),
+ channelizer->outputLen(),
+ wr_segment,
+ recvBuffer[lchan]->getSegmentLen())) {
+ LOG(ALERT) << "Sample rate upsampling error";
+ }
+ }
+}
+
+/* Send a timestamped chunk to the device */
+bool RadioInterfaceMulti::pushBuffer()
+{
+ if (sendBuffer[0]->getAvailSegments() <= 0)
+ return false;
+
+ for (size_t pchan = 0; pchan < MCHANS; pchan++) {
+ if (!active[pchan]) {
+ synthesis->resetBuffer(pchan);
+ continue;
+ }
+
+ int lchan = getLogicalChan(pchan, mChans);
+ if (lchan < 0) {
+ LOG(ALERT) << "Invalid logical channel " << pchan;
+ continue;
+ }
+
+ if (!upsampler->rotate(sendBuffer[lchan]->getReadSegment(),
+ sendBuffer[lchan]->getSegmentLen(),
+ synthesis->inputBuffer(pchan),
+ synthesis->inputLen())) {
+ LOG(ALERT) << "Sample rate downsampling error";
+ }
+ }
+
+ synthesis->rotate((float *) outerSendBuffer->begin(),
+ outerSendBuffer->size());
+
+ convert_float_short(convertSendBuffer[0],
+ (float *) outerSendBuffer->begin(),
+ 1.0 / (float) mChans, 2 * outerSendBuffer->size());
+
+ size_t num = mRadio->writeSamples(convertSendBuffer,
+ outerSendBuffer->size(),
+ &underrun,
+ writeTimestamp);
+ if (num != outerSendBuffer->size()) {
+ LOG(ALERT) << "Transmit error " << num;
+ }
+
+ writeTimestamp += num;
+
+ return true;
+}
+
+/* Frequency comparison limit */
+#define FREQ_DELTA_LIMIT 10.0
+
+static bool fltcmp(double a, double b)
+{
+ return fabs(a - b) < FREQ_DELTA_LIMIT ? true : false;
+}
+
+bool RadioInterfaceMulti::tuneTx(double freq, size_t chan)
+{
+ if (chan >= mChans)
+ return false;
+
+ double shift = (double) getFreqShift(mChans);
+
+ if (!chan)
+ return mRadio->setTxFreq(freq + shift * MCBTS_SPACING);
+
+ double center = mRadio->getTxFreq();
+ if (!fltcmp(freq, center + (double) (chan - shift) * MCBTS_SPACING))
+ return false;
+
+ return true;
+}
+
+bool RadioInterfaceMulti::tuneRx(double freq, size_t chan)
+{
+ if (chan >= mChans)
+ return false;
+
+ double shift = (double) getFreqShift(mChans);
+
+ if (!chan)
+ return mRadio->setRxFreq(freq + shift * MCBTS_SPACING);
+
+ double center = mRadio->getRxFreq();
+ if (!fltcmp(freq, center + (double) (chan - shift) * MCBTS_SPACING))
+ return false;
+
+ return true;
+}
+
+double RadioInterfaceMulti::setRxGain(double db, size_t chan)
+{
+ if (!chan)
+ return mRadio->setRxGain(db);
+ else
+ return mRadio->getRxGain();
+}
diff --git a/Transceiver52M/sigProcLib.cpp b/Transceiver52M/sigProcLib.cpp
index 7a032b3..6495b1e 100644
--- a/Transceiver52M/sigProcLib.cpp
+++ b/Transceiver52M/sigProcLib.cpp
@@ -80,7 +80,6 @@ static Complex<float> psk8_table[8] = {
#define DOWNSAMPLE_OUT_LEN 156
static Resampler *dnsampler = NULL;
-static signalVector *dnsampler_in = NULL;
/*
* RACH and midamble correlation waveforms. Store the buffer separately
@@ -163,7 +162,6 @@ void sigProcLibDestroy()
delete GSMPulse1;
delete GSMPulse4;
delete dnsampler;
- delete dnsampler_in;
GMSKRotation1 = NULL;
GMSKRotation4 = NULL;
@@ -1936,13 +1934,15 @@ int detectEdgeBurst(signalVector &rxBurst, unsigned tsc, float thresh,
signalVector *downsampleBurst(signalVector &burst)
{
- size_t ilen = DOWNSAMPLE_IN_LEN, olen = DOWNSAMPLE_OUT_LEN;
+ signalVector *in, *out;
- signalVector *out = new signalVector(olen);
- memcpy(dnsampler_in->begin(), burst.begin(), ilen * 2 * sizeof(float));
+ in = new signalVector(DOWNSAMPLE_IN_LEN, dnsampler->len());
+ out = new signalVector(DOWNSAMPLE_OUT_LEN);
+ memcpy(in->begin(), burst.begin(), DOWNSAMPLE_IN_LEN * 2 * sizeof(float));
- dnsampler->rotate((float *) dnsampler_in->begin(), ilen,
- (float *) out->begin(), olen);
+ dnsampler->rotate((float *) in->begin(), DOWNSAMPLE_IN_LEN,
+ (float *) out->begin(), DOWNSAMPLE_OUT_LEN);
+ delete in;
return out;
};
@@ -2128,8 +2128,6 @@ bool sigProcLibSetup()
goto fail;
}
- dnsampler_in = new signalVector(DOWNSAMPLE_IN_LEN, dnsampler->len());
-
return true;
fail: