transceiver: separate I/O portion of radio interface implementation
Move push and pull of buffers into a dedicated file. This will allow us to swap out resampling, non-resampling, and possibly floating point device interfaces while presenting a single floating point abstration in the interface itself. Signed-off-by: Thomas Tsou <ttsou@vt.edu> git-svn-id: http://wush.net/svn/range/software/public/openbts/trunk@2670 19bc5d8c-e614-43d4-8b26-e1612bc8e597
This commit is contained in:
parent
8aea56e15f
commit
9b557835d5
|
@ -46,7 +46,8 @@ COMMON_SOURCES = \
|
||||||
DummyLoad.cpp
|
DummyLoad.cpp
|
||||||
|
|
||||||
libtransceiver_la_SOURCES = \
|
libtransceiver_la_SOURCES = \
|
||||||
$(COMMON_SOURCES)
|
$(COMMON_SOURCES) \
|
||||||
|
radioIO.cpp
|
||||||
|
|
||||||
noinst_PROGRAMS = \
|
noinst_PROGRAMS = \
|
||||||
USRPping \
|
USRPping \
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* Radio device I/O interface
|
||||||
|
* Written by Thomas Tsou <ttsou@vt.edu>
|
||||||
|
*
|
||||||
|
* Copyright 2011 Free Software Foundation, Inc.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
* See the COPYING file in the main directory for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <radioInterface.h>
|
||||||
|
#include <Logger.h>
|
||||||
|
|
||||||
|
/* Device side buffers */
|
||||||
|
static short rx_buf[OUTCHUNK * 2 * 2];
|
||||||
|
static short tx_buf[INCHUNK * 2 * 2];
|
||||||
|
|
||||||
|
/* Complex float to short conversion */
|
||||||
|
static int float_to_short(short *shrt_out, float *flt_in, int num)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
shrt_out[2 * i + 0] = flt_in[2 * i + 0];
|
||||||
|
shrt_out[2 * i + 1] = flt_in[2 * i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Comlpex short to float conversion */
|
||||||
|
static int short_to_float(float *flt_out, short *shrt_in, int num)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
flt_out[2 * i + 0] = shrt_in[2 * i + 0];
|
||||||
|
flt_out[2 * i + 1] = shrt_in[2 * i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Receive a timestamped chunk from the device */
|
||||||
|
void RadioInterface::pullBuffer()
|
||||||
|
{
|
||||||
|
bool local_underrun;
|
||||||
|
|
||||||
|
/* Read samples. Fail if we don't get what we want. */
|
||||||
|
int num_rd = mRadio->readSamples(rx_buf, OUTCHUNK, &overrun,
|
||||||
|
readTimestamp, &local_underrun);
|
||||||
|
|
||||||
|
LOG(DEBUG) << "Rx read " << num_rd << " samples from device";
|
||||||
|
assert(num_rd == OUTCHUNK);
|
||||||
|
|
||||||
|
underrun |= local_underrun;
|
||||||
|
readTimestamp += (TIMESTAMP) num_rd;
|
||||||
|
|
||||||
|
short_to_float(rcvBuffer + 2 * rcvCursor, rx_buf, num_rd);
|
||||||
|
rcvCursor += num_rd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send timestamped chunk to the device with arbitrary size */
|
||||||
|
void RadioInterface::pushBuffer()
|
||||||
|
{
|
||||||
|
if (sendCursor < INCHUNK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float_to_short(tx_buf, sendBuffer, sendCursor);
|
||||||
|
|
||||||
|
/* Write samples. Fail if we don't get what we want. */
|
||||||
|
int num_smpls = mRadio->writeSamples(tx_buf,
|
||||||
|
sendCursor,
|
||||||
|
&underrun,
|
||||||
|
writeTimestamp);
|
||||||
|
assert(num_smpls == sendCursor);
|
||||||
|
|
||||||
|
writeTimestamp += (TIMESTAMP) num_smpls;
|
||||||
|
sendCursor = 0;
|
||||||
|
}
|
|
@ -25,6 +25,8 @@
|
||||||
#include "radioInterface.h"
|
#include "radioInterface.h"
|
||||||
#include <Logger.h>
|
#include <Logger.h>
|
||||||
|
|
||||||
|
bool started = false;
|
||||||
|
|
||||||
RadioInterface::RadioInterface(RadioDevice *wRadio,
|
RadioInterface::RadioInterface(RadioDevice *wRadio,
|
||||||
int wReceiveOffset,
|
int wReceiveOffset,
|
||||||
int wRadioOversampling,
|
int wRadioOversampling,
|
||||||
|
@ -73,94 +75,40 @@ void RadioInterface::setPowerAttenuation(double atten)
|
||||||
powerScaling = 1.0/sqrt(pow(10, (digAtten/10.0)));
|
powerScaling = 1.0/sqrt(pow(10, (digAtten/10.0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
short *RadioInterface::radioifyVector(signalVector &wVector,
|
int RadioInterface::radioifyVector(signalVector &wVector,
|
||||||
short *retVector,
|
float *retVector,
|
||||||
float scale,
|
float scale,
|
||||||
bool zeroOut)
|
bool zero)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
signalVector::iterator itr = wVector.begin();
|
signalVector::iterator itr = wVector.begin();
|
||||||
short *shortItr = retVector;
|
|
||||||
if (zeroOut) {
|
if (zero) {
|
||||||
while (itr < wVector.end()) {
|
memset(retVector, 0, wVector.size() * 2 * sizeof(float));
|
||||||
*shortItr++ = 0;
|
return wVector.size();
|
||||||
*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;
|
for (i = 0; i < wVector.size(); i++) {
|
||||||
|
retVector[2 * i + 0] = itr->real() * scale;
|
||||||
|
retVector[2 * i + 1] = itr->imag() * scale;
|
||||||
|
itr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wVector.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioInterface::unRadioifyVector(short *shortVector, signalVector& newVector)
|
int RadioInterface::unRadioifyVector(float *floatVector,
|
||||||
|
signalVector& newVector)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
signalVector::iterator itr = newVector.begin();
|
signalVector::iterator itr = newVector.begin();
|
||||||
short *shortItr = shortVector;
|
|
||||||
while (itr < newVector.end()) {
|
for (i = 0; i < newVector.size(); i++) {
|
||||||
*itr++ = Complex<float>(*shortItr,*(shortItr+1));
|
*itr++ = Complex<float>(floatVector[2 * i + 0],
|
||||||
shortItr += 2;
|
floatVector[2 * i + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
return newVector.size();
|
||||||
|
|
||||||
|
|
||||||
bool started = false;
|
|
||||||
|
|
||||||
void RadioInterface::pushBuffer(void) {
|
|
||||||
|
|
||||||
if (sendCursor < 2*INCHUNK*samplesPerSymbol) return;
|
|
||||||
|
|
||||||
// send resampleVector
|
|
||||||
int samplesWritten = mRadio->writeSamples(sendBuffer,
|
|
||||||
INCHUNK*samplesPerSymbol,
|
|
||||||
&underrun,
|
|
||||||
writeTimestamp);
|
|
||||||
|
|
||||||
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)
|
bool RadioInterface::tuneTx(double freq)
|
||||||
|
@ -186,8 +134,8 @@ void RadioInterface::start()
|
||||||
mRadio->updateAlignment(writeTimestamp-10000);
|
mRadio->updateAlignment(writeTimestamp-10000);
|
||||||
mRadio->updateAlignment(writeTimestamp-10000);
|
mRadio->updateAlignment(writeTimestamp-10000);
|
||||||
|
|
||||||
sendBuffer = new short[2*2*INCHUNK*samplesPerSymbol];
|
sendBuffer = new float[2*2*INCHUNK*samplesPerSymbol];
|
||||||
rcvBuffer = new short[2*2*OUTCHUNK*samplesPerSymbol];
|
rcvBuffer = new float[2*2*OUTCHUNK*samplesPerSymbol];
|
||||||
|
|
||||||
mOn = true;
|
mOn = true;
|
||||||
|
|
||||||
|
@ -211,9 +159,9 @@ void RadioInterface::driveTransmitRadio(signalVector &radioBurst, bool zeroBurst
|
||||||
|
|
||||||
if (!mOn) return;
|
if (!mOn) return;
|
||||||
|
|
||||||
radioifyVector(radioBurst, sendBuffer+sendCursor, powerScaling, zeroBurst);
|
radioifyVector(radioBurst, sendBuffer + 2 * sendCursor, powerScaling, zeroBurst);
|
||||||
|
|
||||||
sendCursor += (radioBurst.size()*2);
|
sendCursor += radioBurst.size();
|
||||||
|
|
||||||
pushBuffer();
|
pushBuffer();
|
||||||
}
|
}
|
||||||
|
@ -229,7 +177,7 @@ void RadioInterface::driveReceiveRadio() {
|
||||||
GSM::Time rcvClock = mClock.get();
|
GSM::Time rcvClock = mClock.get();
|
||||||
rcvClock.decTN(receiveOffset);
|
rcvClock.decTN(receiveOffset);
|
||||||
unsigned tN = rcvClock.TN();
|
unsigned tN = rcvClock.TN();
|
||||||
int rcvSz = rcvCursor/2;
|
int rcvSz = rcvCursor;
|
||||||
int readSz = 0;
|
int readSz = 0;
|
||||||
const int symbolsPerSlot = gSlotLen + 8;
|
const int symbolsPerSlot = gSlotLen + 8;
|
||||||
|
|
||||||
|
@ -263,9 +211,9 @@ void RadioInterface::driveReceiveRadio() {
|
||||||
tN = rcvClock.TN();
|
tN = rcvClock.TN();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readSz > 0) {
|
if (readSz > 0) {
|
||||||
memcpy(rcvBuffer,rcvBuffer+2*readSz,sizeof(short)*2*(rcvCursor-readSz));
|
rcvCursor -= readSz;
|
||||||
rcvCursor = rcvCursor-2*readSz;
|
memmove(rcvBuffer,rcvBuffer+2*readSz,sizeof(float) * 2 * rcvCursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,10 +37,10 @@ private:
|
||||||
|
|
||||||
RadioDevice *mRadio; ///< the USRP object
|
RadioDevice *mRadio; ///< the USRP object
|
||||||
|
|
||||||
short *sendBuffer; //[2*2*INCHUNK];
|
float *sendBuffer;
|
||||||
unsigned sendCursor;
|
unsigned sendCursor;
|
||||||
|
|
||||||
short *rcvBuffer; //[2*2*OUTCHUNK];
|
float *rcvBuffer;
|
||||||
unsigned rcvCursor;
|
unsigned rcvCursor;
|
||||||
|
|
||||||
bool underrun; ///< indicates writes to USRP are too slow
|
bool underrun; ///< indicates writes to USRP are too slow
|
||||||
|
@ -64,13 +64,13 @@ private:
|
||||||
signalVector *finalVec, *finalVec9;
|
signalVector *finalVec, *finalVec9;
|
||||||
|
|
||||||
/** format samples to USRP */
|
/** format samples to USRP */
|
||||||
short *radioifyVector(signalVector &wVector,
|
int radioifyVector(signalVector &wVector,
|
||||||
short *shortVector,
|
float *floatVector,
|
||||||
float scale,
|
float scale,
|
||||||
bool zeroOut);
|
bool zero);
|
||||||
|
|
||||||
/** format samples from USRP */
|
/** format samples from USRP */
|
||||||
void unRadioifyVector(short *shortVector, signalVector &wVector);
|
int unRadioifyVector(float *floatVector, signalVector &wVector);
|
||||||
|
|
||||||
/** push GSM bursts into the transmit buffer */
|
/** push GSM bursts into the transmit buffer */
|
||||||
void pushBuffer(void);
|
void pushBuffer(void);
|
||||||
|
|
Loading…
Reference in New Issue