diff options
-rw-r--r-- | Transceiver52M/Transceiver.cpp | 403 | ||||
-rw-r--r-- | Transceiver52M/Transceiver.h | 88 | ||||
-rw-r--r-- | Transceiver52M/UHDDevice.cpp | 263 | ||||
-rw-r--r-- | Transceiver52M/USRPDevice.cpp | 114 | ||||
-rw-r--r-- | Transceiver52M/USRPDevice.h | 45 | ||||
-rw-r--r-- | Transceiver52M/radioDevice.h | 33 | ||||
-rw-r--r-- | Transceiver52M/radioInterface.cpp | 166 | ||||
-rw-r--r-- | Transceiver52M/radioInterface.h | 41 | ||||
-rw-r--r-- | Transceiver52M/radioInterfaceResamp.cpp | 37 | ||||
-rw-r--r-- | Transceiver52M/radioVector.cpp | 15 | ||||
-rw-r--r-- | Transceiver52M/radioVector.h | 10 | ||||
-rw-r--r-- | Transceiver52M/runTransceiver.cpp | 37 |
12 files changed, 743 insertions, 509 deletions
diff --git a/Transceiver52M/Transceiver.cpp b/Transceiver52M/Transceiver.cpp index fd6a008..2d4a3cb 100644 --- a/Transceiver52M/Transceiver.cpp +++ b/Transceiver52M/Transceiver.cpp @@ -76,142 +76,172 @@ void TransceiverState::init(size_t slot, signalVector *burst) Transceiver::Transceiver(int wBasePort, const char *TRXAddress, - int wSPS, + size_t wSPS, size_t wChans, GSM::Time wTransmitLatency, RadioInterface *wRadioInterface) : mBasePort(wBasePort), mAddr(TRXAddress), - mDataSocket(NULL), mCtrlSocket(NULL), mClockSocket(NULL), - mSPSTx(wSPS), mSPSRx(1), mNoises(NOISE_CNT) + mTransmitLatency(wTransmitLatency), mClockSocket(NULL), mRadioInterface(wRadioInterface), + mNoiseLev(0.0), mNoises(NOISE_CNT), mSPSTx(wSPS), mSPSRx(1), mChans(wChans), + mOn(false), mTxFreq(0.0), mRxFreq(0.0), mPower(-10), mMaxExpectedDelay(0) { GSM::Time startTime(random() % gHyperframe,0); - mRxServiceLoopThread = new Thread(32768); - mTxServiceLoopThread = new Thread(32768); - mControlServiceLoopThread = new Thread(32768); ///< thread to process control messages from GSM core - mTransmitPriorityQueueServiceLoopThread = new Thread(32768);///< thread to process transmit bursts from GSM core + mRxLowerLoopThread = new Thread(32768); + mTxLowerLoopThread = new Thread(32768); - mRadioInterface = wRadioInterface; - mTransmitLatency = wTransmitLatency; mTransmitDeadlineClock = startTime; mLastClockUpdateTime = startTime; mLatencyUpdateTime = startTime; mRadioInterface->getClock()->set(startTime); - mMaxExpectedDelay = 0; txFullScale = mRadioInterface->fullScaleInputValue(); rxFullScale = mRadioInterface->fullScaleOutputValue(); - - mOn = false; - mTxFreq = 0.0; - mRxFreq = 0.0; - mPower = -10; - mNoiseLev = 0.0; } Transceiver::~Transceiver() { sigProcLibDestroy(); - mTransmitPriorityQueue.clear(); delete mClockSocket; - delete mCtrlSocket; - delete mDataSocket; + + for (size_t i = 0; i < mChans; i++) { + mTxPriorityQueues[i].clear(); + delete mCtrlSockets[i]; + delete mDataSockets[i]; + } } bool Transceiver::init() { signalVector *burst; + if (!mChans) { + LOG(ALERT) << "No channels assigned"; + return false; + } + if (!sigProcLibSetup(mSPSTx)) { LOG(ALERT) << "Failed to initialize signal processing library"; return false; } + mDataSockets.resize(mChans); + mCtrlSockets.resize(mChans); + + mControlServiceLoopThreads.resize(mChans); + mTxPriorityQueueServiceLoopThreads.resize(mChans); + mRxServiceLoopThreads.resize(mChans); + + mTxPriorityQueues.resize(mChans); + mReceiveFIFO.resize(mChans); + mStates.resize(mChans); + mClockSocket = new UDPSocket(mBasePort, mAddr.c_str(), mBasePort + 100); - mCtrlSocket = new UDPSocket(mBasePort + 1, mAddr.c_str(), mBasePort + 101); - mDataSocket = new UDPSocket(mBasePort + 2, mAddr.c_str(), mBasePort + 102); - for (size_t n = 0; n < 8; n++) { - burst = modulateBurst(gDummyBurst, 8 + (n % 4 == 0), mSPSTx); - scaleVector(*burst, txFullScale); - mState.init(n, burst); - mState.chanEstimateTime[n] = mTransmitDeadlineClock; + for (size_t i = 0; i < mChans; i++) { + mDataSockets[i] = new UDPSocket(mBasePort + 2 * i + 2, mAddr.c_str(), + mBasePort + 2 * i + 102); + mCtrlSockets[i] = new UDPSocket(mBasePort + 2 * i + 1, mAddr.c_str(), + mBasePort + 2 * i + 101); + } + + for (size_t i = 0; i < mChans; i++) { + mControlServiceLoopThreads[i] = new Thread(32768); + mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768); + mRxServiceLoopThreads[i] = new Thread(32768); - delete burst; + for (size_t n = 0; n < 8; n++) { + burst = modulateBurst(gDummyBurst, 8 + (n % 4 == 0), mSPSTx); + scaleVector(*burst, txFullScale); + mStates[i].init(n, burst); + delete burst; + } } return true; } -void Transceiver::addRadioVector(BitVector &burst, - int RSSI, - GSM::Time &wTime) +void Transceiver::addRadioVector(size_t chan, BitVector &burst, + int RSSI, GSM::Time &wTime) { + if (chan >= mTxPriorityQueues.size()) { + LOG(ALERT) << "Invalid channel " << chan; + return; + } + // modulate and stick into queue signalVector* modBurst = modulateBurst(burst, 8 + (wTime.TN() % 4 == 0), mSPSTx); scaleVector(*modBurst,txFullScale * pow(10,-RSSI/10)); radioVector *newVec = new radioVector(*modBurst,wTime); - mTransmitPriorityQueue.write(newVec); + mTxPriorityQueues[chan].write(newVec); delete modBurst; } void Transceiver::pushRadioVector(GSM::Time &nowTime) { + int TN, modFN; + radioVector *burst; + TransceiverState *state; + std::vector<signalVector *> bursts(mChans); + std::vector<bool> zeros(mChans); - // dump stale bursts, if any - while (radioVector* staleBurst = mTransmitPriorityQueue.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() % mState.fillerModulus[TN]; - delete mState.fillerTable[modFN][TN]; - mState.fillerTable[modFN][TN] = staleBurst; - } - - int TN = nowTime.TN(); - int modFN = nowTime.FN() % mState.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; - delete mState.fillerTable[modFN][TN]; - mState.fillerTable[modFN][TN] = new signalVector(*(next)); - mRadioInterface->driveTransmitRadio(*(next), mState.chanType[TN] == NONE); - delete next; - return; + for (size_t i = 0; i < mChans; i ++) { + state = &mStates[i]; + + while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) { + LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface"; + + TN = burst->getTime().TN(); + modFN = burst->getTime().FN() % state->fillerModulus[TN]; + + delete state->fillerTable[modFN][TN]; + state->fillerTable[modFN][TN] = burst; + } + + TN = nowTime.TN(); + modFN = nowTime.FN() % state->fillerModulus[TN]; + + bursts[i] = state->fillerTable[modFN][TN]; + zeros[i] = state->chanType[TN] == NONE; + + if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) { + delete state->fillerTable[modFN][TN]; + state->fillerTable[modFN][TN] = burst; + bursts[i] = burst; + } } - // otherwise, pull filler data, and push to radio FIFO - mRadioInterface->driveTransmitRadio(*(mState.fillerTable[modFN][TN]), - mState.chanType[TN]==NONE); + mRadioInterface->driveTransmitRadio(bursts, zeros); + + return; } -void Transceiver::setModulus(int timeslot) +void Transceiver::setModulus(size_t timeslot, size_t chan) { - switch (mState.chanType[timeslot]) { + TransceiverState *state = &mStates[chan]; + + switch (state->chanType[timeslot]) { case NONE: case I: case II: case III: case FILL: - mState.fillerModulus[timeslot] = 26; + state->fillerModulus[timeslot] = 26; break; case IV: case VI: case V: - mState.fillerModulus[timeslot] = 51; + state->fillerModulus[timeslot] = 51; break; //case V: case VII: - mState.fillerModulus[timeslot] = 102; + state->fillerModulus[timeslot] = 102; break; case XIII: - mState.fillerModulus[timeslot] = 52; + state->fillerModulus[timeslot] = 52; break; default: break; @@ -219,13 +249,14 @@ void Transceiver::setModulus(int timeslot) } -Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime) +Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime, + size_t chan) { - + TransceiverState *state = &mStates[chan]; unsigned burstTN = currTime.TN(); unsigned burstFN = currTime.FN(); - switch (mState.chanType[burstTN]) { + switch (state->chanType[burstTN]) { case NONE: return OFF; break; @@ -287,25 +318,24 @@ Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime) return OFF; break; } - } -SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, - int &RSSI, - int &timingOffset) +SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI, + int &timingOffset, size_t chan) { - bool needDFE = false, success = false, estimateChannel = false; + bool needDFE = false; + bool success = false; complex amp = 0.0; float TOA = 0.0, avg = 0.0; - signalVector *chanResponse; + TransceiverState *state = &mStates[chan]; - radioVector *rxBurst = (radioVector *) mReceiveFIFO->get(); + radioVector *rxBurst = (radioVector *) mReceiveFIFO[chan]->read(); if (!rxBurst) return NULL; int timeslot = rxBurst->getTime().TN(); - CorrType corrType = expectedCorrType(rxBurst->getTime()); + CorrType corrType = expectedCorrType(rxBurst->getTime(), chan); if ((corrType==OFF) || (corrType==IDLE)) { delete rxBurst; @@ -323,55 +353,58 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, // run the proper correlator if (corrType==TSC) { LOG(DEBUG) << "looking for TSC at time: " << rxBurst->getTime(); - double framesElapsed = rxBurst->getTime() - mState.chanEstimateTime[timeslot]; - if ((framesElapsed > 50) || (!mState.chanResponse[timeslot])) { - delete mState.chanResponse[timeslot]; - delete mState.DFEForward[timeslot]; - delete mState.DFEFeedback[timeslot]; - - mState.chanResponse[timeslot] = NULL; - mState.DFEForward[timeslot] = NULL; - mState.DFEFeedback[timeslot] = NULL; - - if (needDFE) - estimateChannel = true; + signalVector *channelResp; + double framesElapsed = rxBurst->getTime() - state->chanEstimateTime[timeslot]; + bool estimateChannel = false; + if ((framesElapsed > 50) || (state->chanResponse[timeslot]==NULL)) { + if (state->chanResponse[timeslot]) + delete state->chanResponse[timeslot]; + if (state->DFEForward[timeslot]) + delete state->DFEForward[timeslot]; + if (state->DFEFeedback[timeslot]) + delete state->DFEFeedback[timeslot]; + + state->chanResponse[timeslot] = NULL; + state->DFEForward[timeslot] = NULL; + state->DFEFeedback[timeslot] = NULL; + estimateChannel = true; } - + if (!needDFE) estimateChannel = false; float chanOffset; success = analyzeTrafficBurst(*vectorBurst, - mTSC, - 5.0, - mSPSRx, - &, - &TOA, - mMaxExpectedDelay, - estimateChannel, - &chanResponse, - &chanOffset); + mTSC, + 5.0, + mSPSRx, + &, + &TOA, + mMaxExpectedDelay, + estimateChannel, + &channelResp, + &chanOffset); if (success) { - mState.SNRestimate[timeslot] = amp.norm2() / (mNoiseLev * mNoiseLev+1.0); - if (estimateChannel) { - mState.chanResponse[timeslot] = chanResponse; - mState.chanRespOffset[timeslot] = chanOffset; - mState.chanRespAmplitude[timeslot] = amp; - scaleVector(*chanResponse, complex(1.0,0.0) / amp); - - designDFE(*chanResponse, mState.SNRestimate[timeslot], 7, - &mState.DFEForward[timeslot], - &mState.DFEFeedback[timeslot]); + state->SNRestimate[timeslot] = amp.norm2() / (mNoiseLev * mNoiseLev + 1.0); - mState.chanEstimateTime[timeslot] = rxBurst->getTime(); + if (estimateChannel) { + state->chanResponse[timeslot] = channelResp; + state->chanRespOffset[timeslot] = chanOffset; + state->chanRespAmplitude[timeslot] = amp; + scaleVector(*channelResp, complex(1.0, 0.0) / amp); + designDFE(*channelResp, state->SNRestimate[timeslot], + 7, &state->DFEForward[timeslot], + &state->DFEFeedback[timeslot]); + + state->chanEstimateTime[timeslot] = rxBurst->getTime(); } } else { - mState.chanResponse[timeslot] = NULL; + state->chanResponse[timeslot] = NULL; mNoises.insert(avg); } } else { // RACH burst - if (success = detectRACHBurst(*vectorBurst, 6.0, mSPSRx, &, &TOA)) - mState.chanResponse[timeslot] = NULL; + if ((success = detectRACHBurst(*vectorBurst, 6.0, mSPSRx, &, &TOA))) + state->chanResponse[timeslot] = NULL; else mNoises.insert(avg); } @@ -382,12 +415,12 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, if ((corrType==RACH) || (!needDFE)) { burst = demodulateBurst(*vectorBurst, mSPSRx, amp, TOA); } else { - scaleVector(*vectorBurst,complex(1.0,0.0) / amp); + scaleVector(*vectorBurst, complex(1.0, 0.0) / amp); burst = equalizeBurst(*vectorBurst, - TOA - mState.chanRespOffset[timeslot], - mSPSRx, - *mState.DFEForward[timeslot], - *mState.DFEFeedback[timeslot]); + TOA - state->chanRespOffset[timeslot], + mSPSRx, + *state->DFEForward[timeslot], + *state->DFEFeedback[timeslot]); } wTime = rxBurst->getTime(); RSSI = (int) floor(20.0*log10(rxFullScale/avg)); @@ -395,8 +428,6 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, timingOffset = (int) round(TOA * 256.0 / mSPSRx); } - //if (burst) LOG(DEBUG) << "burst: " << *burst << '\n'; - delete rxBurst; return burst; @@ -404,20 +435,24 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, void Transceiver::start() { - mControlServiceLoopThread->start((void * (*)(void*))ControlServiceLoopAdapter,(void*) this); + TransceiverChannel *chan; + + for (size_t i = 0; i < mControlServiceLoopThreads.size(); i++) { + chan = new TransceiverChannel(this, i); + mControlServiceLoopThreads[i]->start((void * (*)(void*)) + ControlServiceLoopAdapter, (void*) chan); + } } void Transceiver::reset() { - mTransmitPriorityQueue.clear(); - //mTransmitFIFO->clear(); - //mReceiveFIFO->clear(); + for (size_t i = 0; i < mTxPriorityQueues.size(); i++) + mTxPriorityQueues[i].clear(); } -void Transceiver::driveControl() +void Transceiver::driveControl(size_t chan) { - int MAX_PACKET_LENGTH = 100; // check control socket @@ -425,7 +460,7 @@ void Transceiver::driveControl() int msgLen = -1; buffer[0] = '\0'; - msgLen = mCtrlSocket->read(buffer); + msgLen = mCtrlSockets[chan]->read(buffer); if (msgLen < 1) { return; @@ -436,8 +471,9 @@ void Transceiver::driveControl() char response[MAX_PACKET_LENGTH]; sscanf(buffer,"%3s %s",cmdcheck,command); - - writeClockInterface(); + + if (!chan) + writeClockInterface(); if (strcmp(cmdcheck,"CMD")!=0) { LOG(WARNING) << "bogus message on control interface"; @@ -455,17 +491,28 @@ void Transceiver::driveControl() sprintf(response,"RSP POWERON 1"); else { sprintf(response,"RSP POWERON 0"); - if (!mOn) { + if (!chan && !mOn) { // Prepare for thread start mPower = -20; mRadioInterface->start(); // Start radio interface threads. - mTxServiceLoopThread->start((void * (*)(void*))TxServiceLoopAdapter,(void*) this); - mRxServiceLoopThread->start((void * (*)(void*))RxServiceLoopAdapter,(void*) this); - mTransmitPriorityQueueServiceLoopThread->start((void * (*)(void*))TransmitPriorityQueueServiceLoopAdapter,(void*) this); - writeClockInterface(); + mTxLowerLoopThread->start((void * (*)(void*)) + TxLowerLoopAdapter,(void*) this); + mRxLowerLoopThread->start((void * (*)(void*)) + RxLowerLoopAdapter,(void*) this); + + for (size_t i = 0; i < mChans; i++) { + TransceiverChannel *chan = new TransceiverChannel(this, i); + mRxServiceLoopThreads[i]->start((void * (*)(void*)) + RxUpperLoopAdapter, (void*) chan); + + chan = new TransceiverChannel(this, i); + mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*)) + TxUpperLoopAdapter, (void*) chan); + } + writeClockInterface(); mOn = true; } } @@ -481,7 +528,7 @@ void Transceiver::driveControl() //set expected maximum time-of-arrival int newGain; sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain); - newGain = mRadioInterface->setRxGain(newGain); + newGain = mRadioInterface->setRxGain(newGain, chan); sprintf(response,"RSP SETRXGAIN 0 %d",newGain); } else if (strcmp(command,"NOISELEV")==0) { @@ -501,7 +548,7 @@ void Transceiver::driveControl() sprintf(response,"RSP SETPOWER 1 %d",dbPwr); else { mPower = dbPwr; - mRadioInterface->setPowerAttenuation(dbPwr); + mRadioInterface->setPowerAttenuation(dbPwr, chan); sprintf(response,"RSP SETPOWER 0 %d",dbPwr); } } @@ -522,7 +569,7 @@ void Transceiver::driveControl() int freqKhz; sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz); mRxFreq = freqKhz*1.0e3+FREQOFFSET; - if (!mRadioInterface->tuneRx(mRxFreq)) { + if (!mRadioInterface->tuneRx(mRxFreq, chan)) { LOG(ALERT) << "RX failed to tune"; sprintf(response,"RSP RXTUNE 1 %d",freqKhz); } @@ -535,7 +582,7 @@ void Transceiver::driveControl() sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz); //freqKhz = 890e3; mTxFreq = freqKhz*1.0e3+FREQOFFSET; - if (!mRadioInterface->tuneTx(mTxFreq)) { + if (!mRadioInterface->tuneTx(mTxFreq, chan)) { LOG(ALERT) << "TX failed to tune"; sprintf(response,"RSP TXTUNE 1 %d",freqKhz); } @@ -564,8 +611,8 @@ void Transceiver::driveControl() sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode); return; } - mState.chanType[timeslot] = corrCode; - setModulus(timeslot); + mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode; + setModulus(timeslot, chan); sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode); } @@ -573,16 +620,15 @@ void Transceiver::driveControl() LOG(WARNING) << "bogus command " << command << " on control interface."; } - mCtrlSocket->write(response, strlen(response) + 1); + mCtrlSockets[chan]->write(response, strlen(response) + 1); } -bool Transceiver::driveTransmitPriorityQueue() +bool Transceiver::driveTxPriorityQueue(size_t chan) { - char buffer[gSlotLen+50]; // check data socket - size_t msgLen = mDataSocket->read(buffer); + size_t msgLen = mDataSockets[chan]->read(buffer); if (msgLen!=gSlotLen+1+4+1) { LOG(ERR) << "badly formatted packet on GSM->TRX interface"; @@ -613,9 +659,11 @@ bool Transceiver::driveTransmitPriorityQueue() // periodically update GSM core clock LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock << " mLastClockUpdateTime " << mLastClockUpdateTime; - if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0)) - writeClockInterface(); + if (!chan) { + if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0)) + writeClockInterface(); + } LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot); @@ -627,27 +675,28 @@ bool Transceiver::driveTransmitPriorityQueue() *itr++ = *bufferItr++; GSM::Time currTime = GSM::Time(frameNum,timeSlot); - - addRadioVector(newBurst,RSSI,currTime); - - LOG(DEBUG) "added burst - time: " << currTime << ", RSSI: " << RSSI; // << ", data: " << newBurst; + + addRadioVector(chan, newBurst, RSSI, currTime); return true; } - -void Transceiver::driveReceiveFIFO() + +void Transceiver::driveReceiveRadio() { + if (!mRadioInterface->driveReceiveRadio()) + usleep(100000); +} +void Transceiver::driveReceiveFIFO(size_t chan) +{ SoftVector *rxBurst = NULL; int RSSI; int TOA; // in 1/256 of a symbol GSM::Time burstTime; - mRadioInterface->driveReceiveRadio(); - - rxBurst = pullRadioVector(burstTime,RSSI,TOA); + rxBurst = pullRadioVector(burstTime, RSSI, TOA, chan); if (rxBurst) { @@ -672,11 +721,11 @@ void Transceiver::driveReceiveFIFO() burstString[gSlotLen+9] = '\0'; delete rxBurst; - mDataSocket->write(burstString, gSlotLen + 10); + mDataSockets[chan]->write(burstString,gSlotLen+10); } } -void Transceiver::driveTransmitFIFO() +void Transceiver::driveTxFIFO() { /** @@ -744,46 +793,70 @@ void Transceiver::writeClockInterface() } -void *RxServiceLoopAdapter(Transceiver *transceiver) +void *RxUpperLoopAdapter(TransceiverChannel *chan) +{ + Transceiver *trx = chan->trx; + size_t num = chan->num; + + delete chan; + + while (1) { + trx->driveReceiveFIFO(num); + pthread_testcancel(); + } + return NULL; +} + +void *RxLowerLoopAdapter(Transceiver *transceiver) { transceiver->setPriority(); while (1) { - transceiver->driveReceiveFIFO(); + transceiver->driveReceiveRadio(); pthread_testcancel(); } return NULL; } -void *TxServiceLoopAdapter(Transceiver *transceiver) +void *TxLowerLoopAdapter(Transceiver *transceiver) { while (1) { - transceiver->driveTransmitFIFO(); + transceiver->driveTxFIFO(); pthread_testcancel(); } return NULL; } -void *ControlServiceLoopAdapter(Transceiver *transceiver) +void *ControlServiceLoopAdapter(TransceiverChannel *chan) { + Transceiver *trx = chan->trx; + size_t num = chan->num; + + delete chan; + while (1) { - transceiver->driveControl(); + trx->driveControl(num); pthread_testcancel(); } return NULL; } -void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *transceiver) +void *TxUpperLoopAdapter(TransceiverChannel *chan) { + Transceiver *trx = chan->trx; + size_t num = chan->num; + + delete chan; + while (1) { bool stale = false; // Flush the UDP packets until a successful transfer. - while (!transceiver->driveTransmitPriorityQueue()) { - stale = true; + while (!trx->driveTxPriorityQueue(num)) { + stale = true; } - if (stale) { + if (!num && stale) { // If a packet was stale, remind the GSM stack of the clock. - transceiver->writeClockInterface(); + trx->writeClockInterface(); } pthread_testcancel(); } diff --git a/Transceiver52M/Transceiver.h b/Transceiver52M/Transceiver.h index 1f8bed2..4356ef2 100644 --- a/Transceiver52M/Transceiver.h +++ b/Transceiver52M/Transceiver.h @@ -86,18 +86,18 @@ private: GSM::Time mTransmitLatency; ///< latency between basestation clock and transmit deadline clock GSM::Time mLatencyUpdateTime; ///< last time latency was updated - UDPSocket *mDataSocket; ///< socket for writing to/reading from GSM core - UDPSocket *mCtrlSocket; ///< socket for writing/reading control commands from GSM core - UDPSocket *mClockSocket; ///< socket for writing clock updates to GSM core + std::vector<UDPSocket *> mDataSockets; ///< socket for writing to/reading from GSM core + std::vector<UDPSocket *> mCtrlSockets; ///< 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 - VectorFIFO* mReceiveFIFO; ///< radioInterface FIFO of receive bursts + std::vector<VectorQueue> mTxPriorityQueues; ///< priority queue of transmit bursts received from GSM core + std::vector<VectorFIFO *> mReceiveFIFO; ///< radioInterface FIFO of receive bursts - Thread *mRxServiceLoopThread; ///< thread to pull bursts into receive FIFO - Thread *mTxServiceLoopThread; ///< thread to push bursts into transmit FIFO - Thread *mControlServiceLoopThread; ///< thread to process control messages from GSM core - Thread *mTransmitPriorityQueueServiceLoopThread;///< thread to process transmit bursts from GSM core + std::vector<Thread *> mRxServiceLoopThreads; ///< thread to pull bursts into receive FIFO + Thread *mRxLowerLoopThread; ///< thread to pull bursts into receive FIFO + Thread *mTxLowerLoopThread; ///< thread to push bursts into transmit FIFO + std::vector<Thread *> mControlServiceLoopThreads; ///< thread to process control messages from GSM core + std::vector<Thread *> mTxPriorityQueueServiceLoopThreads; ///< thread to process transmit bursts from GSM core GSM::Time mTransmitDeadlineClock; ///< deadline for pushing bursts into transmit FIFO GSM::Time mLastClockUpdateTime; ///< last time clock update was sent up to core @@ -118,29 +118,28 @@ private: noiseVector mNoises; ///< Vector holding running noise measurements /** modulate and add a burst to the transmit queue */ - void addRadioVector(BitVector &burst, - int RSSI, - GSM::Time &wTime); + void addRadioVector(size_t chan, 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); - + /** Pull and demodulate a burst from the receive FIFO */ + SoftVector *pullRadioVector(GSM::Time &wTime, int &RSSI, + int &timingOffset, size_t chan = 0); + /** Set modulus for specific timeslot */ - void setModulus(int timeslot); + void setModulus(size_t timeslot, size_t chan); /** return the expected burst type for the specified timestamp */ - CorrType expectedCorrType(GSM::Time currTime); + CorrType expectedCorrType(GSM::Time currTime, size_t chan); /** send messages over the clock socket */ void writeClockInterface(void); int mSPSTx; ///< number of samples per Tx symbol int mSPSRx; ///< number of samples per Rx symbol + size_t mChans; bool mOn; ///< flag to indicate that transceiver is powered on double mTxFreq; ///< the transmit frequency @@ -149,7 +148,7 @@ private: unsigned mTSC; ///< the midamble sequence code unsigned mMaxExpectedDelay; ///< maximum expected time-of-arrival offset in GSM symbols - TransceiverState mState; + std::vector<TransceiverState> mStates; public: @@ -162,10 +161,10 @@ public: */ Transceiver(int wBasePort, const char *TRXAddress, - int wSPS, + size_t wSPS, size_t chans, GSM::Time wTransmitLatency, RadioInterface *wRadioInterface); - + /** Destructor */ ~Transceiver(); @@ -174,10 +173,14 @@ public: bool init(); /** attach the radioInterface receive FIFO */ - void receiveFIFO(VectorFIFO *wFIFO) { mReceiveFIFO = wFIFO;} + bool receiveFIFO(VectorFIFO *wFIFO, size_t chan) + { + if (chan >= mReceiveFIFO.size()) + return false; - /** attach the radioInterface transmit FIFO */ - void transmitFIFO(VectorFIFO *wFIFO) { mTransmitFIFO = wFIFO;} + mReceiveFIFO[chan] = wFIFO; + return true; + } /** Codes for channel combinations */ typedef enum { @@ -200,29 +203,34 @@ public: } ChannelCombination; protected: + /** drive lower receive I/O and burst generation */ + void driveReceiveRadio(); - /** drive reception and demodulation of GSM bursts */ - void driveReceiveFIFO(); + /** drive demodulation of GSM bursts */ + void driveReceiveFIFO(size_t chan); /** drive transmission of GSM bursts */ - void driveTransmitFIFO(); + void driveTxFIFO(); /** drive handling of control messages from GSM core */ - void driveControl(); + void driveControl(size_t chan); /** drive modulation and sorting of GSM bursts from GSM core @return true if a burst was transferred successfully */ - bool driveTransmitPriorityQueue(); + bool driveTxPriorityQueue(size_t chan); - friend void *RxServiceLoopAdapter(Transceiver *); + friend void *RxUpperLoopAdapter(TransceiverChannel *); - friend void *TxServiceLoopAdapter(Transceiver *); + friend void *TxUpperLoopAdapter(TransceiverChannel *); - friend void *ControlServiceLoopAdapter(Transceiver *); + friend void *RxLowerLoopAdapter(Transceiver *); + + friend void *TxLowerLoopAdapter(Transceiver *); + + friend void *ControlServiceLoopAdapter(TransceiverChannel *); - friend void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *); void reset(); @@ -231,13 +239,15 @@ protected: }; +void *RxUpperLoopAdapter(TransceiverChannel *); + /** Main drive threads */ -void *RxServiceLoopAdapter(Transceiver *); -void *TxServiceLoopAdapter(Transceiver *); +void *RxLowerLoopAdapter(Transceiver *); +void *TxLowerLoopAdapter(Transceiver *); /** control message handler thread loop */ -void *ControlServiceLoopAdapter(Transceiver *); +void *ControlServiceLoopAdapter(TransceiverChannel *); /** transmit queueing thread loop */ -void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *); +void *TxUpperLoopAdapter(TransceiverChannel *); diff --git a/Transceiver52M/UHDDevice.cpp b/Transceiver52M/UHDDevice.cpp index 7a1a74d..224ebd0 100644 --- a/Transceiver52M/UHDDevice.cpp +++ b/Transceiver52M/UHDDevice.cpp @@ -211,7 +211,7 @@ private: */ class uhd_device : public RadioDevice { public: - uhd_device(int sps, bool skip_rx); + uhd_device(size_t sps, size_t chans); ~uhd_device(); int open(const std::string &args, bool extref); @@ -221,16 +221,16 @@ public: void setPriority(); enum TxWindowType getWindowType() { return tx_window; } - int readSamples(short *buf, int len, bool *overrun, + int readSamples(std::vector<short *> &bufs, int len, bool *overrun, TIMESTAMP timestamp, bool *underrun, unsigned *RSSI); - int writeSamples(short *buf, int len, bool *underrun, + int writeSamples(std::vector<short *> &bufs, int len, bool *underrun, TIMESTAMP timestamp, bool isControl); bool updateAlignment(TIMESTAMP timestamp); - bool setTxFreq(double wFreq); - bool setRxFreq(double wFreq); + bool setTxFreq(double wFreq, size_t chan); + bool setRxFreq(double wFreq, size_t chan); inline TIMESTAMP initialWriteTimestamp() { return 0; } inline TIMESTAMP initialReadTimestamp() { return 0; } @@ -238,17 +238,18 @@ public: inline double fullScaleInputValue() { return 32000 * TX_AMPL; } inline double fullScaleOutputValue() { return 32000; } - double setRxGain(double db); - double getRxGain(void) { return rx_gain; } + double setRxGain(double db, size_t chan); + double getRxGain(size_t chan); double maxRxGain(void) { return rx_gain_max; } double minRxGain(void) { return rx_gain_min; } - double setTxGain(double db); + double setTxGain(double db, size_t chan); double maxTxGain(void) { return tx_gain_max; } double minTxGain(void) { return tx_gain_min; } - double getTxFreq() { return tx_freq; } - double getRxFreq() { return rx_freq; } + double getTxFreq(size_t chan); + double getRxFreq(size_t chan); + double getRxFreq(); inline double getSampleRate() { return tx_rate; } inline double numberRead() { return rx_pkt_cnt; } @@ -272,25 +273,25 @@ private: enum TxWindowType tx_window; enum uhd_dev_type dev_type; - int sps; + size_t sps, chans; double tx_rate, rx_rate; - double tx_gain, tx_gain_min, tx_gain_max; - double rx_gain, rx_gain_min, rx_gain_max; + double tx_gain_min, tx_gain_max; + double rx_gain_min, rx_gain_max; - double tx_freq, rx_freq; + std::vector<double> tx_gains, rx_gains; + std::vector<double> tx_freqs, rx_freqs; size_t tx_spp, rx_spp; bool started; bool aligned; - bool skip_rx; size_t rx_pkt_cnt; size_t drop_cnt; uhd::time_spec_t prev_ts; TIMESTAMP ts_offset; - smpl_buf *rx_smpl_buf; + std::vector<smpl_buf *> rx_buffers; void init_gains(); int set_master_clk(double rate); @@ -335,23 +336,23 @@ void uhd_msg_handler(uhd::msg::type_t type, const std::string &msg) } } -uhd_device::uhd_device(int sps, bool skip_rx) - : tx_gain(0.0), tx_gain_min(0.0), tx_gain_max(0.0), - rx_gain(0.0), rx_gain_min(0.0), rx_gain_max(0.0), - tx_freq(0.0), rx_freq(0.0), tx_spp(0), rx_spp(0), +uhd_device::uhd_device(size_t sps, size_t chans) + : tx_gain_min(0.0), tx_gain_max(0.0), + rx_gain_min(0.0), rx_gain_max(0.0), + tx_spp(0), rx_spp(0), started(false), aligned(false), rx_pkt_cnt(0), drop_cnt(0), - prev_ts(0,0), ts_offset(0), rx_smpl_buf(NULL) + prev_ts(0,0), ts_offset(0) { this->sps = sps; - this->skip_rx = skip_rx; + this->chans = chans; } uhd_device::~uhd_device() { stop(); - if (rx_smpl_buf) - delete rx_smpl_buf; + for (size_t i = 0; i < rx_buffers.size(); i++) + delete rx_buffers[i]; } void uhd_device::init_gains() @@ -366,13 +367,18 @@ void uhd_device::init_gains() rx_gain_min = range.start(); rx_gain_max = range.stop(); - usrp_dev->set_tx_gain((tx_gain_min + tx_gain_max) / 2); - usrp_dev->set_rx_gain((rx_gain_min + rx_gain_max) / 2); + for (size_t i = 0; i < tx_gains.size(); i++) { + usrp_dev->set_tx_gain((tx_gain_min + tx_gain_max) / 2, i); + tx_gains[i] = usrp_dev->get_tx_gain(i); + } - tx_gain = usrp_dev->get_tx_gain(); - rx_gain = usrp_dev->get_rx_gain(); + for (size_t i = 0; i < rx_gains.size(); i++) { + usrp_dev->set_rx_gain((rx_gain_min + rx_gain_max) / 2, i); + rx_gains[i] = usrp_dev->get_rx_gain(i); + } return; + } int uhd_device::set_master_clk(double clk_rate) @@ -435,24 +441,44 @@ int uhd_device::set_rates(double tx_rate, double rx_rate) return 0; } -double uhd_device::setTxGain(double db) +double uhd_device::setTxGain(double db, size_t chan) { - usrp_dev->set_tx_gain(db); - tx_gain = usrp_dev->get_tx_gain(); + if (chan >= tx_gains.size()) { + LOG(ALERT) << "Requested non-existent channel" << chan; + return 0.0f; + } + + usrp_dev->set_tx_gain(db, chan); + tx_gains[chan] = usrp_dev->get_tx_gain(chan); - LOG(INFO) << "Set TX gain to " << tx_gain << "dB"; + LOG(INFO) << "Set TX gain to " << tx_gains[chan] << "dB"; - return tx_gain; + return tx_gains[chan]; } -double uhd_device::setRxGain(double db) +double uhd_device::setRxGain(double db, size_t chan) { - usrp_dev->set_rx_gain(db); - rx_gain = usrp_dev->get_rx_gain(); + if (chan >= rx_gains.size()) { + LOG(ALERT) << "Requested non-existent channel " << chan; + return 0.0f; + } - LOG(INFO) << "Set RX gain to " << rx_gain << "dB"; + usrp_dev->set_rx_gain(db, chan); + rx_gains[chan] = usrp_dev->get_rx_gain(chan); - return rx_gain; + LOG(INFO) << "Set RX gain to " << rx_gains[chan] << "dB"; + + return rx_gains[chan]; +} + +double uhd_device::getRxGain(size_t chan) +{ + if (chan >= rx_gains.size()) { + LOG(ALERT) << "Requested non-existent channel " << chan; + return 0.0f; + } + + return rx_gains[chan]; } /* @@ -533,11 +559,30 @@ int uhd_device::open(const std::string &args, bool extref) if (!parse_dev_type()) return -1; + // Verify and set channels + if ((dev_type == UMTRX) && (chans == 2)) { + uhd::usrp::subdev_spec_t subdev_spec("A:0 B:0"); + usrp_dev->set_tx_subdev_spec(subdev_spec); + usrp_dev->set_rx_subdev_spec(subdev_spec); + } else if (chans != 1) { + LOG(ALERT) << "Invalid channel combination for device"; + return -1; + } + + tx_freqs.resize(chans); + rx_freqs.resize(chans); + tx_gains.resize(chans); + rx_gains.resize(chans); + rx_buffers.resize(chans); + if (extref) usrp_dev->set_clock_source("external"); // Create TX and RX streamers uhd::stream_args_t stream_args("sc16"); + for (size_t i = 0; i < chans; i++) + stream_args.channels.push_back(i); + tx_stream = usrp_dev->get_tx_stream(stream_args); rx_stream = usrp_dev->get_rx_stream(stream_args); @@ -553,7 +598,8 @@ int uhd_device::open(const std::string &args, bool extref) // Create receive buffer size_t buf_len = SAMPLE_BUF_SZ / sizeof(uint32_t); - rx_smpl_buf = new smpl_buf(buf_len, rx_rate); + for (size_t i = 0; i < rx_buffers.size(); i++) + rx_buffers[i] = new smpl_buf(buf_len, rx_rate); // Set receive chain sample offset double offset = get_dev_offset(dev_type, sps); @@ -608,16 +654,13 @@ bool uhd_device::flush_recv(size_t num_pkts) void uhd_device::restart(uhd::time_spec_t ts) { - uhd::stream_cmd_t cmd = uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS; - usrp_dev->issue_stream_cmd(cmd); - - flush_recv(50); - usrp_dev->set_time_now(ts); aligned = false; - cmd = uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS; - cmd.stream_now = true; + uhd::stream_cmd_t cmd = uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS; + cmd.time_spec = uhd::time_spec_t(0.1); + cmd.stream_now = false; + usrp_dev->issue_stream_cmd(cmd); } @@ -707,16 +750,17 @@ int uhd_device::check_rx_md_err(uhd::rx_metadata_t &md, ssize_t num_smpls) return 0; } -int uhd_device::readSamples(short *buf, int len, bool *overrun, - TIMESTAMP timestamp, bool *underrun, unsigned *RSSI) +int uhd_device::readSamples(std::vector<short *> &bufs, int len, bool *overrun, + TIMESTAMP timestamp, bool *underrun, unsigned *RSSI) { ssize_t rc; uhd::time_spec_t ts; uhd::rx_metadata_t metadata; - uint32_t pkt_buf[rx_spp]; - if (skip_rx) - return 0; + if (bufs.size() != chans) { + LOG(ALERT) << "Invalid channel combination " << bufs.size(); + return -1; + } *overrun = false; *underrun = false; @@ -728,21 +772,25 @@ int uhd_device::readSamples(short *buf, int len, bool *overrun, LOG(DEBUG) << "Requested timestamp = " << ts.get_real_secs(); // Check that timestamp is valid - rc = rx_smpl_buf->avail_smpls(timestamp); + rc = rx_buffers[0]->avail_smpls(timestamp); if (rc < 0) { - LOG(ERR) << rx_smpl_buf->str_code(rc); - LOG(ERR) << rx_smpl_buf->str_status(); + LOG(ERR) << rx_buffers[0]->str_code(rc); + LOG(ERR) << rx_buffers[0]->str_status(); return 0; } + // Create vector buffer + std::vector<std::vector<short> > + pkt_bufs(chans, std::vector<short>(2 * rx_spp)); + + std::vector<short *> pkt_ptrs; + for (size_t i = 0; i < pkt_bufs.size(); i++) + pkt_ptrs.push_back(&pkt_bufs[i].front()); + // Receive samples from the usrp until we have enough - while (rx_smpl_buf->avail_smpls(timestamp) < len) { - size_t num_smpls = rx_stream->recv( - (void*)pkt_buf, - rx_spp, - metadata, - 0.1, - true); + while (rx_buffers[0]->avail_smpls(timestamp) < len) { + size_t num_smpls = rx_stream->recv(pkt_ptrs, rx_spp, + metadata, 0.1, true); rx_pkt_cnt++; // Check for errors @@ -758,36 +806,39 @@ int uhd_device::readSamples(short *buf, int len, bool *overrun, continue; } - ts = metadata.time_spec; LOG(DEBUG) << "Received timestamp = " << ts.get_real_secs(); - rc = rx_smpl_buf->write(pkt_buf, - num_smpls, - metadata.time_spec); - - // Continue on local overrun, exit on other errors - if ((rc < 0)) { - LOG(ERR) << rx_smpl_buf->str_code(rc); - LOG(ERR) << rx_smpl_buf->str_status(); - if (rc != smpl_buf::ERROR_OVERFLOW) - return 0; + for (size_t i = 0; i < rx_buffers.size(); i++) { + rc = rx_buffers[i]->write((short *) &pkt_bufs[i].front(), + num_smpls, + metadata.time_spec); + + // Continue on local overrun, exit on other errors + if ((rc < 0)) { + LOG(ERR) << rx_buffers[i]->str_code(rc); + LOG(ERR) << rx_buffers[i]->str_status(); + if (rc != smpl_buf::ERROR_OVERFLOW) + return 0; + } } } // We have enough samples - rc = rx_smpl_buf->read(buf, len, timestamp); - if ((rc < 0) || (rc != len)) { - LOG(ERR) << rx_smpl_buf->str_code(rc); - LOG(ERR) << rx_smpl_buf->str_status(); - return 0; + for (size_t i = 0; i < rx_buffers.size(); i++) { + rc = rx_buffers[i]->read(bufs[i], len, timestamp); + if ((rc < 0) || (rc != len)) { + LOG(ERR) << rx_buffers[i]->str_code(rc); + LOG(ERR) << rx_buffers[i]->str_status(); + return 0; + } } return len; } -int uhd_device::writeSamples(short *buf, int len, bool *underrun, - unsigned long long timestamp,bool isControl) +int uhd_device::writeSamples(std::vector<short *> &bufs, int len, bool *underrun, + unsigned long long timestamp,bool isControl) { uhd::tx_metadata_t metadata; metadata.has_time_spec = true; @@ -803,6 +854,11 @@ int uhd_device::writeSamples(short *buf, int len, bool *underrun, return 0; } + if (bufs.size() != chans) { + LOG(ALERT) << "Invalid channel combination " << bufs.size(); + return -1; + } + // Drop a fixed number of packets (magic value) if (!aligned) { drop_cnt++; @@ -822,8 +878,7 @@ int uhd_device::writeSamples(short *buf, int len, bool *underrun, } } - size_t num_smpls = tx_stream->send(buf, len, metadata); - + size_t num_smpls = tx_stream->send(bufs, len, metadata); if (num_smpls != (unsigned) len) { LOG(ALERT) << "UHD: Device send timed out"; LOG(ALERT) << "UHD: Version " << uhd::get_version_string(); @@ -839,24 +894,54 @@ bool uhd_device::updateAlignment(TIMESTAMP timestamp) return true; } -bool uhd_device::setTxFreq(double wFreq) +bool uhd_device::setTxFreq(double wFreq, size_t chan) { - uhd::tune_result_t tr = usrp_dev->set_tx_freq(wFreq); + if (chan >= tx_freqs.size()) { + LOG(ALERT) << "Requested non-existent channel " << chan; + return false; + } + + uhd::tune_result_t tr = usrp_dev->set_tx_freq(wFreq, chan); LOG(INFO) << "\n" << tr.to_pp_string(); - tx_freq = usrp_dev->get_tx_freq(); + tx_freqs[chan] = usrp_dev->get_tx_freq(chan); return true; } -bool uhd_device::setRxFreq(double wFreq) +bool uhd_device::setRxFreq(double wFreq, size_t chan) { - uhd::tune_result_t tr = usrp_dev->set_rx_freq(wFreq); + if (chan >= rx_freqs.size()) { + LOG(ALERT) << "Requested non-existent channel " << chan; + return false; + } + + uhd::tune_result_t tr = usrp_dev->set_rx_freq(wFreq, chan); LOG(INFO) << "\n" << tr.to_pp_string(); - rx_freq = usrp_dev->get_rx_freq(); + rx_freqs[chan] = usrp_dev->get_rx_freq(chan); return true; } +double uhd_device::getTxFreq(size_t chan) +{ + if (chan >= tx_freqs.size()) { + LOG(ALERT) << "Requested non-existent channel " << chan; + return 0.0; + } + + return tx_freqs[chan]; +} + +double uhd_device::getRxFreq(size_t chan) +{ + if (chan >= rx_freqs.size()) { + LOG(ALERT) << "Requested non-existent channel " << chan; + return 0.0; + } + + return rx_freqs[chan]; +} + bool uhd_device::recv_async_msg() { uhd::async_metadata_t md; @@ -1085,7 +1170,7 @@ std::string smpl_buf::str_code(ssize_t code) } } -RadioDevice *RadioDevice::make(int sps, bool skip_rx) +RadioDevice *RadioDevice::make(size_t sps, size_t chans) { - return new uhd_device(sps, skip_rx); + return new uhd_device(sps, chans); } diff --git a/Transceiver52M/USRPDevice.cpp b/Transceiver52M/USRPDevice.cpp index 1fff124..e330bc3 100644 --- a/Transceiver52M/USRPDevice.cpp +++ b/Transceiver52M/USRPDevice.cpp @@ -59,7 +59,7 @@ const dboardConfigType dboardConfig = TXA_RXB; const double USRPDevice::masterClockRate = 52.0e6; -USRPDevice::USRPDevice(int sps, bool skipRx) +USRPDevice::USRPDevice(size_t sps, size_t) : skipRx(skipRx) { LOG(INFO) << "creating USRP device..."; @@ -266,49 +266,66 @@ double USRPDevice::minRxGain() return m_dbRx->gain_min(); } -double USRPDevice::setTxGain(double dB) { - - writeLock.lock(); - if (dB > maxTxGain()) dB = maxTxGain(); - if (dB < minTxGain()) dB = minTxGain(); +double USRPDevice::setTxGain(double dB, size_t chan) +{ + if (chan) { + LOG(ALERT) << "Invalid channel " << chan; + return 0.0; + } - LOG(NOTICE) << "Setting TX gain to " << dB << " dB."; + writeLock.lock(); + if (dB > maxTxGain()) + dB = maxTxGain(); + if (dB < minTxGain()) + dB = minTxGain(); - if (!m_dbTx->set_gain(dB)) - LOG(ERR) << "Error setting TX gain"; + LOG(NOTICE) << "Setting TX gain to " << dB << " dB."; - writeLock.unlock(); - - return dB; + if (!m_dbTx->set_gain(dB)) + LOG(ERR) << "Error setting TX gain"; + + writeLock.unlock(); + + return dB; } -double USRPDevice::setRxGain(double dB) { +double USRPDevice::setRxGain(double dB, size_t chan) +{ + if (chan) { + LOG(ALERT) << "Invalid channel " << chan; + return 0.0; + } - writeLock.lock(); - if (dB > maxRxGain()) dB = maxRxGain(); - if (dB < minRxGain()) dB = minRxGain(); - - LOG(NOTICE) << "Setting RX gain to " << dB << " dB."; + dB = 47.0; - if (!m_dbRx->set_gain(dB)) - LOG(ERR) << "Error setting RX gain"; - - writeLock.unlock(); - - return dB; + writeLock.lock(); + if (dB > maxRxGain()) + dB = maxRxGain(); + if (dB < minRxGain()) + dB = minRxGain(); + + LOG(NOTICE) << "Setting RX gain to " << dB << " dB."; + + if (!m_dbRx->set_gain(dB)) + LOG(ERR) << "Error setting RX gain"; + + writeLock.unlock(); + + return dB; } // NOTE: Assumes sequential reads -int USRPDevice::readSamples(short *buf, int len, bool *overrun, - TIMESTAMP timestamp, - bool *underrun, - unsigned *RSSI) +int USRPDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun, + TIMESTAMP timestamp, bool *underrun, unsigned *RSSI) { #ifndef SWLOOPBACK - if (!m_uRx) return 0; - + if (!m_uRx) + return 0; + + short *buf = bufs[0]; + timestamp += timestampOffset; if (timestamp + len < timeStart) { @@ -450,17 +467,20 @@ int USRPDevice::readSamples(short *buf, int len, bool *overrun, #endif } -int USRPDevice::writeSamples(short *buf, int len, bool *underrun, - unsigned long long timestamp, - bool isControl) +int USRPDevice::writeSamples(std::vector<short *> &bufs, int len, + bool *underrun, unsigned long long timestamp, + bool isControl) { writeLock.lock(); #ifndef SWLOOPBACK - if (!m_uTx) return 0; - + if (!m_uTx) + return 0; + + short *buf = bufs[0]; + static uint32_t outData[128*20]; - + for (int i = 0; i < len*2; i++) { buf[i] = host_to_usrp_short(buf[i]); } @@ -512,7 +532,9 @@ bool USRPDevice::updateAlignment(TIMESTAMP timestamp) uint32_t *wordPtr = (uint32_t *) data; *wordPtr = host_to_usrp_u32(*wordPtr); bool tmpUnderrun; - if (writeSamples((short *) data,1,&tmpUnderrun,timestamp & 0x0ffffffffll,true)) { + + std::vector<short *> buf(1, data); + if (writeSamples(buf, 1, &tmpUnderrun, timestamp & 0x0ffffffffll, true)) { pingTimestamp = timestamp; return true; } @@ -523,10 +545,15 @@ bool USRPDevice::updateAlignment(TIMESTAMP timestamp) } #ifndef SWLOOPBACK -bool USRPDevice::setTxFreq(double wFreq) +bool USRPDevice::setTxFreq(double wFreq, size_t chan) { usrp_tune_result result; + if (chan) { + LOG(ALERT) << "Invalid channel " << chan; + return false; + } + if (m_uTx->tune(txSubdevSpec.side, m_dbTx, wFreq, &result)) { LOG(INFO) << "set TX: " << wFreq << std::endl << " baseband freq: " << result.baseband_freq << std::endl @@ -543,10 +570,15 @@ bool USRPDevice::setTxFreq(double wFreq) } } -bool USRPDevice::setRxFreq(double wFreq) +bool USRPDevice::setRxFreq(double wFreq, size_t chan) { usrp_tune_result result; + if (chan) { + LOG(ALERT) << "Invalid channel " << chan; + return false; + } + if (m_uRx->tune(0, m_dbRx, wFreq, &result)) { LOG(INFO) << "set RX: " << wFreq << std::endl << " baseband freq: " << result.baseband_freq << std::endl @@ -569,7 +601,7 @@ bool USRPDevice::setTxFreq(double wFreq) { return true;}; bool USRPDevice::setRxFreq(double wFreq) { return true;}; #endif -RadioDevice *RadioDevice::make(int sps, bool skipRx) +RadioDevice *RadioDevice::make(size_t sps, size_t chans) { - return new USRPDevice(sps, skipRx); + return new USRPDevice(sps, chans); } diff --git a/Transceiver52M/USRPDevice.h b/Transceiver52M/USRPDevice.h index dc86f0e..cfc6222 100644 --- a/Transceiver52M/USRPDevice.h +++ b/Transceiver52M/USRPDevice.h @@ -93,16 +93,10 @@ private: bool firstRead; #endif - /** Set the transmission frequency */ - bool tx_setFreq(double freq, double *actual_freq); - - /** Set the receiver frequency */ - bool rx_setFreq(double freq, double *actual_freq); - public: /** Object constructor */ - USRPDevice(int sps, bool skipRx); + USRPDevice(size_t sps, size_t chans = 1); /** Instantiate the USRP */ int open(const std::string &, bool); @@ -114,7 +108,7 @@ private: bool stop(); /** Set priority not supported */ - void setPriority() { return; } + void setPriority() { } enum TxWindowType getWindowType() { return TX_WINDOW_USRP1; } @@ -128,10 +122,9 @@ private: @param RSSI The received signal strength of the read result @return The number of samples actually read */ - int readSamples(short *buf, int len, bool *overrun, - TIMESTAMP timestamp = 0xffffffff, - bool *underrun = NULL, - unsigned *RSSI = NULL); + int readSamples(std::vector<short *> &buf, int len, bool *overrun, + TIMESTAMP timestamp = 0xffffffff, bool *underrun = NULL, + unsigned *RSSI = NULL); /** Write samples to the USRP. @param buf Contains the data to be written. @@ -141,18 +134,17 @@ private: @param isControl Set if data is a control packet, e.g. a ping command @return The number of samples actually written */ - int writeSamples(short *buf, int len, bool *underrun, - TIMESTAMP timestamp = 0xffffffff, - bool isControl = false); - + int writeSamples(std::vector<short *> &bufs, int len, bool *underrun, + TIMESTAMP timestamp = 0xffffffff, bool isControl = false); + /** Update the alignment between the read and write timestamps */ bool updateAlignment(TIMESTAMP timestamp); - + /** Set the transmitter frequency */ - bool setTxFreq(double wFreq); + bool setTxFreq(double wFreq, size_t chan = 0); /** Set the receiver frequency */ - bool setRxFreq(double wFreq); + bool setRxFreq(double wFreq, size_t chan = 0); /** Returns the starting write Timestamp*/ TIMESTAMP initialWriteTimestamp(void) { return 20000;} @@ -167,10 +159,10 @@ private: double fullScaleOutputValue() {return 9450.0;} /** sets the receive chan gain, returns the gain setting **/ - double setRxGain(double dB); + double setRxGain(double dB, size_t chan = 0); /** get the current receive gain */ - double getRxGain(void) {return rxGain;} + double getRxGain(size_t chan = 0) { return rxGain; } /** return maximum Rx Gain **/ double maxRxGain(void); @@ -179,7 +171,7 @@ private: double minRxGain(void); /** sets the transmit chan gain, returns the gain setting **/ - double setTxGain(double dB); + double setTxGain(double dB, size_t chan = 0); /** return maximum Tx Gain **/ double maxTxGain(void); @@ -187,13 +179,12 @@ private: /** return minimum Rx Gain **/ double minTxGain(void); - /** Return internal status values */ - inline double getTxFreq() { return 0;} - inline double getRxFreq() { return 0;} - inline double getSampleRate() {return actualSampleRate;} + inline double getTxFreq(size_t chan = 0) { return 0; } + inline double getRxFreq(size_t chan = 0) { return 0; } + inline double getSampleRate() { return actualSampleRate; } inline double numberRead() { return samplesRead; } - inline double numberWritten() { return samplesWritten;} + inline double numberWritten() { return samplesWritten; } }; diff --git a/Transceiver52M/radioDevice.h b/Transceiver52M/radioDevice.h index e08904b..e577bc5 100644 --- a/Transceiver52M/radioDevice.h +++ b/Transceiver52M/radioDevice.h @@ -16,6 +16,7 @@ #define __RADIO_DEVICE_H__ #include <string> +#include <vector> #ifdef HAVE_CONFIG_H #include "config.h" @@ -36,7 +37,7 @@ class RadioDevice { /* Radio interface types */ enum RadioInterfaceType { NORMAL, RESAMP_64M, RESAMP_100M }; - static RadioDevice *make(int sps, bool skipRx = false); + static RadioDevice *make(size_t sps, size_t chans = 1); /** Initialize the USRP */ virtual int open(const std::string &args = "", bool extref = false)=0; @@ -63,10 +64,9 @@ class RadioDevice { @param RSSI The received signal strength of the read result @return The number of samples actually read */ - virtual int readSamples(short *buf, int len, bool *overrun, - TIMESTAMP timestamp = 0xffffffff, - bool *underrun = 0, - unsigned *RSSI = 0)=0; + virtual int readSamples(std::vector<short *> &bufs, int len, bool *overrun, + TIMESTAMP timestamp = 0xffffffff, bool *underrun = 0, + unsigned *RSSI = 0) = 0; /** Write samples to the radio. @param buf Contains the data to be written. @@ -76,18 +76,17 @@ class RadioDevice { @param isControl Set if data is a control packet, e.g. a ping command @return The number of samples actually written */ - virtual int writeSamples(short *buf, int len, bool *underrun, - TIMESTAMP timestamp, - bool isControl=false)=0; - + virtual int writeSamples(std::vector<short *> &bufs, int len, bool *underrun, + TIMESTAMP timestamp, bool isControl = false) = 0; + /** Update the alignment between the read and write timestamps */ virtual bool updateAlignment(TIMESTAMP timestamp)=0; - + /** Set the transmitter frequency */ - virtual bool setTxFreq(double wFreq)=0; + virtual bool setTxFreq(double wFreq, size_t chan = 0) = 0; /** Set the receiver frequency */ - virtual bool setRxFreq(double wFreq)=0; + virtual bool setRxFreq(double wFreq, size_t chan = 0) = 0; /** Returns the starting write Timestamp*/ virtual TIMESTAMP initialWriteTimestamp(void)=0; @@ -102,10 +101,10 @@ class RadioDevice { virtual double fullScaleOutputValue()=0; /** sets the receive chan gain, returns the gain setting **/ - virtual double setRxGain(double dB)=0; + virtual double setRxGain(double dB, size_t chan = 0) = 0; /** gets the current receive gain **/ - virtual double getRxGain(void)=0; + virtual double getRxGain(size_t chan = 0) = 0; /** return maximum Rx Gain **/ virtual double maxRxGain(void) = 0; @@ -114,7 +113,7 @@ class RadioDevice { virtual double minRxGain(void) = 0; /** sets the transmit chan gain, returns the gain setting **/ - virtual double setTxGain(double dB)=0; + virtual double setTxGain(double dB, size_t chan = 0) = 0; /** return maximum Tx Gain **/ virtual double maxTxGain(void) = 0; @@ -123,8 +122,8 @@ class RadioDevice { virtual double minTxGain(void) = 0; /** Return internal status values */ - virtual double getTxFreq()=0; - virtual double getRxFreq()=0; + virtual double getTxFreq(size_t chan = 0) = 0; + virtual double getRxFreq(size_t chan = 0) = 0; virtual double getSampleRate()=0; virtual double numberRead()=0; virtual double numberWritten()=0; diff --git a/Transceiver52M/radioInterface.cpp b/Transceiver52M/radioInterface.cpp index a8a54a5..f98194f 100644 --- a/Transceiver52M/radioInterface.cpp +++ b/Transceiver52M/radioInterface.cpp @@ -35,13 +35,12 @@ extern "C" { RadioInterface::RadioInterface(RadioDevice *wRadio, int wReceiveOffset, - int wSPS, + size_t sps, size_t chans, GSM::Time wStartTime) - : underrun(false), sendCursor(0), recvCursor(0), mOn(false), - mRadio(wRadio), receiveOffset(wReceiveOffset), - mSPSTx(wSPS), mSPSRx(1), powerScaling(1.0), - loadTest(false), sendBuffer(NULL), recvBuffer(NULL), - convertRecvBuffer(NULL), convertSendBuffer(NULL) + : mRadio(wRadio), mSPSTx(sps), mSPSRx(1), mChans(chans), + sendCursor(0), recvCursor(0), underrun(false), overrun(false), + receiveOffset(wReceiveOffset), mOn(false), powerScaling(1.0), + loadTest(false) { mClock.set(wStartTime); } @@ -56,13 +55,26 @@ bool RadioInterface::init(int type) if (type != RadioDevice::NORMAL) return false; + if (!mChans) { + LOG(ALERT) << "Invalid number of channels " << mChans; + return false; + } + close(); - sendBuffer = new signalVector(CHUNK * mSPSTx); - recvBuffer = new signalVector(NUMCHUNKS * CHUNK * mSPSRx); + sendBuffer.resize(mChans); + recvBuffer.resize(mChans); + convertSendBuffer.resize(mChans); + convertRecvBuffer.resize(mChans); + mReceiveFIFO.resize(mChans); + + for (size_t i = 0; i < mChans; i++) { + sendBuffer[i] = new signalVector(CHUNK * mSPSTx); + recvBuffer[i] = new signalVector(NUMCHUNKS * CHUNK * mSPSRx); - convertSendBuffer = new short[sendBuffer->size() * 2]; - convertRecvBuffer = new short[recvBuffer->size() * 2]; + convertSendBuffer[i] = new short[sendBuffer[i]->size() * 2]; + convertRecvBuffer[i] = new short[recvBuffer[i]->size() * 2]; + } sendCursor = 0; recvCursor = 0; @@ -72,17 +84,23 @@ bool RadioInterface::init(int type) void RadioInterface::close() { - delete sendBuffer; - delete recvBuffer; - delete convertSendBuffer; - delete convertRecvBuffer; - - sendBuffer = NULL; - recvBuffer = NULL; - convertRecvBuffer = NULL; - convertSendBuffer = NULL; -} + for (size_t i = 0; i < sendBuffer.size(); i++) + delete sendBuffer[i]; + + for (size_t i = 0; i < recvBuffer.size(); i++) + delete recvBuffer[i]; + + for (size_t i = 0; i < convertSendBuffer.size(); i++) + delete convertSendBuffer[i]; + for (size_t i = 0; i < convertRecvBuffer.size(); i++) + delete convertRecvBuffer[i]; + + sendBuffer.resize(0); + recvBuffer.resize(0); + convertSendBuffer.resize(0); + convertRecvBuffer.resize(0); +} double RadioInterface::fullScaleInputValue(void) { return mRadio->fullScaleInputValue(); @@ -93,11 +111,16 @@ double RadioInterface::fullScaleOutputValue(void) { } -void RadioInterface::setPowerAttenuation(double atten) +void RadioInterface::setPowerAttenuation(double atten, size_t chan) { double rfGain, digAtten; - rfGain = mRadio->setTxGain(mRadio->maxTxGain() - atten); + if (chan >= mChans) { + LOG(ALERT) << "Invalid channel requested"; + return; + } + + rfGain = mRadio->setTxGain(mRadio->maxTxGain() - atten, chan); digAtten = atten - mRadio->maxTxGain() + rfGain; if (digAtten < 1.0) @@ -138,14 +161,14 @@ int RadioInterface::unRadioifyVector(float *floatVector, return newVector.size(); } -bool RadioInterface::tuneTx(double freq) +bool RadioInterface::tuneTx(double freq, size_t chan) { - return mRadio->setTxFreq(freq); + return mRadio->setTxFreq(freq, chan); } -bool RadioInterface::tuneRx(double freq) +bool RadioInterface::tuneRx(double freq, size_t chan) { - return mRadio->setRxFreq(freq); + return mRadio->setRxFreq(freq, chan); } @@ -183,24 +206,28 @@ void RadioInterface::alignRadio() { } #endif -void RadioInterface::driveTransmitRadio(signalVector &radioBurst, bool zeroBurst) +void RadioInterface::driveTransmitRadio(std::vector<signalVector *> &bursts, + std::vector<bool> &zeros) { if (!mOn) return; - radioifyVector(radioBurst, - (float *) (sendBuffer->begin() + sendCursor), zeroBurst); + for (size_t i = 0; i < mChans; i++) { + radioifyVector(*bursts[i], + (float *) (sendBuffer[i]->begin() + sendCursor), zeros[i]); + } - sendCursor += radioBurst.size(); + sendCursor += bursts[0]->size(); pushBuffer(); } -void RadioInterface::driveReceiveRadio() { - - if (!mOn) return; +bool RadioInterface::driveReceiveRadio() +{ + radioVector *burst = NULL; - if (mReceiveFIFO.size() > 8) return; + if (!mOn) + return false; pullBuffer(); @@ -215,23 +242,23 @@ void RadioInterface::driveReceiveRadio() { // GSM bursts and pass up to Transceiver // Using the 157-156-156-156 symbols per timeslot format. while (rcvSz > (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx) { - signalVector rxVector((symbolsPerSlot + (tN % 4 == 0)) * mSPSRx); - unRadioifyVector((float *) (recvBuffer->begin() + readSz), rxVector); GSM::Time tmpTime = rcvClock; - if (rcvClock.FN() >= 0) { - //LOG(DEBUG) << "FN: " << rcvClock.FN(); - radioVector *rxBurst = NULL; - if (!loadTest) - rxBurst = new radioVector(rxVector,tmpTime); + + for (size_t i = 0; i < mChans; i++) { + signalVector rxVector((symbolsPerSlot + (tN % 4 == 0)) * mSPSRx); + unRadioifyVector((float *) (recvBuffer[i]->begin() + readSz), rxVector); + + if (rcvClock.FN() >= 0) + burst = new radioVector(rxVector, tmpTime); + + if (burst && (mReceiveFIFO[i].size() < 32)) + mReceiveFIFO[i].write(burst); else { - if (tN % 4 == 0) - rxBurst = new radioVector(*finalVec9,tmpTime); - else - rxBurst = new radioVector(*finalVec,tmpTime); + delete burst; } - mReceiveFIFO.put(rxBurst); } - mClock.incTN(); + + mClock.incTN(); rcvClock.incTN(); readSz += (symbolsPerSlot+(tN % 4 == 0)) * mSPSRx; rcvSz -= (symbolsPerSlot+(tN % 4 == 0)) * mSPSRx; @@ -240,12 +267,16 @@ void RadioInterface::driveReceiveRadio() { } if (readSz > 0) { - memmove(recvBuffer->begin(), - recvBuffer->begin() + readSz, - (recvCursor - readSz) * 2 * sizeof(float)); + for (size_t i = 0; i < recvBuffer.size(); i++) { + memmove(recvBuffer[i]->begin(), + recvBuffer[i]->begin() + readSz, + (recvCursor - readSz) * 2 * sizeof(float)); + } recvCursor -= readSz; } + + return true; } bool RadioInterface::isUnderrun() @@ -256,18 +287,26 @@ bool RadioInterface::isUnderrun() return retVal; } -double RadioInterface::setRxGain(double dB) +VectorFIFO* RadioInterface::receiveFIFO(size_t chan) +{ + if (chan >= mReceiveFIFO.size()) + return NULL; + + return &mReceiveFIFO[chan]; +} + +double RadioInterface::setRxGain(double dB, size_t chan) { if (mRadio) - return mRadio->setRxGain(dB); + return mRadio->setRxGain(dB, chan); else return -1; } -double RadioInterface::getRxGain() +double RadioInterface::getRxGain(size_t chan) { if (mRadio) - return mRadio->getRxGain(); + return mRadio->getRxGain(chan); else return -1; } @@ -279,7 +318,7 @@ void RadioInterface::pullBuffer() int num_recv; float *output; - if (recvCursor > recvBuffer->size() - CHUNK) + if (recvCursor > recvBuffer[0]->size() - CHUNK) return; /* Outer buffer access size is fixed */ @@ -293,9 +332,10 @@ void RadioInterface::pullBuffer() return; } - output = (float *) (recvBuffer->begin() + recvCursor); - - convert_short_float(output, convertRecvBuffer, 2 * num_recv); + for (size_t i = 0; i < mChans; i++) { + output = (float *) (recvBuffer[i]->begin() + recvCursor); + convert_short_float(output, convertRecvBuffer[i], 2 * num_recv); + } underrun |= local_underrun; @@ -311,12 +351,14 @@ void RadioInterface::pushBuffer() if (sendCursor < CHUNK) return; - if (sendCursor > sendBuffer->size()) + if (sendCursor > sendBuffer[0]->size()) LOG(ALERT) << "Send buffer overflow"; - convert_float_short(convertSendBuffer, - (float *) sendBuffer->begin(), - powerScaling, 2 * sendCursor); + for (size_t i = 0; i < mChans; i++) { + convert_float_short(convertSendBuffer[i], + (float *) sendBuffer[i]->begin(), + powerScaling, 2 * sendCursor); + } /* Send the all samples in the send buffer */ num_sent = mRadio->writeSamples(convertSendBuffer, diff --git a/Transceiver52M/radioInterface.h b/Transceiver52M/radioInterface.h index 84de1e5..1e58ecb 100644 --- a/Transceiver52M/radioInterface.h +++ b/Transceiver52M/radioInterface.h @@ -30,19 +30,20 @@ protected: Thread mAlignRadioServiceLoopThread; ///< thread that synchronizes transmit and receive sections - VectorFIFO mReceiveFIFO; ///< FIFO that holds receive bursts + std::vector<VectorFIFO> mReceiveFIFO; ///< FIFO that holds receive bursts RadioDevice *mRadio; ///< the USRP object - int mSPSTx; - int mSPSRx; - signalVector *sendBuffer; - signalVector *recvBuffer; + size_t mSPSTx; + size_t mSPSRx; + size_t mChans; + std::vector<signalVector *> sendBuffer; + std::vector<signalVector *> recvBuffer; unsigned sendCursor; unsigned recvCursor; - short *convertRecvBuffer; - short *convertSendBuffer; + std::vector<short *> convertRecvBuffer; + std::vector<short *> convertSendBuffer; bool underrun; ///< indicates writes to USRP are too slow bool overrun; ///< indicates reads from USRP are too slow @@ -89,43 +90,41 @@ public: /** constructor */ RadioInterface(RadioDevice* wRadio = NULL, int receiveOffset = 3, - int wSPS = 4, + size_t sps = 4, size_t chans = 1, GSM::Time wStartTime = GSM::Time(0)); - + /** destructor */ virtual ~RadioInterface(); /** check for underrun, resets underrun value */ bool isUnderrun(); - - /** attach an existing USRP to this interface */ - void attach(RadioDevice *wRadio, int wRadioOversampling); /** return the receive FIFO */ - VectorFIFO* receiveFIFO() { return &mReceiveFIFO;} + VectorFIFO* receiveFIFO(size_t chan = 0); /** return the basestation clock */ RadioClock* getClock(void) { return &mClock;}; /** set transmit frequency */ - bool tuneTx(double freq); + bool tuneTx(double freq, size_t chan = 0); /** set receive frequency */ - bool tuneRx(double freq); + bool tuneRx(double freq, size_t chan = 0); /** set receive gain */ - double setRxGain(double dB); + double setRxGain(double dB, size_t chan = 0); /** get receive gain */ - double getRxGain(void); + double getRxGain(size_t chan = 0); /** drive transmission of GSM bursts */ - void driveTransmitRadio(signalVector &radioBurst, bool zeroBurst); + void driveTransmitRadio(std::vector<signalVector *> &bursts, + std::vector<bool> &zeros); /** drive reception of GSM bursts */ - void driveReceiveRadio(); + bool driveReceiveRadio(); - void setPowerAttenuation(double atten); + void setPowerAttenuation(double atten, size_t chan = 0); /** returns the full-scale transmit amplitude **/ double fullScaleInputValue(); @@ -169,7 +168,7 @@ public: RadioInterfaceResamp(RadioDevice* wRadio = NULL, int receiveOffset = 3, - int wSPS = 4, + size_t wSPS = 4, size_t chans = 1, GSM::Time wStartTime = GSM::Time(0)); ~RadioInterfaceResamp(); diff --git a/Transceiver52M/radioInterfaceResamp.cpp b/Transceiver52M/radioInterfaceResamp.cpp index 6c3839a..95ed16d 100644 --- a/Transceiver52M/radioInterfaceResamp.cpp +++ b/Transceiver52M/radioInterfaceResamp.cpp @@ -55,14 +55,11 @@ static int resamp_inchunk = 0; static int resamp_outrate = 0; static int resamp_outchunk = 0; -short *convertRecvBuffer = NULL; -short *convertSendBuffer = NULL; - RadioInterfaceResamp::RadioInterfaceResamp(RadioDevice *wRadio, int wReceiveOffset, - int wSPS, + size_t sps, size_t chan, GSM::Time wStartTime) - : RadioInterface(wRadio, wReceiveOffset, wSPS, wStartTime), + : RadioInterface(wRadio, wReceiveOffset, sps, chan, wStartTime), innerSendBuffer(NULL), outerSendBuffer(NULL), innerRecvBuffer(NULL), outerRecvBuffer(NULL) { @@ -87,12 +84,15 @@ void RadioInterfaceResamp::close() outerSendBuffer = NULL; innerRecvBuffer = NULL; outerRecvBuffer = NULL; - sendBuffer = NULL; - recvBuffer = NULL; upsampler = NULL; dnsampler = NULL; + if (sendBuffer.size()) + sendBuffer[0] = NULL; + if (recvBuffer.size()) + recvBuffer[0] = NULL; + RadioInterface::close(); } @@ -101,8 +101,19 @@ bool RadioInterfaceResamp::init(int type) { float cutoff = 1.0f; + if (mChans != 1) { + LOG(ALERT) << "Unsupported channel configuration " << mChans; + return false; + } + close(); + sendBuffer.resize(1); + recvBuffer.resize(1); + convertSendBuffer.resize(1); + convertRecvBuffer.resize(1); + mReceiveFIFO.resize(1); + switch (type) { case RadioDevice::RESAMP_64M: resamp_inrate = RESAMP_64M_INRATE; @@ -156,11 +167,11 @@ bool RadioInterfaceResamp::init(int type) innerRecvBuffer = new signalVector(NUMCHUNKS * resamp_inchunk / mSPSTx); - convertSendBuffer = new short[outerSendBuffer->size() * 2]; - convertRecvBuffer = new short[outerRecvBuffer->size() * 2]; + convertSendBuffer[0] = new short[outerSendBuffer->size() * 2]; + convertRecvBuffer[0] = new short[outerRecvBuffer->size() * 2]; - sendBuffer = innerSendBuffer; - recvBuffer = innerRecvBuffer; + sendBuffer[0] = innerSendBuffer; + recvBuffer[0] = innerRecvBuffer; return true; } @@ -186,7 +197,7 @@ void RadioInterfaceResamp::pullBuffer() } convert_short_float((float *) outerRecvBuffer->begin(), - convertRecvBuffer, 2 * resamp_outchunk); + convertRecvBuffer[0], 2 * resamp_outchunk); underrun |= local_underrun; readTimestamp += (TIMESTAMP) resamp_outchunk; @@ -227,7 +238,7 @@ void RadioInterfaceResamp::pushBuffer() LOG(ALERT) << "Sample rate downsampling error"; } - convert_float_short(convertSendBuffer, + convert_float_short(convertSendBuffer[0], (float *) outerSendBuffer->begin(), powerScaling, 2 * outer_len); diff --git a/Transceiver52M/radioVector.cpp b/Transceiver52M/radioVector.cpp index 043effa..8869821 100644 --- a/Transceiver52M/radioVector.cpp +++ b/Transceiver52M/radioVector.cpp @@ -70,21 +70,6 @@ bool noiseVector::insert(float val) return true; } -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 8dc1c13..0b38bff 100644 --- a/Transceiver52M/radioVector.h +++ b/Transceiver52M/radioVector.h @@ -47,15 +47,7 @@ private: std::vector<float>::iterator it; }; -class VectorFIFO { -public: - unsigned size(); - void put(radioVector *ptr); - radioVector *get(); - -private: - PointerFIFO mQ; -}; +class VectorFIFO : public InterthreadQueue<radioVector> { }; class VectorQueue : public InterthreadPriorityQueue<radioVector> { public: diff --git a/Transceiver52M/runTransceiver.cpp b/Transceiver52M/runTransceiver.cpp index 6a7cc53..395908c 100644 --- a/Transceiver52M/runTransceiver.cpp +++ b/Transceiver52M/runTransceiver.cpp @@ -27,7 +27,6 @@ #include "Transceiver.h" #include "radioDevice.h" -#include "DummyLoad.h" #include <time.h> #include <signal.h> @@ -108,16 +107,21 @@ int testConfig(const char *filename) int main(int argc, char *argv[]) { - int trxPort, radioType, extref = 0, fail = 0; - std::string deviceArgs, logLevel, trxAddr; + int trxPort, radioType, chans = 1, extref = 0, fail = 0; + std::string logLevel, trxAddr, deviceArgs = ""; RadioDevice *usrp = NULL; RadioInterface *radio = NULL; Transceiver *trx = NULL; + VectorFIFO *fifo = NULL; - if (argc == 3) + if (argc == 3) { deviceArgs = std::string(argv[2]); - else - deviceArgs = ""; + chans = atoi(argv[1]); + } else if (argc == 2) { + chans = atoi(argv[1]); + } else if (argc != 1) { + std::cout << argv[0] << " <number of channels> <device args>" << std::endl; + } if (signal(SIGINT, ctrlCHandler) == SIG_ERR) { std::cerr << "Couldn't install signal handler for SIGINT" << std::endl; @@ -151,7 +155,7 @@ int main(int argc, char *argv[]) srandom(time(NULL)); - usrp = RadioDevice::make(SPS); + usrp = RadioDevice::make(SPS, chans); radioType = usrp->open(deviceArgs, extref); if (radioType < 0) { LOG(ALERT) << "Transceiver exiting..." << std::endl; @@ -160,11 +164,11 @@ int main(int argc, char *argv[]) switch (radioType) { case RadioDevice::NORMAL: - radio = new RadioInterface(usrp, 3, SPS, false); + radio = new RadioInterface(usrp, 3, SPS, chans); break; case RadioDevice::RESAMP_64M: case RadioDevice::RESAMP_100M: - radio = new RadioInterfaceResamp(usrp, 3, SPS, false); + radio = new RadioInterfaceResamp(usrp, 3, SPS, chans); break; default: LOG(ALERT) << "Unsupported configuration"; @@ -177,13 +181,24 @@ int main(int argc, char *argv[]) goto shutdown; } - trx = new Transceiver(trxPort, trxAddr.c_str(), SPS, GSM::Time(3,0), radio); + trx = new Transceiver(trxPort, trxAddr.c_str(), + SPS, chans, GSM::Time(3,0), radio); if (!trx->init()) { LOG(ALERT) << "Failed to initialize transceiver"; fail = 1; goto shutdown; } - trx->receiveFIFO(radio->receiveFIFO()); + + for (int i = 0; i < chans; i++) { + fifo = radio->receiveFIFO(i); + if (fifo && trx->receiveFIFO(fifo, i)) + continue; + + LOG(ALERT) << "Could not attach FIFO to channel " << i; + fail = 1; + goto shutdown; + } + trx->start(); while (!gbShutdown) |