aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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));