laforge
/
openbts-osmo
Archived
1
0
Fork 0
This repository has been archived on 2022-03-30. You can view files and clone it, but cannot push or open issues or pull requests.
openbts-osmo/public-trunk/Transceiver/radioInterface.cpp

403 lines
11 KiB
C++

/*
* Copyright 2008, 2009 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//#define NDEBUG
#include "radioInterface.h"
#include <Logger.h>
GSM::Time VectorQueue::nextTime() const
{
GSM::Time retVal;
mLock.lock();
while (mQ.size()==0) mWriteSignal.wait(mLock);
retVal = mQ.top()->time();
mLock.unlock();
return retVal;
}
RadioInterface::RadioInterface(USRPDevice *wUsrp,
int wReceiveOffset,
int wSamplesPerSymbol,
GSM::Time wStartTime)
{
underrun = false;
sendHistory = new signalVector(INHISTORY);
rcvHistory = NULL;
sendBuffer = NULL;
rcvBuffer = NULL;
sendLPF = NULL;
rcvLPF = NULL;
mOn = false;
usrp = wUsrp;
receiveOffset = wReceiveOffset;
samplesPerSymbol = wSamplesPerSymbol;
mClock.set(wStartTime);
}
RadioInterface::~RadioInterface(void) {
if (sendBuffer!=NULL) delete sendBuffer;
if (rcvBuffer!=NULL) delete rcvBuffer;
if (sendHistory!=NULL) delete sendHistory;
if (rcvHistory!=NULL) delete rcvHistory;
if (sendLPF!=NULL) delete sendLPF;
if (rcvLPF!=NULL) delete rcvLPF;
mTransmitFIFO.clear();
mReceiveFIFO.clear();
}
short *RadioInterface::USRPifyVector(signalVector &wVector)
{
short *retVector = new short[2*wVector.size()];
signalVector::iterator itr = wVector.begin();
short *shortItr = retVector;
while (itr < wVector.end()) {
*shortItr++ = (short) host_to_usrp_short((short)itr->real());
*shortItr++ = (short) host_to_usrp_short((short)itr->imag());
itr++;
}
return retVector;
}
signalVector *RadioInterface::unUSRPifyVector(short *shortVector, int numSamples)
{
signalVector *newVector = new signalVector(numSamples);
signalVector::iterator itr = newVector->begin();
short *shortItr = shortVector;
// need to flip I and Q from USRP
#ifndef SWLOOPBACK
#define FLIP_IQ 1
#else
#define FLIP_IQ 0
#endif
while (itr < newVector->end()) {
*itr++ = Complex<float>(usrp_to_host_short(*(shortItr+FLIP_IQ)),
usrp_to_host_short(*(shortItr+1-FLIP_IQ)));
//LOG(DEEPDEBUG) << (*(itr-1));
shortItr += 2;
}
return newVector;
}
bool started = false;
#define POLYPHASESPAN 10
void RadioInterface::pushBuffer(void) {
if (sendBuffer->size() < INCHUNK) {
return;
}
int numChunks = sendBuffer->size()/INCHUNK;
signalVector* truncatedBuffer = new signalVector(numChunks*INCHUNK);
sendBuffer->segmentCopyTo(*truncatedBuffer,0,numChunks*INCHUNK);
if (!sendLPF) {
int P = OUTRATE; int Q = INRATE;
float cutoffFreq = (P < Q) ? (1.0/(float) Q) : (1.0/(float) P);
sendLPF = createLPF(cutoffFreq,651,P);
}
// resample data to USRP sample rate
signalVector *inputVector = new signalVector(*sendHistory,*truncatedBuffer);
signalVector *resampledVector = polyphaseResampleVector(*inputVector,
OUTRATE,
INRATE,sendLPF);
delete inputVector;
// Set transmit gain and power here.
scaleVector(*resampledVector,13500.0); ///2.25); // this gets 2W out of 3318PA at 885Mhz
//scaleVector(*resampledVector,100.0);
short *resampledVectorShort = USRPifyVector(*resampledVector);
// start the USRP when we actually have data to send to the USRP.
if (!started) {
started = true;
LOG(INFO) << "Starting USRP";
usrp->start();
LOG(DEBUG) << "USRP started";
usrp->updateAlignment(10000);
usrp->updateAlignment(10000);
}
// send resampleVector
writingRadioLock.lock();
int samplesWritten = usrp->writeSamples(resampledVectorShort+OUTHISTORY*2,
(resampledVector->size()-OUTHISTORY),
&underrun,
writeTimestamp);
//LOG(DEEPDEBUG) << "writeTimestamp: " << writeTimestamp << ", samplesWritten: " << samplesWritten;
writeTimestamp += (TIMESTAMP) samplesWritten;
wroteRadioSignal.signal();
writingRadioLock.unlock();
LOG(DEEPDEBUG) << "converted " << truncatedBuffer->size()
<< " transceiver samples into " << samplesWritten
<< " radio samples ";
delete resampledVector;
delete []resampledVectorShort;
// update the history of sent data
truncatedBuffer->segmentCopyTo(*sendHistory,truncatedBuffer->size()-INHISTORY,
INHISTORY);
// update the buffer, i.e. keep the samples we didn't send
signalVector *tmp = sendBuffer;
sendBuffer = new signalVector(sendBuffer->size()-truncatedBuffer->size());
tmp->segmentCopyTo(*sendBuffer,truncatedBuffer->size(),
sendBuffer->size());
delete tmp;
delete truncatedBuffer;
}
void RadioInterface::pullBuffer(void)
{
writingRadioLock.lock();
// These timestamps are in samples @ 400 kHz.
while (readTimestamp > writeTimestamp - (TIMESTAMP) 2*OUTCHUNK) {
LOG(DEEPDEBUG) << "waiting..." << readTimestamp << " " << writeTimestamp;
wroteRadioSignal.wait(writingRadioLock);
//wroteRadioSignal.wait(writingRadioLock,1);
}
writingRadioLock.unlock();
bool localUnderrun;
// receive receiveVector
short* shortVector = new short[OUTCHUNK*2];
int samplesRead = usrp->readSamples(shortVector,OUTCHUNK,&overrun,readTimestamp,&localUnderrun);
underrun |= localUnderrun;
readTimestamp += (TIMESTAMP) samplesRead;
while (samplesRead < OUTCHUNK) {
int oldSamplesRead = samplesRead;
samplesRead += usrp->readSamples(shortVector+2*samplesRead,
OUTCHUNK-samplesRead,
&overrun,
readTimestamp,
&localUnderrun);
underrun |= localUnderrun;
readTimestamp += (TIMESTAMP) (samplesRead - oldSamplesRead);
}
signalVector *receiveVector = unUSRPifyVector(shortVector,samplesRead);
delete []shortVector;
if (!rcvLPF) {
int P = INRATE; int Q = OUTRATE;
float cutoffFreq = (P < Q) ? (1.0/(float) Q) : (1.0/(float) P);
rcvLPF = createLPF(cutoffFreq,961,P);
}
signalVector *retVector = NULL;
if (!rcvHistory) {
rcvHistory = new signalVector(OUTHISTORY);
rcvHistory->fill(0);
}
// resample received data to multiple of GSM symbol rate
signalVector inputVector(*rcvHistory,*receiveVector);
retVector = polyphaseResampleVector(inputVector,
INRATE,OUTRATE,rcvLPF);
// push sampled data to back of receive buffer
signalVector *tmp = retVector;
retVector = new signalVector(retVector->size()-INHISTORY);
tmp->segmentCopyTo(*retVector,INHISTORY,tmp->size()-INHISTORY);
delete tmp;
LOG(DEEPDEBUG) << "converted " << receiveVector->size()
<< " radio samples into " << retVector->size()
<< " transceiver samples ";
// update history of received data
receiveVector->segmentCopyTo(*rcvHistory,receiveVector->size()-OUTHISTORY,OUTHISTORY);
delete receiveVector;
if (rcvBuffer) {
signalVector *tmp = rcvBuffer;
rcvBuffer = new signalVector(*tmp,*retVector);
delete tmp;
delete retVector;
}
else
rcvBuffer = retVector;
}
bool RadioInterface::tuneTx(double freq)
{
if (mOn) return false;
return usrp->setTxFreq(freq);
}
bool RadioInterface::tuneRx(double freq)
{
if (mOn) return false;
return usrp->setRxFreq(freq);
}
void RadioInterface::start()
{
LOG(INFO) << "starting radio interface...";
writeTimestamp = 20000;
readTimestamp = 20000;
mTransmitRadioServiceLoopThread.start((void* (*)(void*))TransmitRadioServiceLoopAdapter,
(void*)this);
mReceiveRadioServiceLoopThread.start((void* (*)(void*))ReceiveRadioServiceLoopAdapter,
(void*)this);
mAlignRadioServiceLoopThread.start((void * (*)(void*))AlignRadioServiceLoopAdapter,
(void*)this);
mOn = true;
LOG(DEBUG) << "radio interface started!";
}
void *TransmitRadioServiceLoopAdapter(RadioInterface *radioInterface)
{
while (1) {
radioInterface->driveTransmitRadio();
pthread_testcancel();
}
return NULL;
}
void *ReceiveRadioServiceLoopAdapter(RadioInterface *radioInterface)
{
while (1) {
radioInterface->driveReceiveRadio();
pthread_testcancel();
}
return NULL;
}
void *AlignRadioServiceLoopAdapter(RadioInterface *radioInterface)
{
while (1) {
radioInterface->alignRadio();
pthread_testcancel();
}
return NULL;
}
void RadioInterface::alignRadio() {
sleep(60);
usrp->updateAlignment(writeTimestamp+ (TIMESTAMP) 10000);
}
void RadioInterface::driveTransmitRadio() {
radioVector *radioBurst = NULL;
radioBurst = mTransmitFIFO.read();
LOG(DEEPDEBUG) << "transmitFIFO: read radio vector at time: " << radioBurst->time();
signalVector *newBurst = radioBurst;
if (sendBuffer) {
signalVector *tmp = sendBuffer;
sendBuffer = new signalVector(*sendBuffer,*newBurst);
delete tmp;
}
else
sendBuffer = new signalVector(*newBurst);
delete radioBurst;
pushBuffer();
}
void RadioInterface::driveReceiveRadio() {
pullBuffer();
if (!rcvBuffer) {
return;}
GSM::Time rcvClock = mClock.get();
rcvClock.decTN(receiveOffset);
unsigned tN = rcvClock.TN();
int rcvSz = rcvBuffer->size();
int readSz = 0;
const int symbolsPerSlot = gSlotLen + 8;
// while there's enough data in receive buffer, form received
// GSM bursts and pass up to Transceiver
// Using the 157-156-156-156 symbols per timeslot format.
while (rcvSz > (symbolsPerSlot + (tN % 4 == 0))*samplesPerSymbol) {
signalVector rxVector(rcvBuffer->begin(),
readSz,
(symbolsPerSlot + (tN % 4 == 0))*samplesPerSymbol);
GSM::Time tmpTime = rcvClock;
if (rcvClock.FN() >= 0) {
LOG(DEEPDEBUG) << "FN: " << rcvClock.FN();
radioVector* rxBurst = new radioVector(rxVector,tmpTime);
mReceiveFIFO.write(rxBurst);
}
mClock.incTN();
rcvClock.incTN();
if (mReceiveFIFO.size() >= 16) mReceiveFIFO.wait(8);
LOG(DEEPDEBUG) << "receiveFIFO: wrote radio vector at time: " << mClock.get() << ", new size: " << mReceiveFIFO.size() ;
readSz += (symbolsPerSlot+(tN % 4 == 0))*samplesPerSymbol;
rcvSz -= (symbolsPerSlot+(tN % 4 == 0))*samplesPerSymbol;
tN = rcvClock.TN();
}
signalVector *tmp = new signalVector(rcvBuffer->size()-readSz);
rcvBuffer->segmentCopyTo(*tmp,readSz,tmp->size());
delete rcvBuffer;
rcvBuffer = tmp;
}