mirror of
https://github.com/PentHertz/OpenBTS.git
synced 2026-04-30 04:19:28 +00:00
The output of the modulator or resampler is scaled and converted from floating point to fixed point. The scaling factor is the leftover dB in RF attention (relative to max transmit power), which is handled prior to the integer conversion. This should work across all daughterboards and non-UHD installations. Signed-off-by: Thomas Tsou <ttsou@vt.edu> git-svn-id: http://wush.net/svn/range/software/public/openbts/trunk@2650 19bc5d8c-e614-43d4-8b26-e1612bc8e597
314 lines
7.9 KiB
C++
314 lines
7.9 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;
|
|
ScopedLock lock(mLock);
|
|
while (mQ.size()==0) mWriteSignal.wait(mLock);
|
|
return mQ.top()->time();
|
|
}
|
|
|
|
radioVector* VectorQueue::getStaleBurst(const GSM::Time& targTime)
|
|
{
|
|
ScopedLock lock(mLock);
|
|
if ((mQ.size()==0)) {
|
|
return NULL;
|
|
}
|
|
if (mQ.top()->time() < targTime) {
|
|
radioVector* retVal = mQ.top();
|
|
mQ.pop();
|
|
return retVal;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
radioVector* VectorQueue::getCurrentBurst(const GSM::Time& targTime)
|
|
{
|
|
ScopedLock lock(mLock);
|
|
if ((mQ.size()==0)) {
|
|
return NULL;
|
|
}
|
|
if (mQ.top()->time() == targTime) {
|
|
radioVector* retVal = mQ.top();
|
|
mQ.pop();
|
|
return retVal;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
RadioInterface::RadioInterface(RadioDevice *wRadio,
|
|
int wReceiveOffset,
|
|
int wRadioOversampling,
|
|
int wTransceiverOversampling,
|
|
GSM::Time wStartTime)
|
|
|
|
{
|
|
underrun = false;
|
|
|
|
sendCursor = 0;
|
|
rcvCursor = 0;
|
|
mOn = false;
|
|
|
|
mRadio = wRadio;
|
|
receiveOffset = wReceiveOffset;
|
|
samplesPerSymbol = wRadioOversampling;
|
|
mClock.set(wStartTime);
|
|
powerScaling = 1.0;
|
|
loadTest = false;
|
|
}
|
|
|
|
RadioInterface::~RadioInterface(void) {
|
|
if (rcvBuffer!=NULL) delete rcvBuffer;
|
|
//mReceiveFIFO.clear();
|
|
}
|
|
|
|
double RadioInterface::fullScaleInputValue(void) {
|
|
return mRadio->fullScaleInputValue();
|
|
}
|
|
|
|
double RadioInterface::fullScaleOutputValue(void) {
|
|
return mRadio->fullScaleOutputValue();
|
|
}
|
|
|
|
|
|
void RadioInterface::setPowerAttenuation(double atten)
|
|
{
|
|
double HWatten = mRadio->setTxGain(mRadio->maxTxGain() - atten);
|
|
atten -= HWatten;
|
|
if (atten < 1.0)
|
|
powerScaling = 1.0;
|
|
else
|
|
powerScaling = 1.0 / sqrt(pow(10, (atten / 10.0)));
|
|
}
|
|
|
|
|
|
short *RadioInterface::radioifyVector(signalVector &wVector, short *retVector, double scale, bool zeroOut)
|
|
{
|
|
|
|
|
|
signalVector::iterator itr = wVector.begin();
|
|
short *shortItr = retVector;
|
|
if (zeroOut) {
|
|
while (itr < wVector.end()) {
|
|
*shortItr++ = 0;
|
|
*shortItr++ = 0;
|
|
itr++;
|
|
}
|
|
}
|
|
else if (scale != 1.0) {
|
|
while (itr < wVector.end()) {
|
|
*shortItr++ = (short) (itr->real()*scale);
|
|
*shortItr++ = (short) (itr->imag()*scale);
|
|
itr++;
|
|
}
|
|
}
|
|
else {
|
|
while (itr < wVector.end()) {
|
|
*shortItr++ = (short) (itr->real());
|
|
*shortItr++ = (short) (itr->imag());
|
|
itr++;
|
|
}
|
|
}
|
|
|
|
return retVector;
|
|
|
|
}
|
|
|
|
void RadioInterface::unRadioifyVector(short *shortVector, signalVector& newVector)
|
|
{
|
|
|
|
signalVector::iterator itr = newVector.begin();
|
|
short *shortItr = shortVector;
|
|
while (itr < newVector.end()) {
|
|
*itr++ = Complex<float>(*shortItr,*(shortItr+1));
|
|
//LOG(DEBUG) << (*(itr-1));
|
|
shortItr += 2;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
bool started = false;
|
|
|
|
void RadioInterface::pushBuffer(void) {
|
|
|
|
if (sendCursor < 2*INCHUNK*samplesPerSymbol) return;
|
|
|
|
// send resampleVector
|
|
int samplesWritten = mRadio->writeSamples(sendBuffer,
|
|
INCHUNK*samplesPerSymbol,
|
|
&underrun,
|
|
writeTimestamp);
|
|
//LOG(DEBUG) << "writeTimestamp: " << writeTimestamp << ", samplesWritten: " << samplesWritten;
|
|
|
|
writeTimestamp += (TIMESTAMP) samplesWritten;
|
|
|
|
if (sendCursor > 2*samplesWritten)
|
|
memcpy(sendBuffer,sendBuffer+samplesWritten*2,sizeof(short)*2*(sendCursor-2*samplesWritten));
|
|
sendCursor = sendCursor - 2*samplesWritten;
|
|
}
|
|
|
|
|
|
void RadioInterface::pullBuffer(void)
|
|
{
|
|
|
|
bool localUnderrun;
|
|
|
|
// receive receiveVector
|
|
short* shortVector = rcvBuffer+rcvCursor;
|
|
//LOG(DEBUG) << "Reading USRP samples at timestamp " << readTimestamp;
|
|
int samplesRead = mRadio->readSamples(shortVector,OUTCHUNK*samplesPerSymbol,&overrun,readTimestamp,&localUnderrun);
|
|
underrun |= localUnderrun;
|
|
readTimestamp += (TIMESTAMP) samplesRead;
|
|
while (samplesRead < OUTCHUNK*samplesPerSymbol) {
|
|
int oldSamplesRead = samplesRead;
|
|
samplesRead += mRadio->readSamples(shortVector+2*samplesRead,
|
|
OUTCHUNK*samplesPerSymbol-samplesRead,
|
|
&overrun,
|
|
readTimestamp,
|
|
&localUnderrun);
|
|
underrun |= localUnderrun;
|
|
readTimestamp += (TIMESTAMP) (samplesRead - oldSamplesRead);
|
|
}
|
|
//LOG(DEBUG) << "samplesRead " << samplesRead;
|
|
|
|
rcvCursor += samplesRead*2;
|
|
|
|
}
|
|
|
|
bool RadioInterface::tuneTx(double freq)
|
|
{
|
|
return mRadio->setTxFreq(freq);
|
|
}
|
|
|
|
bool RadioInterface::tuneRx(double freq)
|
|
{
|
|
return mRadio->setRxFreq(freq);
|
|
}
|
|
|
|
|
|
void RadioInterface::start()
|
|
{
|
|
LOG(INFO) << "starting radio interface...";
|
|
mAlignRadioServiceLoopThread.start((void * (*)(void*))AlignRadioServiceLoopAdapter,
|
|
(void*)this);
|
|
writeTimestamp = mRadio->initialWriteTimestamp();
|
|
readTimestamp = mRadio->initialReadTimestamp();
|
|
mRadio->start();
|
|
LOG(DEBUG) << "Radio started";
|
|
mRadio->updateAlignment(writeTimestamp-10000);
|
|
mRadio->updateAlignment(writeTimestamp-10000);
|
|
|
|
sendBuffer = new short[2*2*INCHUNK*samplesPerSymbol];
|
|
rcvBuffer = new short[2*2*OUTCHUNK*samplesPerSymbol];
|
|
|
|
mOn = true;
|
|
|
|
}
|
|
|
|
void *AlignRadioServiceLoopAdapter(RadioInterface *radioInterface)
|
|
{
|
|
while (1) {
|
|
radioInterface->alignRadio();
|
|
pthread_testcancel();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void RadioInterface::alignRadio() {
|
|
sleep(60);
|
|
mRadio->updateAlignment(writeTimestamp+ (TIMESTAMP) 10000);
|
|
}
|
|
|
|
void RadioInterface::driveTransmitRadio(signalVector &radioBurst, bool zeroBurst) {
|
|
|
|
if (!mOn) return;
|
|
|
|
radioifyVector(radioBurst, sendBuffer+sendCursor, powerScaling, zeroBurst);
|
|
|
|
sendCursor += (radioBurst.size()*2);
|
|
|
|
pushBuffer();
|
|
}
|
|
|
|
void RadioInterface::driveReceiveRadio() {
|
|
|
|
if (!mOn) return;
|
|
|
|
if (mReceiveFIFO.size() > 8) return;
|
|
|
|
pullBuffer();
|
|
|
|
GSM::Time rcvClock = mClock.get();
|
|
rcvClock.decTN(receiveOffset);
|
|
unsigned tN = rcvClock.TN();
|
|
int rcvSz = rcvCursor/2;
|
|
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((symbolsPerSlot + (tN % 4 == 0))*samplesPerSymbol);
|
|
unRadioifyVector(rcvBuffer+readSz*2,rxVector);
|
|
GSM::Time tmpTime = rcvClock;
|
|
if (rcvClock.FN() >= 0) {
|
|
//LOG(DEBUG) << "FN: " << rcvClock.FN();
|
|
radioVector *rxBurst = NULL;
|
|
if (!loadTest)
|
|
rxBurst = new radioVector(rxVector,tmpTime);
|
|
else {
|
|
if (tN % 4 == 0)
|
|
rxBurst = new radioVector(*finalVec9,tmpTime);
|
|
else
|
|
rxBurst = new radioVector(*finalVec,tmpTime);
|
|
}
|
|
mReceiveFIFO.put(rxBurst);
|
|
}
|
|
mClock.incTN();
|
|
rcvClock.incTN();
|
|
//if (mReceiveFIFO.size() >= 16) mReceiveFIFO.wait(8);
|
|
//LOG(DEBUG) << "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();
|
|
}
|
|
|
|
if (readSz > 0) {
|
|
memcpy(rcvBuffer,rcvBuffer+2*readSz,sizeof(short)*2*(rcvCursor-readSz));
|
|
rcvCursor = rcvCursor-2*readSz;
|
|
}
|
|
}
|
|
|