/* * Copyright 2008 Free Software Foundation, Inc. * * This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion. * * This use of this software may be subject to additional restrictions. * See the LEGAL file in the main directory for details. 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. */ #include "sigProcLib.h" #include "GSMCommon.h" #include "LinkedLists.h" #include "radioDevice.h" /** samples per GSM symbol */ #define SAMPSPERSYM 1 #define INCHUNK (625) #define OUTCHUNK (625) /** class used to organize GSM bursts by GSM timestamps */ class radioVector : public signalVector { private: GSM::Time mTime; ///< the burst's GSM timestamp public: /** constructor */ radioVector(const signalVector& wVector, GSM::Time& wTime): signalVector(wVector),mTime(wTime) {}; /** timestamp read and write operators */ GSM::Time time() const { return mTime;} void time(const GSM::Time& wTime) { mTime = wTime;} /** comparison operator, used for sorting */ bool operator>(const radioVector& other) const {return mTime > other.mTime;} }; /** a priority queue of radioVectors, i.e. GSM bursts, sorted so that earliest element is at top */ class VectorQueue : public InterthreadPriorityQueue { public: /** the top element of the queue */ GSM::Time nextTime() const; /** Get stale burst, if any. @param targTime The target time. @return Pointer to burst older than target time, removed from queue, or NULL. */ radioVector* getStaleBurst(const GSM::Time& targTime); /** Get current burst, if any. @param targTime The target time. @return Pointer to burst at the target time, removed from queue, or NULL. */ radioVector* getCurrentBurst(const GSM::Time& targTime); }; /** a FIFO of radioVectors */ class VectorFIFO { private: PointerFIFO mQ; Mutex mLock; public: unsigned size() {return mQ.size();} void put(radioVector *ptr) {ScopedLock lock(mLock); mQ.put((void*) ptr);} radioVector *get() { ScopedLock lock(mLock); return (radioVector*) mQ.get();} }; /** the basestation clock class */ class RadioClock { private: GSM::Time mClock; Mutex mLock; Signal updateSignal; public: /** Set clock */ //void set(const GSM::Time& wTime) { ScopedLock lock(mLock); mClock = wTime; updateSignal.signal();} void set(const GSM::Time& wTime) { ScopedLock lock(mLock); mClock = wTime; updateSignal.broadcast();;} /** Increment clock */ //void incTN() { ScopedLock lock(mLock); mClock.incTN(); updateSignal.signal();} void incTN() { ScopedLock lock(mLock); mClock.incTN(); updateSignal.broadcast();} /** Get clock value */ GSM::Time get() { ScopedLock lock(mLock); return mClock; } /** Wait until clock has changed */ //void wait() {ScopedLock lock(mLock); updateSignal.wait(mLock,1);} // FIXME -- If we take away the timeout, a lot of threads don't start. Why? void wait() {ScopedLock lock(mLock); updateSignal.wait(mLock);} }; /** class to interface the transceiver with the USRP */ class RadioInterface { private: Thread mAlignRadioServiceLoopThread; ///< thread that synchronizes transmit and receive sections VectorFIFO mReceiveFIFO; ///< FIFO that holds receive bursts RadioDevice *mRadio; ///< the USRP object short *sendBuffer; //[2*2*INCHUNK]; unsigned sendCursor; short *rcvBuffer; //[2*2*OUTCHUNK]; unsigned rcvCursor; bool underrun; ///< indicates writes to USRP are too slow bool overrun; ///< indicates reads from USRP are too slow TIMESTAMP writeTimestamp; ///< sample timestamp of next packet written to USRP TIMESTAMP readTimestamp; ///< sample timestamp of next packet read from USRP RadioClock mClock; ///< the basestation clock! int samplesPerSymbol; ///< samples per GSM symbol int receiveOffset; ///< offset b/w transmit and receive GSM timestamps, in timeslots int mRadioOversampling; int mTransceiverOversampling; bool mOn; ///< indicates radio is on double powerScaling; bool loadTest; int mNumARFCNs; signalVector *finalVec, *finalVec9; /** format samples to USRP */ short *radioifyVector(signalVector &wVector, short *shortVector, bool zeroOut); /** format samples from USRP */ void unRadioifyVector(short *shortVector, signalVector &wVector); /** push GSM bursts into the transmit buffer */ void pushBuffer(void); /** pull GSM bursts from the receive buffer */ void pullBuffer(void); public: /** start the interface */ void start(); /** constructor */ RadioInterface(RadioDevice* wRadio = NULL, int receiveOffset = 3, int wRadioOversampling = SAMPSPERSYM, int wTransceiverOversampling = SAMPSPERSYM, GSM::Time wStartTime = GSM::Time(0)); /** destructor */ ~RadioInterface(); void setSamplesPerSymbol(int wSamplesPerSymbol) {if (!mOn) samplesPerSymbol = wSamplesPerSymbol;} int getSamplesPerSymbol() { return samplesPerSymbol;} /** check for underrun, resets underrun value */ bool isUnderrun() { bool retVal = underrun; underrun = false; return retVal;} /** attach an existing USRP to this interface */ void attach(RadioDevice *wRadio, int wRadioOversampling) {if (!mOn) {mRadio = wRadio; mRadioOversampling = SAMPSPERSYM;} } /** return the receive FIFO */ VectorFIFO* receiveFIFO() { return &mReceiveFIFO;} /** return the basestation clock */ RadioClock* getClock(void) { return &mClock;}; /** set receive gain */ double setRxGain(double dB) {if (mRadio) return mRadio->setRxGain(dB); else return -1;} /** get receive gain */ double getRxGain(void) {if (mRadio) return mRadio->getRxGain(); else return -1;} /** set transmit frequency */ bool tuneTx(double freq); /** set receive frequency */ bool tuneRx(double freq); /** drive transmission of GSM bursts */ void driveTransmitRadio(signalVector &radioBurst, bool zeroBurst); /** drive reception of GSM bursts */ void driveReceiveRadio(); void setPowerAttenuation(double atten); /** returns the full-scale transmit amplitude **/ double fullScaleInputValue(); /** returns the full-scale receive amplitude **/ double fullScaleOutputValue(); /** set thread priority on current thread */ void setPriority() { mRadio->setPriority(); } protected: /** drive synchronization of Tx/Rx of USRP */ void alignRadio(); /** reset the interface */ void reset(); friend void *AlignRadioServiceLoopAdapter(RadioInterface*); }; /** synchronization thread loop */ void *AlignRadioServiceLoopAdapter(RadioInterface*);