From fa003728202a7b940292730ebbf25a416da1b268 Mon Sep 17 00:00:00 2001 From: Kurtis Heimerl Date: Thu, 31 May 2012 00:05:17 +0000 Subject: [PATCH] Adding MultiARFCN support to RAD1 radio. git-svn-id: http://wush.net/svn/range/software/public/openbts/trunk@3689 19bc5d8c-e614-43d4-8b26-e1612bc8e597 --- TransceiverRAD1/RAD1Device.h | 6 +- TransceiverRAD1/Transceiver.cpp | 1179 +++++++++++++++++----------- TransceiverRAD1/Transceiver.h | 165 +++- TransceiverRAD1/radioInterface.cpp | 40 +- TransceiverRAD1/radioInterface.h | 18 +- TransceiverRAD1/rnrad1Core.cpp | 2 +- TransceiverRAD1/runTransceiver.cpp | 67 +- TransceiverRAD1/sigProcLib.cpp | 1 + 8 files changed, 978 insertions(+), 500 deletions(-) diff --git a/TransceiverRAD1/RAD1Device.h b/TransceiverRAD1/RAD1Device.h index 378ecce..e1c5d75 100644 --- a/TransceiverRAD1/RAD1Device.h +++ b/TransceiverRAD1/RAD1Device.h @@ -124,21 +124,21 @@ private: static const unsigned BSC = 3; // bits 21,20 Div by 8 to be safe static const unsigned TEST = 0; // bit 19 static const unsigned LDP = 1; // bit 18 - static const unsigned ABP = 0; // bit 17,16 3ns + static const unsigned ABP = 2; // bit 17,16 6ns, 0 = 3ns // N-Register Common Values static const unsigned N_RSV = 0; // bit 7 // Control Register Common Values static const unsigned PD = 0; // bits 21,20 Normal operation - static const unsigned PL = 2; // bits 13,12 7.5mA, -6dbm + static const unsigned PL = 1; // bits 13,12 7.5mA, -6dbm static const unsigned MTLD = 1; // bit 11 enabled static const unsigned CPG = 0; // bit 10 CP setting 1 static const unsigned CP3S = 0; // bit 9 Normal static const unsigned PDP = 1; // bit 8 Positive static const unsigned MUXOUT = 1;// bits 7:5 Digital Lock Detect static const unsigned CR = 0; // bit 4 Normal - static const unsigned PC = 2; // bits 3,2 Core power 15mA + static const unsigned PC = 0; // bits 3,2 Core power 15mA // ATR register value //static const int FR_ATR_MASK_0 = 20; diff --git a/TransceiverRAD1/Transceiver.cpp b/TransceiverRAD1/Transceiver.cpp index e2e20a8..1cd6b93 100644 --- a/TransceiverRAD1/Transceiver.cpp +++ b/TransceiverRAD1/Transceiver.cpp @@ -39,19 +39,26 @@ Transceiver::Transceiver(int wBasePort, const char *TRXAddress, int wSamplesPerSymbol, GSM::Time wTransmitLatency, - RadioInterface *wRadioInterface) - :mDataSocket(wBasePort+2,TRXAddress,wBasePort+102), - mControlSocket(wBasePort+1,TRXAddress,wBasePort+101), - mClockSocket(wBasePort,TRXAddress,wBasePort+100) + RadioInterface *wRadioInterface, + unsigned int wNumARFCNs, + unsigned int wOversamplingRate, + bool wLoadTest) + :mClockSocket(wBasePort,TRXAddress,wBasePort+100) { //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 + GSM::Time startTime = mStartTime = GSM::Time(random() % gHyperframe,0); + mFIFOServiceLoopThread = new Thread(2*32768); ///< thread to push bursts into transmit FIFO + mRFIFOServiceLoopThread = new Thread(4*32768); + for (int j = 0; j< wNumARFCNs; j++) { + mControlServiceLoopThread[j] = new Thread(32768); + mTransmitPriorityQueueServiceLoopThread[j] = new Thread(32768); + if (wNumARFCNs > 1) mDemodServiceLoopThread[j] = new Thread(32768); + mDemodFIFO[j] = new VectorFIFO; + mDataSocket[j] = new UDPSocket(wBasePort+2*(j+1),TRXAddress,wBasePort+100+2*(j+1)); + mControlSocket[j] = new UDPSocket(wBasePort+2*j+1,TRXAddress,wBasePort+100+2*j+1); + } mSamplesPerSymbol = wSamplesPerSymbol; mRadioInterface = wRadioInterface; @@ -60,7 +67,13 @@ Transceiver::Transceiver(int wBasePort, mLastClockUpdateTime = startTime; mLatencyUpdateTime = startTime; mRadioInterface->getClock()->set(startTime); - mMaxExpectedDelay = 0; + mMaxExpectedDelay = 1; + + mNumARFCNs = wNumARFCNs; + mOversamplingRate = wOversamplingRate; + mLoadTest = wLoadTest; + + LOG(INFO) << "running " << mNumARFCNs << " ARFCNs"; // generate pulse and setup up signal processing library gsmPulse = generateGSMPulse(2,mSamplesPerSymbol); @@ -76,24 +89,64 @@ Transceiver::Transceiver(int wBasePort, 8 + (i % 4 == 0), mSamplesPerSymbol); scaleVector(*modBurst,txFullScale); - fillerModulus[i]=26; + 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; + for (int j = 0; j < mNumARFCNs; j++) { + mChanType[j][i] = NONE; + } + } + + mFreqOffset = 0.0; + mMultipleARFCN = (mNumARFCNs > 1); + if (mMultipleARFCN) { + //mOversamplingRate = mNumARFCNs/2 + mNumARFCNs; + //mOversamplingRate = 15; //mOversamplingRate*4; + //if (mOversamplingRate % 2) mOversamplingRate++; + double beaconFreq = -1.0*(mNumARFCNs-1)*200e3; + for (int j = 0; j < mNumARFCNs; j++) { + frequencyShifter[j] = new signalVector(157*mOversamplingRate); + frequencyShifter[j]->fill(complex(1.0,0.0)); + frequencyShifter[j]->isRealOnly(false); + frequencyShift(frequencyShifter[j],frequencyShifter[j],2.0*M_PI*(beaconFreq+j*400e3)/(1625.0e3/6.0*mOversamplingRate)); + } + + int filtLen = 6*mOversamplingRate; + decimationFilter = createLPF(0.5/mOversamplingRate,filtLen,1); + interpolationFilter = createLPF(0.5/mOversamplingRate,filtLen,1); + scaleVector(*interpolationFilter,mOversamplingRate); + mFreqOffset = -beaconFreq; + mRadioInterface->setSamplesPerSymbol(SAMPSPERSYM*mOversamplingRate); + + // refill filler table + for (int i = 0; i < 8; i++) { + signalVector* modBurst = modulateBurst(gDummyBurst,*gsmPulse, + 8 + (i % 4 == 0), + mSamplesPerSymbol); + scaleVector(*modBurst,txFullScale/mNumARFCNs); + signalVector *interpVec = polyphaseResampleVector(*modBurst,mOversamplingRate,1,interpolationFilter); + //signalVector *interpVec = new signalVector(modBurst->size()*mOversamplingRate); + //interpVec->fill(txFullScale); + multVector(*interpVec,*frequencyShifter[0]); + for (int j = 0; j < 102; j++) { + delete fillerTable[j][i]; + fillerTable[j][i] = new signalVector(*interpVec); + } + delete modBurst; + delete interpVec; + } } mOn = false; mTxFreq = 0.0; mRxFreq = 0.0; mPower = -10; - mEnergyThreshold = 5.0; // based on empirical data - prevFalseDetectionTime = startTime; + + mControlLock.unlock(); + mTransmitPriorityQueueLock.unlock(); + } Transceiver::~Transceiver() @@ -106,14 +159,33 @@ Transceiver::~Transceiver() void Transceiver::addRadioVector(BitVector &burst, int RSSI, - GSM::Time &wTime) + GSM::Time &wTime, + int ARFCN) { // modulate and stick into queue signalVector* modBurst = modulateBurst(burst,*gsmPulse, 8 + (wTime.TN() % 4 == 0), mSamplesPerSymbol); - scaleVector(*modBurst,txFullScale * pow(10,-RSSI/10)); - radioVector *newVec = new radioVector(*modBurst,wTime); + /*complex rScale = complex(2*M_PI*((float) rand()/(float) RAND_MAX),(2*M_PI*((float) rand()/(float) RAND_MAX))); + rScale = rScale/rScale.abs(); + scaleVector(*modBurst,rScale);*/ + float headRoom = (mNumARFCNs > 1) ? 0.5 : 1.0; + scaleVector(*modBurst,txFullScale * headRoom * pow(10,-RSSI/10)/mNumARFCNs); + radioVector *newVec = new radioVector(*modBurst,wTime,ARFCN); + + // upsample and filter and freq shift + if (mMultipleARFCN) { + signalVector *interpVec = polyphaseResampleVector(*((signalVector *)newVec),mOversamplingRate,1,interpolationFilter); + //LOG(DEBUG) << "newVec size: " << newVec->size() << ", interpVec: " << interpVec->size(); + delete newVec; + + //if (ARFCN!=0) printf("ARFCN: %d\n",ARFCN); + multVector(*interpVec,*frequencyShifter[ARFCN]); + + newVec = new radioVector(*interpVec,wTime,ARFCN); + delete interpVec; + } + mTransmitPriorityQueue.write(newVec); delete modBurst; @@ -150,43 +222,65 @@ void Transceiver::pushRadioVector(GSM::Time &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->time(); - int TN = nextTime.TN(); - int modFN = nextTime.FN() % fillerModulus[TN]; - delete fillerTable[modFN][TN]; - fillerTable[modFN][TN] = staleBurst; + if (staleBurst->ARFCN()==0) { + const GSM::Time& nextTime = staleBurst->time(); + int TN = nextTime.TN(); + int modFN = nextTime.FN() % fillerModulus[TN]; + // FIXME!!!!!! + delete fillerTable[modFN][TN]; + fillerTable[modFN][TN] = staleBurst; + } + else + delete staleBurst; } int TN = nowTime.TN(); int modFN = nowTime.FN() % fillerModulus[nowTime.TN()]; + bool addFiller = true; + radioVector *sendVec = NULL; + // 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 fillerTable[modFN][TN]; - fillerTable[modFN][TN] = new signalVector(*(next)); - mRadioInterface->driveTransmitRadio(*(next),(mChanType[TN]==NONE)); //fillerTable[modFN][TN])); - delete next; -#ifdef TRANSMIT_LOGGING - if (nowTime.TN()==TRANSMIT_LOGGING) { - unModulateVector(*(fillerTable[modFN][TN])); + while (radioVector *next = (radioVector*) mTransmitPriorityQueue.getCurrentBurst(nowTime)) { + //LOG(DEBUG) << "transmitFIFO: wrote burst " << next << " at time: " << nowTime; + if (next->ARFCN() == 0) { + delete fillerTable[modFN][TN]; + fillerTable[modFN][TN] = new signalVector(*(next)); + addFiller = false; + } + if (!sendVec) + sendVec = next; + else { + addVector(*sendVec,*next); + delete next; } -#endif - return; } + if (addFiller) { + // pull filler data, and push to radio FIFO + int dummy = 0; + radioVector *tmpVec = new radioVector(*fillerTable[modFN][TN],nowTime,dummy); + if (!sendVec) + sendVec = tmpVec; + else { + addVector(*sendVec,*tmpVec); + delete tmpVec; + } + } + + //LOG(DEBUG) << "sendVec size: " << sendVec->size(); + // 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 + mRadioInterface->driveTransmitRadio(*sendVec,(mChanType[0][TN]==NONE)); + + delete sendVec; } void Transceiver::setModulus(int timeslot) { - switch (mChanType[timeslot]) { + + switch (mChanType[0][timeslot]) { case NONE: case I: case II: @@ -209,13 +303,13 @@ void Transceiver::setModulus(int timeslot) } -Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime) +CorrType Transceiver::expectedCorrType(GSM::Time currTime, int ARFCN) { unsigned burstTN = currTime.TN(); unsigned burstFN = currTime.FN(); - switch (mChanType[burstTN]) { + switch (mChanType[ARFCN][burstTN]) { case NONE: return OFF; break; @@ -273,42 +367,606 @@ Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime) } -SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, - int &RSSI, - int &timingOffset) +void Transceiver::pullRadioVector() { - bool needDFE = (mMaxExpectedDelay > 1); + radioVector *rxBurst = NULL; + rxBurst = (radioVector *) mReceiveFIFO->get(); + if (!rxBurst) return; - radioVector *rxBurst = (radioVector *) mReceiveFIFO->get(); - - if (!rxBurst) return NULL; - - LOG(DEBUG) << "receiveFIFO: read radio vector at time: " << rxBurst->time() << ", new size: " << mReceiveFIFO->size(); + //LOG(DEBUG) << "receiveFIFO: read radio vector " << rxBurst << " at time: " << rxBurst->time() << ", new size: " << mReceiveFIFO->size(); + GSM::Time theTime = rxBurst->time(); int timeslot = rxBurst->time().TN(); - CorrType corrType = expectedCorrType(rxBurst->time()); + for (int i = 0; i < mNumARFCNs; i++) { + CorrType corrType = expectedCorrType(rxBurst->time(),i); + if ((corrType == OFF) || (corrType == IDLE)) continue; + radioVector *ARFCNVec = new radioVector(*(signalVector *)rxBurst,theTime,i); + if (mMultipleARFCN) { + multVector(*ARFCNVec,*frequencyShifter[mNumARFCNs-1-i]); + signalVector *rcvVec = polyphaseResampleVector(*ARFCNVec,1,mOversamplingRate,decimationFilter); + delete ARFCNVec; + ARFCNVec = new radioVector(*rcvVec,theTime,i); + delete rcvVec; + } + //LOG(INFO) << "putting " << ARFCNVec << " in queue " << i << " at time " << theTime; + mDemodFIFO[i]->put(ARFCNVec); + } + + delete rxBurst; +} + +void Transceiver::start() +{ + for(int i = 0; i < mNumARFCNs; i++) { + ThreadStruct *cs = new ThreadStruct; + cs->trx = this; + cs->ARFCN = i; + mControlServiceLoopThread[i]->start((void * (*)(void*))ControlServiceLoopAdapter,(void*) cs); + } +} + +void Transceiver::reset() +{ + mTransmitPriorityQueue.clear(); + //mTransmitFIFO->clear(); + //mReceiveFIFO->clear(); +} + + +void Transceiver::driveControl(unsigned ARFCN) +{ + + int MAX_PACKET_LENGTH = 100; + + // check control socket + char buffer[MAX_PACKET_LENGTH]; + int msgLen = -1; + buffer[0] = '\0'; + + msgLen = mControlSocket[ARFCN]->read(buffer); + + mControlLock.lock(); + + if (msgLen < 1) { + mControlLock.unlock(); + return; + } + + char cmdcheck[4]; + char command[MAX_PACKET_LENGTH]; + char response[MAX_PACKET_LENGTH]; + + sscanf(buffer,"%3s %s",cmdcheck,command); + + writeClockInterface(); + + if (strcmp(cmdcheck,"CMD")!=0) { + LOG(ERR) << "bogus message on control interface"; + mControlLock.unlock(); + return; + } + LOG(INFO) << "command is " << buffer; + + if (strcmp(command,"POWEROFF")==0) { + // turn off transmitter/demod + sprintf(response,"RSP POWEROFF 0"); + } + else if (strcmp(command,"POWERON")==0) { + // turn on transmitter/demod + if (!mTxFreq || !mRxFreq) + sprintf(response,"RSP POWERON 1"); + else { + sprintf(response,"RSP POWERON 0"); + if (!mOn) { + // Prepare for thread start + mPower = -20; + mRadioInterface->start(); + + // Start radio interface threads. + writeClockInterface(); + generateRACHSequence(*gsmPulse,mSamplesPerSymbol); + + mRFIFOServiceLoopThread->start((void * (*)(void*))RFIFOServiceLoopAdapter,(void*) this); + mFIFOServiceLoopThread->start((void * (*)(void*))FIFOServiceLoopAdapter,(void*) this); + + for (int i = 0; i < mNumARFCNs; i++) { + ThreadStruct *cs = new ThreadStruct; + cs->trx = this; + cs->ARFCN = i; + mTransmitPriorityQueueServiceLoopThread[i]->start((void * (*)(void*))TransmitPriorityQueueServiceLoopAdapter,(void*) cs); + Demodulator *demod = new Demodulator(i,this,mStartTime); + mDemodulators[i] = demod; + if (mNumARFCNs > 1) mDemodServiceLoopThread[i]->start((void * (*)(void*))DemodServiceLoopAdapter,(void*) demod); + } + + //mRFIFOServiceLoopThread->start((void * (*)(void*))RFIFOServiceLoopAdapter,(void*) this); + //mFIFOServiceLoopThread->start((void * (*)(void*))FIFOServiceLoopAdapter,(void*) this); + + + mOn = true; + } + } + } + else if (strcmp(command,"SETMAXDLY")==0) { + // FIXME -- Use the configuration table instead. + //set expected maximum time-of-arrival + int maxDelay; + sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay); + mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km + sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay); + } + else if (strcmp(command,"SETRXGAIN")==0) { + // FIXME -- Use the configuration table instead. + //set expected maximum time-of-arrival + int newGain; + sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain); + newGain = mRadioInterface->setRxGain(newGain); + sprintf(response,"RSP SETRXGAIN 0 %d",newGain); + } + else if (strcmp(command,"NOISELEV")==0) { + // FIXME -- Use the status table instead. + if (mOn) { + sprintf(response,"RSP NOISELEV 0 %d", + (int) round(20.0*log10(rxFullScale/mDemodulators[0]->getEnergyThreshold()))); + } + else { + sprintf(response,"RSP NOISELEV 1 0"); + } + } + else if (strcmp(command,"SETPOWER")==0) { + // set output power in dB + int dbPwr; + sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbPwr); + if (!mOn) + sprintf(response,"RSP SETPOWER 1 %d",dbPwr); + else { + if (ARFCN==0) { + mPower = dbPwr; + mRadioInterface->setPowerAttenuation(dbPwr + gConfig.getNum("TRX.TxAttenOffset")); + } + sprintf(response,"RSP SETPOWER 0 %d",dbPwr); + } + } + else if (strcmp(command,"ADJPOWER")==0) { + // FIXME -- Use the configuration table instead. + // adjust power in dB steps + int dbStep; + sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbStep); + if (!mOn) + sprintf(response,"RSP ADJPOWER 1 %d",mPower); + else { + if (ARFCN==0) + mPower += dbStep; + sprintf(response,"RSP ADJPOWER 0 %d",mPower); + } + } + else if (strcmp(command,"RXTUNE")==0) { + // tune receiver + int freqKhz; + sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz); + mRxFreq = freqKhz*1.0e3+mFreqOffset; + if ((ARFCN==0) && !mRadioInterface->tuneRx(mRxFreq,gConfig.getNum("TRX.RadioFrequencyOffset"))) { + LOG(ALERT) << "RX failed to tune"; + sprintf(response,"RSP RXTUNE 1 %d",freqKhz); + } + else + sprintf(response,"RSP RXTUNE 0 %d",freqKhz); + } + else if (strcmp(command,"TXTUNE")==0) { + // tune txmtr + int freqKhz; + sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz); + //freqKhz = 890e3; + mTxFreq = freqKhz*1.0e3+mFreqOffset; + if ((ARFCN==0) && !mRadioInterface->tuneTx(mTxFreq,gConfig.getNum("TRX.RadioFrequencyOffset"))) { + LOG(ALERT) << "TX failed to tune"; + sprintf(response,"RSP TXTUNE 1 %d",freqKhz); + } + else + sprintf(response,"RSP TXTUNE 0 %d",freqKhz); + } + else if (strcmp(command,"SETTSC")==0) { + // set TSC + int TSC; + sscanf(buffer,"%3s %s %d",cmdcheck,command,&TSC); + if (mOn) + sprintf(response,"RSP SETTSC 1 %d",TSC); + else { + if (ARFCN==0) { + mTSC = TSC; + generateMidamble(*gsmPulse,mSamplesPerSymbol,TSC); + } + sprintf(response,"RSP SETTSC 0 %d",TSC); + } + } + else if (strcmp(command,"SETSLOT")==0) { + // set TSC + int corrCode; + int timeslot; + sscanf(buffer,"%3s %s %d %d",cmdcheck,command,×lot,&corrCode); + //sscanf(buffer,"%3s %s %d %d %d",cmdcheck,command,×lot,&corrCode,&ARFCN); + if ((timeslot < 0) || (timeslot > 7)) { + LOG(ERR) << "bogus message on control interface"; + sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode); + } + else if ((ARFCN < 0) || (ARFCN >= MAXARFCN)) { + LOG(ERR) << "bogus message on control interface"; + sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode); + } + else { + mChanType[ARFCN][timeslot] = (ChannelCombination) corrCode; + setModulus(timeslot); + sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode); + } + } + else { + LOG(ERR) << "bogus command " << command << " on control interface."; + } + + mControlSocket[ARFCN]->write(response,strlen(response)+1); + + mControlLock.unlock(); + + +} + +bool Transceiver::driveTransmitPriorityQueue(unsigned ARFCN) +{ + + +#if 1 + char buffer[gSlotLen+50]; + + // check data socket + size_t msgLen = mDataSocket[ARFCN]->read(buffer); + + mTransmitPriorityQueueLock.lock(); + + if (msgLen!=gSlotLen+1+4+1) { + LOG(ERR) << "badly formatted packet on GSM->TRX interface"; + mTransmitPriorityQueueLock.unlock(); + return false; + } + + int timeSlot = (int) buffer[0]; + uint64_t frameNum = 0; + for (int i = 0; i < 4; i++) + frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]); + + /* + if (GSM::Time(frameNum,timeSlot) > mTransmitDeadlineClock + GSM::Time(51,0)) { + // stale burst + //LOG(DEBUG) << "FAST! "<< GSM::Time(frameNum,timeSlot); + //writeClockInterface(); + }*/ + +/* + DAB -- Just let these go through the demod. + if (GSM::Time(frameNum,timeSlot) < mTransmitDeadlineClock) { + // stale burst from GSM core + LOG(NOTICE) << "STALE packet on GSM->TRX interface at time "<< GSM::Time(frameNum,timeSlot); + return false; + } +*/ + + // periodically update GSM core clock + //LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock + // << " mLastClockUpdateTime " << mLastClockUpdateTime; + if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0)) + writeClockInterface(); + + + //LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot); + + int RSSI = (int) buffer[5]; + static BitVector newBurst(gSlotLen); + BitVector::iterator itr = newBurst.begin(); + char *bufferItr = buffer+6; + while (itr < newBurst.end()) + *itr++ = *bufferItr++; + + GSM::Time currTime = GSM::Time(frameNum,timeSlot); + + addRadioVector(newBurst,RSSI,currTime,ARFCN); + + //LOG(DEBUG) "added burst - time: " << currTime << ", RSSI: " << RSSI; // << ", data: " << newBurst; + + mTransmitPriorityQueueLock.unlock(); +#else + RadioClock *radioClock = (mRadioInterface->getClock()); + + if (mOn) { + radioClock->wait(); // wait until clock updates + // time to push burst to transmit FIFO + mTransmitPriorityQueueLock.lock(); + for (int i = 0; i < 4; i++) + { + int iSlot = radioClock->get().TN(); //mTransmitDeadlineClock.TN(); + static BitVector newBurst(gSlotLen); + GSM::Time currTime = GSM::Time(mTransmitDeadlineClock.FN()+50,(iSlot+i)%8); + addRadioVector(newBurst,0,currTime,ARFCN); + //printf("adding %d %d\n",mTransmitDeadlineClock.FN(),iSlot); + } + mTransmitPriorityQueueLock.unlock(); + } +#endif + + + return true; + + +} + +void Transceiver::driveReceiveFIFO() +{ + mRadioInterface->driveReceiveRadio(); + + pullRadioVector(); +} + + +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->isUnderrun()) { + // only do latency update every 10 frames, so we don't over update + if (radioClock->get() > mLatencyUpdateTime + GSM::Time(100,0)) { + mTransmitLatency = mTransmitLatency + GSM::Time(1,0); + LOG(NOTICE) << "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(1,1)) { + if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) { + mTransmitLatency.decTN(); + LOG(NOTICE) << "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]; + // FIME -- See tracker #315. + //sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+10)); + sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2)); + + LOG(INFO) << "ClockInterface: sending " << command; + + mClockSocket.write(command,strlen(command)+1); + + mLastClockUpdateTime = mTransmitDeadlineClock; + +} + +void *FIFOServiceLoopAdapter(Transceiver *transceiver) +{ + while (1) { + //transceiver->driveReceiveFIFO(); + transceiver->driveTransmitFIFO(); + pthread_testcancel(); + } + return NULL; +} + +void *RFIFOServiceLoopAdapter(Transceiver *transceiver) +{ + bool isMulti = transceiver->multiARFCN(); + while (1) { + transceiver->driveReceiveFIFO(); + if (!isMulti) transceiver->mDemodulators[0]->driveDemod(true); + //transceiver->driveTransmitFIFO(); + pthread_testcancel(); + } + return NULL; +} + + +void *ControlServiceLoopAdapter(ThreadStruct *ts) +{ + Transceiver *transceiver = ts->trx; + unsigned ARFCN = ts->ARFCN; + while (1) { + transceiver->driveControl(ARFCN); + pthread_testcancel(); + } + return NULL; +} + +void *DemodServiceLoopAdapter(Demodulator *demodulator) +{ + while(1) { + demodulator->driveDemod(); + pthread_testcancel(); + } + return NULL; +} + +void *TransmitPriorityQueueServiceLoopAdapter(ThreadStruct *ts) +{ + Transceiver *transceiver = ts->trx; + unsigned ARFCN = ts->ARFCN; + while (1) { + bool stale = false; + // Flush the UDP packets until a successful transfer. + while (!transceiver->driveTransmitPriorityQueue(ARFCN)) { + stale = true; + } + if (stale) { + // If a packet was stale, remind the GSM stack of the clock. + transceiver->writeClockInterface(); + } + pthread_testcancel(); + } + return NULL; +} + + +Demodulator::Demodulator(int wARFCN, + Transceiver *wTRX, + GSM::Time wStartTime) +{ + + assert(wTRX); + + mARFCN = wARFCN; + mTRX = wTRX; + mRadioInterface = mTRX->radioInterface(); + mTRXDataSocket = mTRX->dataSocket(mARFCN); + mSamplesPerSymbol = mTRX->samplesPerSymbol(); + mDemodFIFO = mTRX->demodFIFO(mARFCN); + signalVector *gsmPulse = mTRX->GSMPulse(); + mTSC = mTRX->getTSC(); + + rxFullScale = mRadioInterface->fullScaleOutputValue(); + + LOG(DEBUG) << "Creating demodulator for ARFCN " << mARFCN << " with TSC " << mTSC; + + for (unsigned i = 0; i < 8; i++) { + channelResponse[i] = NULL; + DFEForward[i] = NULL; + DFEFeedback[i] = NULL; + channelEstimateTime[i] = wStartTime; + mEnergyThreshold = 7.07; + } + + prevFalseDetectionTime = wStartTime; + +} + +void Demodulator::driveDemod(bool wSingleARFCN) +{ + + //LOG(DEBUG) << "calling driveDemod "; + + radioVector *demodBurst = NULL; + SoftVector *rxBurst = NULL; + int RSSI; + int TOA; // in 1/256 of a symbol + GSM::Time burstTime; + + //RadioClock *radioClock = (mRadioInterface->getClock()); + //radioClock->wait(); + + demodBurst = mDemodFIFO->get(); + if (!wSingleARFCN) { + while (!demodBurst) { + RadioClock *radioClock = (mRadioInterface->getClock()); + radioClock->wait(); + demodBurst = mDemodFIFO->get(); + } + } + else { + if (!demodBurst) return; + } + + mMaxExpectedDelay = mTRX->maxDelay(); + + rxBurst = demodRadioVector(demodBurst,burstTime,RSSI,TOA); + + if (rxBurst) { + + LOG(DEBUG) << "burst parameters: " + << " ARFCN: " << mARFCN + << " 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; + + mTRXDataSocket->write(burstString,gSlotLen+10); + } + +} + +SoftVector *Demodulator::demodRadioVector(radioVector *rxBurst, + GSM::Time &wTime, + int &RSSI, + int &timingOffset) +{ + + bool needDFE = (mMaxExpectedDelay > 1); + + int timeslot = rxBurst->time().TN(); + + CorrType corrType = mTRX->expectedCorrType(rxBurst->time(),mARFCN); + + //LOG(INFO) << "Demoding ptr " << rxBurst << " at " << rxBurst->time() << " for ARFCN " << mARFCN; if ((corrType==OFF) || (corrType==IDLE)) { + //LOG(DEBUG) << "Illegal burst"; delete rxBurst; return NULL; } // check to see if received burst has sufficient signalVector *vectorBurst = rxBurst; + //LOG(DEBUG) << "vectorBurst: " << vectorBurst << " rxBurst: " << rxBurst; complex amplitude = 0.0; float TOA = 0.0; float avgPwr = 0.0; - if (!energyDetect(*vectorBurst,20*mSamplesPerSymbol,mEnergyThreshold,&avgPwr)) { + /*if (!energyDetect(*vectorBurst,20*mSamplesPerSymbol,mEnergyThreshold,&avgPwr)) { LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->time(); double framesElapsed = rxBurst->time()-prevFalseDetectionTime; if (framesElapsed > 50) { // if we haven't had any false detections for a while, lower threshold - mEnergyThreshold -= 10.0/10.0; + //mEnergyThreshold -= 1.0; prevFalseDetectionTime = rxBurst->time(); } + //LOG(INFO) << "Low burst energy."; delete rxBurst; + LOG(INFO) << "Deleting " << rxBurst; return NULL; - } + }*/ LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->time(); // run the proper correlator @@ -318,7 +976,8 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, signalVector *channelResp; double framesElapsed = rxBurst->time()-channelEstimateTime[timeslot]; bool estimateChannel = false; - if ((framesElapsed > 50) || (channelResponse[timeslot]==NULL)) { + //if ((framesElapsed > 50) || (channelResponse[timeslot]==NULL)) { + { if (channelResponse[timeslot]) delete channelResponse[timeslot]; if (DFEForward[timeslot]) delete DFEForward[timeslot]; if (DFEFeedback[timeslot]) delete DFEFeedback[timeslot]; @@ -327,8 +986,10 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, DFEFeedback[timeslot] = NULL; estimateChannel = true; } + estimateChannel = true; if (!needDFE) estimateChannel = false; float chanOffset; + success = analyzeTrafficBurst(*vectorBurst, mTSC, 3.0, @@ -336,12 +997,13 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, &litude, &TOA, mMaxExpectedDelay, - estimateChannel, + estimateChannel, &channelResp, &chanOffset); + if (success) { LOG(DEBUG) << "FOUND TSC!!!!!! " << amplitude << " " << TOA; - mEnergyThreshold -= 1.0F/10.0F; + //mEnergyThreshold -= 0.1F; if (mEnergyThreshold < 0.0) mEnergyThreshold = 0.0; SNRestimate[timeslot] = amplitude.norm2()/(mEnergyThreshold*mEnergyThreshold+1.0); // this is not highly accurate if (estimateChannel) { @@ -358,7 +1020,7 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, else { double framesElapsed = rxBurst->time()-prevFalseDetectionTime; LOG(DEBUG) << "wTime: " << rxBurst->time() << ", pTime: " << prevFalseDetectionTime << ", fElapsed: " << framesElapsed; - mEnergyThreshold += 10.0F/10.0F*exp(-framesElapsed); + //mEnergyThreshold += 0.1F*exp(-framesElapsed); prevFalseDetectionTime = rxBurst->time(); channelResponse[timeslot] = NULL; } @@ -366,19 +1028,19 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, else { // RACH burst success = detectRACHBurst(*vectorBurst, - 5.0, // detection threshold + 3.0, // detection threshold mSamplesPerSymbol, &litude, &TOA); if (success) { LOG(DEBUG) << "FOUND RACH!!!!!! " << amplitude << " " << TOA; - mEnergyThreshold -= (1.0F/10.0F); + //mEnergyThreshold -= 0.1F; if (mEnergyThreshold < 0.0) mEnergyThreshold = 0.0; channelResponse[timeslot] = NULL; } else { double framesElapsed = rxBurst->time()-prevFalseDetectionTime; - mEnergyThreshold += (1.0F/10.0F)*exp(-framesElapsed); + //mEnergyThreshold += 0.1F*exp(-framesElapsed); prevFalseDetectionTime = rxBurst->time(); } } @@ -408,392 +1070,9 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, timingOffset = (int) round(TOA*256.0/mSamplesPerSymbol); } - //if (burst) LOG(DEBUG) << "burst: " << *burst << '\n'; - + //if (burst) LOG(DEEPDEBUG) << "burst: " << *burst << '\n'; + LOG(DEBUG) << "Deleting rxBurst"; delete rxBurst; return burst; } - -void Transceiver::start() -{ - mControlServiceLoopThread->start((void * (*)(void*))ControlServiceLoopAdapter,(void*) this); -} - -void Transceiver::reset() -{ - mTransmitPriorityQueue.clear(); - //mTransmitFIFO->clear(); - //mReceiveFIFO->clear(); -} - - -void Transceiver::driveControl() -{ - - int MAX_PACKET_LENGTH = 100; - - // check control socket - char buffer[MAX_PACKET_LENGTH]; - int msgLen = -1; - buffer[0] = '\0'; - - msgLen = mControlSocket.read(buffer); - - if (msgLen < 1) { - return; - } - - char cmdcheck[4]; - char command[MAX_PACKET_LENGTH]; - char response[MAX_PACKET_LENGTH]; - - sscanf(buffer,"%3s %s",cmdcheck,command); - - writeClockInterface(); - - if (strcmp(cmdcheck,"CMD")!=0) { - LOG(WARNING) << "bogus message on control interface"; - return; - } - LOG(INFO) << "command is " << buffer; - - if (strcmp(command,"POWEROFF")==0) { - // turn off transmitter/demod - sprintf(response,"RSP POWEROFF 0"); - } - else if (strcmp(command,"POWERON")==0) { - // turn on transmitter/demod - if (!mTxFreq || !mRxFreq) - sprintf(response,"RSP POWERON 1"); - else { - sprintf(response,"RSP POWERON 0"); - if (!mOn) { - // Prepare for thread start - mPower = -20; - mRadioInterface->start(); - generateRACHSequence(*gsmPulse,mSamplesPerSymbol); - - // Start radio interface threads. - mFIFOServiceLoopThread->start((void * (*)(void*))FIFOServiceLoopAdapter,(void*) this); - mTransmitPriorityQueueServiceLoopThread->start((void * (*)(void*))TransmitPriorityQueueServiceLoopAdapter,(void*) this); - writeClockInterface(); - - mOn = true; - } - } - } - else if (strcmp(command,"SETMAXDLY")==0) { - //set expected maximum time-of-arrival - int maxDelay; - sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay); - mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km - sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay); - } - else if (strcmp(command,"SETRXGAIN")==0) { - //set expected maximum time-of-arrival - int newGain; - sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain); - newGain = mRadioInterface->setRxGain(newGain); - sprintf(response,"RSP SETRXGAIN 0 %d",newGain); - } - else if (strcmp(command,"NOISELEV")==0) { - if (mOn) { - sprintf(response,"RSP NOISELEV 0 %d", - (int) round(20.0*log10(rxFullScale/mEnergyThreshold))); - } - else { - sprintf(response,"RSP NOISELEV 1 0"); - } - } - else if (strcmp(command,"SETPOWER")==0) { - // set output power in dB - int dbPwr; - sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbPwr); - if (!mOn) - sprintf(response,"RSP SETPOWER 1 %d",dbPwr); - else { - mPower = dbPwr; - mRadioInterface->setPowerAttenuation(dbPwr); - sprintf(response,"RSP SETPOWER 0 %d",dbPwr); - } - } - else if (strcmp(command,"ADJPOWER")==0) { - // adjust power in dB steps - int dbStep; - sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbStep); - if (!mOn) - sprintf(response,"RSP ADJPOWER 1 %d",mPower); - else { - mPower += dbStep; - sprintf(response,"RSP ADJPOWER 0 %d",mPower); - } - } -#define FREQOFFSET 0//11.2e3 - else if (strcmp(command,"RXTUNE")==0) { - // tune receiver - int freqKhz; - sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz); - mRxFreq = freqKhz*1.0e3+FREQOFFSET; - if (!mRadioInterface->tuneRx(mRxFreq,gConfig.getNum("TRX.RadioFrequencyOffset"))) { - LOG(ALERT) << "RX failed to tune"; - sprintf(response,"RSP RXTUNE 1 %d",freqKhz); - } - else - sprintf(response,"RSP RXTUNE 0 %d",freqKhz); - } - else if (strcmp(command,"TXTUNE")==0) { - // tune txmtr - int freqKhz; - sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz); - //freqKhz = 890e3; - mTxFreq = freqKhz*1.0e3+FREQOFFSET; - if (!mRadioInterface->tuneTx(mTxFreq,gConfig.getNum("TRX.RadioFrequencyOffset"))) { - LOG(ALERT) << "TX failed to tune"; - sprintf(response,"RSP TXTUNE 1 %d",freqKhz); - } - else - sprintf(response,"RSP TXTUNE 0 %d",freqKhz); - } - else if (strcmp(command,"SETTSC")==0) { - // set TSC - int TSC; - sscanf(buffer,"%3s %s %d",cmdcheck,command,&TSC); - if (mOn) - sprintf(response,"RSP SETTSC 1 %d",TSC); - else { - mTSC = TSC; - generateMidamble(*gsmPulse,mSamplesPerSymbol,TSC); - sprintf(response,"RSP SETTSC 0 %d",TSC); - } - } - else if (strcmp(command,"SETSLOT")==0) { - // set TSC - int corrCode; - int timeslot; - sscanf(buffer,"%3s %s %d %d",cmdcheck,command,×lot,&corrCode); - if ((timeslot < 0) || (timeslot > 7)) { - LOG(WARNING) << "bogus message on control interface"; - sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode); - return; - } - mChanType[timeslot] = (ChannelCombination) corrCode; - setModulus(timeslot); - sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode); - - } - else { - LOG(WARNING) << "bogus command " << command << " on control interface."; - } - - mControlSocket.write(response,strlen(response)+1); - -} - -bool Transceiver::driveTransmitPriorityQueue() -{ - - char buffer[gSlotLen+50]; - - // check data socket - size_t msgLen = mDataSocket.read(buffer); - - if (msgLen!=gSlotLen+1+4+1) { - LOG(ERR) << "badly formatted packet on GSM->TRX interface"; - return false; - } - - int timeSlot = (int) buffer[0]; - uint64_t frameNum = 0; - for (int i = 0; i < 4; i++) - frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]); - - /* - if (GSM::Time(frameNum,timeSlot) > mTransmitDeadlineClock + GSM::Time(51,0)) { - // stale burst - //LOG(DEBUG) << "FAST! "<< GSM::Time(frameNum,timeSlot); - //writeClockInterface(); - }*/ - -/* - DAB -- Just let these go through the demod. - if (GSM::Time(frameNum,timeSlot) < mTransmitDeadlineClock) { - // stale burst from GSM core - LOG(NOTICE) << "STALE packet on GSM->TRX interface at time "<< GSM::Time(frameNum,timeSlot); - return false; - } -*/ - - // periodically update GSM core clock - LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock - << " mLastClockUpdateTime " << mLastClockUpdateTime; - if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0)) - writeClockInterface(); - - - LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot); - - int RSSI = (int) buffer[5]; - static BitVector newBurst(gSlotLen); - BitVector::iterator itr = newBurst.begin(); - char *bufferItr = buffer+6; - while (itr < newBurst.end()) - *itr++ = *bufferItr++; - - GSM::Time currTime = GSM::Time(frameNum,timeSlot); - - addRadioVector(newBurst,RSSI,currTime); - - LOG(DEBUG) "added burst - time: " << currTime << ", RSSI: " << RSSI; // << ", data: " << newBurst; - - return true; - - -} - -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->isUnderrun()) { - // only do latency update every 10 frames, so we don't over update - if (radioClock->get() > mLatencyUpdateTime + GSM::Time(10,0)) { - 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(1,1)) { - 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)); - - LOG(INFO) << "ClockInterface: sending " << command; - - mClockSocket.write(command,strlen(command)+1); - - mLastClockUpdateTime = mTransmitDeadlineClock; - -} - - - - -void *FIFOServiceLoopAdapter(Transceiver *transceiver) -{ - while (1) { - transceiver->driveReceiveFIFO(); - transceiver->driveTransmitFIFO(); - pthread_testcancel(); - } - return NULL; -} - -void *ControlServiceLoopAdapter(Transceiver *transceiver) -{ - while (1) { - transceiver->driveControl(); - pthread_testcancel(); - } - return NULL; -} - -void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *transceiver) -{ - while (1) { - bool stale = false; - // Flush the UDP packets until a successful transfer. - while (!transceiver->driveTransmitPriorityQueue()) { - stale = true; - } - if (stale) { - // If a packet was stale, remind the GSM stack of the clock. - transceiver->writeClockInterface(); - } - pthread_testcancel(); - } - return NULL; -} diff --git a/TransceiverRAD1/Transceiver.h b/TransceiverRAD1/Transceiver.h index e724c03..e480c81 100644 --- a/TransceiverRAD1/Transceiver.h +++ b/TransceiverRAD1/Transceiver.h @@ -40,6 +40,25 @@ /** Define this to be the slot number to be logged. */ //#define TRANSMIT_LOGGING 1 +#define MAXARFCN 5 + + +/** 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; + +class Demodulator; +class Transceiver; + +typedef struct ThreadStruct { + Transceiver *trx; + unsigned ARFCN; +} ThreadStruct; + /** The Transceiver class, responsible for physical layer of basestation */ class Transceiver { @@ -48,33 +67,33 @@ 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 mControlSocket; ///< socket for writing/reading control commands from GSM core + UDPSocket *mDataSocket[MAXARFCN]; ///< socket for writing to/reading from GSM core + UDPSocket *mControlSocket[MAXARFCN]; ///< 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 + VectorFIFO* mDemodFIFO[MAXARFCN]; 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 + Thread *mRFIFOServiceLoopThread; + Thread *mDemodServiceLoopThread[MAXARFCN]; ///< threads for demodulating individual ARFCNs + Thread *mControlServiceLoopThread[MAXARFCN]; ///< thread to process control messages from GSM core + Thread *mTransmitPriorityQueueServiceLoopThread[MAXARFCN];///< 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 + GSM::Time mStartTime; RadioInterface *mRadioInterface; ///< associated radioInterface object double txFullScale; ///< full scale input to radio - double rxFullScale; ///< full scale output to radio + double rxFullScale; - /** 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; + Mutex mControlLock; + Mutex mTransmitPriorityQueueLock; + bool mLoadTest; /** Codes for channel combinations */ typedef enum { @@ -99,22 +118,18 @@ private: /** modulate and add a burst to the transmit queue */ void addRadioVector(BitVector &burst, int RSSI, - GSM::Time &wTime); + GSM::Time &wTime, + int ARFCN); /** 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); + void pullRadioVector(void); /** 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); @@ -123,24 +138,27 @@ private: 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 + ChannelCombination mChanType[MAXARFCN][8]; ///< channel types for all timeslots double mTxFreq; ///< the transmit frequency double mRxFreq; ///< the receive frequency int mPower; ///< the transmit power in dB unsigned 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 - signalVector *channelResponse[8]; ///< most recent channel estimate of all timeslots - float SNRestimate[8]; ///< most recent SNR estimate of all timeslots - signalVector *DFEForward[8]; ///< most recent DFE feedforward filter of all timeslots - signalVector *DFEFeedback[8]; ///< most recent DFE feedback filter of all timeslots - float chanRespOffset[8]; ///< most recent timing offset, e.g. TOA, of all timeslots - complex chanRespAmplitude[8]; ///< most recent channel amplitude of all timeslots + unsigned int mNumARFCNs; + bool mMultipleARFCN; + unsigned char mOversamplingRate; + double mFreqOffset; + signalVector *frequencyShifter[MAXARFCN]; + signalVector *decimationFilter; + signalVector *interpolationFilter; + + Demodulator *mDemodulators[MAXARFCN]; + + + public: @@ -155,7 +173,10 @@ public: const char *TRXAddress, int wSamplesPerSymbol, GSM::Time wTransmitLatency, - RadioInterface *wRadioInterface); + RadioInterface *wRadioInterface, + unsigned int wNumARFCNs, + unsigned int wOversamplingRate, + bool wLoadTest); /** Destructor */ ~Transceiver(); @@ -163,12 +184,30 @@ public: /** start the Transceiver */ void start(); + bool multiARFCN() {return mMultipleARFCN;} + + /** return the expected burst type for the specified timestamp */ + CorrType expectedCorrType(GSM::Time currTime, int ARFCN); + /** attach the radioInterface receive FIFO */ void receiveFIFO(VectorFIFO *wFIFO) { mReceiveFIFO = wFIFO;} /** attach the radioInterface transmit FIFO */ void transmitFIFO(VectorFIFO *wFIFO) { mTransmitFIFO = wFIFO;} + VectorFIFO *demodFIFO(unsigned ARFCN) { return mDemodFIFO[ARFCN]; } + + RadioInterface *radioInterface(void) { return mRadioInterface; } + + unsigned samplesPerSymbol(void) { return mSamplesPerSymbol; } + + UDPSocket *dataSocket(int ARFCN) { return mDataSocket[ARFCN]; } + + signalVector *GSMPulse(void) { return gsmPulse; } + + unsigned maxDelay(void) { return mMaxExpectedDelay; } + + unsigned getTSC(void) { return mTSC; } protected: @@ -179,19 +218,21 @@ protected: void driveTransmitFIFO(); /** drive handling of control messages from GSM core */ - void driveControl(); + void driveControl(unsigned ARFCN); /** drive modulation and sorting of GSM bursts from GSM core @return true if a burst was transferred successfully */ - bool driveTransmitPriorityQueue(); + bool driveTransmitPriorityQueue(unsigned ARFCN); friend void *FIFOServiceLoopAdapter(Transceiver *); - friend void *ControlServiceLoopAdapter(Transceiver *); + friend void *RFIFOServiceLoopAdapter(Transceiver *); + + friend void *ControlServiceLoopAdapter(ThreadStruct *); - friend void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *); + friend void *TransmitPriorityQueueServiceLoopAdapter(ThreadStruct *); void reset(); }; @@ -199,9 +240,61 @@ protected: /** FIFO thread loop */ void *FIFOServiceLoopAdapter(Transceiver *); +void *RFIFOServiceLoopAdapter(Transceiver *); + /** control message handler thread loop */ -void *ControlServiceLoopAdapter(Transceiver *); +void *ControlServiceLoopAdapter(ThreadStruct *); /** transmit queueing thread loop */ -void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *); +void *TransmitPriorityQueueServiceLoopAdapter(ThreadStruct *); +class Demodulator { + + private: + + int mARFCN; + Transceiver *mTRX; + RadioInterface *mRadioInterface; + VectorFIFO *mDemodFIFO; + double mEnergyThreshold; ///< threshold to determine if received data is potentially a GSM burst + GSM::Time prevFalseDetectionTime; ///< last timestamp of a false energy detection + GSM::Time channelEstimateTime[8]; ///< last timestamp of each timeslot's channel estimate + signalVector *channelResponse[8]; ///< most recent channel estimate of all timeslots + float SNRestimate[8]; ///< most recent SNR estimate of all timeslots + signalVector *DFEForward[8]; ///< most recent DFE feedforward filter of all timeslots + signalVector *DFEFeedback[8]; ///< most recent DFE feedback filter of all timeslots + float chanRespOffset[8]; ///< most recent timing offset, e.g. TOA, of all timeslots + complex chanRespAmplitude[8]; ///< most recent channel amplitude of all timeslots + signalVector *gsmPulse; + unsigned mTSC; + unsigned mSamplesPerSymbol; + + UDPSocket *mTRXDataSocket; + + unsigned mMaxExpectedDelay; + + double rxFullScale; ///< full scale output to radio + + SoftVector* demodRadioVector(radioVector *rxBurst, + GSM::Time &wTime, + int &RSSI, + int &timingOffset); + + public: + + Demodulator(int wARFCN, + Transceiver *wTRX, + GSM::Time wStartTime); + + double getEnergyThreshold() {return mEnergyThreshold;} + + + //protected: + + void driveDemod(bool wSingleARFCN = true); + protected: + friend void *DemodServiceLoopAdapter(Demodulator *); + +}; + +void *DemodServiceLoopAdapter(Demodulator *); diff --git a/TransceiverRAD1/radioInterface.cpp b/TransceiverRAD1/radioInterface.cpp index fa03a03..6866ab2 100644 --- a/TransceiverRAD1/radioInterface.cpp +++ b/TransceiverRAD1/radioInterface.cpp @@ -71,6 +71,8 @@ RadioInterface::RadioInterface(RadioDevice *wRadio, int wReceiveOffset, int wRadioOversampling, int wTransceiverOversampling, + bool wLoadTest, + unsigned int wNumARFCNs, GSM::Time wStartTime) { @@ -85,6 +87,9 @@ RadioInterface::RadioInterface(RadioDevice *wRadio, samplesPerSymbol = wRadioOversampling; mClock.set(wStartTime); powerScaling = 1.0; + mNumARFCNs = wNumARFCNs; + + loadTest = wLoadTest; } RadioInterface::~RadioInterface(void) { @@ -236,6 +241,34 @@ void RadioInterface::start() mOn = true; + if (loadTest) { + int mOversamplingRate = samplesPerSymbol; + int numARFCN = mNumARFCNs; + signalVector *gsmPulse = generateGSMPulse(2,1); + BitVector normalBurstSeg = "0000101010100111110010101010010110101110011000111001101010000"; + BitVector normalBurst(BitVector(normalBurstSeg,gTrainingSequence[2]),normalBurstSeg); + signalVector *modBurst = modulateBurst(normalBurst,*gsmPulse,8,1); + signalVector *modBurst9 = modulateBurst(normalBurst,*gsmPulse,9,1); + signalVector *interpolationFilter = createLPF(0.6/mOversamplingRate,6*mOversamplingRate,1); + scaleVector(*modBurst,mRadio->fullScaleInputValue()); + scaleVector(*modBurst9,mRadio->fullScaleInputValue()); + double beaconFreq = -1.0*(numARFCN-1)*200e3; + finalVec = new signalVector(156*mOversamplingRate); + finalVec9 = new signalVector(157*mOversamplingRate); + for (int j = 0; j < numARFCN; j++) { + signalVector *frequencyShifter = new signalVector(157*mOversamplingRate); + frequencyShifter->fill(1.0); + frequencyShift(frequencyShifter,frequencyShifter,2.0*M_PI*(beaconFreq+j*400e3)/(1625.0e3/6.0*mOversamplingRate)); + signalVector *interpVec = polyphaseResampleVector(*modBurst,mOversamplingRate,1,interpolationFilter); + multVector(*interpVec,*frequencyShifter); + addVector(*finalVec,*interpVec); + interpVec = polyphaseResampleVector(*modBurst9,mOversamplingRate,1,interpolationFilter); + multVector(*interpVec,*frequencyShifter); + addVector(*finalVec9,*interpVec); + } + } + + } void *AlignRadioServiceLoopAdapter(RadioInterface *radioInterface) @@ -287,14 +320,15 @@ void RadioInterface::driveReceiveRadio() { GSM::Time tmpTime = rcvClock; if (rcvClock.FN() >= 0) { //LOG(DEBUG) << "FN: " << rcvClock.FN(); + int dummyARFCN = 0; radioVector *rxBurst = NULL; if (!loadTest) - rxBurst = new radioVector(rxVector,tmpTime); + rxBurst = new radioVector(rxVector,tmpTime,dummyARFCN); else { if (tN % 4 == 0) - rxBurst = new radioVector(*finalVec9,tmpTime); + rxBurst = new radioVector(*finalVec9,tmpTime,dummyARFCN); else - rxBurst = new radioVector(*finalVec,tmpTime); + rxBurst = new radioVector(*finalVec,tmpTime,dummyARFCN); } mReceiveFIFO.put(rxBurst); } diff --git a/TransceiverRAD1/radioInterface.h b/TransceiverRAD1/radioInterface.h index ca3d57b..491fec3 100644 --- a/TransceiverRAD1/radioInterface.h +++ b/TransceiverRAD1/radioInterface.h @@ -40,16 +40,22 @@ class radioVector : public signalVector { private: GSM::Time mTime; ///< the burst's GSM timestamp + int mARFCN; public: /** constructor */ radioVector(const signalVector& wVector, - GSM::Time& wTime): signalVector(wVector),mTime(wTime) {}; + GSM::Time& wTime, + int& wARFCN): signalVector(wVector),mTime(wTime),mARFCN(wARFCN){}; /** timestamp read and write operators */ GSM::Time time() const { return mTime;} void time(const GSM::Time& wTime) { mTime = wTime;} + /** ARFCN read and write operators */ + int ARFCN() const { return mARFCN;} + void ARFCN(const int& wARFCN) { mARFCN = wARFCN;} + /** comparison operator, used for sorting */ bool operator>(const radioVector& other) const {return mTime > other.mTime;} @@ -111,12 +117,12 @@ private: 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();;} + 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();} + 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; } @@ -188,6 +194,8 @@ public: int receiveOffset = 3, int wRadioOversampling = SAMPSPERSYM, int wTransceiverOversampling = SAMPSPERSYM, + bool wLoadTest = false, + unsigned int wNumARFCNS = 1, GSM::Time wStartTime = GSM::Time(0)); /** destructor */ diff --git a/TransceiverRAD1/rnrad1Core.cpp b/TransceiverRAD1/rnrad1Core.cpp index 4c6bdef..828629e 100644 --- a/TransceiverRAD1/rnrad1Core.cpp +++ b/TransceiverRAD1/rnrad1Core.cpp @@ -74,7 +74,7 @@ int usbMsg (struct libusb_device_handle *udh, if (ret < 0) { // we get EPIPE if the firmware stalls the endpoint. if (ret != LIBUSB_ERROR_PIPE) { - LOG(ALERT) << "libusb_control_transfer failed: " << _get_usb_error_str(ret); + LOG(ERR) << "libusb_control_transfer failed: " << _get_usb_error_str(ret); } } diff --git a/TransceiverRAD1/runTransceiver.cpp b/TransceiverRAD1/runTransceiver.cpp index 04dea50..542ede7 100644 --- a/TransceiverRAD1/runTransceiver.cpp +++ b/TransceiverRAD1/runTransceiver.cpp @@ -66,16 +66,79 @@ int main(int argc, char *argv[]) // Configure logger. gLogInit("transceiver",gConfig.getStr("Log.Level").c_str(),LOG_LOCAL7); + int numARFCN=1; + if (argc>1) numARFCN = atoi(argv[1]); + +#ifdef SINGLEARFCN + numARFCN=1; +#endif + srandom(time(NULL)); int mOversamplingRate = 1; + switch(numARFCN) { + + case 1: + mOversamplingRate = 1; + break; + case 2: + mOversamplingRate = 6; + break; + case 3: + mOversamplingRate = 8; + break; + case 4: + mOversamplingRate = 12; + break; + case 5: + mOversamplingRate = 16; + break; + default: + break; + } + //int mOversamplingRate = numARFCN/2 + numARFCN; + //mOversamplingRate = 15; //mOversamplingRate*2; + //if ((numARFCN > 1) && (mOversamplingRate % 2)) mOversamplingRate++; RAD1Device *usrp = new RAD1Device(mOversamplingRate*1625.0e3/6.0); + //DummyLoad *usrp = new DummyLoad(mOversamplingRate*1625.0e3/6.0); usrp->make(); - RadioInterface* radio = new RadioInterface(usrp,3,SAMPSPERSYM,mOversamplingRate,false); - Transceiver *trx = new Transceiver(5700,"127.0.0.1",SAMPSPERSYM,GSM::Time(2,0),radio); + RadioInterface* radio = new RadioInterface(usrp,3,SAMPSPERSYM,mOversamplingRate,false,numARFCN); + Transceiver *trx = new Transceiver(5700,"127.0.0.1",SAMPSPERSYM,GSM::Time(2,0),radio, + numARFCN,mOversamplingRate,false); trx->receiveFIFO(radio->receiveFIFO()); +/* + signalVector *gsmPulse = generateGSMPulse(2,1); + BitVector normalBurstSeg = "0000101010100111110010101010010110101110011000111001101010000"; + BitVector normalBurst(BitVector(normalBurstSeg,gTrainingSequence[0]),normalBurstSeg); + signalVector *modBurst = modulateBurst(normalBurst,*gsmPulse,8,1); + signalVector *modBurst9 = modulateBurst(normalBurst,*gsmPulse,9,1); + signalVector *interpolationFilter = createLPF(0.6/mOversamplingRate,6*mOversamplingRate,1); + signalVector totalBurst1(*modBurst,*modBurst9); + signalVector totalBurst2(*modBurst,*modBurst); + signalVector totalBurst(totalBurst1,totalBurst2); + scaleVector(totalBurst,usrp->fullScaleInputValue()); + double beaconFreq = -1.0*(numARFCN-1)*200e3; + signalVector finalVec(625*mOversamplingRate); + for (int j = 0; j < numARFCN; j++) { + signalVector *frequencyShifter = new signalVector(625*mOversamplingRate); + frequencyShifter->fill(1.0); + frequencyShift(frequencyShifter,frequencyShifter,2.0*M_PI*(beaconFreq+j*400e3)/(1625.0e3/6.0*mOversamplingRate)); + signalVector *interpVec = polyphaseResampleVector(totalBurst,mOversamplingRate,1,interpolationFilter); + multVector(*interpVec,*frequencyShifter); + addVector(finalVec,*interpVec); + } + signalVector::iterator itr = finalVec.begin(); + short finalVecShort[2*finalVec.size()]; + short *shortItr = finalVecShort; + while (itr < finalVec.end()) { + *shortItr++ = (short) (itr->real()); + *shortItr++ = (short) (itr->imag()); + itr++; + } + usrp->loadBurst(finalVecShort,finalVec.size()); +*/ trx->start(); //int i = 0; while(!gbShutdown) { sleep(1); } //i++; if (i==60) exit(1);} diff --git a/TransceiverRAD1/sigProcLib.cpp b/TransceiverRAD1/sigProcLib.cpp index 3b43401..f020fdd 100644 --- a/TransceiverRAD1/sigProcLib.cpp +++ b/TransceiverRAD1/sigProcLib.cpp @@ -599,6 +599,7 @@ signalVector *modulateBurst(const BitVector &wBurst, modBurst.isRealOnly(true); //memset(staticBurst,0,sizeof(complex)*burstSize); modBurst.fill(0.0); + //modBurst.fill(1.0); signalVector::iterator modBurstItr = modBurst.begin(); #if 0