aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Transceiver52M/DriveLoop.cpp264
-rw-r--r--Transceiver52M/DriveLoop.h185
-rw-r--r--Transceiver52M/Transceiver.cpp439
-rw-r--r--Transceiver52M/Transceiver.h65
-rw-r--r--Transceiver52M/radioVector.cpp17
-rw-r--r--Transceiver52M/radioVector.h11
6 files changed, 566 insertions, 415 deletions
diff --git a/Transceiver52M/DriveLoop.cpp b/Transceiver52M/DriveLoop.cpp
new file mode 100644
index 0000000..997d009
--- /dev/null
+++ b/Transceiver52M/DriveLoop.cpp
@@ -0,0 +1,264 @@
+/*
+* Copyright 2008, 2009, 2010, 2012 Free Software Foundation, Inc.
+*
+* This software is distributed under the terms of the GNU Public License.
+* See the COPYING file in the main directory for details.
+*
+* This use of this software may be subject to additional restrictions.
+* See the LEGAL file in the main directory for details.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include "DriveLoop.h"
+#include <Logger.h>
+
+DriveLoop::DriveLoop(int wSamplesPerSymbol,
+ GSM::Time wTransmitLatency,
+ RadioInterface *wRadioInterface)
+{
+ mRadioDriveLoopThread = new Thread(32768);
+
+ mSamplesPerSymbol = wSamplesPerSymbol;
+ mRadioInterface = wRadioInterface;
+
+ GSM::Time startTime(random() % gHyperframe, 0);
+ mTransmitDeadlineClock = startTime;
+ mLatencyUpdateTime = startTime;
+ mTransmitLatency = wTransmitLatency;
+
+ mRadioInterface->getClock()->set(startTime);
+
+ // generate pulse and setup up signal processing library
+ gsmPulse = generateGSMPulse(2, mSamplesPerSymbol);
+ LOG(DEBUG) << "gsmPulse: " << *gsmPulse;
+ sigProcLibSetup(mSamplesPerSymbol);
+
+ txFullScale = mRadioInterface->fullScaleInputValue();
+
+ // initialize filler tables with dummy bursts, initialize other per-timeslot variables
+ 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);
+ }
+ delete modBurst;
+
+ for (int n = 0; n < CHAN_M; n++) {
+ fillerModulus[n][i] = 26;
+ mChanType[n][i] = NONE;
+ }
+ }
+
+ mOn = false;
+}
+
+DriveLoop::~DriveLoop()
+{
+ delete gsmPulse;
+ sigProcLibDestroy();
+}
+
+void DriveLoop::start()
+{
+ mOn = true;
+ mRadioDriveLoopThread->start((void * (*)(void*))RadioDriveLoopAdapter, (void*) this);
+}
+
+void DriveLoop::pushRadioVector(GSM::Time &nowTime)
+{
+ int i;
+ radioVector *staleBurst;
+ radioVector *next;
+
+ for (i = 0; i < CHAN_M; 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;
+ }
+
+ int TN = nowTime.TN();
+ int modFN = nowTime.FN() % fillerModulus[i][nowTime.TN()];
+
+ mTxBursts[i] = fillerTable[i][modFN][TN];
+ mIsFiller[i] = true;
+ mIsZero[i] = (mChanType[i][TN] == NONE);
+
+ // 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));
+ mTxBursts[i] = next;
+ mIsFiller[i] = false;
+ }
+ }
+
+ mRadioInterface->driveTransmitRadio(mTxBursts, mIsZero);
+
+ for (i = 0; i < CHAN_M; i++) {
+ if (!mIsFiller[i])
+ delete mTxBursts[i];
+ }
+}
+
+void DriveLoop::setModulus(int channel, int timeslot)
+{
+ switch (mChanType[channel][timeslot]) {
+ case NONE:
+ case I:
+ case II:
+ case III:
+ case FILL:
+ fillerModulus[channel][timeslot] = 26;
+ break;
+ case IV:
+ case VI:
+ case V:
+ fillerModulus[channel][timeslot] = 51;
+ break;
+ //case V:
+ case VII:
+ fillerModulus[channel][timeslot] = 102;
+ break;
+ default:
+ break;
+ }
+}
+
+DriveLoop::CorrType DriveLoop::expectedCorrType(int channel, GSM::Time currTime)
+{
+ unsigned burstTN = currTime.TN();
+ unsigned burstFN = currTime.FN();
+
+ switch (mChanType[channel][burstTN]) {
+ case NONE:
+ return OFF;
+ break;
+ case FILL:
+ return IDLE;
+ break;
+ case I:
+ return TSC;
+ /*if (burstFN % 26 == 25)
+ return IDLE;
+ else
+ return TSC;*/
+ break;
+ case II:
+ if (burstFN % 2 == 1)
+ return IDLE;
+ else
+ return TSC;
+ break;
+ case III:
+ return TSC;
+ break;
+ case IV:
+ case VI:
+ return RACH;
+ break;
+ case V: {
+ int mod51 = burstFN % 51;
+ if ((mod51 <= 36) && (mod51 >= 14))
+ return RACH;
+ else if ((mod51 == 4) || (mod51 == 5))
+ return RACH;
+ else if ((mod51 == 45) || (mod51 == 46))
+ return RACH;
+ else
+ return TSC;
+ break;
+ }
+ case VII:
+ if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
+ return IDLE;
+ else
+ return TSC;
+ break;
+ case LOOPBACK:
+ if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
+ return IDLE;
+ else
+ return TSC;
+ break;
+ default:
+ return OFF;
+ break;
+ }
+}
+
+void DriveLoop::reset()
+{
+}
+
+void DriveLoop::driveReceiveFIFO()
+{
+ SoftVector *rxBurst = NULL;
+ int RSSI;
+ int TOA; // in 1/256 of a symbol
+ GSM::Time burstTime;
+
+ mRadioInterface->driveReceiveRadio();
+}
+
+/*
+ * Features a carefully controlled latency mechanism, to
+ * assure that transmit packets arrive at the radio/USRP
+ * before they need to be transmitted.
+ *
+ * Deadline clock indicates the burst that needs to be
+ * pushed into the FIFO right NOW. If transmit queue does
+ * not have a burst, stick in filler data.
+ */
+void DriveLoop::driveTransmitFIFO()
+{
+ int i;
+
+ if (!mOn)
+ return;
+
+ RadioClock *radioClock = (mRadioInterface->getClock());
+ while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
+ pushRadioVector(mTransmitDeadlineClock);
+ mTransmitDeadlineClock.incTN();
+ }
+
+ // FIXME -- This should not be a hard spin.
+ // But any delay here causes us to throw omni_thread_fatal.
+ //else radioClock->wait();
+}
+
+void *RadioDriveLoopAdapter(DriveLoop *transceiver)
+{
+ transceiver->setPriority();
+
+ while (1) {
+ transceiver->driveReceiveFIFO();
+ transceiver->driveTransmitFIFO();
+ pthread_testcancel();
+ }
+ return NULL;
+}
diff --git a/Transceiver52M/DriveLoop.h b/Transceiver52M/DriveLoop.h
new file mode 100644
index 0000000..7a59caa
--- /dev/null
+++ b/Transceiver52M/DriveLoop.h
@@ -0,0 +1,185 @@
+/*
+* Copyright 2008, 2012 Free Software Foundation, Inc.
+*
+* This software is distributed under the terms of the GNU Public License.
+* See the COPYING file in the main directory for details.
+*
+* This use of this software may be subject to additional restrictions.
+* See the LEGAL file in the main directory for details.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+
+/*
+ Compilation switches
+ TRANSMIT_LOGGING write every burst on the given slot to a log
+*/
+
+#ifndef _DRIVELOOP_H_
+#define _DRIVELOOP_H_
+
+#include "radioInterface.h"
+#include "Interthread.h"
+#include "GSMCommon.h"
+#include "Sockets.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+/** Define this to be the slot number to be logged. */
+//#define TRANSMIT_LOGGING 1
+
+/** The Transceiver class, responsible for physical layer of basestation */
+class DriveLoop {
+
+private:
+
+ GSM::Time mTransmitLatency; ///< latency between basestation clock and transmit deadline clock
+ GSM::Time mLatencyUpdateTime; ///< last time latency was updated
+
+ UDPSocket mClockSocket; ///< socket for writing clock updates to GSM core
+
+ VectorQueue mTransmitPriorityQueue[CHAN_M]; ///< priority queue of transmit bursts received from GSM core
+
+ Thread *mRadioDriveLoopThread; ///< thread to push/pull bursts into transmit/receive FIFO
+
+ GSM::Time mTransmitDeadlineClock; ///< deadline for pushing bursts into transmit FIFO
+
+ RadioInterface *mRadioInterface; ///< associated radioInterface object
+ double txFullScale; ///< full scale input to radio
+ double rxFullScale; ///< full scale output to radio
+
+
+ /** unmodulate a modulated burst */
+#ifdef TRANSMIT_LOGGING
+ void unModulateVector(signalVector wVector);
+#endif
+
+ /** modulate and add a burst to the transmit queue */
+ void addRadioVector(BitVector &burst, int RSSI, GSM::Time &wTime);
+
+ /** Push modulated burst into transmit FIFO corresponding to a particular timestamp */
+ void pushRadioVector(GSM::Time &nowTime);
+
+ /** 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
+
+ signalVector *mTxBursts[CHAN_M];
+ bool mIsFiller[CHAN_M];
+ bool mIsZero[CHAN_M];
+
+public:
+
+ /** Transceiver constructor
+ @param wBasePort base port number of UDP sockets
+ @param TRXAddress IP address of the TRX manager, as a string
+ @param wSamplesPerSymbol number of samples per GSM symbol
+ @param wTransmitLatency initial setting of transmit latency
+ @param radioInterface associated radioInterface object
+ */
+ DriveLoop(int wSamplesPerSymbol,
+ GSM::Time wTransmitLatency,
+ RadioInterface *wRadioInterface);
+
+ /** Destructor */
+ ~DriveLoop();
+
+ /** start the Transceiver */
+ void start();
+
+ 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
+ TSC, ///< timeslot should contain a normal burst
+ RACH, ///< timeslot should contain an access burst
+ IDLE ///< timeslot is an idle (or dummy) burst
+ } CorrType;
+
+ /** Codes for channel combinations */
+ typedef enum {
+ FILL, ///< Channel is transmitted, but unused
+ I, ///< TCH/FS
+ II, ///< TCH/HS, idle every other slot
+ III, ///< TCH/HS
+ IV, ///< FCCH+SCH+CCCH+BCCH, uplink RACH
+ V, ///< FCCH+SCH+CCCH+BCCH+SDCCH/4+SACCH/4, uplink RACH+SDCCH/4
+ VI, ///< CCCH+BCCH, uplink RACH
+ VII, ///< SDCCH/8 + SACCH/8
+ NONE, ///< Channel is inactive, default
+ LOOPBACK ///< similar go VII, used in loopback testing
+ } ChannelCombination;
+
+ /** Set modulus for specific timeslot */
+ void setModulus(int channel, int timeslot);
+
+ /** return the expected burst type for the specified timestamp */
+ CorrType expectedCorrType(int channel, GSM::Time currTime);
+
+ void setTimeslot(int m, int timeslot, ChannelCombination comb)
+ {
+ mChanType[m][timeslot] = comb;
+ }
+
+private:
+
+ ChannelCombination mChanType[CHAN_M][8]; ///< channel types for all timeslots
+
+protected:
+
+ /** drive reception and demodulation of GSM bursts */
+ void driveReceiveFIFO();
+
+ /** drive transmission of GSM bursts */
+ void driveTransmitFIFO();
+
+ /** drive handling of control messages from GSM core */
+ void driveControl();
+
+ /**
+ drive modulation and sorting of GSM bursts from GSM core
+ @return true if a burst was transferred successfully
+ */
+ bool driveTransmitPriorityQueue();
+
+ friend void *RadioDriveLoopAdapter(DriveLoop *);
+
+ void reset();
+
+ /** set priority on current thread */
+ void setPriority() { mRadioInterface->setPriority(); }
+
+};
+
+/** FIFO thread loop */
+void *RadioDriveLoopAdapter(DriveLoop *);
+
+#endif /* _DRIVELOOP_H_ */
diff --git a/Transceiver52M/Transceiver.cpp b/Transceiver52M/Transceiver.cpp
index 017b641..6cfcf32 100644
--- a/Transceiver52M/Transceiver.cpp
+++ b/Transceiver52M/Transceiver.cpp
@@ -1,5 +1,5 @@
/*
-* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
+* Copyright 2008, 2009, 2010, 2012 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
@@ -51,17 +51,15 @@ using namespace GSM;
Transceiver::Transceiver(int wBasePort,
const char *TRXAddress,
int wSamplesPerSymbol,
- GSM::Time wTransmitLatency,
- RadioInterface *wRadioInterface)
+ RadioInterface *wRadioInterface,
+ DriveLoop *wDriveLoop,
+ int wChannel)
:mDataSocket(wBasePort+2,TRXAddress,wBasePort+102),
mControlSocket(wBasePort+1,TRXAddress,wBasePort+101),
mClockSocket(wBasePort,TRXAddress,wBasePort+100),
- mTSC(-1)
+ mDriveLoop(wDriveLoop), mTransmitPriorityQueue(NULL),
+ mChannel(wChannel), mTSC(-1)
{
- //GSM::Time startTime(0,0);
- //GSM::Time startTime(gHyperframe/2 - 4*216*60,0);
- GSM::Time startTime(random() % gHyperframe,0);
-
mFIFOServiceLoopThread = new Thread(32768); ///< thread to push bursts into transmit FIFO
mControlServiceLoopThread = new Thread(32768); ///< thread to process control messages from GSM core
mTransmitPriorityQueueServiceLoopThread = new Thread(32768);///< thread to process transmit bursts from GSM core
@@ -69,37 +67,24 @@ Transceiver::Transceiver(int wBasePort,
mSamplesPerSymbol = wSamplesPerSymbol;
mRadioInterface = wRadioInterface;
- mTransmitLatency = wTransmitLatency;
- mTransmitDeadlineClock = startTime;
- mLastClockUpdateTime = startTime;
- mLatencyUpdateTime = startTime;
- mRadioInterface->getClock()->set(startTime);
+ mLastClockUpdateTime = GSM::Time(0, 0);
mMaxExpectedDelay = 0;
+ mTransmitDeadlineClock = wDriveLoop->deadlineClock();
+
// generate pulse and setup up signal processing library
gsmPulse = generateGSMPulse(2,mSamplesPerSymbol);
LOG(DEBUG) << "gsmPulse: " << *gsmPulse;
- sigProcLibSetup(mSamplesPerSymbol);
txFullScale = mRadioInterface->fullScaleInputValue();
rxFullScale = mRadioInterface->fullScaleOutputValue();
- // initialize filler tables with dummy bursts, initialize other per-timeslot variables
+ // initialize per-timeslot variables
for (int i = 0; i < 8; i++) {
- signalVector* modBurst = modulateBurst(gDummyBurst,*gsmPulse,
- 8 + (i % 4 == 0),
- mSamplesPerSymbol);
- scaleVector(*modBurst,txFullScale);
- fillerModulus[i]=26;
- for (int j = 0; j < 102; j++) {
- fillerTable[j][i] = new signalVector(*modBurst);
- }
- delete modBurst;
- mChanType[i] = NONE;
channelResponse[i] = NULL;
DFEForward[i] = NULL;
DFEFeedback[i] = NULL;
- channelEstimateTime[i] = startTime;
+ channelEstimateTime[i] = GSM::Time(0, 0);
}
mOn = false;
@@ -107,14 +92,15 @@ Transceiver::Transceiver(int wBasePort,
mRxFreq = 0.0;
mPower = -10;
mEnergyThreshold = INIT_ENERGY_THRSHD;
- prevFalseDetectionTime = startTime;
+ prevFalseDetectionTime = GSM::Time(0, 0);
+
+ mRadioLocked = mRadioInterface->started();
}
Transceiver::~Transceiver()
{
delete gsmPulse;
- sigProcLibDestroy();
- mTransmitPriorityQueue.clear();
+ mTransmitPriorityQueue->clear();
}
@@ -128,199 +114,18 @@ void Transceiver::addRadioVector(BitVector &burst,
mSamplesPerSymbol);
scaleVector(*modBurst,txFullScale * pow(10,-RSSI/10));
radioVector *newVec = new radioVector(*modBurst,wTime);
- mTransmitPriorityQueue.write(newVec);
+ mTransmitPriorityQueue->write(newVec);
delete modBurst;
}
-#ifdef TRANSMIT_LOGGING
-void Transceiver::unModulateVector(signalVector wVector)
-{
- SoftVector *burst = demodulateBurst(wVector,
- *gsmPulse,
- mSamplesPerSymbol,
- 1.0,0.0);
- LOG(DEBUG) << "LOGGED BURST: " << *burst;
-
-/*
- unsigned char burstStr[gSlotLen+1];
- SoftVector::iterator burstItr = burst->begin();
- for (int i = 0; i < gSlotLen; i++) {
- // FIXME: Demod bits are inverted!
- burstStr[i] = (unsigned char) ((*burstItr++)*255.0);
- }
- burstStr[gSlotLen]='\0';
- LOG(DEBUG) << "LOGGED BURST: " << burstStr;
-*/
- delete burst;
-}
-#endif
-
-void Transceiver::pushRadioVector(GSM::Time &nowTime)
-{
-
- // dump stale bursts, if any
- unsigned BCCH_SCH_FCCH_CCCH_Frames[26] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,30,31,40,41};
-
- while (radioVector* staleBurst = mTransmitPriorityQueue.getStaleBurst(nowTime)) {
- // Even if the burst is stale, put it in the fillter table.
- // (It might be an idle pattern.)
- // Now we do it only for BEACON channels.
- LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
- const GSM::Time& nextTime = staleBurst->getTime();
- int TN = nextTime.TN();
- int modFN = nextTime.FN() % fillerModulus[TN];
- if (TN==0) {
- for (unsigned i =0; i < 26; i++) {
- if(BCCH_SCH_FCCH_CCCH_Frames[i] == modFN) {
- delete fillerTable[modFN][TN];
- fillerTable[modFN][TN] = staleBurst;
- break;
- }
- }
- }
- }
-
- int TN = nowTime.TN();
- int modFN = nowTime.FN() % fillerModulus[nowTime.TN()];
-
- // if queue contains data at the desired timestamp, stick it into FIFO
- if (radioVector *next = (radioVector*) mTransmitPriorityQueue.getCurrentBurst(nowTime)) {
- LOG(DEBUG) << "transmitFIFO: wrote burst " << next << " at time: " << nowTime;
- if (TN==0) {
- for (unsigned i =0; i < 26; i++) {
- if(BCCH_SCH_FCCH_CCCH_Frames[i] == modFN) {
- delete fillerTable[modFN][TN];
- fillerTable[modFN][TN] = new signalVector(*(next));
- break;
- }
- }
- }
- mRadioInterface->driveTransmitRadio(*(next),(mChanType[TN]==NONE)); //fillerTable[modFN][TN]));
- delete next;
-#ifdef TRANSMIT_LOGGING
- if (nowTime.TN()==TRANSMIT_LOGGING) {
- unModulateVector(*(fillerTable[modFN][TN]));
- }
-#endif
- return;
- }
-
- // otherwise, pull filler data, and push to radio FIFO
- mRadioInterface->driveTransmitRadio(*(fillerTable[modFN][TN]),(mChanType[TN]==NONE));
-#ifdef TRANSMIT_LOGGING
- if (nowTime.TN()==TRANSMIT_LOGGING)
- unModulateVector(*fillerTable[modFN][TN]);
-#endif
-
-}
-
-void Transceiver::setModulus(int timeslot)
-{
- switch (mChanType[timeslot]) {
- case NONE:
- case I:
- case II:
- case III:
- case FILL:
- fillerModulus[timeslot] = 26;
- break;
- case IV:
- case VI:
- case V:
- fillerModulus[timeslot] = 51;
- break;
- //case V:
- case VII:
- fillerModulus[timeslot] = 102;
- break;
- case XIII:
- fillerModulus[timeslot] = 52;
- break;
- default:
- break;
- }
-}
-
-
-Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime)
-{
-
- unsigned burstTN = currTime.TN();
- unsigned burstFN = currTime.FN();
-
- switch (mChanType[burstTN]) {
- case NONE:
- return OFF;
- break;
- case FILL:
- return IDLE;
- break;
- case I:
- return TSC;
- /*if (burstFN % 26 == 25)
- return IDLE;
- else
- return TSC;*/
- break;
- case II:
- return TSC;
- break;
- case III:
- return TSC;
- break;
- case IV:
- case VI:
- return RACH;
- break;
- case V: {
- int mod51 = burstFN % 51;
- if ((mod51 <= 36) && (mod51 >= 14))
- return RACH;
- else if ((mod51 == 4) || (mod51 == 5))
- return RACH;
- else if ((mod51 == 45) || (mod51 == 46))
- return RACH;
- else
- return TSC;
- break;
- }
- case VII:
- if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
- return IDLE;
- else
- return TSC;
- break;
- case XIII: {
- int mod52 = burstFN % 52;
- if ((mod52 == 12) || (mod52 == 38))
- return RACH;
- else if ((mod52 == 25) || (mod52 == 51))
- return IDLE;
- else
- return TSC;
- break;
- }
- case LOOPBACK:
- if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
- return IDLE;
- else
- return TSC;
- break;
- default:
- return OFF;
- break;
- }
-
-}
-
SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
int &RSSI,
int &timingOffset)
{
bool needDFE = (mMaxExpectedDelay > 1);
- radioVector *rxBurst = (radioVector *) mReceiveFIFO->get();
+ radioVector *rxBurst = (radioVector *) mReceiveFIFO->read();
if (!rxBurst) return NULL;
@@ -328,9 +133,9 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
int timeslot = rxBurst->getTime().TN();
- CorrType corrType = expectedCorrType(rxBurst->getTime());
+ DriveLoop::CorrType corrType = mDriveLoop->expectedCorrType(mChannel, rxBurst->getTime());
- if ((corrType==OFF) || (corrType==IDLE)) {
+ if ((corrType == DriveLoop::OFF) || (corrType == DriveLoop::IDLE)) {
delete rxBurst;
return NULL;
}
@@ -340,6 +145,7 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
complex amplitude = 0.0;
float TOA = 0.0;
float avgPwr = 0.0;
+
if (!energyDetect(*vectorBurst,20*mSamplesPerSymbol,mEnergyThreshold,&avgPwr)) {
LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->getTime();
double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
@@ -357,7 +163,7 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
// run the proper correlator
bool success = false;
- if (corrType==TSC) {
+ if (corrType == DriveLoop::TSC) {
LOG(DEBUG) << "looking for TSC at time: " << rxBurst->getTime();
signalVector *channelResp;
double framesElapsed = rxBurst->getTime()-channelEstimateTime[timeslot];
@@ -431,7 +237,7 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
// demodulate burst
SoftVector *burst = NULL;
if ((rxBurst) && (success)) {
- if ((corrType==RACH) || (!needDFE)) {
+ if ((corrType == DriveLoop::RACH) || (!needDFE)) {
burst = demodulateBurst(*vectorBurst,
*gsmPulse,
mSamplesPerSymbol,
@@ -458,6 +264,44 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
return burst;
}
+void Transceiver::pullFIFO()
+{
+ SoftVector *rxBurst = NULL;
+ int RSSI;
+ int TOA; // in 1/256 of a symbol
+ GSM::Time burstTime;
+
+ rxBurst = pullRadioVector(burstTime,RSSI,TOA);
+
+ if (rxBurst) {
+ LOG(DEBUG) << "burst parameters: "
+ << " time: " << burstTime
+ << " RSSI: " << RSSI
+ << " TOA: " << TOA
+ << " bits: " << *rxBurst;
+
+ char burstString[gSlotLen+10];
+ burstString[0] = burstTime.TN();
+ for (int i = 0; i < 4; i++) {
+ burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
+ }
+
+ burstString[5] = RSSI;
+ burstString[6] = (TOA >> 8) & 0x0ff;
+ burstString[7] = TOA & 0x0ff;
+ SoftVector::iterator burstItr = rxBurst->begin();
+
+ for (unsigned int i = 0; i < gSlotLen; i++) {
+ burstString[8+i] =(char) round((*burstItr++)*255.0);
+ }
+
+ burstString[gSlotLen+9] = '\0';
+ delete rxBurst;
+
+ mDataSocket.write(burstString,gSlotLen+10);
+ }
+}
+
void Transceiver::start()
{
mControlServiceLoopThread->start((void * (*)(void*))ControlServiceLoopAdapter,(void*) this);
@@ -465,9 +309,7 @@ void Transceiver::start()
void Transceiver::reset()
{
- mTransmitPriorityQueue.clear();
- //mTransmitFIFO->clear();
- //mReceiveFIFO->clear();
+ mTransmitPriorityQueue->clear();
}
@@ -492,7 +334,7 @@ void Transceiver::driveControl()
char response[MAX_PACKET_LENGTH];
sscanf(buffer,"%3s %s",cmdcheck,command);
-
+
writeClockInterface();
if (strcmp(cmdcheck,"CMD")!=0) {
@@ -514,7 +356,9 @@ void Transceiver::driveControl()
if (!mOn) {
// Prepare for thread start
mPower = -20;
- mRadioInterface->start();
+ if (mRadioInterface->start())
+ mDriveLoop->start();
+
generateRACHSequence(*gsmPulse,mSamplesPerSymbol);
// Start radio interface threads.
@@ -539,6 +383,8 @@ void Transceiver::driveControl()
sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
newGain = mRadioInterface->setRxGain(newGain);
mEnergyThreshold = INIT_ENERGY_THRSHD;
+ if (!mRadioLocked)
+ newGain = mRadioInterface->setRxGain(newGain);
sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
}
else if (strcmp(command,"NOISELEV")==0) {
@@ -558,7 +404,8 @@ void Transceiver::driveControl()
sprintf(response,"RSP SETPOWER 1 %d",dbPwr);
else {
mPower = dbPwr;
- mRadioInterface->setPowerAttenuation(dbPwr);
+ if (!mRadioLocked)
+ mRadioInterface->setPowerAttenuation(dbPwr);
sprintf(response,"RSP SETPOWER 0 %d",dbPwr);
}
}
@@ -579,12 +426,18 @@ void Transceiver::driveControl()
int freqKhz;
sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
mRxFreq = freqKhz*1.0e3+FREQOFFSET;
- if (!mRadioInterface->tuneRx(mRxFreq)) {
- LOG(ALERT) << "RX failed to tune";
- sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
- }
- else
+ 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);
+ }
+ } else {
+ sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
+ }
}
else if (strcmp(command,"TXTUNE")==0) {
// tune txmtr
@@ -592,12 +445,17 @@ void Transceiver::driveControl()
sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
//freqKhz = 890e3;
mTxFreq = freqKhz*1.0e3+FREQOFFSET;
- if (!mRadioInterface->tuneTx(mTxFreq)) {
- LOG(ALERT) << "TX failed to tune";
- sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
+ 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);
+ }
+ } else {
+ sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
}
- else
- sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
}
else if (strcmp(command,"SETTSC")==0) {
// set TSC
@@ -621,8 +479,8 @@ void Transceiver::driveControl()
sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
return;
}
- mChanType[timeslot] = (ChannelCombination) corrCode;
- setModulus(timeslot);
+ mDriveLoop->setTimeslot(mChannel, timeslot, (DriveLoop::ChannelCombination) corrCode);
+ mDriveLoop->setModulus(mChannel, timeslot);
sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
}
@@ -670,9 +528,9 @@ bool Transceiver::driveTransmitPriorityQueue()
*/
// periodically update GSM core clock
- LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock
- << " mLastClockUpdateTime " << mLastClockUpdateTime;
- if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
+ LOG(DEBUG) << "mTransmitDeadlineClock " << *mTransmitDeadlineClock
+ << " mLastClockUpdateTime " << mLastClockUpdateTime;
+ if (*mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
writeClockInterface();
@@ -695,115 +553,19 @@ bool Transceiver::driveTransmitPriorityQueue()
}
-
-void Transceiver::driveReceiveFIFO()
-{
-
- SoftVector *rxBurst = NULL;
- int RSSI;
- int TOA; // in 1/256 of a symbol
- GSM::Time burstTime;
-
- mRadioInterface->driveReceiveRadio();
-
- rxBurst = pullRadioVector(burstTime,RSSI,TOA);
-
- if (rxBurst) {
-
- LOG(DEBUG) << "burst parameters: "
- << " time: " << burstTime
- << " RSSI: " << RSSI
- << " TOA: " << TOA
- << " bits: " << *rxBurst;
-
- char burstString[gSlotLen+10];
- burstString[0] = burstTime.TN();
- for (int i = 0; i < 4; i++)
- burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
- burstString[5] = RSSI;
- burstString[6] = (TOA >> 8) & 0x0ff;
- burstString[7] = TOA & 0x0ff;
- SoftVector::iterator burstItr = rxBurst->begin();
-
- for (unsigned int i = 0; i < gSlotLen; i++) {
- burstString[8+i] =(char) round((*burstItr++)*255.0);
- }
- burstString[gSlotLen+9] = '\0';
- delete rxBurst;
-
- mDataSocket.write(burstString,gSlotLen+10);
- }
-
-}
-
-void Transceiver::driveTransmitFIFO()
-{
-
- /**
- Features a carefully controlled latency mechanism, to
- assure that transmit packets arrive at the radio/USRP
- before they need to be transmitted.
-
- Deadline clock indicates the burst that needs to be
- pushed into the FIFO right NOW. If transmit queue does
- not have a burst, stick in filler data.
- */
-
-
- RadioClock *radioClock = (mRadioInterface->getClock());
-
- if (mOn) {
- //radioClock->wait(); // wait until clock updates
- LOG(DEBUG) << "radio clock " << radioClock->get();
- while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
- // if underrun, then we're not providing bursts to radio/USRP fast
- // enough. Need to increase latency by one GSM frame.
- if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
- if (mRadioInterface->isUnderrun()) {
- // only update latency at the defined frame interval
- if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
- mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
- LOG(INFO) << "new latency: " << mTransmitLatency;
- mLatencyUpdateTime = radioClock->get();
- }
- }
- else {
- // if underrun hasn't occurred in the last sec (216 frames) drop
- // transmit latency by a timeslot
- if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
- if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
- mTransmitLatency.decTN();
- LOG(INFO) << "reduced latency: " << mTransmitLatency;
- mLatencyUpdateTime = radioClock->get();
- }
- }
- }
- }
- // time to push burst to transmit FIFO
- pushRadioVector(mTransmitDeadlineClock);
- mTransmitDeadlineClock.incTN();
- }
-
- }
- // FIXME -- This should not be a hard spin.
- // But any delay here causes us to throw omni_thread_fatal.
- //else radioClock->wait();
-}
-
-
void Transceiver::writeClockInterface()
{
char command[50];
// FIXME -- This should be adaptive.
- sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
+ sprintf(command,"IND CLOCK %llu",
+ (unsigned long long) (mTransmitDeadlineClock->FN() + 2));
LOG(INFO) << "ClockInterface: sending " << command;
mClockSocket.write(command,strlen(command)+1);
- mLastClockUpdateTime = mTransmitDeadlineClock;
-
+ mLastClockUpdateTime = *mTransmitDeadlineClock;
}
@@ -811,11 +573,8 @@ void Transceiver::writeClockInterface()
void *FIFOServiceLoopAdapter(Transceiver *transceiver)
{
- transceiver->setPriority();
-
while (1) {
- transceiver->driveReceiveFIFO();
- transceiver->driveTransmitFIFO();
+ transceiver->pullFIFO();
pthread_testcancel();
}
return NULL;
diff --git a/Transceiver52M/Transceiver.h b/Transceiver52M/Transceiver.h
index b23c3fa..fed2df9 100644
--- a/Transceiver52M/Transceiver.h
+++ b/Transceiver52M/Transceiver.h
@@ -1,5 +1,5 @@
/*
-* Copyright 2008 Free Software Foundation, Inc.
+* Copyright 2008, 2012 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Public License.
* See the COPYING file in the main directory for details.
@@ -29,6 +29,7 @@
TRANSMIT_LOGGING write every burst on the given slot to a log
*/
+#include "DriveLoop.h"
#include "radioInterface.h"
#include "Interthread.h"
#include "GSMCommon.h"
@@ -44,59 +45,28 @@
class Transceiver {
private:
-
- GSM::Time mTransmitLatency; ///< latency between basestation clock and transmit deadline clock
- GSM::Time mLatencyUpdateTime; ///< last time latency was updated
+ DriveLoop *mDriveLoop;
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* mTransmitFIFO; ///< radioInterface FIFO of transmit bursts
+ VectorQueue *mTransmitPriorityQueue; ///< priority queue of transmit bursts received from GSM core
VectorFIFO* mReceiveFIFO; ///< radioInterface FIFO of receive bursts
Thread *mFIFOServiceLoopThread; ///< thread to push/pull bursts into transmit/receive FIFO
Thread *mControlServiceLoopThread; ///< thread to process control messages from GSM core
Thread *mTransmitPriorityQueueServiceLoopThread;///< thread to process transmit bursts from GSM core
- GSM::Time mTransmitDeadlineClock; ///< deadline for pushing bursts into transmit FIFO
+ 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
- /** Codes for burst types of received bursts*/
- typedef enum {
- OFF, ///< timeslot is off
- TSC, ///< timeslot should contain a normal burst
- RACH, ///< timeslot should contain an access burst
- IDLE ///< timeslot is an idle (or dummy) burst
- } CorrType;
-
-
- /** Codes for channel combinations */
- typedef enum {
- FILL, ///< Channel is transmitted, but unused
- I, ///< TCH/FS
- II, ///< TCH/HS, idle every other slot
- III, ///< TCH/HS
- IV, ///< FCCH+SCH+CCCH+BCCH, uplink RACH
- V, ///< FCCH+SCH+CCCH+BCCH+SDCCH/4+SACCH/4, uplink RACH+SDCCH/4
- VI, ///< CCCH+BCCH, uplink RACH
- VII, ///< SDCCH/8 + SACCH/8
- VIII, ///< TCH/F + FACCH/F + SACCH/M
- IX, ///< TCH/F + SACCH/M
- X, ///< TCH/FD + SACCH/MD
- XI, ///< PBCCH+PCCCH+PDTCH+PACCH+PTCCH
- XII, ///< PCCCH+PDTCH+PACCH+PTCCH
- XIII, ///< PDTCH+PACCH+PTCCH
- NONE, ///< Channel is inactive, default
- LOOPBACK ///< similar go VII, used in loopback testing
- } ChannelCombination;
-
-
/** unmodulate a modulated burst */
#ifdef TRANSMIT_LOGGING
void unModulateVector(signalVector wVector);
@@ -115,29 +85,22 @@ private:
int &RSSI,
int &timingOffset);
- /** Set modulus for specific timeslot */
- void setModulus(int timeslot);
-
- /** return the expected burst type for the specified timestamp */
- CorrType expectedCorrType(GSM::Time currTime);
-
/** send messages over the clock socket */
void writeClockInterface(void);
+ void pullFIFO(void); ///< blocking call on receive FIFO
+
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
- ChannelCombination mChanType[8]; ///< channel types for all timeslots
double mTxFreq; ///< the transmit frequency
double mRxFreq; ///< the receive frequency
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
GSM::Time prevFalseDetectionTime; ///< last timestamp of a false energy detection
- int fillerModulus[8]; ///< modulus values of all timeslots, in frames
- signalVector *fillerTable[102][8]; ///< table of modulated filler waveforms for all timeslots
unsigned mMaxExpectedDelay; ///< maximum expected time-of-arrival offset in GSM symbols
GSM::Time channelEstimateTime[8]; ///< last timestamp of each timeslot's channel estimate
@@ -148,6 +111,8 @@ 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;
+
public:
/** Transceiver constructor
@@ -160,9 +125,9 @@ public:
Transceiver(int wBasePort,
const char *TRXAddress,
int wSamplesPerSymbol,
- GSM::Time wTransmitLatency,
- RadioInterface *wRadioInterface);
-
+ RadioInterface *wRadioInterface,
+ DriveLoop *wDriveLoop,
+ int wChannel);
/** Destructor */
~Transceiver();
@@ -173,7 +138,7 @@ public:
void receiveFIFO(VectorFIFO *wFIFO) { mReceiveFIFO = wFIFO;}
/** attach the radioInterface transmit FIFO */
- void transmitFIFO(VectorFIFO *wFIFO) { mTransmitFIFO = wFIFO;}
+ void transmitQueue(VectorQueue *wQ) { mTransmitPriorityQueue = wQ; }
protected:
diff --git a/Transceiver52M/radioVector.cpp b/Transceiver52M/radioVector.cpp
index f20d97a..dcdb375 100644
--- a/Transceiver52M/radioVector.cpp
+++ b/Transceiver52M/radioVector.cpp
@@ -2,7 +2,7 @@
* Written by Thomas Tsou <ttsou@vt.edu>
* Based on code by Harvind S Samra <hssamra@kestrelsp.com>
*
- * Copyright 2011 Free Software Foundation, Inc.
+ * Copyright 2011, 2012 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
@@ -41,21 +41,6 @@ bool radioVector::operator>(const radioVector& other) const
return mTime > other.mTime;
}
-unsigned VectorFIFO::size()
-{
- return mQ.size();
-}
-
-void VectorFIFO::put(radioVector *ptr)
-{
- mQ.put((void*) ptr);
-}
-
-radioVector *VectorFIFO::get()
-{
- return (radioVector*) mQ.get();
-}
-
GSM::Time VectorQueue::nextTime() const
{
GSM::Time retVal;
diff --git a/Transceiver52M/radioVector.h b/Transceiver52M/radioVector.h
index 8de4493..c41a8a8 100644
--- a/Transceiver52M/radioVector.h
+++ b/Transceiver52M/radioVector.h
@@ -2,7 +2,7 @@
* Written by Thomas Tsou <ttsou@vt.edu>
* Based on code by Harvind S Samra <hssamra@kestrelsp.com>
*
- * Copyright 2011 Free Software Foundation, Inc.
+ * Copyright 2011, 2012 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
@@ -37,14 +37,7 @@ private:
GSM::Time mTime;
};
-class VectorFIFO {
-public:
- unsigned size();
- void put(radioVector *ptr);
- radioVector *get();
-
-private:
- PointerFIFO mQ;
+class VectorFIFO : public InterthreadQueue<radioVector> {
};
class VectorQueue : public InterthreadPriorityQueue<radioVector> {