dburgess | b3a0ca4 | 2011-10-12 07:44:40 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2008 Free Software Foundation, Inc. |
| 3 | * |
| 4 | * This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion. |
| 5 | * |
| 6 | * This use of this software may be subject to additional restrictions. |
| 7 | * See the LEGAL file in the main directory for details. |
| 8 | |
| 9 | This program is distributed in the hope that it will be useful, |
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| 12 | |
| 13 | */ |
| 14 | |
| 15 | |
| 16 | |
| 17 | #include "sigProcLib.h" |
| 18 | #include "GSMCommon.h" |
| 19 | #include "LinkedLists.h" |
| 20 | #include "radioDevice.h" |
| 21 | |
| 22 | /** samples per GSM symbol */ |
| 23 | #define SAMPSPERSYM 1 |
| 24 | #define INCHUNK (625) |
| 25 | #define OUTCHUNK (625) |
| 26 | |
| 27 | /** class used to organize GSM bursts by GSM timestamps */ |
| 28 | class radioVector : public signalVector { |
| 29 | |
| 30 | private: |
| 31 | |
| 32 | GSM::Time mTime; ///< the burst's GSM timestamp |
| 33 | |
| 34 | public: |
| 35 | /** constructor */ |
| 36 | radioVector(const signalVector& wVector, |
| 37 | GSM::Time& wTime): signalVector(wVector),mTime(wTime) {}; |
| 38 | |
| 39 | /** timestamp read and write operators */ |
| 40 | GSM::Time time() const { return mTime;} |
| 41 | void time(const GSM::Time& wTime) { mTime = wTime;} |
| 42 | |
| 43 | /** comparison operator, used for sorting */ |
| 44 | bool operator>(const radioVector& other) const {return mTime > other.mTime;} |
| 45 | |
| 46 | }; |
| 47 | |
| 48 | /** a priority queue of radioVectors, i.e. GSM bursts, sorted so that earliest element is at top */ |
| 49 | class VectorQueue : public InterthreadPriorityQueue<radioVector> { |
| 50 | |
| 51 | public: |
| 52 | |
| 53 | /** the top element of the queue */ |
| 54 | GSM::Time nextTime() const; |
| 55 | |
| 56 | /** |
| 57 | Get stale burst, if any. |
| 58 | @param targTime The target time. |
| 59 | @return Pointer to burst older than target time, removed from queue, or NULL. |
| 60 | */ |
| 61 | radioVector* getStaleBurst(const GSM::Time& targTime); |
| 62 | |
| 63 | /** |
| 64 | Get current burst, if any. |
| 65 | @param targTime The target time. |
| 66 | @return Pointer to burst at the target time, removed from queue, or NULL. |
| 67 | */ |
| 68 | radioVector* getCurrentBurst(const GSM::Time& targTime); |
| 69 | |
| 70 | |
| 71 | }; |
| 72 | |
| 73 | /** a FIFO of radioVectors */ |
| 74 | class VectorFIFO { |
| 75 | |
| 76 | private: |
| 77 | |
| 78 | PointerFIFO mQ; |
| 79 | Mutex mLock; |
| 80 | |
| 81 | public: |
| 82 | |
| 83 | unsigned size() {return mQ.size();} |
| 84 | |
| 85 | void put(radioVector *ptr) {ScopedLock lock(mLock); mQ.put((void*) ptr);} |
| 86 | |
| 87 | radioVector *get() { ScopedLock lock(mLock); return (radioVector*) mQ.get();} |
| 88 | |
| 89 | }; |
| 90 | |
| 91 | |
| 92 | /** the basestation clock class */ |
| 93 | class RadioClock { |
| 94 | |
| 95 | private: |
| 96 | |
| 97 | GSM::Time mClock; |
| 98 | Mutex mLock; |
| 99 | Signal updateSignal; |
| 100 | |
| 101 | public: |
| 102 | |
| 103 | /** Set clock */ |
| 104 | //void set(const GSM::Time& wTime) { ScopedLock lock(mLock); mClock = wTime; updateSignal.signal();} |
| 105 | void set(const GSM::Time& wTime) { ScopedLock lock(mLock); mClock = wTime; updateSignal.broadcast();;} |
| 106 | |
| 107 | /** Increment clock */ |
| 108 | //void incTN() { ScopedLock lock(mLock); mClock.incTN(); updateSignal.signal();} |
| 109 | void incTN() { ScopedLock lock(mLock); mClock.incTN(); updateSignal.broadcast();} |
| 110 | |
| 111 | /** Get clock value */ |
| 112 | GSM::Time get() { ScopedLock lock(mLock); return mClock; } |
| 113 | |
| 114 | /** Wait until clock has changed */ |
| 115 | //void wait() {ScopedLock lock(mLock); updateSignal.wait(mLock,1);} |
| 116 | // FIXME -- If we take away the timeout, a lot of threads don't start. Why? |
| 117 | void wait() {ScopedLock lock(mLock); updateSignal.wait(mLock);} |
| 118 | |
| 119 | }; |
| 120 | |
| 121 | |
| 122 | /** class to interface the transceiver with the USRP */ |
| 123 | class RadioInterface { |
| 124 | |
| 125 | private: |
| 126 | |
| 127 | Thread mAlignRadioServiceLoopThread; ///< thread that synchronizes transmit and receive sections |
| 128 | |
| 129 | VectorFIFO mReceiveFIFO; ///< FIFO that holds receive bursts |
| 130 | |
| 131 | RadioDevice *mRadio; ///< the USRP object |
| 132 | |
| 133 | short *sendBuffer; //[2*2*INCHUNK]; |
| 134 | unsigned sendCursor; |
| 135 | |
| 136 | short *rcvBuffer; //[2*2*OUTCHUNK]; |
| 137 | unsigned rcvCursor; |
| 138 | |
| 139 | bool underrun; ///< indicates writes to USRP are too slow |
| 140 | bool overrun; ///< indicates reads from USRP are too slow |
| 141 | TIMESTAMP writeTimestamp; ///< sample timestamp of next packet written to USRP |
| 142 | TIMESTAMP readTimestamp; ///< sample timestamp of next packet read from USRP |
| 143 | |
| 144 | RadioClock mClock; ///< the basestation clock! |
| 145 | |
| 146 | int samplesPerSymbol; ///< samples per GSM symbol |
| 147 | int receiveOffset; ///< offset b/w transmit and receive GSM timestamps, in timeslots |
| 148 | int mRadioOversampling; |
| 149 | int mTransceiverOversampling; |
| 150 | |
| 151 | bool mOn; ///< indicates radio is on |
| 152 | |
| 153 | double powerScaling; |
| 154 | |
| 155 | bool loadTest; |
| 156 | int mNumARFCNs; |
| 157 | signalVector *finalVec, *finalVec9; |
| 158 | |
| 159 | /** format samples to USRP */ |
kurtis.heimerl | ee5347a | 2011-11-26 03:18:05 +0000 | [diff] [blame^] | 160 | short *radioifyVector(signalVector &wVector, |
| 161 | short *shortVector, |
| 162 | float scale, |
| 163 | bool zeroOut); |
dburgess | b3a0ca4 | 2011-10-12 07:44:40 +0000 | [diff] [blame] | 164 | |
| 165 | /** format samples from USRP */ |
| 166 | void unRadioifyVector(short *shortVector, signalVector &wVector); |
| 167 | |
| 168 | /** push GSM bursts into the transmit buffer */ |
| 169 | void pushBuffer(void); |
| 170 | |
| 171 | /** pull GSM bursts from the receive buffer */ |
| 172 | void pullBuffer(void); |
| 173 | |
| 174 | public: |
| 175 | |
| 176 | /** start the interface */ |
| 177 | void start(); |
| 178 | |
| 179 | /** constructor */ |
| 180 | RadioInterface(RadioDevice* wRadio = NULL, |
| 181 | int receiveOffset = 3, |
| 182 | int wRadioOversampling = SAMPSPERSYM, |
| 183 | int wTransceiverOversampling = SAMPSPERSYM, |
| 184 | GSM::Time wStartTime = GSM::Time(0)); |
| 185 | |
| 186 | /** destructor */ |
| 187 | ~RadioInterface(); |
| 188 | |
| 189 | void setSamplesPerSymbol(int wSamplesPerSymbol) {if (!mOn) samplesPerSymbol = wSamplesPerSymbol;} |
| 190 | |
| 191 | int getSamplesPerSymbol() { return samplesPerSymbol;} |
| 192 | |
| 193 | /** check for underrun, resets underrun value */ |
| 194 | bool isUnderrun() { bool retVal = underrun; underrun = false; return retVal;} |
| 195 | |
| 196 | /** attach an existing USRP to this interface */ |
| 197 | void attach(RadioDevice *wRadio, int wRadioOversampling) {if (!mOn) {mRadio = wRadio; mRadioOversampling = SAMPSPERSYM;} } |
| 198 | |
| 199 | /** return the receive FIFO */ |
| 200 | VectorFIFO* receiveFIFO() { return &mReceiveFIFO;} |
| 201 | |
| 202 | /** return the basestation clock */ |
| 203 | RadioClock* getClock(void) { return &mClock;}; |
| 204 | |
| 205 | /** set receive gain */ |
| 206 | double setRxGain(double dB) {if (mRadio) return mRadio->setRxGain(dB); else return -1;} |
| 207 | |
| 208 | /** get receive gain */ |
| 209 | double getRxGain(void) {if (mRadio) return mRadio->getRxGain(); else return -1;} |
| 210 | |
| 211 | |
| 212 | /** set transmit frequency */ |
| 213 | bool tuneTx(double freq); |
| 214 | |
| 215 | /** set receive frequency */ |
| 216 | bool tuneRx(double freq); |
| 217 | |
| 218 | /** drive transmission of GSM bursts */ |
| 219 | void driveTransmitRadio(signalVector &radioBurst, bool zeroBurst); |
| 220 | |
| 221 | /** drive reception of GSM bursts */ |
| 222 | void driveReceiveRadio(); |
| 223 | |
| 224 | void setPowerAttenuation(double atten); |
| 225 | |
| 226 | /** returns the full-scale transmit amplitude **/ |
| 227 | double fullScaleInputValue(); |
| 228 | |
| 229 | /** returns the full-scale receive amplitude **/ |
| 230 | double fullScaleOutputValue(); |
| 231 | |
kurtis.heimerl | 6b495a5 | 2011-11-26 03:17:21 +0000 | [diff] [blame] | 232 | /** set thread priority on current thread */ |
| 233 | void setPriority() { mRadio->setPriority(); } |
dburgess | b3a0ca4 | 2011-10-12 07:44:40 +0000 | [diff] [blame] | 234 | |
| 235 | protected: |
| 236 | |
| 237 | /** drive synchronization of Tx/Rx of USRP */ |
| 238 | void alignRadio(); |
| 239 | |
| 240 | /** reset the interface */ |
| 241 | void reset(); |
| 242 | |
| 243 | friend void *AlignRadioServiceLoopAdapter(RadioInterface*); |
| 244 | |
| 245 | }; |
| 246 | |
| 247 | /** synchronization thread loop */ |
| 248 | void *AlignRadioServiceLoopAdapter(RadioInterface*); |