blob: 587ade6a7f8bf4597d319dd8f4536c68f2ba9d79 [file] [log] [blame]
dburgessb3a0ca42011-10-12 07:44:40 +00001/*
2* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
3*
4* This software is distributed under the terms of the GNU Public License.
5* See the COPYING file in the main directory for details.
6*
7* This use of this software may be subject to additional restrictions.
8* See the LEGAL file in the main directory for details.
9
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22*/
23
dburgessb3a0ca42011-10-12 07:44:40 +000024#include <stdio.h>
Alexander Chemerise8905a02015-06-03 23:47:56 -040025#include <iomanip> // std::setprecision
dburgessb3a0ca42011-10-12 07:44:40 +000026#include "Transceiver.h"
27#include <Logger.h>
28
ttsou2173abf2012-08-08 00:51:31 +000029#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
dburgessb3a0ca42011-10-12 07:44:40 +000032
Alexander Chemerisd734e2d2013-06-16 14:30:58 +040033using namespace GSM;
34
kurtis.heimerlec842de2012-11-23 08:37:32 +000035#define USB_LATENCY_INTRVL 10,0
ttsou2173abf2012-08-08 00:51:31 +000036
37#if USE_UHD
kurtis.heimerlec842de2012-11-23 08:37:32 +000038# define USB_LATENCY_MIN 6,7
ttsou2173abf2012-08-08 00:51:31 +000039#else
kurtis.heimerlec842de2012-11-23 08:37:32 +000040# define USB_LATENCY_MIN 1,1
ttsou2173abf2012-08-08 00:51:31 +000041#endif
dburgessb3a0ca42011-10-12 07:44:40 +000042
Thomas Tsoufa3a7872013-10-17 21:23:34 -040043/* Number of running values use in noise average */
44#define NOISE_CNT 20
ttsoue8dde022012-12-06 15:43:55 +000045
Thomas Tsouf0782732013-10-29 15:55:47 -040046TransceiverState::TransceiverState()
Tom Tsoua4d1a412014-11-25 15:46:56 -080047 : mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT), mPower(0.0)
Thomas Tsouf0782732013-10-29 15:55:47 -040048{
49 for (int i = 0; i < 8; i++) {
50 chanType[i] = Transceiver::NONE;
51 fillerModulus[i] = 26;
52 chanResponse[i] = NULL;
53 DFEForward[i] = NULL;
54 DFEFeedback[i] = NULL;
55
56 for (int n = 0; n < 102; n++)
57 fillerTable[n][i] = NULL;
58 }
59}
60
61TransceiverState::~TransceiverState()
62{
63 for (int i = 0; i < 8; i++) {
64 delete chanResponse[i];
65 delete DFEForward[i];
66 delete DFEFeedback[i];
67
68 for (int n = 0; n < 102; n++)
69 delete fillerTable[n][i];
70 }
71}
72
Tom Tsou64ad7122015-05-19 18:26:31 -070073static BitVector *genRandNormalBurst(size_t tsc)
Thomas Tsouf0782732013-10-29 15:55:47 -040074{
Tom Tsou64ad7122015-05-19 18:26:31 -070075 if (tsc > 7)
76 return NULL;
Thomas Tsou15d743e2014-01-25 02:34:03 -050077
Tom Tsou64ad7122015-05-19 18:26:31 -070078 BitVector *bits = new BitVector(148);
Thomas Tsou15d743e2014-01-25 02:34:03 -050079
Tom Tsou64ad7122015-05-19 18:26:31 -070080 size_t i = 0;
81
82 /* Tail bits */
83 for (; i < 4; i++)
84 (*bits)[i] = 0;
85
86 /* Random bits */
87 for (; i < 61; i++)
88 (*bits)[i] = rand() % 2;
89
90 /* Training sequence */
Alexander Chemeris29660482015-05-24 19:13:38 -040091 for (int j = 0; i < 87; i++, j++)
92 (*bits)[i] = GSM::gTrainingSequence[tsc][j];
Tom Tsou64ad7122015-05-19 18:26:31 -070093
94 /* Random bits */
95 for (; i < 144; i++)
96 (*bits)[i] = rand() % 2;
97
98 /* Tail bits */
99 for (; i < 148; i++)
100 (*bits)[i] = 0;
101
102 return bits;
103}
104
105bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc)
106{
107 BitVector *bits;
108 signalVector *burst;
109
110 if ((sps != 1) && (sps != 4))
111 return false;
112
113 for (size_t n = 0; n < 8; n++) {
114 size_t guard = 8 + !(n % 4);
115 size_t len = sps == 4 ? 625 : 148 + guard;
116
117 for (size_t i = 0; i < 102; i++) {
118 switch (filler) {
119 case Transceiver::FILLER_DUMMY:
120 burst = modulateBurst(gDummyBurst, guard, sps);
121 break;
122 case Transceiver::FILLER_RAND:
123 bits = genRandNormalBurst(rtsc);
124 burst = modulateBurst(*bits, guard, sps);
125 delete bits;
126 break;
127 case Transceiver::FILLER_ZERO:
128 default:
129 burst = new signalVector(len);
130 }
131
132 scaleVector(*burst, scale);
133 fillerTable[i][n] = burst;
134 }
135
136 if (filler == Transceiver::FILLER_RAND)
137 chanType[n] = Transceiver::TSC;
Thomas Tsou15d743e2014-01-25 02:34:03 -0500138 }
Tom Tsou64ad7122015-05-19 18:26:31 -0700139
140 return false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400141}
142
dburgessb3a0ca42011-10-12 07:44:40 +0000143Transceiver::Transceiver(int wBasePort,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400144 const char *wTRXAddress,
145 size_t wSPS, size_t wChans,
146 GSM::Time wTransmitLatency,
147 RadioInterface *wRadioInterface,
148 double wRssiOffset)
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800149 : mBasePort(wBasePort), mAddr(wTRXAddress),
150 mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
151 mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
Alexander Chemerise8905a02015-06-03 23:47:56 -0400152 rssiOffset(wRssiOffset),
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800153 mSPSTx(wSPS), mSPSRx(1), mChans(wChans), mOn(false),
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700154 mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelay(0)
dburgessb3a0ca42011-10-12 07:44:40 +0000155{
dburgessb3a0ca42011-10-12 07:44:40 +0000156 txFullScale = mRadioInterface->fullScaleInputValue();
157 rxFullScale = mRadioInterface->fullScaleOutputValue();
dburgessb3a0ca42011-10-12 07:44:40 +0000158}
159
160Transceiver::~Transceiver()
161{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800162 stop();
163
dburgessb3a0ca42011-10-12 07:44:40 +0000164 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400165
Thomas Tsou204a9f12013-10-29 18:34:16 -0400166 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800167 mControlServiceLoopThreads[i]->cancel();
168 mControlServiceLoopThreads[i]->join();
169 delete mControlServiceLoopThreads[i];
170
Thomas Tsou204a9f12013-10-29 18:34:16 -0400171 mTxPriorityQueues[i].clear();
172 delete mCtrlSockets[i];
173 delete mDataSockets[i];
174 }
dburgessb3a0ca42011-10-12 07:44:40 +0000175}
Thomas Tsou83e06892013-08-20 16:10:01 -0400176
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800177/*
178 * Initialize transceiver
179 *
180 * Start or restart the control loop. Any further control is handled through the
181 * socket API. Randomize the central radio clock set the downlink burst
182 * counters. Note that the clock will not update until the radio starts, but we
183 * are still expected to report clock indications through control channel
184 * activity.
185 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700186bool Transceiver::init(int filler, size_t rtsc)
Thomas Tsou83e06892013-08-20 16:10:01 -0400187{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500188 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400189
Thomas Tsou204a9f12013-10-29 18:34:16 -0400190 if (!mChans) {
191 LOG(ALERT) << "No channels assigned";
192 return false;
193 }
194
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400195 if (!sigProcLibSetup(mSPSTx)) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400196 LOG(ALERT) << "Failed to initialize signal processing library";
197 return false;
198 }
199
Thomas Tsou204a9f12013-10-29 18:34:16 -0400200 mDataSockets.resize(mChans);
201 mCtrlSockets.resize(mChans);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400202 mControlServiceLoopThreads.resize(mChans);
203 mTxPriorityQueueServiceLoopThreads.resize(mChans);
204 mRxServiceLoopThreads.resize(mChans);
205
206 mTxPriorityQueues.resize(mChans);
207 mReceiveFIFO.resize(mChans);
208 mStates.resize(mChans);
209
Thomas Tsouccb73e12014-04-15 17:41:28 -0400210 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700211 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400212 mStates[0].mRetrans = true;
213
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800214 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400215 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500216 c_srcport = mBasePort + 2 * i + 1;
217 c_dstport = mBasePort + 2 * i + 101;
218 d_srcport = mBasePort + 2 * i + 2;
219 d_dstport = mBasePort + 2 * i + 102;
220
221 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
222 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400223 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400224
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800225 /* Randomize the central clock */
226 GSM::Time startTime(random() % gHyperframe, 0);
227 mRadioInterface->getClock()->set(startTime);
228 mTransmitDeadlineClock = startTime;
229 mLastClockUpdateTime = startTime;
230 mLatencyUpdateTime = startTime;
231
232 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400233 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800234 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400235 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800236 mControlServiceLoopThreads[i]->start((void * (*)(void*))
237 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400238
Tom Tsou64ad7122015-05-19 18:26:31 -0700239 if (i && filler == FILLER_DUMMY)
240 filler = FILLER_ZERO;
241
242 mStates[i].init(filler, mSPSTx, txFullScale, rtsc);
Thomas Tsou83e06892013-08-20 16:10:01 -0400243 }
244
245 return true;
246}
dburgessb3a0ca42011-10-12 07:44:40 +0000247
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800248/*
249 * Start the transceiver
250 *
251 * Submit command(s) to the radio device to commence streaming samples and
252 * launch threads to handle sample I/O. Re-synchronize the transmit burst
253 * counters to the central radio clock here as well.
254 */
255bool Transceiver::start()
256{
257 ScopedLock lock(mLock);
258
259 if (mOn) {
260 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300261 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800262 }
263
264 LOG(NOTICE) << "Starting the transceiver";
265
266 GSM::Time time = mRadioInterface->getClock()->get();
267 mTransmitDeadlineClock = time;
268 mLastClockUpdateTime = time;
269 mLatencyUpdateTime = time;
270
271 if (!mRadioInterface->start()) {
272 LOG(ALERT) << "Device failed to start";
273 return false;
274 }
275
276 /* Device is running - launch I/O threads */
277 mRxLowerLoopThread = new Thread(32768);
278 mTxLowerLoopThread = new Thread(32768);
279 mTxLowerLoopThread->start((void * (*)(void*))
280 TxLowerLoopAdapter,(void*) this);
281 mRxLowerLoopThread->start((void * (*)(void*))
282 RxLowerLoopAdapter,(void*) this);
283
284 /* Launch uplink and downlink burst processing threads */
285 for (size_t i = 0; i < mChans; i++) {
286 TransceiverChannel *chan = new TransceiverChannel(this, i);
287 mRxServiceLoopThreads[i] = new Thread(32768);
288 mRxServiceLoopThreads[i]->start((void * (*)(void*))
289 RxUpperLoopAdapter, (void*) chan);
290
291 chan = new TransceiverChannel(this, i);
292 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
293 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
294 TxUpperLoopAdapter, (void*) chan);
295 }
296
297 writeClockInterface();
298 mOn = true;
299 return true;
300}
301
302/*
303 * Stop the transceiver
304 *
305 * Perform stopping by disabling receive streaming and issuing cancellation
306 * requests to running threads. Most threads will timeout and terminate once
307 * device is disabled, but the transmit loop may block waiting on the central
308 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
309 * makes it to the thread cancellation point.
310 */
311void Transceiver::stop()
312{
313 ScopedLock lock(mLock);
314
315 if (!mOn)
316 return;
317
318 LOG(NOTICE) << "Stopping the transceiver";
319 mTxLowerLoopThread->cancel();
320 mRxLowerLoopThread->cancel();
321
322 for (size_t i = 0; i < mChans; i++) {
323 mRxServiceLoopThreads[i]->cancel();
324 mTxPriorityQueueServiceLoopThreads[i]->cancel();
325 }
326
327 LOG(INFO) << "Stopping the device";
328 mRadioInterface->stop();
329
330 for (size_t i = 0; i < mChans; i++) {
331 mRxServiceLoopThreads[i]->join();
332 mTxPriorityQueueServiceLoopThreads[i]->join();
333 delete mRxServiceLoopThreads[i];
334 delete mTxPriorityQueueServiceLoopThreads[i];
335
336 mTxPriorityQueues[i].clear();
337 }
338
339 mTxLowerLoopThread->join();
340 mRxLowerLoopThread->join();
341 delete mTxLowerLoopThread;
342 delete mRxLowerLoopThread;
343
344 mOn = false;
345 LOG(NOTICE) << "Transceiver stopped";
346}
347
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500348void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400349 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000350{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500351 signalVector *burst;
352 radioVector *radio_burst;
353
Thomas Tsou204a9f12013-10-29 18:34:16 -0400354 if (chan >= mTxPriorityQueues.size()) {
355 LOG(ALERT) << "Invalid channel " << chan;
356 return;
357 }
358
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500359 if (wTime.TN() > 7) {
360 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
361 return;
362 }
363
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500364 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
365 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000366
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500367 radio_burst = new radioVector(wTime, burst);
368
369 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000370}
371
Thomas Tsou15d743e2014-01-25 02:34:03 -0500372void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
373{
374 int TN, modFN;
375 TransceiverState *state = &mStates[chan];
376
377 TN = burst->getTime().TN();
378 modFN = burst->getTime().FN() % state->fillerModulus[TN];
379
380 delete state->fillerTable[modFN][TN];
381 state->fillerTable[modFN][TN] = burst->getVector();
382 burst->setVector(NULL);
383}
384
dburgessb3a0ca42011-10-12 07:44:40 +0000385void Transceiver::pushRadioVector(GSM::Time &nowTime)
386{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400387 int TN, modFN;
388 radioVector *burst;
389 TransceiverState *state;
390 std::vector<signalVector *> bursts(mChans);
391 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500392 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000393
Thomas Tsou204a9f12013-10-29 18:34:16 -0400394 for (size_t i = 0; i < mChans; i ++) {
395 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000396
Thomas Tsou204a9f12013-10-29 18:34:16 -0400397 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
398 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500399 if (state->mRetrans)
400 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500401 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400402 }
403
404 TN = nowTime.TN();
405 modFN = nowTime.FN() % state->fillerModulus[TN];
406
407 bursts[i] = state->fillerTable[modFN][TN];
408 zeros[i] = state->chanType[TN] == NONE;
409
410 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500411 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500412
413 if (state->mRetrans) {
414 updateFillerTable(i, burst);
415 } else {
416 burst->setVector(NULL);
417 filler[i] = false;
418 }
419
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500420 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400421 }
dburgessb3a0ca42011-10-12 07:44:40 +0000422 }
423
Thomas Tsou204a9f12013-10-29 18:34:16 -0400424 mRadioInterface->driveTransmitRadio(bursts, zeros);
425
Thomas Tsou15d743e2014-01-25 02:34:03 -0500426 for (size_t i = 0; i < mChans; i++) {
427 if (!filler[i])
428 delete bursts[i];
429 }
dburgessb3a0ca42011-10-12 07:44:40 +0000430}
431
Thomas Tsou204a9f12013-10-29 18:34:16 -0400432void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000433{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400434 TransceiverState *state = &mStates[chan];
435
436 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000437 case NONE:
438 case I:
439 case II:
440 case III:
441 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400442 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000443 break;
444 case IV:
445 case VI:
446 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400447 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000448 break;
449 //case V:
450 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400451 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000452 break;
ttsoufc40a842013-06-09 22:38:18 +0000453 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400454 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000455 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000456 default:
457 break;
458 }
459}
460
461
Thomas Tsou204a9f12013-10-29 18:34:16 -0400462Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
463 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000464{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400465 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000466 unsigned burstTN = currTime.TN();
467 unsigned burstFN = currTime.FN();
468
Thomas Tsou204a9f12013-10-29 18:34:16 -0400469 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000470 case NONE:
471 return OFF;
472 break;
473 case FILL:
474 return IDLE;
475 break;
476 case I:
477 return TSC;
478 /*if (burstFN % 26 == 25)
479 return IDLE;
480 else
481 return TSC;*/
482 break;
483 case II:
ttsou20642972013-03-27 22:00:25 +0000484 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000485 break;
486 case III:
487 return TSC;
488 break;
489 case IV:
490 case VI:
491 return RACH;
492 break;
493 case V: {
494 int mod51 = burstFN % 51;
495 if ((mod51 <= 36) && (mod51 >= 14))
496 return RACH;
497 else if ((mod51 == 4) || (mod51 == 5))
498 return RACH;
499 else if ((mod51 == 45) || (mod51 == 46))
500 return RACH;
501 else
502 return TSC;
503 break;
504 }
505 case VII:
506 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
507 return IDLE;
508 else
509 return TSC;
510 break;
ttsoufc40a842013-06-09 22:38:18 +0000511 case XIII: {
512 int mod52 = burstFN % 52;
513 if ((mod52 == 12) || (mod52 == 38))
514 return RACH;
515 else if ((mod52 == 25) || (mod52 == 51))
516 return IDLE;
517 else
518 return TSC;
519 break;
520 }
dburgessb3a0ca42011-10-12 07:44:40 +0000521 case LOOPBACK:
522 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
523 return IDLE;
524 else
525 return TSC;
526 break;
527 default:
528 return OFF;
529 break;
530 }
dburgessb3a0ca42011-10-12 07:44:40 +0000531}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400532
Thomas Tsou30421a72013-11-13 23:14:48 -0500533/*
534 * Detect RACH synchronization sequence within a burst. No equalization
535 * is used or available on the RACH channel.
536 */
537bool Transceiver::detectRACH(TransceiverState *state,
538 signalVector &burst,
539 complex &amp, float &toa)
540{
541 float threshold = 6.0;
542
543 return detectRACHBurst(burst, threshold, mSPSRx, &amp, &toa);
544}
545
546/*
547 * Detect normal burst training sequence midamble. Update equalization
548 * state information and channel estimate if necessary. Equalization
549 * is currently disabled.
550 */
Thomas Tsoua0179e32013-11-14 15:52:04 -0500551bool Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
Thomas Tsou30421a72013-11-13 23:14:48 -0500552 complex &amp, float &toa, GSM::Time &time)
553{
554 int tn = time.TN();
555 float chanOffset, threshold = 5.0;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500556 bool noise, needDFE = false, estimateChan = false;
Thomas Tsou30421a72013-11-13 23:14:48 -0500557 double elapsed = time - state->chanEstimateTime[tn];
558 signalVector *chanResp;
559
560 /* Check equalization update state */
Thomas Tsoufb827d02013-11-16 16:14:12 -0500561 if (needDFE && ((elapsed > 50) || (!state->chanResponse[tn]))) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500562 delete state->DFEForward[tn];
563 delete state->DFEFeedback[tn];
564 state->DFEForward[tn] = NULL;
565 state->DFEFeedback[tn] = NULL;
566
567 estimateChan = true;
568 }
569
570 /* Detect normal burst midambles */
571 if (!analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, &amp,
572 &toa, mMaxExpectedDelay, estimateChan,
573 &chanResp, &chanOffset)) {
574 return false;
575 }
576
Thomas Tsoua0179e32013-11-14 15:52:04 -0500577 noise = state->mNoiseLev;
578 state->SNRestimate[tn] = amp.norm2() / (noise * noise + 1.0);
Thomas Tsou30421a72013-11-13 23:14:48 -0500579
580 /* Set equalizer if unabled */
581 if (needDFE && estimateChan) {
582 state->chanResponse[tn] = chanResp;
583 state->chanRespOffset[tn] = chanOffset;
584 state->chanRespAmplitude[tn] = amp;
585
586 scaleVector(*chanResp, complex(1.0, 0.0) / amp);
587
588 designDFE(*chanResp, state->SNRestimate[tn],
589 7, &state->DFEForward[tn], &state->DFEFeedback[tn]);
590
591 state->chanEstimateTime[tn] = time;
592 }
593
594 return true;;
595}
596
597/*
598 * Demodulate GMSK burst using equalization if requested. Otherwise
599 * demodulate by direct rotation and soft slicing.
600 */
601SoftVector *Transceiver::demodulate(TransceiverState *state,
602 signalVector &burst, complex amp,
603 float toa, size_t tn, bool equalize)
604{
605 if (equalize) {
606 scaleVector(burst, complex(1.0, 0.0) / amp);
607 return equalizeBurst(burst,
608 toa - state->chanRespOffset[tn],
609 mSPSRx,
610 *state->DFEForward[tn],
611 *state->DFEFeedback[tn]);
612 }
613
614 return demodulateBurst(burst, mSPSRx, amp, toa);
615}
616
617/*
618 * Pull bursts from the FIFO and handle according to the slot
619 * and burst correlation type. Equalzation is currently disabled.
620 */
Alexander Chemerise8905a02015-06-03 23:47:56 -0400621SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400622 double &timingOffset, double &noise,
623 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000624{
Thomas Tsou30421a72013-11-13 23:14:48 -0500625 bool success, equalize = false;
626 complex amp;
627 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500628 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500629 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500630 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500631 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000632
Thomas Tsou30421a72013-11-13 23:14:48 -0500633 /* Blocking FIFO read */
634 radioVector *radio_burst = mReceiveFIFO[chan]->read();
635 if (!radio_burst)
636 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000637
Thomas Tsou30421a72013-11-13 23:14:48 -0500638 /* Set time and determine correlation type */
639 GSM::Time time = radio_burst->getTime();
640 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000641
Thomas Tsou30421a72013-11-13 23:14:48 -0500642 if ((type == OFF) || (type == IDLE)) {
643 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000644 return NULL;
645 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000646
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500647 /* Select the diversity channel with highest energy */
648 for (size_t i = 0; i < radio_burst->chans(); i++) {
649 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
650 if (pow > max) {
651 max = pow;
652 max_i = i;
653 }
654 avg += pow;
655 }
656
657 if (max_i < 0) {
658 LOG(ALERT) << "Received empty burst";
659 delete radio_burst;
660 return NULL;
661 }
662
Thomas Tsou30421a72013-11-13 23:14:48 -0500663 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500664 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500665 avg = sqrt(avg / radio_burst->chans());
Thomas Tsoua0179e32013-11-14 15:52:04 -0500666 state->mNoiseLev = state->mNoises.avg();
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400667
Thomas Tsou30421a72013-11-13 23:14:48 -0500668 /* Detect normal or RACH bursts */
669 if (type == TSC)
Thomas Tsoua0179e32013-11-14 15:52:04 -0500670 success = detectTSC(state, *burst, amp, toa, time);
Thomas Tsou30421a72013-11-13 23:14:48 -0500671 else
Thomas Tsoua0179e32013-11-14 15:52:04 -0500672 success = detectRACH(state, *burst, amp, toa);
Thomas Tsouf0782732013-10-29 15:55:47 -0400673
Tom Tsou577cd022015-05-18 13:57:54 -0700674 /* Update noise average if no bust detected or alert on error */
675 if (success <= 0) {
676 if (!success) {
677 state->mNoises.insert(avg);
678 } else if (success == -SIGERR_CLIP) {
679 LOG(ALERT) << "Clipping detected on RACH input";
680 } else if (success < 0) {
681 LOG(ALERT) << "Unhandled RACH error";
682 }
683
Thomas Tsou30421a72013-11-13 23:14:48 -0500684 delete radio_burst;
685 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000686 }
dburgessb3a0ca42011-10-12 07:44:40 +0000687
Thomas Tsou30421a72013-11-13 23:14:48 -0500688 /* Demodulate and set output info */
689 if (equalize && (type != TSC))
690 equalize = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000691
Thomas Tsoua0179e32013-11-14 15:52:04 -0500692 if (avg - state->mNoiseLev > 0.0)
693 bits = demodulate(state, *burst, amp, toa, time.TN(), equalize);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500694
Thomas Tsou30421a72013-11-13 23:14:48 -0500695 wTime = time;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400696 RSSI = 20.0 * log10(rxFullScale / avg);
697 timingOffset = toa / mSPSRx;
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400698 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
dburgessb3a0ca42011-10-12 07:44:40 +0000699
Thomas Tsou30421a72013-11-13 23:14:48 -0500700 delete radio_burst;
701
702 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000703}
704
dburgessb3a0ca42011-10-12 07:44:40 +0000705void Transceiver::reset()
706{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400707 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
708 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000709}
710
711
Thomas Tsou204a9f12013-10-29 18:34:16 -0400712void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000713{
dburgessb3a0ca42011-10-12 07:44:40 +0000714 int MAX_PACKET_LENGTH = 100;
715
716 // check control socket
717 char buffer[MAX_PACKET_LENGTH];
718 int msgLen = -1;
719 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400720
Thomas Tsou204a9f12013-10-29 18:34:16 -0400721 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000722
723 if (msgLen < 1) {
724 return;
725 }
726
727 char cmdcheck[4];
728 char command[MAX_PACKET_LENGTH];
729 char response[MAX_PACKET_LENGTH];
730
731 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400732
733 if (!chan)
734 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000735
736 if (strcmp(cmdcheck,"CMD")!=0) {
737 LOG(WARNING) << "bogus message on control interface";
738 return;
739 }
740 LOG(INFO) << "command is " << buffer;
741
742 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800743 stop();
744 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000745 }
746 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800747 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000748 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800749 else
dburgessb3a0ca42011-10-12 07:44:40 +0000750 sprintf(response,"RSP POWERON 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000751 }
752 else if (strcmp(command,"SETMAXDLY")==0) {
753 //set expected maximum time-of-arrival
754 int maxDelay;
755 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
756 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
757 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
758 }
759 else if (strcmp(command,"SETRXGAIN")==0) {
760 //set expected maximum time-of-arrival
761 int newGain;
762 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400763 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000764 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
765 }
766 else if (strcmp(command,"NOISELEV")==0) {
767 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500768 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000769 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500770 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000771 }
772 else {
773 sprintf(response,"RSP NOISELEV 1 0");
774 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500775 }
776 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800777 int power;
778 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
779 power = mRadioInterface->setPowerAttenuation(power, chan);
780 mStates[chan].mPower = power;
781 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000782 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500783 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800784 int power, step;
785 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
786 power = mStates[chan].mPower + step;
787 power = mRadioInterface->setPowerAttenuation(power, chan);
788 mStates[chan].mPower = power;
789 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000790 }
dburgessb3a0ca42011-10-12 07:44:40 +0000791 else if (strcmp(command,"RXTUNE")==0) {
792 // tune receiver
793 int freqKhz;
794 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500795 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400796 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000797 LOG(ALERT) << "RX failed to tune";
798 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
799 }
800 else
801 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
802 }
803 else if (strcmp(command,"TXTUNE")==0) {
804 // tune txmtr
805 int freqKhz;
806 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500807 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400808 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000809 LOG(ALERT) << "TX failed to tune";
810 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
811 }
812 else
813 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
814 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500815 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000816 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500817 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500818 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700819 if (mOn || (TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500820 sprintf(response, "RSP SETTSC 1 %d", TSC);
821 else if (chan && (TSC != mTSC))
822 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000823 else {
824 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400825 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400826 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000827 }
828 }
829 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700830 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000831 int corrCode;
832 int timeslot;
833 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
834 if ((timeslot < 0) || (timeslot > 7)) {
835 LOG(WARNING) << "bogus message on control interface";
836 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
837 return;
838 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400839 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
840 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000841 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
842
843 }
844 else {
845 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200846 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000847 }
848
Thomas Tsou204a9f12013-10-29 18:34:16 -0400849 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000850}
851
Thomas Tsou204a9f12013-10-29 18:34:16 -0400852bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000853{
dburgessb3a0ca42011-10-12 07:44:40 +0000854 char buffer[gSlotLen+50];
855
856 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400857 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000858
859 if (msgLen!=gSlotLen+1+4+1) {
860 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
861 return false;
862 }
863
864 int timeSlot = (int) buffer[0];
865 uint64_t frameNum = 0;
866 for (int i = 0; i < 4; i++)
867 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000868
dburgessb3a0ca42011-10-12 07:44:40 +0000869 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
870
871 int RSSI = (int) buffer[5];
872 static BitVector newBurst(gSlotLen);
873 BitVector::iterator itr = newBurst.begin();
874 char *bufferItr = buffer+6;
875 while (itr < newBurst.end())
876 *itr++ = *bufferItr++;
877
878 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400879
880 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000881
882 return true;
883
884
885}
dburgessb3a0ca42011-10-12 07:44:40 +0000886
Thomas Tsou204a9f12013-10-29 18:34:16 -0400887void Transceiver::driveReceiveRadio()
888{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400889 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400890 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400891 } else {
892 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
893 writeClockInterface();
894 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400895}
896
897void Transceiver::driveReceiveFIFO(size_t chan)
898{
dburgessb3a0ca42011-10-12 07:44:40 +0000899 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400900 double RSSI; // in dBFS
901 double dBm; // in dBm
902 double TOA; // in symbols
903 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400904 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000905 GSM::Time burstTime;
906
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400907 rxBurst = pullRadioVector(burstTime, RSSI, TOA, noise, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000908
909 if (rxBurst) {
Alexander Chemerise8905a02015-06-03 23:47:56 -0400910 dBm = RSSI+rssiOffset;
911 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000912
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400913 LOG(DEBUG) << std::fixed << std::right
914 << " time: " << burstTime
915 << " RSSI: " << std::setw(5) << std::setprecision(1) << RSSI << "dBFS/" << std::setw(6) << -dBm << "dBm"
916 << " noise: " << std::setw(5) << std::setprecision(1) << noise << "dBFS/" << std::setw(6) << -(noise+rssiOffset) << "dBm"
917 << " TOA: " << std::setw(5) << std::setprecision(2) << TOA
918 << " bits: " << *rxBurst;
919
dburgessb3a0ca42011-10-12 07:44:40 +0000920 char burstString[gSlotLen+10];
921 burstString[0] = burstTime.TN();
922 for (int i = 0; i < 4; i++)
923 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400924 burstString[5] = (int)dBm;
925 burstString[6] = (TOAint >> 8) & 0x0ff;
926 burstString[7] = TOAint & 0x0ff;
dburgessb3a0ca42011-10-12 07:44:40 +0000927 SoftVector::iterator burstItr = rxBurst->begin();
928
929 for (unsigned int i = 0; i < gSlotLen; i++) {
930 burstString[8+i] =(char) round((*burstItr++)*255.0);
931 }
932 burstString[gSlotLen+9] = '\0';
933 delete rxBurst;
934
Thomas Tsou204a9f12013-10-29 18:34:16 -0400935 mDataSockets[chan]->write(burstString,gSlotLen+10);
dburgessb3a0ca42011-10-12 07:44:40 +0000936 }
dburgessb3a0ca42011-10-12 07:44:40 +0000937}
938
Thomas Tsou204a9f12013-10-29 18:34:16 -0400939void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000940{
941
942 /**
943 Features a carefully controlled latency mechanism, to
944 assure that transmit packets arrive at the radio/USRP
945 before they need to be transmitted.
946
947 Deadline clock indicates the burst that needs to be
948 pushed into the FIFO right NOW. If transmit queue does
949 not have a burst, stick in filler data.
950 */
951
952
953 RadioClock *radioClock = (mRadioInterface->getClock());
954
955 if (mOn) {
956 //radioClock->wait(); // wait until clock updates
957 LOG(DEBUG) << "radio clock " << radioClock->get();
958 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
959 // if underrun, then we're not providing bursts to radio/USRP fast
960 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400961 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000962 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000963 // only update latency at the defined frame interval
964 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000965 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
966 LOG(INFO) << "new latency: " << mTransmitLatency;
967 mLatencyUpdateTime = radioClock->get();
968 }
969 }
970 else {
971 // if underrun hasn't occurred in the last sec (216 frames) drop
972 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000973 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000974 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
975 mTransmitLatency.decTN();
976 LOG(INFO) << "reduced latency: " << mTransmitLatency;
977 mLatencyUpdateTime = radioClock->get();
978 }
979 }
980 }
dburgessb3a0ca42011-10-12 07:44:40 +0000981 }
dburgessb3a0ca42011-10-12 07:44:40 +0000982 // time to push burst to transmit FIFO
983 pushRadioVector(mTransmitDeadlineClock);
984 mTransmitDeadlineClock.incTN();
985 }
dburgessb3a0ca42011-10-12 07:44:40 +0000986 }
Thomas Tsou92c16df2013-09-28 18:04:19 -0400987
988 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +0000989}
990
991
992
993void Transceiver::writeClockInterface()
994{
995 char command[50];
996 // FIXME -- This should be adaptive.
997 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
998
999 LOG(INFO) << "ClockInterface: sending " << command;
1000
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001001 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001002
1003 mLastClockUpdateTime = mTransmitDeadlineClock;
1004
Thomas Tsou92c16df2013-09-28 18:04:19 -04001005}
dburgessb3a0ca42011-10-12 07:44:40 +00001006
Thomas Tsou204a9f12013-10-29 18:34:16 -04001007void *RxUpperLoopAdapter(TransceiverChannel *chan)
1008{
1009 Transceiver *trx = chan->trx;
1010 size_t num = chan->num;
1011
1012 delete chan;
1013
Thomas Tsou7553aa92013-11-08 12:50:03 -05001014 trx->setPriority(0.42);
1015
Thomas Tsou204a9f12013-10-29 18:34:16 -04001016 while (1) {
1017 trx->driveReceiveFIFO(num);
1018 pthread_testcancel();
1019 }
1020 return NULL;
1021}
1022
1023void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001024{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001025 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001026
dburgessb3a0ca42011-10-12 07:44:40 +00001027 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001028 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001029 pthread_testcancel();
1030 }
1031 return NULL;
1032}
1033
Thomas Tsou204a9f12013-10-29 18:34:16 -04001034void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001035{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001036 transceiver->setPriority(0.44);
1037
Thomas Tsou92c16df2013-09-28 18:04:19 -04001038 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001039 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001040 pthread_testcancel();
1041 }
1042 return NULL;
1043}
1044
Thomas Tsou204a9f12013-10-29 18:34:16 -04001045void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001046{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001047 Transceiver *trx = chan->trx;
1048 size_t num = chan->num;
1049
1050 delete chan;
1051
dburgessb3a0ca42011-10-12 07:44:40 +00001052 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001053 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001054 pthread_testcancel();
1055 }
1056 return NULL;
1057}
1058
Thomas Tsou204a9f12013-10-29 18:34:16 -04001059void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001060{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001061 Transceiver *trx = chan->trx;
1062 size_t num = chan->num;
1063
1064 delete chan;
1065
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001066 trx->setPriority(0.40);
1067
dburgessb3a0ca42011-10-12 07:44:40 +00001068 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001069 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001070 pthread_testcancel();
1071 }
1072 return NULL;
1073}