aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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)