aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Tsou <ttsou@vt.edu>2012-06-05 20:31:28 -0400
committerAlexander Chemeris <Alexander.Chemeris@gmail.com>2013-06-24 01:51:02 +0400
commit41c6657938e930a1c20070d5a8952e6dea12ec32 (patch)
tree37245a030b3e44e1e3d25086af9fa29b94f6054e
parentcd576c9636244938a42d8c69da012e45e9fdd4f5 (diff)
multi-arfcn: refactor to match upstream GSM core
This patch aligns the multicarrier (MC) USRP code with released GSM core changes that accommodate the MC RAD1. Primary changes are: 1. Runtime setting of number of channelizer paths 2. Matching channelizer path to ARFCN mapping of GSM core 3. Use a single clock update socket on the drive loop 4. Match transceiver data and control socket ports Setting of channelizer paths (or width) was previously fixed at compile time. In either case, channelizer width is limited by the sample rate of the device and channel spacing of the maximally decimated filterbank. Available settings are 1, 5, and 10 channels, which accommodate any number of ARFCN's in between. Also add the frequency offsets to handle the effective shift in setting RF frequency. Previous assumption was to place C0 at the center frequency, but RAD1 assumes C0 at the leftmost carrier, so adjust accordingly. The rest is general consolidation to mostly match the RAD1 interaction with GSM core. There is some loss of flexibility to run, say, multiple independent instances of OpenBTS through a single bank of channelized transceivers. But, the better compatibility and reduction in code is the appropriate tradeoff. Signed-off-by: Thomas Tsou <ttsou@vt.edu>
-rw-r--r--Transceiver52M/DriveLoop.cpp56
-rw-r--r--Transceiver52M/DriveLoop.h33
-rw-r--r--Transceiver52M/Transceiver.cpp120
-rw-r--r--Transceiver52M/Transceiver.h15
-rw-r--r--Transceiver52M/multiTRX.cpp69
-rw-r--r--Transceiver52M/radioInterface.cpp21
-rw-r--r--Transceiver52M/radioInterface.h10
7 files changed, 174 insertions, 150 deletions
diff --git a/Transceiver52M/DriveLoop.cpp b/Transceiver52M/DriveLoop.cpp
index c925d20..1f1ea7c 100644
--- a/Transceiver52M/DriveLoop.cpp
+++ b/Transceiver52M/DriveLoop.cpp
@@ -25,10 +25,13 @@
#include "DriveLoop.h"
#include <Logger.h>
-DriveLoop::DriveLoop(int wSamplesPerSymbol,
+DriveLoop::DriveLoop(int wBasePort, const char *TRXAddress,
+ int wChanM, int wC0, int wSamplesPerSymbol,
GSM::Time wTransmitLatency,
RadioInterface *wRadioInterface)
+ :mClockSocket(wBasePort, TRXAddress, wBasePort + 100), mC0(wC0)
{
+ mChanM = wChanM;
mRadioDriveLoopThread = NULL;
mSamplesPerSymbol = wSamplesPerSymbol;
mRadioInterface = wRadioInterface;
@@ -38,6 +41,7 @@ DriveLoop::DriveLoop(int wSamplesPerSymbol,
mTransmitDeadlineClock = mStartTime;
mLatencyUpdateTime = mStartTime;
mTransmitLatency = wTransmitLatency;
+ mLastClockUpdateTime = mStartTime;
mRadioInterface->getClock()->set(mStartTime);
@@ -48,18 +52,22 @@ DriveLoop::DriveLoop(int wSamplesPerSymbol,
txFullScale = mRadioInterface->fullScaleInputValue();
- // initialize filler tables with dummy bursts, initialize other per-timeslot variables
+ // initialize filler tables with dummy bursts on C0, empty bursts otherwise
for (int i = 0; i < 8; i++) {
signalVector* modBurst = modulateBurst(gDummyBurst, *gsmPulse,
8 + (i % 4 == 0), mSamplesPerSymbol);
scaleVector(*modBurst, txFullScale);
for (int j = 0; j < 102; j++) {
- for (int n = 0; n < CHAN_M; n++)
- fillerTable[n][j][i] = new signalVector(*modBurst);
+ for (int n = 0; n < mChanM; n++) {
+ if (n == mC0)
+ fillerTable[n][j][i] = new signalVector(*modBurst);
+ else
+ fillerTable[n][j][i] = new signalVector(modBurst->size());
+ }
}
delete modBurst;
- for (int n = 0; n < CHAN_M; n++) {
+ for (int n = 0; n < mChanM; n++) {
fillerModulus[n][i] = 26;
mChanType[n][i] = NONE;
}
@@ -97,17 +105,19 @@ void DriveLoop::pushRadioVector(GSM::Time &nowTime)
radioVector *staleBurst;
radioVector *next;
- for (i = 0; i < CHAN_M; i++) {
+ for (i = 0; i < mChanM; i++) {
// dump stale bursts, if any
while (staleBurst = mTransmitPriorityQueue[i].getStaleBurst(nowTime)) {
// Even if the burst is stale, put it in the fillter table.
// (It might be an idle pattern.)
LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
- const GSM::Time& nextTime = staleBurst->getTime();
- int TN = nextTime.TN();
- int modFN = nextTime.FN() % fillerModulus[i][TN];
- delete fillerTable[i][modFN][TN];
- fillerTable[i][modFN][TN] = staleBurst;
+ if (i == mC0) {
+ const GSM::Time& nextTime = staleBurst->getTime();
+ int TN = nextTime.TN();
+ int modFN = nextTime.FN() % fillerModulus[i][TN];
+ delete fillerTable[i][modFN][TN];
+ fillerTable[i][modFN][TN] = staleBurst;
+ }
}
int TN = nowTime.TN();
@@ -120,16 +130,18 @@ void DriveLoop::pushRadioVector(GSM::Time &nowTime)
// if queue contains data at the desired timestamp, stick it into FIFO
if (next = (radioVector*) mTransmitPriorityQueue[i].getCurrentBurst(nowTime)) {
LOG(DEBUG) << "transmitFIFO: wrote burst " << next << " at time: " << nowTime;
- delete fillerTable[i][modFN][TN];
- fillerTable[i][modFN][TN] = new signalVector(*(next));
+ if (i == mC0) {
+ delete fillerTable[i][modFN][TN];
+ fillerTable[i][modFN][TN] = new signalVector(*(next));
+ mIsFiller[i] = false;
+ }
mTxBursts[i] = next;
- mIsFiller[i] = false;
}
}
mRadioInterface->driveTransmitRadio(mTxBursts, mIsZero);
- for (i = 0; i < CHAN_M; i++) {
+ for (i = 0; i < mChanM; i++) {
if (!mIsFiller[i])
delete mTxBursts[i];
}
@@ -255,6 +267,20 @@ void DriveLoop::driveTransmitFIFO()
//else radioClock->wait();
}
+void DriveLoop::writeClockInterface()
+{
+ char command[50];
+ // FIXME -- This should be adaptive.
+ sprintf(command,"IND CLOCK %llu",
+ (unsigned long long) (mTransmitDeadlineClock.FN() + 2));
+
+ LOG(INFO) << "ClockInterface: sending " << command;
+
+ mClockSocket.write(command,strlen(command)+1);
+
+ mLastClockUpdateTime = mTransmitDeadlineClock;
+}
+
void *RadioDriveLoopAdapter(DriveLoop *drive)
{
drive->setPriority();
diff --git a/Transceiver52M/DriveLoop.h b/Transceiver52M/DriveLoop.h
index 593ef58..442d27c 100644
--- a/Transceiver52M/DriveLoop.h
+++ b/Transceiver52M/DriveLoop.h
@@ -50,10 +50,11 @@ private:
GSM::Time mTransmitLatency; ///< latency between basestation clock and transmit deadline clock
GSM::Time mLatencyUpdateTime; ///< last time latency was updated
+ GSM::Time mLastClockUpdateTime; ///< last time clock update was sent up to core
UDPSocket mClockSocket; ///< socket for writing clock updates to GSM core
- VectorQueue mTransmitPriorityQueue[CHAN_M]; ///< priority queue of transmit bursts received from GSM core
+ VectorQueue mTransmitPriorityQueue[CHAN_MAX]; ///< priority queue of transmit bursts received from GSM core
Thread *mRadioDriveLoopThread; ///< thread to push/pull bursts into transmit/receive FIFO
@@ -64,6 +65,8 @@ private:
double txFullScale; ///< full scale input to radio
double rxFullScale; ///< full scale output to radio
+ /** Number of channels supported by the channelizer */
+ int mChanM;
/** unmodulate a modulated burst */
#ifdef TRANSMIT_LOGGING
@@ -79,20 +82,20 @@ private:
/** Pull and demodulate a burst from the receive FIFO */
SoftVector *pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset);
- /** send messages over the clock socket */
- void writeClockInterface(void);
-
signalVector *gsmPulse; ///< the GSM shaping pulse for modulation
int mSamplesPerSymbol; ///< number of samples per GSM symbol
bool mOn; ///< flag to indicate that transceiver is powered on
- int fillerModulus[CHAN_M][8]; ///< modulus values of all timeslots, in frames
- signalVector *fillerTable[CHAN_M][102][8]; ///< table of modulated filler waveforms for all timeslots
+ int fillerModulus[CHAN_MAX][8]; ///< modulus values of all timeslots, in frames
+ signalVector *fillerTable[CHAN_MAX][102][8]; ///< table of modulated filler waveforms for all timeslots
+
+ /** Channelizer path for primary ARFCN */
+ int mC0;
- signalVector *mTxBursts[CHAN_M];
- bool mIsFiller[CHAN_M];
- bool mIsZero[CHAN_M];
+ signalVector *mTxBursts[CHAN_MAX];
+ bool mIsFiller[CHAN_MAX];
+ bool mIsZero[CHAN_MAX];
public:
@@ -103,7 +106,8 @@ public:
@param wTransmitLatency initial setting of transmit latency
@param radioInterface associated radioInterface object
*/
- DriveLoop(int wSamplesPerSymbol,
+ DriveLoop(int wBasePort, const char *TRXAddress,
+ int wChanM, int wC0, int wSamplesPerSymbol,
GSM::Time wTransmitLatency,
RadioInterface *wRadioInterface);
@@ -115,8 +119,6 @@ public:
VectorQueue *priorityQueue(int m) { return &mTransmitPriorityQueue[m]; }
- GSM::Time *deadlineClock() { return &mTransmitDeadlineClock; }
-
/** Codes for burst types of received bursts*/
typedef enum {
OFF, ///< timeslot is off
@@ -151,10 +153,15 @@ public:
}
GSM::Time getStartTime() { return mStartTime; }
+ GSM::Time getLastClockUpdate() { return mLastClockUpdateTime; }
+ GSM::Time getDeadlineClock() { return mTransmitDeadlineClock; }
+
+ /** send messages over the clock socket */
+ void writeClockInterface(void);
private:
- ChannelCombination mChanType[CHAN_M][8]; ///< channel types for all timeslots
+ ChannelCombination mChanType[CHAN_MAX][8]; ///< channel types for all timeslots
protected:
diff --git a/Transceiver52M/Transceiver.cpp b/Transceiver52M/Transceiver.cpp
index 81b0aad..b8d9d9d 100644
--- a/Transceiver52M/Transceiver.cpp
+++ b/Transceiver52M/Transceiver.cpp
@@ -53,12 +53,11 @@ Transceiver::Transceiver(int wBasePort,
int wSamplesPerSymbol,
RadioInterface *wRadioInterface,
DriveLoop *wDriveLoop,
- int wChannel)
+ int wChannel, bool wPrimary)
:mDataSocket(wBasePort+2,TRXAddress,wBasePort+102),
mControlSocket(wBasePort+1,TRXAddress,wBasePort+101),
- mClockSocket(wBasePort,TRXAddress,wBasePort+100),
mDriveLoop(wDriveLoop), mTransmitPriorityQueue(NULL),
- mChannel(wChannel), mTSC(-1)
+ mChannel(wChannel), mPrimary(wPrimary), mTSC(-1)
{
mFIFOServiceLoopThread = NULL;
mControlServiceLoopThread = NULL;
@@ -66,11 +65,8 @@ Transceiver::Transceiver(int wBasePort,
mSamplesPerSymbol = wSamplesPerSymbol;
mRadioInterface = wRadioInterface;
- mLastClockUpdateTime = mDriveLoop->getStartTime();
mMaxExpectedDelay = 0;
- mTransmitDeadlineClock = wDriveLoop->deadlineClock();
-
// generate pulse and setup up signal processing library
gsmPulse = generateGSMPulse(2,mSamplesPerSymbol);
LOG(DEBUG) << "gsmPulse: " << *gsmPulse;
@@ -93,11 +89,15 @@ Transceiver::Transceiver(int wBasePort,
mRunning = false;
mTxFreq = 0.0;
mRxFreq = 0.0;
+
+ if (mPrimary)
+ mFreqOffset = mChannel * CHAN_RATE;
+ else
+ mFreqOffset = 0.0;
+
mPower = -10;
mEnergyThreshold = INIT_ENERGY_THRSHD;
prevFalseDetectionTime = mDriveLoop->getStartTime();
-
- mRadioLocked = mRadioInterface->started();
}
Transceiver::~Transceiver()
@@ -172,6 +172,7 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
bool success = false;
if (corrType == DriveLoop::TSC) {
LOG(DEBUG) << "looking for TSC at time: " << rxBurst->getTime();
+
signalVector *channelResp;
double framesElapsed = rxBurst->getTime()-channelEstimateTime[timeslot];
bool estimateChannel = false;
@@ -314,6 +315,15 @@ void Transceiver::start()
mRunning = true;
mControlServiceLoopThread = new Thread(32768);
mControlServiceLoopThread->start((void * (*)(void*))ControlServiceLoopAdapter,(void*) this);
+
+ if (!mPrimary) {
+ mOn = true;
+ mFIFOServiceLoopThread = new Thread(32768);
+ mFIFOServiceLoopThread->start((void * (*)(void*))FIFOServiceLoopAdapter,(void*) this);
+
+ mTransmitPriorityQueueServiceLoopThread = new Thread(32768);
+ mTransmitPriorityQueueServiceLoopThread->start((void * (*)(void*))TransmitPriorityQueueServiceLoopAdapter,(void*) this);
+ }
}
void Transceiver::shutdown()
@@ -359,7 +369,7 @@ void Transceiver::driveControl()
sscanf(buffer,"%3s %s",cmdcheck,command);
- writeClockInterface();
+ mDriveLoop->writeClockInterface();
if (strcmp(cmdcheck,"CMD")!=0) {
LOG(WARNING) << "bogus message on control interface";
@@ -377,22 +387,22 @@ void Transceiver::driveControl()
sprintf(response,"RSP POWERON 1");
else {
sprintf(response,"RSP POWERON 0");
- if (!mOn) {
+ if (mPrimary && !mOn) {
// Prepare for thread start
mPower = -20;
- if (mRadioInterface->start())
- mDriveLoop->start();
+ mRadioInterface->start();
+ mDriveLoop->start();
+ mDriveLoop->writeClockInterface();
generateRACHSequence(*gsmPulse,mSamplesPerSymbol);
// Start radio interface threads.
mOn = true;
mFIFOServiceLoopThread = new Thread(32768);
- mTransmitPriorityQueueServiceLoopThread = new Thread(32768);
-
mFIFOServiceLoopThread->start((void * (*)(void*))FIFOServiceLoopAdapter,(void*) this);
+
+ mTransmitPriorityQueueServiceLoopThread = new Thread(32768);
mTransmitPriorityQueueServiceLoopThread->start((void * (*)(void*))TransmitPriorityQueueServiceLoopAdapter,(void*) this);
- writeClockInterface();
}
}
}
@@ -409,7 +419,7 @@ void Transceiver::driveControl()
sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
newGain = mRadioInterface->setRxGain(newGain);
mEnergyThreshold = INIT_ENERGY_THRSHD;
- if (!mRadioLocked)
+ if (mPrimary)
newGain = mRadioInterface->setRxGain(newGain);
sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
}
@@ -430,7 +440,7 @@ void Transceiver::driveControl()
sprintf(response,"RSP SETPOWER 1 %d",dbPwr);
else {
mPower = dbPwr;
- if (!mRadioLocked)
+ if (mPrimary)
mRadioInterface->setPowerAttenuation(dbPwr);
sprintf(response,"RSP SETPOWER 0 %d",dbPwr);
}
@@ -446,21 +456,14 @@ void Transceiver::driveControl()
sprintf(response,"RSP ADJPOWER 0 %d",mPower);
}
}
-#define FREQOFFSET 0//11.2e3
else if (strcmp(command,"RXTUNE")==0) {
// tune receiver
int freqKhz;
sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
- mRxFreq = freqKhz*1.0e3+FREQOFFSET;
- mRadioLocked = mRadioInterface->started();
-
- if (!mRadioLocked) {
- if (!mRadioInterface->tuneRx(mRxFreq)) {
- LOG(ALERT) << "RX failed to tune";
- sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
- } else {
- sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
- }
+ mRxFreq = freqKhz * 1.0e3 + mFreqOffset;
+ if (mPrimary && (!mRadioInterface->tuneRx(mRxFreq))) {
+ LOG(ALERT) << "RX failed to tune";
+ sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
} else {
sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
}
@@ -470,17 +473,12 @@ void Transceiver::driveControl()
int freqKhz;
sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
//freqKhz = 890e3;
- mTxFreq = freqKhz*1.0e3+FREQOFFSET;
- mRadioLocked = mRadioInterface->started();
- if (!mRadioLocked) {
- if (!mRadioInterface->tuneTx(mTxFreq)) {
- LOG(ALERT) << "TX failed to tune";
- sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
- } else {
- sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
- }
+ mTxFreq = freqKhz * 1.0e3 + mFreqOffset;
+ if (mPrimary && (!mRadioInterface->tuneTx(mTxFreq))) {
+ LOG(ALERT) << "TX failed to tune";
+ sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
} else {
- sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
+ sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
}
}
else if (strcmp(command,"SETTSC")==0) {
@@ -547,28 +545,12 @@ bool Transceiver::driveTransmitPriorityQueue()
for (int i = 0; i < 4; i++)
frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
- /*
- if (GSM::Time(frameNum,timeSlot) > mTransmitDeadlineClock + GSM::Time(51,0)) {
- // stale burst
- //LOG(DEBUG) << "FAST! "<< GSM::Time(frameNum,timeSlot);
- //writeClockInterface();
- }*/
-
-/*
- DAB -- Just let these go through the demod.
- if (GSM::Time(frameNum,timeSlot) < mTransmitDeadlineClock) {
- // stale burst from GSM core
- LOG(NOTICE) << "STALE packet on GSM->TRX interface at time "<< GSM::Time(frameNum,timeSlot);
- return false;
- }
-*/
-
// periodically update GSM core clock
- LOG(DEBUG) << "mTransmitDeadlineClock " << *mTransmitDeadlineClock
- << " mLastClockUpdateTime " << mLastClockUpdateTime;
- if (*mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
- writeClockInterface();
-
+ LOG(DEBUG) << "mTransmitDeadlineClock " << mDriveLoop->getDeadlineClock()
+ << " mLastClockUpdateTime " << mDriveLoop->getLastClockUpdate();
+ if (mDriveLoop->getDeadlineClock() > mDriveLoop->getLastClockUpdate() + GSM::Time(216,0)) {
+ mDriveLoop->writeClockInterface();
+ }
LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
@@ -590,23 +572,6 @@ bool Transceiver::driveTransmitPriorityQueue()
}
-void Transceiver::writeClockInterface()
-{
- char command[50];
- // FIXME -- This should be adaptive.
- sprintf(command,"IND CLOCK %llu",
- (unsigned long long) (mTransmitDeadlineClock->FN() + 2));
-
- LOG(INFO) << "ClockInterface: sending " << command;
-
- mClockSocket.write(command,strlen(command)+1);
-
- mLastClockUpdateTime = *mTransmitDeadlineClock;
-}
-
-
-
-
void *FIFOServiceLoopAdapter(Transceiver *transceiver)
{
while (transceiver->on()) {
@@ -629,13 +594,14 @@ void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *transceiver)
{
while (transceiver->on()) {
bool stale = false;
+
// Flush the UDP packets until a successful transfer.
while (!transceiver->driveTransmitPriorityQueue()) {
stale = true;
}
if (stale) {
// If a packet was stale, remind the GSM stack of the clock.
- transceiver->writeClockInterface();
+ transceiver->getDriveLoop()->writeClockInterface();
}
pthread_testcancel();
}
diff --git a/Transceiver52M/Transceiver.h b/Transceiver52M/Transceiver.h
index 840f87b..56acd9c 100644
--- a/Transceiver52M/Transceiver.h
+++ b/Transceiver52M/Transceiver.h
@@ -49,7 +49,6 @@ private:
UDPSocket mDataSocket; ///< socket for writing to/reading from GSM core
UDPSocket mControlSocket; ///< socket for writing/reading control commands from GSM core
- UDPSocket mClockSocket; ///< socket for writing clock updates to GSM core
VectorQueue *mTransmitPriorityQueue; ///< priority queue of transmit bursts received from GSM core
VectorFIFO* mReceiveFIFO; ///< radioInterface FIFO of receive bursts
@@ -60,9 +59,6 @@ private:
int mChannel; ///< channelizer attach number between 0 and 'M-1'
- GSM::Time *mTransmitDeadlineClock; ///< deadline for pushing bursts into transmit FIFO
- GSM::Time mLastClockUpdateTime; ///< last time clock update was sent up to core
-
RadioInterface *mRadioInterface; ///< associated radioInterface object
double txFullScale; ///< full scale input to radio
double rxFullScale; ///< full scale output to radio
@@ -96,8 +92,10 @@ private:
bool mOn; ///< flag to indicate that transceiver is powered on
bool mRunning; ///< flag to indicate control loop is running
+ bool mPrimary; ///< flag to indicate C0 channel
double mTxFreq; ///< the transmit frequency
double mRxFreq; ///< the receive frequency
+ double mFreqOffset; ///< RF frequency offset
int mPower; ///< the transmit power in dB
int mTSC; ///< the midamble sequence code
double mEnergyThreshold; ///< threshold to determine if received data is potentially a GSM burst
@@ -112,7 +110,7 @@ private:
float chanRespOffset[8]; ///< most recent timing offset, e.g. TOA, of all timeslots
complex chanRespAmplitude[8]; ///< most recent channel amplitude of all timeslots
- bool mRadioLocked;
+ static int mTSC; ///< the midamble sequence code
public:
@@ -128,7 +126,7 @@ public:
int wSamplesPerSymbol,
RadioInterface *wRadioInterface,
DriveLoop *wDriveLoop,
- int wChannel);
+ int wChannel, bool wPrimary);
/** Destructor */
~Transceiver();
@@ -169,9 +167,11 @@ protected:
/** return control loop operational status */
bool running() { return mRunning; }
+ /** return the drive loop pointer */
+ DriveLoop *getDriveLoop() { return mDriveLoop; }
+
/** set priority on current thread */
void setPriority() { mRadioInterface->setPriority(); }
-
};
/** FIFO thread loop */
@@ -182,4 +182,3 @@ void *ControlServiceLoopAdapter(Transceiver *);
/** transmit queueing thread loop */
void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *);
-
diff --git a/Transceiver52M/multiTRX.cpp b/Transceiver52M/multiTRX.cpp
index 85d4046..04e2c95 100644
--- a/Transceiver52M/multiTRX.cpp
+++ b/Transceiver52M/multiTRX.cpp
@@ -32,6 +32,8 @@ ConfigurationTable gConfig("/etc/OpenBTS/OpenBTS.db");
volatile bool gbShutdown = false;
+int Transceiver::mTSC = 0;
+
static void sigHandler(int signum)
{
LOG(NOTICE) << "Received shutdown signal";
@@ -56,23 +58,23 @@ static int setupSignals()
}
/*
- * Generate the channel-transceiver ordering. Channel 0 is always centered
- * at the RF tuning frequecy. Fill remaining channels alternating left and
- * right moving out from the center channel.
+ * Generate the channel-transceiver ordering. Attempt to match the RAD1
+ * ordering where the active channels are centered in the overall device
+ * bandwidth. C0 is always has the lowest ARFCN with increasing subsequent
+ * channels. When an even number of channels is selected, the carriers will
+ * be offset from the RF center by -200 kHz, or half ARFCN spacing.
*/
-static void genChanMap(int *chans)
+static void genChanMap(int numARFCN, int chanM, int *chans)
{
int i, n;
- chans[0] = 0;
+ chans[0] = numARFCN / 2;
- for (i = 1, n = 1; i < CHAN_M; i++) {
- if (i % 2) {
- chans[i] = n;
- } else {
- chans[i] = CHAN_M - n;
- n++;
- }
+ for (i = 1, n = 1; i < numARFCN; i++) {
+ if (!chans[i - 1])
+ chans[i] = chanM - 1;
+ else
+ chans[i] = chans[i - 1] - 1;
}
}
@@ -80,44 +82,66 @@ static void createTrx(Transceiver **trx, int *map, int num,
RadioInterface *radio, DriveLoop *drive)
{
int i;
+ bool primary = true;
for (i = 0; i < num; i++) {
LOG(NOTICE) << "Creating TRX" << i
<< " attached on channel " << map[i];
radio->activateChan(map[i]);
- trx[i] = new Transceiver(5700 + i * 1000, "127.0.0.1",
- SAMPSPERSYM, radio, drive, map[i]);
+ trx[i] = new Transceiver(5700 + 2 * i, "127.0.0.1",
+ SAMPSPERSYM, radio, drive,
+ map[i], primary);
trx[i]->start();
+ primary = false;
}
}
int main(int argc, char *argv[])
{
- int i, numARFCN = 1;
- int chanMap[CHAN_M];
+ int i, chanM, numARFCN = 1;
+ int chanMap[CHAN_MAX];
RadioDevice *usrp;
RadioInterface* radio;
DriveLoop *drive;
- Transceiver *trx[CHAN_M];
+ Transceiver *trx[CHAN_MAX];
gLogInit("transceiver", gConfig.getStr("Log.Level").c_str(), LOG_LOCAL7);
if (argc > 1) {
numARFCN = atoi(argv[1]);
- if (numARFCN > CHAN_M) {
+ if (numARFCN > (CHAN_MAX - 1)) {
LOG(ALERT) << numARFCN << " channels not supported with current build";
exit(-1);
}
}
+ srandom(time(NULL));
+
if (setupSignals() < 0) {
LOG(ERR) << "Failed to setup signal handlers, exiting...";
exit(-1);
}
- srandom(time(NULL));
- genChanMap(chanMap);
+ /*
+ * Select the number of channels according to the number of ARFCNs's
+ * and generate ARFCN-to-channelizer path mappings. The channelizer
+ * aliases and extracts 'M' equally spaced channels to baseband. The
+ * number of ARFCN's must be less than the number of channels in the
+ * channelizer.
+ */
+ switch (numARFCN) {
+ case 1:
+ chanM = 1;
+ break;
+ case 2:
+ case 3:
+ chanM = 5;
+ break;
+ default:
+ chanM = 10;
+ }
+ genChanMap(numARFCN, chanM, chanMap);
usrp = RadioDevice::make(DEVICERATE);
if (!usrp->open()) {
@@ -125,8 +149,9 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
- radio = new RadioInterface(usrp, numARFCN, SAMPSPERSYM, 0, false);
- drive = new DriveLoop(SAMPSPERSYM, GSM::Time(3,0), radio);
+ radio = new RadioInterface(usrp, chanM, 3, SAMPSPERSYM, 0, false);
+ drive = new DriveLoop(5700, "127.0.0.1", chanM, chanMap[0],
+ SAMPSPERSYM, GSM::Time(3,0), radio);
/* Create, attach, and activate all transceivers */
createTrx(trx, chanMap, numARFCN, radio, drive);
diff --git a/Transceiver52M/radioInterface.cpp b/Transceiver52M/radioInterface.cpp
index 98af480..b3bc07c 100644
--- a/Transceiver52M/radioInterface.cpp
+++ b/Transceiver52M/radioInterface.cpp
@@ -50,10 +50,11 @@ static void shortToFloat(float *out, short *in, int num)
}
RadioInterface::RadioInterface(RadioDevice *wRadio,
+ int wChanM,
int wReceiveOffset,
int wSPS,
GSM::Time wStartTime)
- : underrun(false), sendCursor(0), rcvCursor(0), mOn(false),
+ : mChanM(wChanM), underrun(false), sendCursor(0), rcvCursor(0), mOn(false),
mRadio(wRadio), receiveOffset(wReceiveOffset),
samplesPerSymbol(wSPS), powerScaling(1.0),
loadTest(false)
@@ -62,7 +63,7 @@ RadioInterface::RadioInterface(RadioDevice *wRadio,
mClock.set(wStartTime);
- for (i = 0; i < CHAN_M; i++) {
+ for (i = 0; i < mChanM; i++) {
chanActive[i] = false;
}
}
@@ -77,7 +78,7 @@ RadioInterface::~RadioInterface(void)
delete mAlignRadioServiceLoopThread;
- for (i = 0; i < CHAN_M; i++) {
+ for (i = 0; i < mChanM; i++) {
if (rcvBuffer[i] != NULL)
delete rcvBuffer[i];
if (sendBuffer[i] != NULL)
@@ -170,9 +171,7 @@ bool RadioInterface::start()
#endif
writeTimestamp = mRadio->initialWriteTimestamp();
readTimestamp = mRadio->initialReadTimestamp();
- mRadio->start();
-
- for (i = 0; i < CHAN_M; i++) {
+ for (i = 0; i < mChanM; i++) {
sendBuffer[i] = new float[8*2*INCHUNK];
rcvBuffer[i] = new float[8*2*OUTCHUNK];
}
@@ -220,7 +219,7 @@ void RadioInterface::driveTransmitRadio(signalVector **radioBurst, bool *zeroBur
if (!mOn)
return;
- for (i = 0; i < CHAN_M; i++) {
+ for (i = 0; i < mChanM; i++) {
if (chanActive[i]) {
radioifyVector(*radioBurst[i], sendBuffer[i] + 2 * sendCursor,
powerScaling, zeroBurst[i]);
@@ -236,11 +235,11 @@ void RadioInterface::driveTransmitRadio(signalVector **radioBurst, bool *zeroBur
pushBuffer();
}
-void shiftRxBuffers(float **buf, int offset, int len, bool *active)
+void shiftRxBuffers(float **buf, int offset, int len, int chanM, bool *active)
{
int i;
- for (i = 0; i < CHAN_M; i++) {
+ for (i = 0; i < chanM; i++) {
if (active[i]) {
memmove(buf[i], buf[i] + offset, sizeof(float) * len);
}
@@ -252,7 +251,7 @@ void RadioInterface::loadVectors(unsigned tN, int samplesPerBurst,
{
int i;
- for (i = 0; i < CHAN_M; i++) {
+ for (i = 0; i < mChanM; i++) {
if (chanActive[i]) {
signalVector rxVector(samplesPerBurst);
unRadioifyVector(rcvBuffer[i], idx * 2, rxVector);
@@ -300,7 +299,7 @@ void RadioInterface::driveReceiveRadio()
if (readSz > 0) {
rcvCursor -= readSz;
- shiftRxBuffers(rcvBuffer, 2 * readSz, 2 * rcvCursor, chanActive);
+ shiftRxBuffers(rcvBuffer, 2 * readSz, 2 * rcvCursor, mChanM, chanActive);
}
}
diff --git a/Transceiver52M/radioInterface.h b/Transceiver52M/radioInterface.h
index bc32763..f301511 100644
--- a/Transceiver52M/radioInterface.h
+++ b/Transceiver52M/radioInterface.h
@@ -36,19 +36,20 @@ class RadioInterface {
protected:
+ int mChanM; ///< channelizer width
Thread *mAlignRadioServiceLoopThread; ///< thread that synchronizes transmit and receive sections
- VectorFIFO mReceiveFIFO[CHAN_M]; ///< FIFO that holds receive bursts
+ VectorFIFO mReceiveFIFO[CHAN_MAX]; ///< FIFO that holds receive bursts
RadioDevice *mRadio; ///< the USRP object
- float *sendBuffer[CHAN_M];
+ float *sendBuffer[CHAN_MAX];
unsigned sendCursor;
- float *rcvBuffer[CHAN_M];
+ float *rcvBuffer[CHAN_MAX];
unsigned rcvCursor;
- bool chanActive[CHAN_M];
+ bool chanActive[CHAN_MAX];
bool underrun; ///< indicates writes to USRP are too slow
bool overrun; ///< indicates reads from USRP are too slow
@@ -103,6 +104,7 @@ public:
/** constructor */
RadioInterface(RadioDevice* wRadio = NULL,
+ int wChanM = 1,
int receiveOffset = 3,
int wSPS = SAMPSPERSYM,
GSM::Time wStartTime = GSM::Time(0));