aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Tsou <tom@tsou.cc>2013-10-29 18:34:16 -0400
committerThomas Tsou <tom@tsou.cc>2013-11-15 14:45:20 -0500
commit204a9f135ac2408dd62b55462ebe4b2d10be4f56 (patch)
tree80de459f10c23a103bf80172ba762f2577da0859
parent0169b310de2789cbe2ec9a447caae494fbea13d0 (diff)
Transceiver52M: Add multi channel transceiver support
This patch primarily addresses devices with multiple RF front end support. Currently device support is limited to UmTRX. Vectorize transceiver variables to allow multiple asynchronous threads on the upper layer with single downlink and uplink threads driving the UHD I/O interface synchronously. Signed-off-by: Thomas Tsou <tom@tsou.cc>
-rw-r--r--Transceiver52M/Transceiver.cpp403
-rw-r--r--Transceiver52M/Transceiver.h88
-rw-r--r--Transceiver52M/UHDDevice.cpp263
-rw-r--r--Transceiver52M/USRPDevice.cpp114
-rw-r--r--Transceiver52M/USRPDevice.h45
-rw-r--r--Transceiver52M/radioDevice.h33
-rw-r--r--Transceiver52M/radioInterface.cpp166
-rw-r--r--Transceiver52M/radioInterface.h41
-rw-r--r--Transceiver52M/radioInterfaceResamp.cpp37
-rw-r--r--Transceiver52M/radioVector.cpp15
-rw-r--r--Transceiver52M/radioVector.h10
-rw-r--r--Transceiver52M/runTransceiver.cpp37
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,
- &amp,
- &TOA,
- mMaxExpectedDelay,
- estimateChannel,
- &chanResponse,
- &chanOffset);
+ mTSC,
+ 5.0,
+ mSPSRx,
+ &amp,
+ &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, &amp, &TOA))
- mState.chanResponse[timeslot] = NULL;
+ if ((success = detectRACHBurst(*vectorBurst, 6.0, mSPSRx, &amp, &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)