aboutsummaryrefslogtreecommitdiffstats
path: root/Transceiver52M/DriveLoop.cpp
diff options
context:
space:
mode:
authorThomas Tsou <ttsou@vt.edu>2012-02-28 15:41:50 -0500
committerAlexander Chemeris <Alexander.Chemeris@gmail.com>2013-06-24 01:50:59 +0400
commit996f426c16d7cf804fc6692e4eb4c59589e82691 (patch)
tree1afb953de58ca51662f33df3abbfddf0838d47d2 /Transceiver52M/DriveLoop.cpp
parent711e6afddf46a3ad231521ff44836b0613a17743 (diff)
multi-arfcn, trx: split transceiver to handle multiple channels
This patch separates the 'Transceiver' into a multi-channel I/O component and single channel component. The latter may may have multiple instances. The receive FIFO is converted to a thread-safe queue. The 'TransceiverIO' continuously drives the receive and transmit loops. In this process, bursts are driven into thread-safe FIFO's and read from the priority queues. Filler bursts are inserted if no transmit data is available. Each 'Transceiver' instance attaches to the I/O object and creates its own threads and sockets, which include blocking on the receive FIFO for the attached channel. Each instance also handles its own control loop and clock indications. Signed-off-by: Thomas Tsou <ttsou@vt.edu>
Diffstat (limited to 'Transceiver52M/DriveLoop.cpp')
-rw-r--r--Transceiver52M/DriveLoop.cpp264
1 files changed, 264 insertions, 0 deletions
diff --git a/Transceiver52M/DriveLoop.cpp b/Transceiver52M/DriveLoop.cpp
new file mode 100644
index 0000000..997d009
--- /dev/null
+++ b/Transceiver52M/DriveLoop.cpp
@@ -0,0 +1,264 @@
+/*
+* Copyright 2008, 2009, 2010, 2012 Free Software Foundation, Inc.
+*
+* This software is distributed under the terms of the GNU Public License.
+* See the COPYING file in the main directory for details.
+*
+* This use of this software may be subject to additional restrictions.
+* See the LEGAL file in the main directory for details.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include "DriveLoop.h"
+#include <Logger.h>
+
+DriveLoop::DriveLoop(int wSamplesPerSymbol,
+ GSM::Time wTransmitLatency,
+ RadioInterface *wRadioInterface)
+{
+ mRadioDriveLoopThread = new Thread(32768);
+
+ mSamplesPerSymbol = wSamplesPerSymbol;
+ mRadioInterface = wRadioInterface;
+
+ GSM::Time startTime(random() % gHyperframe, 0);
+ mTransmitDeadlineClock = startTime;
+ mLatencyUpdateTime = startTime;
+ mTransmitLatency = wTransmitLatency;
+
+ mRadioInterface->getClock()->set(startTime);
+
+ // generate pulse and setup up signal processing library
+ gsmPulse = generateGSMPulse(2, mSamplesPerSymbol);
+ LOG(DEBUG) << "gsmPulse: " << *gsmPulse;
+ sigProcLibSetup(mSamplesPerSymbol);
+
+ txFullScale = mRadioInterface->fullScaleInputValue();
+
+ // initialize filler tables with dummy bursts, initialize other per-timeslot variables
+ for (int i = 0; i < 8; i++) {
+ signalVector* modBurst = modulateBurst(gDummyBurst, *gsmPulse,
+ 8 + (i % 4 == 0), mSamplesPerSymbol);
+ scaleVector(*modBurst, txFullScale);
+ for (int j = 0; j < 102; j++) {
+ for (int n = 0; n < CHAN_M; n++)
+ fillerTable[n][j][i] = new signalVector(*modBurst);
+ }
+ delete modBurst;
+
+ for (int n = 0; n < CHAN_M; n++) {
+ fillerModulus[n][i] = 26;
+ mChanType[n][i] = NONE;
+ }
+ }
+
+ mOn = false;
+}
+
+DriveLoop::~DriveLoop()
+{
+ delete gsmPulse;
+ sigProcLibDestroy();
+}
+
+void DriveLoop::start()
+{
+ mOn = true;
+ mRadioDriveLoopThread->start((void * (*)(void*))RadioDriveLoopAdapter, (void*) this);
+}
+
+void DriveLoop::pushRadioVector(GSM::Time &nowTime)
+{
+ int i;
+ radioVector *staleBurst;
+ radioVector *next;
+
+ for (i = 0; i < CHAN_M; i++) {
+ // dump stale bursts, if any
+ while (staleBurst = mTransmitPriorityQueue[i].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() % fillerModulus[i][TN];
+ delete fillerTable[i][modFN][TN];
+ fillerTable[i][modFN][TN] = staleBurst;
+ }
+
+ int TN = nowTime.TN();
+ int modFN = nowTime.FN() % fillerModulus[i][nowTime.TN()];
+
+ mTxBursts[i] = fillerTable[i][modFN][TN];
+ mIsFiller[i] = true;
+ mIsZero[i] = (mChanType[i][TN] == NONE);
+
+ // if queue contains data at the desired timestamp, stick it into FIFO
+ if (next = (radioVector*) mTransmitPriorityQueue[i].getCurrentBurst(nowTime)) {
+ LOG(DEBUG) << "transmitFIFO: wrote burst " << next << " at time: " << nowTime;
+ delete fillerTable[i][modFN][TN];
+ fillerTable[i][modFN][TN] = new signalVector(*(next));
+ mTxBursts[i] = next;
+ mIsFiller[i] = false;
+ }
+ }
+
+ mRadioInterface->driveTransmitRadio(mTxBursts, mIsZero);
+
+ for (i = 0; i < CHAN_M; i++) {
+ if (!mIsFiller[i])
+ delete mTxBursts[i];
+ }
+}
+
+void DriveLoop::setModulus(int channel, int timeslot)
+{
+ switch (mChanType[channel][timeslot]) {
+ case NONE:
+ case I:
+ case II:
+ case III:
+ case FILL:
+ fillerModulus[channel][timeslot] = 26;
+ break;
+ case IV:
+ case VI:
+ case V:
+ fillerModulus[channel][timeslot] = 51;
+ break;
+ //case V:
+ case VII:
+ fillerModulus[channel][timeslot] = 102;
+ break;
+ default:
+ break;
+ }
+}
+
+DriveLoop::CorrType DriveLoop::expectedCorrType(int channel, GSM::Time currTime)
+{
+ unsigned burstTN = currTime.TN();
+ unsigned burstFN = currTime.FN();
+
+ switch (mChanType[channel][burstTN]) {
+ case NONE:
+ return OFF;
+ break;
+ case FILL:
+ return IDLE;
+ break;
+ case I:
+ return TSC;
+ /*if (burstFN % 26 == 25)
+ return IDLE;
+ else
+ return TSC;*/
+ break;
+ case II:
+ if (burstFN % 2 == 1)
+ return IDLE;
+ else
+ return TSC;
+ break;
+ case III:
+ return TSC;
+ break;
+ case IV:
+ case VI:
+ return RACH;
+ break;
+ case V: {
+ int mod51 = burstFN % 51;
+ if ((mod51 <= 36) && (mod51 >= 14))
+ return RACH;
+ else if ((mod51 == 4) || (mod51 == 5))
+ return RACH;
+ else if ((mod51 == 45) || (mod51 == 46))
+ return RACH;
+ else
+ return TSC;
+ break;
+ }
+ case VII:
+ if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
+ return IDLE;
+ else
+ return TSC;
+ break;
+ case LOOPBACK:
+ if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
+ return IDLE;
+ else
+ return TSC;
+ break;
+ default:
+ return OFF;
+ break;
+ }
+}
+
+void DriveLoop::reset()
+{
+}
+
+void DriveLoop::driveReceiveFIFO()
+{
+ SoftVector *rxBurst = NULL;
+ int RSSI;
+ int TOA; // in 1/256 of a symbol
+ GSM::Time burstTime;
+
+ mRadioInterface->driveReceiveRadio();
+}
+
+/*
+ * Features a carefully controlled latency mechanism, to
+ * assure that transmit packets arrive at the radio/USRP
+ * before they need to be transmitted.
+ *
+ * Deadline clock indicates the burst that needs to be
+ * pushed into the FIFO right NOW. If transmit queue does
+ * not have a burst, stick in filler data.
+ */
+void DriveLoop::driveTransmitFIFO()
+{
+ int i;
+
+ if (!mOn)
+ return;
+
+ RadioClock *radioClock = (mRadioInterface->getClock());
+ while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
+ pushRadioVector(mTransmitDeadlineClock);
+ mTransmitDeadlineClock.incTN();
+ }
+
+ // FIXME -- This should not be a hard spin.
+ // But any delay here causes us to throw omni_thread_fatal.
+ //else radioClock->wait();
+}
+
+void *RadioDriveLoopAdapter(DriveLoop *transceiver)
+{
+ transceiver->setPriority();
+
+ while (1) {
+ transceiver->driveReceiveFIFO();
+ transceiver->driveTransmitFIFO();
+ pthread_testcancel();
+ }
+ return NULL;
+}