diff options
-rw-r--r-- | Transceiver52M/DriveLoop.cpp | 264 | ||||
-rw-r--r-- | Transceiver52M/DriveLoop.h | 185 | ||||
-rw-r--r-- | Transceiver52M/Transceiver.cpp | 439 | ||||
-rw-r--r-- | Transceiver52M/Transceiver.h | 65 | ||||
-rw-r--r-- | Transceiver52M/radioVector.cpp | 17 | ||||
-rw-r--r-- | Transceiver52M/radioVector.h | 11 |
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> { |